diff --git a/.eslintrc.js b/.eslintrc.js index 184b042813d..5b69afa019f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -61,6 +61,7 @@ module.exports = { 'no-useless-escape': 'off', 'no-console': 'error', 'jsdoc/check-types': 'off', + 'jsdoc/no-defaults': 'off', 'jsdoc/newline-after-description': 'off', 'jsdoc/require-jsdoc': 'off', 'jsdoc/require-param': 'off', @@ -83,27 +84,52 @@ module.exports = { files: key + '/**/*.js', rules: { 'prebid/validate-imports': ['error', allowedModules[key]], - 'prebid/no-innerText': ['error', allowedModules[key]], 'no-restricted-globals': [ 'error', { name: 'require', message: 'use import instead' } + ], + 'prebid/no-global': [ + 'error', + ...['localStorage', 'sessionStorage'].map(name => ({name, message: 'use storageManager instead'})), + { + name: 'XMLHttpRequest', + message: 'use ajax.js instead' + }, + ], + 'prebid/no-member': [ + 'error', + { + name: 'cookie', + target: 'document', + message: 'use storageManager instead' + }, + { + name: 'sendBeacon', + target: 'navigator', + message: 'use ajax.js instead' + }, + ...['outerText', 'innerText'].map(name => ({ + name, + message: 'use .textContent instead' + })) ] } })).concat([{ // code in other packages (such as plugins/eslint) is not "seen" by babel and its parser will complain. files: 'plugins/*/**/*.js', parser: 'esprima' - }, - { + }, { files: '**BidAdapter.js', rules: { 'no-restricted-imports': [ 'error', { - patterns: ["**/src/events.js", - "**/src/adloader.js"] + patterns: [ + '**/src/events.js', + '**/src/adloader.js' + ] } ] } diff --git a/.github/workflows/jscpd.yml b/.github/workflows/jscpd.yml index 21e7aadf97c..315fbb2ff09 100644 --- a/.github/workflows/jscpd.yml +++ b/.github/workflows/jscpd.yml @@ -101,7 +101,7 @@ jobs: const filteredReport = JSON.parse(fs.readFileSync('filtered-jscpd-report.json', 'utf8')); let comment = "Whoa there, partner! 🌵🤠 We wrangled some duplicated code in your PR:\n\n"; function link(dup) { - return `https://github.com/${{ github.event.repository.full_name }}/blob/${{ github.event.pull_request.head.sha }}/${dup.name}#L${dup.start}-L${dup.end - 1}` + return `https://github.com/${{ github.event.repository.full_name }}/blob/${{ github.event.pull_request.head.sha }}/${dup.name}#L${dup.start + 1}-L${dup.end - 1}` } filteredReport.forEach(duplication => { const firstFile = duplication.firstFile; @@ -109,7 +109,7 @@ jobs: const lines = duplication.lines; comment += `- [\`${firstFile.name}\`](${link(firstFile)}) has ${lines} duplicated lines with [\`${secondFile.name}\`](${link(secondFile)})\n`; }); - comment += "\nReducing code duplication by importing common functions from a library not only makes our code cleaner but also easier to maintain. Please move the common code from both files into a library and import it in each. Keep up the great work! 🚀"; + comment += "\nReducing code duplication by importing common functions from a library not only makes our code cleaner but also easier to maintain. Please move the common code from both files into a library and import it in each. We hate that we have to mention this, however, commits designed to hide from this utility by renaming variables or reordering an object are poor conduct. We will not look upon them kindly! Keep up the great work! 🚀"; github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml new file mode 100644 index 00000000000..034e0eddee7 --- /dev/null +++ b/.github/workflows/linter.yml @@ -0,0 +1,107 @@ +name: Check for linter warnings / exceptions + +on: + pull_request_target: + branches: + - master + +jobs: + check-linter: + runs-on: ubuntu-latest + + steps: + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.base.sha }} + + - name: Fetch base and target branches + run: | + git fetch origin +refs/heads/${{ github.event.pull_request.base.ref }}:refs/remotes/origin/${{ github.event.pull_request.base.ref }} + git fetch origin +refs/pull/${{ github.event.pull_request.number }}/merge:refs/remotes/pull/${{ github.event.pull_request.number }}/merge + + - name: Install dependencies + run: npm ci + + - name: Get the diff + run: git diff --name-only origin/${{ github.event.pull_request.base.ref }}...refs/remotes/pull/${{ github.event.pull_request.number }}/merge | grep '^\(modules\|src\|libraries\|creative\)/.*\.js$' > __changed_files.txt || true + + - name: Run linter on base branch + run: npx eslint --no-inline-config --format json $(cat __changed_files.txt | xargs stat --printf '%n\n' 2> /dev/null) > __base.json || true + + - name: Check out PR + run: git checkout ${{ github.event.pull_request.head.sha }} + + - name: Run linter on PR + run: npx eslint --no-inline-config --format json $(cat __changed_files.txt | xargs stat --printf '%n\n' 2> /dev/null) > __pr.json || true + + - name: Compare them and post comment if necessary + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const path = require('path'); + const process = require('process'); + + function parse(fn) { + return JSON.parse(fs.readFileSync(fn)).reduce((memo, data) => { + const file = path.relative(process.cwd(), data.filePath); + if (!memo.hasOwnProperty(file)) { memo[file] = { errors: 0, warnings: 0} } + data.messages.forEach(({severity}) => { + memo[file][severity > 1 ? 'errors' : 'warnings']++; + }); + return memo; + }, {}) + } + + function mkDiff(old, new_) { + const files = Object.fromEntries( + Object.entries(new_) + .map(([file, {errors, warnings}]) => { + const {errors: oldErrors, warnings: oldWarnings} = old[file] || {}; + return [file, {errors: Math.max(0, errors - (oldErrors ?? 0)), warnings: Math.max(0, warnings - (oldWarnings ?? 0))}] + }) + .filter(([_, {errors, warnings}]) => errors > 0 || warnings > 0) + ) + return Object.values(files).reduce((memo, {warnings, errors}) => { + memo.errors += errors; + memo.warnings += warnings; + return memo; + }, {errors: 0, warnings: 0, files}) + } + + function mkComment({errors, warnings, files}) { + function pl(noun, number) { + return noun + (number === 1 ? '' : 's') + } + if (errors === 0 && warnings === 0) return; + const summary = []; + if (errors) summary.push(`**${errors}** linter ${pl('error', errors)}`) + if (warnings) summary.push(`**${warnings}** linter ${pl('warning', warnings)}`) + let cm = `Tread carefully! This PR adds ${summary.join(' and ')} (possibly disabled through directives):\n\n`; + Object.entries(files).forEach(([file, {errors, warnings}]) => { + const summary = []; + if (errors) summary.push(`+${errors} ${pl('error', errors)}`); + if (warnings) summary.push(`+${warnings} ${pl('warning', warnings)}`) + cm += ` * \`${file}\` (${summary.join(', ')})\n` + }) + return cm; + } + + const [base, pr] = ['__base.json', '__pr.json'].map(parse); + const comment = mkComment(mkDiff(base, pr)); + + if (comment) { + github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: comment + }); + } diff --git a/creative/constants.js b/creative/constants.js index d02c4c9d5e4..5f807c69f87 100644 --- a/creative/constants.js +++ b/creative/constants.js @@ -1,6 +1,7 @@ // eslint-disable-next-line prebid/validate-imports -import { AD_RENDER_FAILED_REASON, EVENTS, MESSAGES } from '../src/constants.js'; +import {AD_RENDER_FAILED_REASON, EVENTS, MESSAGES} from '../src/constants.js'; +export {PB_LOCATOR} from '../src/constants.js'; export const MESSAGE_REQUEST = MESSAGES.REQUEST; export const MESSAGE_RESPONSE = MESSAGES.RESPONSE; export const MESSAGE_EVENT = MESSAGES.EVENT; diff --git a/creative/crossDomain.js b/creative/crossDomain.js index a851885bfc0..d3524f61d4b 100644 --- a/creative/crossDomain.js +++ b/creative/crossDomain.js @@ -1,9 +1,11 @@ import { ERROR_EXCEPTION, - EVENT_AD_RENDER_FAILED, EVENT_AD_RENDER_SUCCEEDED, + EVENT_AD_RENDER_FAILED, + EVENT_AD_RENDER_SUCCEEDED, MESSAGE_EVENT, MESSAGE_REQUEST, - MESSAGE_RESPONSE + MESSAGE_RESPONSE, + PB_LOCATOR } from './constants.js'; const mkFrame = (() => { @@ -24,14 +26,27 @@ const mkFrame = (() => { }; })(); +function isPrebidWindow(win) { + return !!win.frames[PB_LOCATOR]; +} + export function renderer(win) { + let target = win.parent; + try { + while (target !== win.top && !isPrebidWindow(target)) { + target = target.parent; + } + if (!isPrebidWindow(target)) target = win.parent; + } catch (e) { + } + return function ({adId, pubUrl, clickUrl}) { const pubDomain = new URL(pubUrl, window.location).origin; function sendMessage(type, payload, responseListener) { const channel = new MessageChannel(); channel.port1.onmessage = guard(responseListener); - win.parent.postMessage(JSON.stringify(Object.assign({message: type, adId}, payload)), pubDomain, [channel.port2]); + target.postMessage(JSON.stringify(Object.assign({message: type, adId}, payload)), pubDomain, [channel.port2]); } function onError(e) { @@ -77,7 +92,7 @@ export function renderer(win) { W.Promise.resolve(W.render(data, {sendMessage, mkFrame}, win)).then( () => sendMessage(MESSAGE_EVENT, {event: EVENT_AD_RENDER_SUCCEEDED}), onError - ) + ); }); win.document.body.appendChild(renderer); } diff --git a/integrationExamples/gpt/x-domain/creative.html b/integrationExamples/gpt/x-domain/creative.html index 0d0f63cbf1b..63842b00882 100644 --- a/integrationExamples/gpt/x-domain/creative.html +++ b/integrationExamples/gpt/x-domain/creative.html @@ -2,7 +2,7 @@ // creative will be rendered, e.g. GAM delivering a SafeFrame // this code is autogenerated, also available in 'build/creative/creative.js' - + + + + `; +} + +export function getAd(bid) { + let ad, adUrl, vastXml, vastUrl; + + switch (deepAccess(bid, 'ext.prebid.type')) { + case VIDEO: + if (bid.adm.substr(0, 4) === 'http') { + vastUrl = bid.adm; + } else { + vastXml = bid.adm; + }; + break; + default: + if (bid.adm && bid.nurl) { + ad = bid.adm; + ad += createTrackPixelHtml(decodeURIComponent(bid.nurl)); + } else if (bid.adm) { + ad = bid.adm; + } else if (bid.nurl) { + adUrl = bid.nurl; + }; + } + + return {ad, adUrl, vastXml, vastUrl}; +} + +export function getSiteObj() { + const refInfo = (getRefererInfo && getRefererInfo()) || {}; + + return { + page: refInfo.page, + ref: refInfo.ref, + domain: refInfo.domain + } +} diff --git a/libraries/targetVideoUtils/constants.js b/libraries/targetVideoUtils/constants.js new file mode 100644 index 00000000000..8ce94c0eaeb --- /dev/null +++ b/libraries/targetVideoUtils/constants.js @@ -0,0 +1,23 @@ +const SOURCE = 'pbjs'; +const GVLID = 786; +const MARGIN = 1.35; +const BIDDER_CODE = 'targetVideo'; + +const TIME_TO_LIVE = 300; +const BANNER_ENDPOINT_URL = 'https://ib.adnxs.com/ut/v3/prebid'; +const VIDEO_ENDPOINT_URL = 'https://pbs.prebrid.tv/openrtb2/auction'; +const VIDEO_PARAMS = [ + 'api', 'linearity', 'maxduration', 'mimes', 'minduration', + 'plcmt', 'playbackmethod', 'protocols', 'startdelay' +]; + +export { + SOURCE, + GVLID, + MARGIN, + BIDDER_CODE, + TIME_TO_LIVE, + BANNER_ENDPOINT_URL, + VIDEO_ENDPOINT_URL, + VIDEO_PARAMS +} diff --git a/libraries/teqblazeUtils/bidderUtils.js b/libraries/teqblazeUtils/bidderUtils.js index 42db3194308..ce061ac7f3c 100644 --- a/libraries/teqblazeUtils/bidderUtils.js +++ b/libraries/teqblazeUtils/bidderUtils.js @@ -188,20 +188,24 @@ export const buildRequests = (adUrl) => (validBidRequests = [], bidderRequest = return buildRequestsBase({ adUrl, validBidRequests, bidderRequest, placementProcessingFunction }); }; -export const interpretResponse = (serverResponse) => { - let response = []; - for (let i = 0; i < serverResponse.body.length; i++) { - let resItem = serverResponse.body[i]; - if (isBidResponseValid(resItem)) { - const advertiserDomains = resItem.adomain && resItem.adomain.length ? resItem.adomain : []; - resItem.meta = { ...resItem.meta, advertiserDomains }; - - response.push(resItem); +export function interpretResponseBuilder({addtlBidValidation = (bid) => true} = {}) { + return function (serverResponse) { + let response = []; + for (let i = 0; i < serverResponse.body.length; i++) { + let resItem = serverResponse.body[i]; + if (isBidResponseValid(resItem) && addtlBidValidation(resItem)) { + const advertiserDomains = resItem.adomain && resItem.adomain.length ? resItem.adomain : []; + resItem.meta = { ...resItem.meta, advertiserDomains }; + + response.push(resItem); + } } + + return response; } +} - return response; -}; +export const interpretResponse = interpretResponseBuilder(); export const getUserSyncs = (syncUrl) => (syncOptions, serverResponses, gdprConsent, uspConsent, gppConsent) => { const type = syncOptions.iframeEnabled ? 'iframe' : 'image'; diff --git a/libraries/userAgentUtils/index.js b/libraries/userAgentUtils/index.js new file mode 100644 index 00000000000..7300bbd519a --- /dev/null +++ b/libraries/userAgentUtils/index.js @@ -0,0 +1,58 @@ +import { deviceTypes, browserTypes, osTypes } from './userAgentTypes.enums.js'; + +/** + * Get the approximate device type enum from the user agent + * @returns {number} + */ +export const getDeviceType = () => { + if ( + /ipad|android 3.0|xoom|sch-i800|playbook|tablet|kindle/i.test( + navigator.userAgent.toLowerCase() + ) + ) return deviceTypes.TABLET; + if ( + /iphone|ipod|android|blackberry|opera|mini|windows\sce|palm|smartphone|iemobile/i.test( + navigator.userAgent.toLowerCase() + ) + ) return deviceTypes.MOBILE; + return deviceTypes.DESKTOP; +}; + +/** + * Get the approximate browser type enum from the user agent (or vendor + * if available) + * @returns {number} + */ +export const getBrowser = () => { + if (/Edg/.test(navigator.userAgent)) return browserTypes.EDGE; + else if ( + /Chrome/.test(navigator.userAgent) && + /Google Inc/.test(navigator.vendor) + ) return browserTypes.CHROME; + else if (navigator.userAgent.match('CriOS')) return browserTypes.CHROME; + else if (/Firefox/.test(navigator.userAgent)) return browserTypes.FIREFOX; + else if ( + /Safari/.test(navigator.userAgent) && + /Apple Computer/.test(navigator.vendor) + ) return browserTypes.SAFARI; + else if ( + /Trident/.test(navigator.userAgent) || + /MSIE/.test(navigator.userAgent) + ) return browserTypes.INTERNET_EXPLORER; + else return browserTypes.OTHER; +}; + +/** + * Get the approximate OS enum from the user agent (or app version, + * if available) + * @returns {number} + */ +export const getOS = () => { + if (navigator.userAgent.indexOf('Android') != -1) return osTypes.ANDROID; + if (navigator.userAgent.indexOf('like Mac') != -1) return osTypes.IOS; + if (navigator.userAgent.indexOf('Win') != -1) return osTypes.WINDOWS; + if (navigator.userAgent.indexOf('Mac') != -1) return osTypes.MAC; + if (navigator.userAgent.indexOf('Linux') != -1) return osTypes.LINUX; + if (navigator.appVersion.indexOf('X11') != -1) return osTypes.UNIX; + return osTypes.OTHER; +}; diff --git a/libraries/userAgentUtils/userAgentTypes.enums.js b/libraries/userAgentUtils/userAgentTypes.enums.js new file mode 100644 index 00000000000..8a0255e88bf --- /dev/null +++ b/libraries/userAgentUtils/userAgentTypes.enums.js @@ -0,0 +1,22 @@ +export const deviceTypes = Object.freeze({ + DESKTOP: 0, + MOBILE: 1, + TABLET: 2, +}) +export const browserTypes = Object.freeze({ + CHROME: 0, + FIREFOX: 1, + SAFARI: 2, + EDGE: 3, + INTERNET_EXPLORER: 4, + OTHER: 5 +}) +export const osTypes = Object.freeze({ + WINDOWS: 0, + MAC: 1, + LINUX: 2, + UNIX: 3, + IOS: 4, + ANDROID: 5, + OTHER: 6 +}) diff --git a/libraries/vidazooUtils/bidderUtils.js b/libraries/vidazooUtils/bidderUtils.js index 99579fbf7ff..4b9f2fe37d0 100644 --- a/libraries/vidazooUtils/bidderUtils.js +++ b/libraries/vidazooUtils/bidderUtils.js @@ -200,6 +200,7 @@ export function appendUserIdsToRequestPayload(payloadRef, userIds) { let key; _each(userIds, (userId, idSystemProviderName) => { key = `uid.${idSystemProviderName}`; + switch (idSystemProviderName) { case 'lipb': payloadRef[key] = userId.lipbid; @@ -217,7 +218,7 @@ export function getVidazooSessionId(storage) { return getStorageItem(storage, SESSION_ID_KEY) || ''; } -export function buildRequestData(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout, webSessionId, storage, bidderVersion, bidderCode, getUniqueRequestData) { +export function buildRequestData(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout, storage, bidderVersion, bidderCode, getUniqueRequestData) { const { params, bidId, @@ -234,7 +235,7 @@ export function buildRequestData(bid, topWindowUrl, sizes, bidderRequest, bidder const {ext} = params; let {bidFloor} = params; const hashUrl = hashCode(topWindowUrl); - const uniqueRequestData = isFn(getUniqueRequestData) ? getUniqueRequestData(hashUrl) : {}; + const uniqueRequestData = isFn(getUniqueRequestData) ? getUniqueRequestData(hashUrl, bid) : {}; const uniqueDealId = getUniqueDealId(storage, hashUrl); const pId = extractPID(params); const isStorageAllowed = bidderSettings.get(bidderCode, 'storageAllowed'); @@ -285,7 +286,6 @@ export function buildRequestData(bid, topWindowUrl, sizes, bidderRequest, bidder bidderRequestsCount: bidderRequestsCount, bidderWinsCount: bidderWinsCount, bidderTimeout: bidderTimeout, - webSessionId: webSessionId, ...uniqueRequestData }; @@ -324,6 +324,22 @@ export function buildRequestData(bid, topWindowUrl, sizes, bidderRequest, bidder } } + const api = deepAccess(mediaTypes, 'video.api', []); + if (api.includes(7)) { + const sourceExt = deepAccess(bidderRequest, 'ortb2.source.ext'); + if (sourceExt?.omidpv) { + data.omidpv = sourceExt.omidpv; + } + if (sourceExt?.omidpn) { + data.omidpn = sourceExt.omidpn; + } + } + + const dsa = deepAccess(bidderRequest, 'ortb2.regs.ext.dsa'); + if (dsa) { + data.dsa = dsa; + } + _each(ext, (value, key) => { data['ext.' + key] = value; }); @@ -331,13 +347,13 @@ export function buildRequestData(bid, topWindowUrl, sizes, bidderRequest, bidder return data; } -export function createInterpretResponseFn(bidderCode) { +export function createInterpretResponseFn(bidderCode, allowSingleRequest) { return function interpretResponse(serverResponse, request) { if (!serverResponse || !serverResponse.body) { return []; } - const singleRequestMode = config.getConfig(`${bidderCode}.singleRequest`); + const singleRequestMode = allowSingleRequest && config.getConfig(`${bidderCode}.singleRequest`); const reqBidId = deepAccess(request, 'data.bidId'); const {results} = serverResponse.body; @@ -410,12 +426,12 @@ export function createInterpretResponseFn(bidderCode) { } } -export function createBuildRequestsFn(createRequestDomain, createUniqueRequestData, webSessionId, storage, bidderCode, bidderVersion) { +export function createBuildRequestsFn(createRequestDomain, createUniqueRequestData, storage, bidderCode, bidderVersion, allowSingleRequest) { function buildRequest(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout) { const {params} = bid; const cId = extractCID(params); const subDomain = extractSubDomain(params); - const data = buildRequestData(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout, webSessionId, storage, bidderVersion, bidderCode, createUniqueRequestData); + const data = buildRequestData(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout, storage, bidderVersion, bidderCode, createUniqueRequestData); const dto = { method: 'POST', url: `${createRequestDomain(subDomain)}/prebid/multi/${cId}`, data: data }; @@ -428,7 +444,7 @@ export function createBuildRequestsFn(createRequestDomain, createUniqueRequestDa const subDomain = extractSubDomain(params); const data = bidRequests.map(bid => { const sizes = parseSizesInput(bid.sizes); - return buildRequestData(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout, webSessionId, storage, bidderVersion, bidderCode, createUniqueRequestData) + return buildRequestData(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout, storage, bidderVersion, bidderCode, createUniqueRequestData) }); const chunkSize = Math.min(20, config.getConfig(`${bidderCode}.chunkSize`) || 10); @@ -445,11 +461,10 @@ export function createBuildRequestsFn(createRequestDomain, createUniqueRequestDa } return function buildRequests(validBidRequests, bidderRequest) { - // TODO: does the fallback make sense here? const topWindowUrl = bidderRequest.refererInfo.page || bidderRequest.refererInfo.topmostLocation; const bidderTimeout = config.getConfig('bidderTimeout'); - const singleRequestMode = config.getConfig('vidazoo.singleRequest'); + const singleRequestMode = allowSingleRequest && config.getConfig(`${bidderCode}.singleRequest`); const requests = []; diff --git a/modules/.submodules.json b/modules/.submodules.json index 38cf5f71cc6..ea128e91579 100644 --- a/modules/.submodules.json +++ b/modules/.submodules.json @@ -87,6 +87,7 @@ "jwplayerRtdProvider", "medianetRtdProvider", "mgidRtdProvider", + "mobianRtdProvider", "neuwoRtdProvider", "oneKeyRtdProvider", "optimeraRtdProvider", @@ -97,6 +98,7 @@ "reconciliationRtdProvider", "relevadRtdProvider", "sirdataRtdProvider", + "symitriDapRtdProvider", "timeoutRtdProvider", "weboramaRtdProvider" ], diff --git a/modules/33acrossAnalyticsAdapter.js b/modules/33acrossAnalyticsAdapter.js index 890c963fa71..1de986cd28e 100644 --- a/modules/33acrossAnalyticsAdapter.js +++ b/modules/33acrossAnalyticsAdapter.js @@ -629,6 +629,8 @@ function setCachedBidStatus(auctionId, bidId, status) { * @param {string} endpoint URL */ function sendReport(report, endpoint) { + // TODO FIX THIS RULES VIOLATION + // eslint-disable-next-line if (navigator.sendBeacon(endpoint, JSON.stringify(report))) { log.info(`Analytics report sent to ${endpoint}`, report); diff --git a/modules/adagioAnalyticsAdapter.js b/modules/adagioAnalyticsAdapter.js index bb5de41d3ce..033809e7f1b 100644 --- a/modules/adagioAnalyticsAdapter.js +++ b/modules/adagioAnalyticsAdapter.js @@ -2,12 +2,13 @@ * Analytics Adapter for Adagio */ +import { _ADAGIO, getBestWindowForAdagio } from '../libraries/adagioUtils/adagioUtils.js'; +import { deepAccess, logError, logInfo, logWarn } from '../src/utils.js'; +import { BANNER } from '../src/mediaTypes.js'; +import { EVENTS } from '../src/constants.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import adapterManager from '../src/adapterManager.js'; -import { EVENTS } from '../src/constants.js'; import { ajax } from '../src/ajax.js'; -import { BANNER } from '../src/mediaTypes.js'; -import { getWindowTop, getWindowSelf, deepAccess, logInfo, logError } from '../src/utils.js'; import { getGlobal } from '../src/prebidGlobal.js'; const emptyUrl = ''; @@ -19,6 +20,13 @@ const PREBID_VERSION = '$prebid.version$'; const ENDPOINT = 'https://c.4dex.io/pba.gif'; const CURRENCY_USD = 'USD'; const ADAGIO_CODE = 'adagio'; + +export const _internal = { + getAdagioNs: function() { + return _ADAGIO; + } +}; + const cache = { auctions: {}, getAuction: function(auctionId, adUnitCode) { @@ -48,34 +56,6 @@ const cache = { }; const enc = window.encodeURIComponent; -/** -/* BEGIN ADAGIO.JS CODE - */ - -function canAccessTopWindow() { - try { - if (getWindowTop().location.href) { - return true; - } - } catch (error) { - return false; - } -}; - -function getCurrentWindow() { - return currentWindow; -}; - -let currentWindow; - -const adagioEnqueue = function adagioEnqueue(action, data) { - getCurrentWindow().ADAGIO.queue.push({ action, data, ts: Date.now() }); -}; - -/** - * END ADAGIO.JS CODE - */ - /** * UTILS FUNCTIONS */ @@ -150,6 +130,10 @@ function getCurrencyData(bid) { * @param {Object} qp */ function sendRequest(qp) { + if (!qp.org_id || !qp.site) { + logInfo('request is missing org_id or site, skipping beacon.'); + return; + } // Removing null values qp = Object.keys(qp).reduce((acc, key) => { if (qp[key] !== null) { @@ -194,37 +178,28 @@ function getTargetedAuctionId(bid) { */ function handlerAuctionInit(event) { - const w = getCurrentWindow(); + const w = getBestWindowForAdagio(); const prebidAuctionId = event.auctionId; const adUnitCodes = removeDuplicates(event.adUnitCodes, adUnitCode => adUnitCode); // Check if Adagio is on the bid requests. - // If not, we don't need to track the auction. const adagioBidRequest = event.bidderRequests.find(bidRequest => isAdagio(bidRequest.bidderCode)); - if (!adagioBidRequest) { - logInfo(`Adagio is not on the bid requests for auction '${prebidAuctionId}'`) - return; - } + + const rtdUid = deepAccess(adagioBidRequest, 'ortb2.site.ext.data.adg_rtd.uid'); + cache.addPrebidAuctionIdRef(prebidAuctionId, rtdUid); cache.auctions[prebidAuctionId] = {}; adUnitCodes.forEach(adUnitCode => { + // event.adUnits are splitted by mediatypes const adUnits = event.adUnits.filter(adUnit => adUnit.code === adUnitCode); - // Get all bidders configures for the ad unit. - const bidders = removeDuplicates( - adUnits.map(adUnit => adUnit.bids.map(bid => ({bidder: bid.bidder, params: bid.params}))).flat(), - bidder => bidder.bidder - ); - - // Check if Adagio is configured for the ad unit. - // If not, we don't need to track the ad unit. - const adagioBidder = bidders.find(bidder => isAdagio(bidder.bidder)); - if (!adagioBidder) { - logInfo(`Adagio is not configured for ad unit '${adUnitCode}'`); - return; - } + // Get all bidders configured for the ad unit. + // AdUnits with the same code can have a different bidder list, aggregate all of them. + const biddersAggregate = adUnits.reduce((bidders, adUnit) => bidders.concat(adUnit.bids.map(bid => bid.bidder)), []) + // remove duplicates + const bidders = [...new Set(biddersAggregate)]; // Get all media types and banner sizes configured for the ad unit. const mediaTypes = adUnits.map(adUnit => adUnit.mediaTypes); @@ -239,45 +214,56 @@ function handlerAuctionInit(event) { bannerSize => bannerSize ).sort(); - // Get all Adagio bids for the ad unit from the bidRequest. - // If no bids, we don't need to track the ad unit. - const adagioAdUnitBids = adagioBidRequest.bids.filter(bid => bid.adUnitCode === adUnitCode); - if (deepAccess(adagioAdUnitBids, 'length', 0) <= 0) { - logInfo(`Adagio is not on the bid requests for ad unit '${adUnitCode}' and auction '${prebidAuctionId}'`) - return; + const sortedBidderCodes = bidders.sort() + + const bidSrcMapper = (bidder) => { + const request = event.bidderRequests.find(br => br.bidderCode === bidder) + return request ? request.bids[0].src : null } - // Get Adagio params from the first bid. - // We assume that all Adagio bids for a same adunit have the same params. - const params = adagioAdUnitBids[0].params; + const biddersSrc = sortedBidderCodes.map(bidSrcMapper).join(','); - const adagioAuctionId = params.adagioAuctionId; - cache.addPrebidAuctionIdRef(prebidAuctionId, adagioAuctionId); + // if adagio was involved in the auction we identified it with rtdUid, if not use the prebid auctionId + const auctionId = rtdUid || prebidAuctionId; - // Get all media types requested for Adagio. - const adagioMediaTypes = removeDuplicates( - adagioAdUnitBids.map(bid => Object.keys(bid.mediaTypes)).flat(), - mediaTypeKey => mediaTypeKey - ).flat().map(mediaType => getMediaTypeAlias(mediaType)).sort(); + const adgRtdSession = deepAccess(event.bidderRequests[0], 'ortb2.site.ext.data.adg_rtd.session', {}); const qp = { + org_id: adagioAdapter.options.organizationId, + site: adagioAdapter.options.site, v: 0, pbjsv: PREBID_VERSION, - org_id: params.organizationId, - site: params.site, - pv_id: params.pageviewId, - auct_id: adagioAuctionId, + pv_id: _internal.getAdagioNs().pageviewId, + auct_id: auctionId, adu_code: adUnitCode, url_dmn: w.location.hostname, - pgtyp: params.pagetype, - plcmt: params.placement, - t_n: params.testName || null, - t_v: params.testVersion || null, mts: mediaTypesKeys.join(','), ban_szs: bannerSizes.join(','), - bdrs: bidders.map(bidder => bidder.bidder).sort().join(','), - adg_mts: adagioMediaTypes.join(',') + bdrs: sortedBidderCodes.join(','), + pgtyp: deepAccess(event.bidderRequests[0], 'ortb2.site.ext.data.pagetype', null), + plcmt: deepAccess(adUnits[0], 'ortb2Imp.ext.data.placement', null), + t_n: adgRtdSession.testName || null, + t_v: adgRtdSession.testVersion || null, + s_id: adgRtdSession.id || null, + s_new: adgRtdSession.new || null, + bdrs_src: biddersSrc, }; + if (adagioBidRequest && adagioBidRequest.bids) { + const adagioAdUnitBids = adagioBidRequest.bids.filter(bid => bid.adUnitCode === adUnitCode); + if (adagioAdUnitBids.length > 0) { + // Get all media types requested for Adagio. + const adagioMediaTypes = removeDuplicates( + adagioAdUnitBids.map(bid => Object.keys(bid.mediaTypes)).flat(), + mediaTypeKey => mediaTypeKey + ).flat().map(mediaType => getMediaTypeAlias(mediaType)).sort(); + + qp.adg_mts = adagioMediaTypes.join(','); + // for backward compatibility: if we didn't find organizationId & site but we have a bid from adagio we might still find it in params + qp.org_id = qp.org_id || adagioAdUnitBids[0].params.organizationId; + qp.site = qp.site || adagioAdUnitBids[0].params.site; + } + } + cache.auctions[prebidAuctionId][adUnitCode] = qp; sendNewBeacon(prebidAuctionId, adUnitCode); }); @@ -324,13 +310,21 @@ function handlerAuctionEnd(event) { return bid ? getCurrencyData(bid).netCpm : null } + const perfNavigation = performance.getEntriesByType('navigation')[0]; + cache.updateAuction(auctionId, adUnitCode, { bdrs_bid: cache.getBiddersFromAuction(auctionId, adUnitCode).map(bidResponseMapper).join(','), - bdrs_cpm: cache.getBiddersFromAuction(auctionId, adUnitCode).map(bidCpmMapper).join(',') + bdrs_cpm: cache.getBiddersFromAuction(auctionId, adUnitCode).map(bidCpmMapper).join(','), + // check timings at the end of the auction to leave time to the browser to update it + dom_i: Math.round(perfNavigation['domInteractive']) || null, + dom_c: Math.round(perfNavigation['domComplete']) || null, + loa_e: Math.round(perfNavigation['loadEventEnd']) || null, }); + sendNewBeacon(auctionId, adUnitCode); }); } + function handlerBidWon(event) { let auctionId = getTargetedAuctionId(event); @@ -345,6 +339,8 @@ function handlerBidWon(event) { ? cache.getAdagioAuctionId(event.auctionId) : null); + const perfNavigation = performance.getEntriesByType('navigation')[0]; + cache.updateAuction(auctionId, event.adUnitCode, { win_bdr: event.bidder, win_mt: getMediaTypeAlias(event.mediaType), @@ -353,6 +349,11 @@ function handlerBidWon(event) { win_net_cpm: currencyData.netCpm, win_og_cpm: currencyData.orginalCpm, + // check timings at the end of the auction to leave time to the browser to update it + dom_i: Math.round(perfNavigation['domInteractive']) || null, + dom_c: Math.round(perfNavigation['domComplete']) || null, + loa_e: Math.round(perfNavigation['loadEventEnd']) || null, + // cache bid id auct_id_c: adagioAuctionCacheId, }); @@ -407,7 +408,11 @@ let adagioAdapter = Object.assign(adapter({ emptyUrl, analyticsType }), { try { if (typeof args !== 'undefined' && events.indexOf(eventType) !== -1) { - adagioEnqueue('pb-analytics-event', { eventName: eventType, args }); + _internal.getAdagioNs().queue.push({ + action: 'pb-analytics-event', + data: { eventName: eventType, args }, + ts: Date.now() + }); } } catch (error) { logError('Error on Adagio Analytics Adapter - adagio.js', error); @@ -418,14 +423,26 @@ let adagioAdapter = Object.assign(adapter({ emptyUrl, analyticsType }), { adagioAdapter.originEnableAnalytics = adagioAdapter.enableAnalytics; adagioAdapter.enableAnalytics = config => { - const w = (canAccessTopWindow()) ? getWindowTop() : getWindowSelf(); - currentWindow = w; + _internal.getAdagioNs().versions.adagioAnalyticsAdapter = VERSION; - w.ADAGIO = w.ADAGIO || {}; - w.ADAGIO.queue = w.ADAGIO.queue || []; - w.ADAGIO.versions = w.ADAGIO.versions || {}; - w.ADAGIO.versions.adagioAnalyticsAdapter = VERSION; + let modules = getGlobal().installedModules; + if (modules && (!modules.length || modules.indexOf('adagioRtdProvider') === -1 || modules.indexOf('rtdModule') === -1)) { + logError('Adagio Analytics Adapter requires rtdModule & adagioRtdProvider modules which are not installed. No beacon will be sent'); + return; + } + adagioAdapter.options = config.options || {}; + if (!adagioAdapter.options.organizationId) { + logWarn('Adagio Analytics Adapter: organizationId is required and is missing will try to fallback on params.'); + } else { + adagioAdapter.options.organizationId = adagioAdapter.options.organizationId.toString(); // allows publisher to pass it as a number + } + if (!adagioAdapter.options.site) { + logWarn('Adagio Analytics Adapter: site is required and is missing will try to fallback on params.'); + } else if (typeof adagioAdapter.options.site !== 'string') { + logWarn('Adagio Analytics Adapter: site should be a string will try to fallback on params.'); + adagioAdapter.options.site = undefined; + } adagioAdapter.originEnableAnalytics(config); } diff --git a/modules/adagioAnalyticsAdapter.md b/modules/adagioAnalyticsAdapter.md index 9fc2cb0bb88..916f9ec9c58 100644 --- a/modules/adagioAnalyticsAdapter.md +++ b/modules/adagioAnalyticsAdapter.md @@ -13,5 +13,9 @@ Analytics adapter for Adagio ```js pbjs.enableAnalytics({ provider: 'adagio', + options: { + organizationId: '1000', // Required. Provided by Adagio + site: 'my-website', // Required. Provided by Adagio + } }); ``` diff --git a/modules/adagioBidAdapter.js b/modules/adagioBidAdapter.js index 8d945beafa1..9bcebf9205e 100644 --- a/modules/adagioBidAdapter.js +++ b/modules/adagioBidAdapter.js @@ -20,11 +20,11 @@ import { import { getRefererInfo, parseDomain } from '../src/refererDetection.js'; import { OUTSTREAM } from '../src/video.js'; import { Renderer } from '../src/Renderer.js'; +import { _ADAGIO } from '../libraries/adagioUtils/adagioUtils.js'; import { config } from '../src/config.js'; import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; import { find } from '../src/polyfill.js'; import { getGptSlotInfoForAdUnitCode } from '../libraries/gptUtils/gptUtils.js'; -import { _ADAGIO } from '../libraries/adagioUtils/adagioUtils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { userSync } from '../src/userSync.js'; @@ -176,17 +176,6 @@ function _getUspConsent(bidderRequest) { return (deepAccess(bidderRequest, 'uspConsent')) ? { uspConsent: bidderRequest.uspConsent } : false; } -function _getGppConsent(bidderRequest) { - let gpp = deepAccess(bidderRequest, 'gppConsent.gppString') - let gppSid = deepAccess(bidderRequest, 'gppConsent.applicableSections') - - if (!gpp || !gppSid) { - gpp = deepAccess(bidderRequest, 'ortb2.regs.gpp', '') - gppSid = deepAccess(bidderRequest, 'ortb2.regs.gpp_sid', []) - } - return { gpp, gppSid } -} - function _getSchain(bidRequest) { return deepAccess(bidRequest, 'schain'); } @@ -559,7 +548,7 @@ export const spec = { const gdprConsent = _getGdprConsent(bidderRequest) || {}; const uspConsent = _getUspConsent(bidderRequest) || {}; const coppa = _getCoppa(); - const gppConsent = _getGppConsent(bidderRequest) + const { gpp, gpp_sid: gppSid } = deepAccess(bidderRequest, 'ortb2.regs', {}); const schain = _getSchain(validBidRequests[0]); const eids = _getEids(validBidRequests[0]) || []; const syncEnabled = deepAccess(config.getConfig('userSync'), 'syncEnabled') @@ -576,7 +565,7 @@ export const spec = { sessionData.rnd = Math.random() } - const aucId = deepAccess('bidderRequest', 'ortb2.site.ext.data.adg_rtd.uid') || generateUUID() + const aucId = deepAccess(bidderRequest, 'ortb2.site.ext.data.adg_rtd.uid') || generateUUID() const adUnits = validBidRequests.map(rawBidRequest => { const bidRequest = deepClone(rawBidRequest); @@ -724,7 +713,6 @@ export const spec = { // Those params are not sent to the server. // They are used for further operations on analytics adapter. validBidRequests.forEach(rawBidRequest => { - rawBidRequest.params.adagioAuctionId = aucId rawBidRequest.params.pageviewId = pageviewId }); @@ -748,8 +736,8 @@ export const spec = { gdpr: gdprConsent, coppa: coppa, ccpa: uspConsent, - gpp: gppConsent.gpp, - gppSid: gppConsent.gppSid, + gpp: gpp || '', + gppSid: gppSid || [], dsa: dsa // populated if exists }, schain: schain, diff --git a/modules/adagioRtdProvider.js b/modules/adagioRtdProvider.js index 16bd8fc2ae2..91f446e68fd 100644 --- a/modules/adagioRtdProvider.js +++ b/modules/adagioRtdProvider.js @@ -73,20 +73,34 @@ const _SESSION = (function() { storage.getDataFromLocalStorage('adagio', (storageValue) => { // session can be an empty object - const { rnd, new: isNew, vwSmplg, vwSmplgNxt, lastActivityTime } = _internal.getSessionFromLocalStorage(storageValue); + const { rnd, new: isNew = false, vwSmplg, vwSmplgNxt, lastActivityTime, id, testName, testVersion, initiator } = _internal.getSessionFromLocalStorage(storageValue); + + // isNew can be `true` if the session has been initialized by the A/B test snippet (external) + const isNewSess = (initiator === 'snippet') ? isNew : isNewSession(lastActivityTime); data.session = { rnd, - new: isNew || false, // legacy: `new` was used but the choosen name is not good. + new: isNewSess, // legacy: `new` was used but the choosen name is not good. // Don't use values if they are not defined. ...(vwSmplg !== undefined && { vwSmplg }), ...(vwSmplgNxt !== undefined && { vwSmplgNxt }), - ...(lastActivityTime !== undefined && { lastActivityTime }) + ...(lastActivityTime !== undefined && { lastActivityTime }), + ...(id !== undefined && { id }), + ...(testName !== undefined && { testName }), + ...(testVersion !== undefined && { testVersion }), + ...(initiator !== undefined && { initiator }), }; - if (isNewSession(lastActivityTime)) { + // `initiator` is a pseudo flag used to know if the session has been initialized by the A/B test snippet (external). + // If the AB Test snippet has not been used, then `initiator` value is `adgjs` or `undefined`. + // The check on `testName` is used to ensure that the A/B test values are removed. + if (initiator !== 'snippet' && (isNewSess || testName)) { data.session.new = true; + data.session.id = generateUUID(); data.session.rnd = Math.random(); + // Ensure that the A/B test values are removed. + delete data.session.testName; + delete data.session.testVersion; } _internal.getAdagioNs().queue.push({ @@ -278,15 +292,18 @@ function onGetBidRequestData(bidReqConfig, callback, config) { const adUnits = bidReqConfig.adUnits || getGlobal().adUnits || []; adUnits.forEach(adUnit => { + adUnit.ortb2Imp = adUnit.ortb2Imp || {}; const ortb2Imp = deepAccess(adUnit, 'ortb2Imp'); + // A divId is required to compute the slot position and later to track viewability. // If nothing has been explicitly set, we try to get the divId from the GPT slot and fallback to the adUnit code in last resort. - if (!deepAccess(ortb2Imp, 'ext.data.divId')) { - const divId = getGptSlotInfoForAdUnitCode(adUnit.code).divId; + let divId = deepAccess(ortb2Imp, 'ext.data.divId') + if (!divId) { + divId = getGptSlotInfoForAdUnitCode(adUnit.code).divId; deepSetValue(ortb2Imp, `ext.data.divId`, divId || adUnit.code); } - const slotPosition = getSlotPosition(adUnit); + const slotPosition = getSlotPosition(divId); deepSetValue(ortb2Imp, `ext.data.adg_rtd.adunit_position`, slotPosition); // It is expected that the publisher set a `adUnits[].ortb2Imp.ext.data.placement` value. @@ -430,7 +447,7 @@ function getElementFromTopWindow(element, currentWindow) { } }; -function getSlotPosition(adUnit) { +function getSlotPosition(divId) { if (!isSafeFrameWindow() && !canAccessWindowTop()) { return ''; } @@ -451,16 +468,15 @@ function getSlotPosition(adUnit) { // window.top based computing const wt = getWindowTop(); const d = wt.document; - const adUnitElementId = deepAccess(adUnit, 'ortb2Imp.ext.data.divId'); let domElement; if (inIframe() === true) { const ws = getWindowSelf(); - const currentElement = ws.document.getElementById(adUnitElementId); + const currentElement = ws.document.getElementById(divId); domElement = getElementFromTopWindow(currentElement, ws); } else { - domElement = wt.document.getElementById(adUnitElementId); + domElement = wt.document.getElementById(divId); } if (!domElement) { diff --git a/modules/adfBidAdapter.js b/modules/adfBidAdapter.js index 27fb36a225d..925c0b3500e 100644 --- a/modules/adfBidAdapter.js +++ b/modules/adfBidAdapter.js @@ -3,7 +3,7 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; -import {deepAccess, deepClone, deepSetValue, mergeDeep, parseSizesInput} from '../src/utils.js'; +import {deepAccess, deepClone, deepSetValue, mergeDeep, parseSizesInput, setOnAny} from '../src/utils.js'; import {config} from '../src/config.js'; import {Renderer} from '../src/Renderer.js'; @@ -255,15 +255,6 @@ export const spec = { registerBidder(spec); -function setOnAny(collection, key) { - for (let i = 0, result; i < collection.length; i++) { - result = deepAccess(collection[i], key); - if (result) { - return result; - } - } -} - function flatten(arr) { return [].concat(...arr); } diff --git a/modules/adkernelAdnBidAdapter.js b/modules/adkernelAdnBidAdapter.js index 81067a3efcf..ae5528f2aeb 100644 --- a/modules/adkernelAdnBidAdapter.js +++ b/modules/adkernelAdnBidAdapter.js @@ -2,6 +2,7 @@ import {deepAccess, deepSetValue, isArray, isNumber, isStr, logInfo, parseSizesI import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; import {config} from '../src/config.js'; +import {getBidFloor} from '../libraries/adkernelUtils/adkernelUtils.js' const DEFAULT_ADKERNEL_DSP_DOMAIN = 'tag.adkernel.com'; const DEFAULT_MIMES = ['video/mp4', 'video/webm', 'application/x-shockwave-flash', 'application/javascript']; @@ -143,18 +144,6 @@ function fillBidMeta(bid, tag) { } } -function getBidFloor(bid, mediaType, sizes) { - var floor; - var size = sizes.length === 1 ? sizes[0] : '*'; - if (typeof bid.getFloor === 'function') { - const floorInfo = bid.getFloor({currency: 'USD', mediaType, size}); - if (typeof floorInfo === 'object' && floorInfo.currency === 'USD' && !isNaN(parseFloat(floorInfo.floor))) { - floor = parseFloat(floorInfo.floor); - } - } - return floor; -} - export const spec = { code: 'adkernelAdn', gvlid: GVLID, diff --git a/modules/adkernelBidAdapter.js b/modules/adkernelBidAdapter.js index 151e08bd2bb..36a359170c4 100644 --- a/modules/adkernelBidAdapter.js +++ b/modules/adkernelBidAdapter.js @@ -20,6 +20,7 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; import {find} from '../src/polyfill.js'; import {config} from '../src/config.js'; import {getAdUnitSizes} from '../libraries/sizeUtils/sizeUtils.js'; +import {getBidFloor} from '../libraries/adkernelUtils/adkernelUtils.js' /** * In case you're AdKernel whitelable platform's client who needs branded adapter to @@ -95,7 +96,9 @@ export const spec = { {code: 'headbidder'}, {code: 'digiad'}, {code: 'monetix'}, - {code: 'hyperbrainz'} + {code: 'hyperbrainz'}, + {code: 'voisetech'}, + {code: 'global_sun'} ], supportedMediaTypes: [BANNER, VIDEO, NATIVE], @@ -246,18 +249,6 @@ function groupImpressionsByHostZone(bidRequests, refererInfo) { ); } -function getBidFloor(bid, mediaType, sizes) { - var floor; - var size = sizes.length === 1 ? sizes[0] : '*'; - if (typeof bid.getFloor === 'function') { - const floorInfo = bid.getFloor({currency: 'USD', mediaType, size}); - if (typeof floorInfo === 'object' && floorInfo.currency === 'USD' && !isNaN(parseFloat(floorInfo.floor))) { - floor = parseFloat(floorInfo.floor); - } - } - return floor; -} - /** * Builds rtb imp object(s) for single adunit * @param bidRequest {BidRequest} diff --git a/modules/adlooxAnalyticsAdapter.js b/modules/adlooxAnalyticsAdapter.js index e31ea290e11..f18c9e72337 100644 --- a/modules/adlooxAnalyticsAdapter.js +++ b/modules/adlooxAnalyticsAdapter.js @@ -232,6 +232,7 @@ analyticsAdapter[`handle_${EVENTS.AUCTION_END}`] = function(auctionDetails) { link.setAttribute('href', `${uri.protocol}://${uri.host}${uri.pathname}`); link.setAttribute('rel', 'preload'); link.setAttribute('as', 'script'); + // TODO fix rules violation insertElement(link); } diff --git a/modules/admixerBidAdapter.js b/modules/admixerBidAdapter.js index de7b941d614..e979bd07b51 100644 --- a/modules/admixerBidAdapter.js +++ b/modules/admixerBidAdapter.js @@ -13,7 +13,7 @@ const ALIASES = [ {code: 'futureads', endpoint: 'https://ads.futureads.io/prebid.1.2.aspx'}, {code: 'smn', endpoint: 'https://ads.smn.rs/prebid.1.2.aspx'}, {code: 'admixeradx', endpoint: 'https://inv-nets.admixer.net/adxprebid.1.2.aspx'}, - {code: 'admixerwl', endpoint: 'https://inv-nets-adxwl.admixer.com/adxwlprebid.aspx'}, + 'rtbstack' ]; export const spec = { code: BIDDER_CODE, @@ -23,8 +23,8 @@ export const spec = { * Determines whether or not the given bid request is valid. */ isBidRequestValid: function (bid) { - return bid.bidder === 'admixerwl' - ? !!bid.params.clientId && !!bid.params.endpointId + return bid.bidder === 'rtbstack' + ? !!bid.params.tagId : !!bid.params.zone; }, /** @@ -51,8 +51,12 @@ export const spec = { }; let endpointUrl; if (bidderRequest) { - const {bidderCode} = bidderRequest; - endpointUrl = config.getConfig(`${bidderCode}.endpoint_url`); + // checks if there is specified any endpointUrl in bidder config + endpointUrl = config.getConfig('bidderURL'); + if (!endpointUrl && bidderRequest.bidderCode === 'rtbstack') { + logError('The bidderUrl config is required for RTB Stack bids. Please set it with setBidderConfig() for "rtbstack".'); + return; + } // TODO: is 'page' the right value here? if (bidderRequest.refererInfo?.page) { payload.referrer = encodeURIComponent(bidderRequest.refererInfo.page); @@ -82,7 +86,7 @@ export const spec = { let urlForRequest = endpointUrl || getEndpointUrl(bidderRequest.bidderCode) return { method: 'POST', - url: bidderRequest.bidderCode === 'admixerwl' ? `${urlForRequest}?client=${payload.imps[0]?.params?.clientId}` : urlForRequest, + url: urlForRequest, data: payload, }; }, diff --git a/modules/admixerBidAdapter.md b/modules/admixerBidAdapter.md index 64f8dd64ee4..097e7feb95e 100644 --- a/modules/admixerBidAdapter.md +++ b/modules/admixerBidAdapter.md @@ -51,7 +51,7 @@ Please use ```admixer``` as the bidder code. ]; ``` -### AdmixerWL Test Parameters +### RTB Stack Test Parameters ``` var adUnits = [ { @@ -59,10 +59,9 @@ Please use ```admixer``` as the bidder code. sizes: [[300, 250]], // a display size bids: [ { - bidder: "admixer", + bidder: "rtbstack", params: { - endpointId: 41512, - clientId: 62 + tagId: 41512 } } ] @@ -71,10 +70,9 @@ Please use ```admixer``` as the bidder code. sizes: [[300, 50]], // a mobile size bids: [ { - bidder: "admixer", + bidder: "rtbstack", params: { - endpointId: 41512, - clientId: 62 + tagId: 41512 } } ] @@ -84,10 +82,9 @@ Please use ```admixer``` as the bidder code. mediaType: 'video', bids: [ { - bidder: "admixer", + bidder: "rtbstack", params: { - endpointId: 41512, - clientId: 62 + tagId: 41512 } } ] diff --git a/modules/adtrgtmeBidAdapter.js b/modules/adtrgtmeBidAdapter.js index 4dc95ce6bc1..955e908f000 100644 --- a/modules/adtrgtmeBidAdapter.js +++ b/modules/adtrgtmeBidAdapter.js @@ -2,7 +2,7 @@ import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER } from '../src/mediaTypes.js'; import { deepAccess, isFn, isStr, isNumber, isArray, isEmpty, isPlainObject, generateUUID, logWarn } from '../src/utils.js'; import { config } from '../src/config.js'; -import { hasPurpose1Consent } from '../src/utils/gpdr.js'; +import { hasPurpose1Consent } from '../src/utils/gdpr.js'; const INTEGRATION_METHOD = 'prebid.js'; const BIDDER_CODE = 'adtrgtme'; diff --git a/modules/advRedAnalyticsAdapter.js b/modules/advRedAnalyticsAdapter.js new file mode 100644 index 00000000000..8ad30ed351d --- /dev/null +++ b/modules/advRedAnalyticsAdapter.js @@ -0,0 +1,198 @@ +import {generateUUID, logInfo} from '../src/utils.js' +import {ajaxBuilder} from '../src/ajax.js' +import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js' +import adapterManager from '../src/adapterManager.js' +import {EVENTS} from '../src/constants.js' +import {getRefererInfo} from '../src/refererDetection.js'; + +/** + * advRedAnalyticsAdapter.js - analytics adapter for AdvRed + */ +const DEFAULT_EVENT_URL = 'https://api.adv.red/api/event' + +let ajax = ajaxBuilder(10000) +let pwId +let initOptions +let flushInterval +let queue = [] + +let advRedAnalytics = Object.assign(adapter({url: DEFAULT_EVENT_URL, analyticsType: 'endpoint'}), { + track({eventType, args}) { + handleEvent(eventType, args) + } +}) + +function sendEvents() { + if (queue.length > 0) { + const message = { + pwId: pwId, + publisherId: initOptions.publisherId, + events: queue, + pageUrl: getRefererInfo().page + } + queue = [] + + const url = initOptions.url ? initOptions.url : DEFAULT_EVENT_URL + ajax( + url, + () => logInfo('AdvRed Analytics sent ' + queue.length + ' events'), + JSON.stringify(message), + { + method: 'POST', + contentType: 'application/json', + withCredentials: true + } + ) + } +} + +function convertAdUnit(adUnit) { + if (!adUnit) return adUnit + + const shortAdUnit = {} + shortAdUnit.code = adUnit.code + shortAdUnit.sizes = adUnit.sizes + return shortAdUnit +} + +function convertBid(bid) { + if (!bid) return bid + + const shortBid = {} + shortBid.adUnitCode = bid.adUnitCode + shortBid.bidder = bid.bidder + shortBid.cpm = bid.cpm + shortBid.currency = bid.currency + shortBid.mediaTypes = bid.mediaTypes + shortBid.sizes = bid.sizes + shortBid.serverResponseTimeMs = bid.serverResponseTimeMs + return shortBid +} + +function convertAuctionInit(origEvent) { + let shortEvent = {} + shortEvent.auctionId = origEvent.auctionId + shortEvent.timeout = origEvent.timeout + shortEvent.adUnits = origEvent.adUnits && origEvent.adUnits.map(convertAdUnit) + return shortEvent +} + +function convertBidRequested(origEvent) { + let shortEvent = {} + shortEvent.bidderCode = origEvent.bidderCode + shortEvent.bids = origEvent.bids && origEvent.bids.map(convertBid) + shortEvent.timeout = origEvent.timeout + return shortEvent +} + +function convertBidTimeout(origEvent) { + let shortEvent = {} + shortEvent.bids = origEvent && origEvent.map ? origEvent.map(convertBid) : origEvent + return shortEvent +} + +function convertBidderError(origEvent) { + let shortEvent = {} + shortEvent.bids = origEvent.bidderRequest && origEvent.bidderRequest.bids && origEvent.bidderRequest.bids.map(convertBid) + return shortEvent +} + +function convertAuctionEnd(origEvent) { + let shortEvent = {} + shortEvent.adUnitCodes = origEvent.adUnitCodes + shortEvent.bidsReceived = origEvent.bidsReceived && origEvent.bidsReceived.map(convertBid) + shortEvent.noBids = origEvent.noBids && origEvent.noBids.map(convertBid) + return shortEvent +} + +function convertBidWon(origEvent) { + let shortEvent = {} + shortEvent.adUnitCode = origEvent.adUnitCode + shortEvent.bidderCode = origEvent.bidderCode + shortEvent.mediaType = origEvent.mediaType + shortEvent.netRevenue = origEvent.netRevenue + shortEvent.cpm = origEvent.cpm + shortEvent.size = origEvent.size + shortEvent.currency = origEvent.currency + return shortEvent +} + +function handleEvent(eventType, origEvent) { + try { + origEvent = origEvent ? JSON.parse(JSON.stringify(origEvent)) : {} + } catch (e) { + } + + let shortEvent + switch (eventType) { + case EVENTS.AUCTION_INIT: { + shortEvent = convertAuctionInit(origEvent) + break + } + case EVENTS.BID_REQUESTED: { + shortEvent = convertBidRequested(origEvent) + break + } + case EVENTS.BID_TIMEOUT: { + shortEvent = convertBidTimeout(origEvent) + break + } + case EVENTS.BIDDER_ERROR: { + shortEvent = convertBidderError(origEvent) + break + } + case EVENTS.AUCTION_END: { + shortEvent = convertAuctionEnd(origEvent) + break + } + case EVENTS.BID_WON: { + shortEvent = convertBidWon(origEvent) + break + } + default: + return + } + + shortEvent.eventType = eventType + shortEvent.auctionId = origEvent.auctionId + shortEvent.timestamp = origEvent.timestamp || Date.now() + + sendEvent(shortEvent) +} + +function sendEvent(event) { + queue.push(event) + + if (event.eventType === EVENTS.AUCTION_END) { + sendEvents() + } +} + +advRedAnalytics.originEnableAnalytics = advRedAnalytics.enableAnalytics +advRedAnalytics.enableAnalytics = function (config) { + initOptions = config.options || {} + pwId = generateUUID() + flushInterval = setInterval(sendEvents, 1000) + + advRedAnalytics.originEnableAnalytics(config) +} + +advRedAnalytics.originDisableAnalytics = advRedAnalytics.disableAnalytics +advRedAnalytics.disableAnalytics = function () { + clearInterval(flushInterval) + sendEvents() + advRedAnalytics.originDisableAnalytics() +} + +adapterManager.registerAnalyticsAdapter({ + adapter: advRedAnalytics, + code: 'advRed' +}) + +advRedAnalytics.getOptions = function () { + return initOptions +} + +advRedAnalytics.sendEvents = sendEvents + +export default advRedAnalytics diff --git a/modules/advRedAnalyticsAdapter.md b/modules/advRedAnalyticsAdapter.md new file mode 100644 index 00000000000..59345dfd01e --- /dev/null +++ b/modules/advRedAnalyticsAdapter.md @@ -0,0 +1,30 @@ +# Overview +``` +Module Name: AdvRed Analytics Adapter +Module Type: Analytics Adapter +Maintainer: support@adv.red +``` + +### Usage + +The AdvRed analytics adapter can be used by all clients after approval. For more information, +please visit + +### Analytics Options +| Param enableAnalytics | Scope | Type | Description | Example | +|-----------------------|----------|--------|------------------------------------------------------|----------------------------------------| +| provider | Required | String | The name of this Adapter. | `'advRed'` | +| params | Required | Object | Details of module params. | | +| params.publisherId | Required | String | This is the Publisher ID value obtained from AdvRed. | `'123456'` | +| params.url | Optional | String | Custom URL of the endpoint to collect the events | `'https://pub1.api.adv.red/api/event'` | + +### Example Configuration + +```javascript +pbjs.enableAnalytics({ + provider: 'advRed', + options: { + publisherId: '123456' // change to the Publisher ID you received from AdvRed + } +}); +``` diff --git a/modules/aidemBidAdapter.js b/modules/aidemBidAdapter.js index 3b55682b217..07aee262baa 100644 --- a/modules/aidemBidAdapter.js +++ b/modules/aidemBidAdapter.js @@ -10,6 +10,7 @@ const BIDDER_CODE = 'aidem'; const BASE_URL = 'https://zero.aidemsrv.com'; const LOCAL_BASE_URL = 'http://127.0.0.1:8787'; +const GVLID = 1218 const SUPPORTED_MEDIA_TYPES = [BANNER, VIDEO]; const REQUIRED_VIDEO_PARAMS = [ 'mimes', 'protocols', 'context' ]; @@ -232,6 +233,7 @@ function hasValidParameters(bidRequest) { export const spec = { code: BIDDER_CODE, + gvlid: GVLID, supportedMediaTypes: SUPPORTED_MEDIA_TYPES, isBidRequestValid: function(bidRequest) { logInfo('bid: ', bidRequest); diff --git a/modules/akamaiDapRtdProvider.js b/modules/akamaiDapRtdProvider.js index 0bd53b2a91f..e5a647a90ef 100644 --- a/modules/akamaiDapRtdProvider.js +++ b/modules/akamaiDapRtdProvider.js @@ -5,802 +5,23 @@ * @module modules/akamaiDapRtdProvider * @requires module:modules/realTimeData */ -import {ajax} from '../src/ajax.js'; -import {getStorageManager} from '../src/storageManager.js'; -import {submodule} from '../src/hook.js'; -import {isPlainObject, mergeDeep, logMessage, logInfo, logError} from '../src/utils.js'; -import { loadExternalScript } from '../src/adloader.js'; -import {MODULE_TYPE_RTD} from '../src/activities/modules.js'; -/** - * @typedef {import('../modules/rtdModule/index.js').RtdSubmodule} RtdSubmodule - */ - -const MODULE_NAME = 'realTimeData'; -const SUBMODULE_NAME = 'dap'; -const MODULE_CODE = 'akamaidap'; - -export const DAP_TOKEN = 'async_dap_token'; -export const DAP_MEMBERSHIP = 'async_dap_membership'; -export const DAP_ENCRYPTED_MEMBERSHIP = 'encrypted_dap_membership'; -export const DAP_SS_ID = 'dap_ss_id'; -export const DAP_DEFAULT_TOKEN_TTL = 3600; // in seconds -export const DAP_MAX_RETRY_TOKENIZE = 1; -export const DAP_CLIENT_ENTROPY = 'dap_client_entropy' - -export const storage = getStorageManager({moduleType: MODULE_TYPE_RTD, moduleName: SUBMODULE_NAME}); -let dapRetryTokenize = 0; - -/** - * Lazy merge objects. - * @param {String} target - * @param {String} source - */ -function mergeLazy(target, source) { - if (!isPlainObject(target)) { - target = {}; - } - if (!isPlainObject(source)) { - source = {}; - } - return mergeDeep(target, source); -} - -/** - * Add real-time data & merge segments. - * @param {Object} ortb2 destination object to merge RTD into - * @param {Object} rtd - */ -export function addRealTimeData(ortb2, rtd) { - logInfo('DEBUG(addRealTimeData) - ENTER'); - if (isPlainObject(rtd.ortb2)) { - logMessage('DEBUG(addRealTimeData): merging original: ', ortb2); - logMessage('DEBUG(addRealTimeData): merging in: ', rtd.ortb2); - mergeLazy(ortb2, rtd.ortb2); - } - logInfo('DEBUG(addRealTimeData) - EXIT'); -} - -/** - * Real-time data retrieval from Audigent - * @param {Object} bidConfig - * @param {function} onDone - * @param {Object} rtdConfig - * @param {Object} userConsent - */ -export function getRealTimeData(bidConfig, onDone, rtdConfig, userConsent) { - let entropyDict = JSON.parse(storage.getDataFromLocalStorage(DAP_CLIENT_ENTROPY)); - let loadScriptPromise = new Promise((resolve, reject) => { - if (rtdConfig && rtdConfig.params && rtdConfig.params.dapEntropyTimeout && Number.isInteger(rtdConfig.params.dapEntropyTimeout)) { - setTimeout(reject, rtdConfig.params.dapEntropyTimeout, Error('DapEntropy script could not be loaded')); - } - if (entropyDict && entropyDict.expires_at > Math.round(Date.now() / 1000.0)) { - logMessage('Using cached entropy'); - resolve(); - } else { - if (typeof window.dapCalculateEntropy === 'function') { - window.dapCalculateEntropy(resolve, reject); - } else { - if (rtdConfig && rtdConfig.params && dapUtils.isValidHttpsUrl(rtdConfig.params.dapEntropyUrl)) { - loadExternalScript(rtdConfig.params.dapEntropyUrl, MODULE_CODE, () => { dapUtils.dapGetEntropy(resolve, reject) }); - } else { - reject(Error('Please check if dapEntropyUrl is specified and is valid under config.params')); - } - } - } - }); - loadScriptPromise - .catch((error) => { - logError('Entropy could not be calculated due to: ', error.message); - }) - .finally(() => { - generateRealTimeData(bidConfig, onDone, rtdConfig, userConsent); - }); -} - -export function generateRealTimeData(bidConfig, onDone, rtdConfig, userConsent) { - logInfo('DEBUG(generateRealTimeData) - ENTER'); - logMessage(' - apiHostname: ' + rtdConfig.params.apiHostname); - logMessage(' - apiVersion: ' + rtdConfig.params.apiVersion); - dapRetryTokenize = 0; - var jsonData = null; - if (rtdConfig && isPlainObject(rtdConfig.params)) { - if (rtdConfig.params.segtax == 504) { - let encMembership = dapUtils.dapGetEncryptedMembershipFromLocalStorage(); - if (encMembership) { - jsonData = dapUtils.dapGetEncryptedRtdObj(encMembership, rtdConfig.params.segtax) - } - } else { - let membership = dapUtils.dapGetMembershipFromLocalStorage(); - if (membership) { - jsonData = dapUtils.dapGetRtdObj(membership, rtdConfig.params.segtax) - } - } - } - if (jsonData) { - if (jsonData.rtd) { - addRealTimeData(bidConfig.ortb2Fragments?.global, jsonData.rtd); - onDone(); - logInfo('DEBUG(generateRealTimeData) - 1'); - // Don't return - ensure the data is always fresh. - } - } - // Calling setTimeout to release the main thread so that the bid request could be sent. - setTimeout(dapUtils.callDapAPIs, 0, bidConfig, onDone, rtdConfig, userConsent); -} - -/** - * Module init - * @param {Object} provider - * @param {Object} userConsent - * @return {boolean} - */ -function init(provider, userConsent) { - if (dapUtils.checkConsent(userConsent) === false) { - return false; - } - return true; -} - -/** @type {RtdSubmodule} */ -export const akamaiDapRtdSubmodule = { - name: SUBMODULE_NAME, - getBidRequestData: getRealTimeData, - init: init -}; - -submodule(MODULE_NAME, akamaiDapRtdSubmodule); -export const dapUtils = { - - callDapAPIs: function(bidConfig, onDone, rtdConfig, userConsent) { - if (rtdConfig && isPlainObject(rtdConfig.params)) { - let config = { - api_hostname: rtdConfig.params.apiHostname, - api_version: rtdConfig.params.apiVersion, - domain: rtdConfig.params.domain, - segtax: rtdConfig.params.segtax, - identity: {type: rtdConfig.params.identityType} - }; - let refreshMembership = true; - let token = dapUtils.dapGetTokenFromLocalStorage(); - const ortb2 = bidConfig.ortb2Fragments.global; - logMessage('token is: ', token); - if (token !== null) { // If token is not null then check the membership in storage and add the RTD object - if (config.segtax == 504) { // Follow the encrypted membership path - dapUtils.dapRefreshEncryptedMembership(ortb2, config, token, onDone) // Get the encrypted membership from server - refreshMembership = false; - } else { - dapUtils.dapRefreshMembership(ortb2, config, token, onDone) // Get the membership from server - refreshMembership = false; - } - } - dapUtils.dapRefreshToken(ortb2, config, refreshMembership, onDone) // Refresh Token and membership in all the cases - } - }, - dapGetEntropy: function(resolve, reject) { - if (typeof window.dapCalculateEntropy === 'function') { - window.dapCalculateEntropy(resolve, reject); - } else { - reject(Error('window.dapCalculateEntropy function is not defined')) - } - }, - - dapGetTokenFromLocalStorage: function(ttl) { - let now = Math.round(Date.now() / 1000.0); // in seconds - let token = null; - let item = JSON.parse(storage.getDataFromLocalStorage(DAP_TOKEN)); - if (item) { - if (now < item.expires_at) { - token = item.token; - } - } - return token; - }, - - dapRefreshToken: function(ortb2, config, refreshMembership, onDone) { - dapUtils.dapLog('Token missing or expired, fetching a new one...'); - // Trigger a refresh - let now = Math.round(Date.now() / 1000.0); // in seconds - let item = {} - let configAsync = {...config}; - dapUtils.dapTokenize(configAsync, config.identity, onDone, - function(token, status, xhr, onDone) { - item.expires_at = now + DAP_DEFAULT_TOKEN_TTL; - let exp = dapUtils.dapExtractExpiryFromToken(token); - if (typeof exp == 'number') { - item.expires_at = exp - 10; - } - item.token = token; - storage.setDataInLocalStorage(DAP_TOKEN, JSON.stringify(item)); - dapUtils.dapLog('Successfully updated and stored token; expires at ' + item.expires_at); - let dapSSID = xhr.getResponseHeader('Akamai-DAP-SS-ID'); - if (dapSSID) { - storage.setDataInLocalStorage(DAP_SS_ID, JSON.stringify(dapSSID)); - } - let deviceId100 = xhr.getResponseHeader('Akamai-DAP-100'); - if (deviceId100 != null) { - storage.setDataInLocalStorage('dap_deviceId100', deviceId100); - dapUtils.dapLog('Successfully stored DAP 100 Device ID: ' + deviceId100); - } - if (refreshMembership) { - if (config.segtax == 504) { - dapUtils.dapRefreshEncryptedMembership(ortb2, config, token, onDone); - } else { - dapUtils.dapRefreshMembership(ortb2, config, token, onDone); - } - } - }, - function(xhr, status, error, onDone) { - logError('ERROR(' + error + '): failed to retrieve token! ' + status); - onDone() - } - ); - }, - - dapGetMembershipFromLocalStorage: function() { - let now = Math.round(Date.now() / 1000.0); // in seconds - let membership = null; - let item = JSON.parse(storage.getDataFromLocalStorage(DAP_MEMBERSHIP)); - if (item) { - if (now < item.expires_at) { - membership = { - said: item.said, - cohorts: item.cohorts, - attributes: null - }; - } - } - return membership; - }, - - dapRefreshMembership: function(ortb2, config, token, onDone) { - let now = Math.round(Date.now() / 1000.0); // in seconds - let item = {} - let configAsync = {...config}; - dapUtils.dapMembership(configAsync, token, onDone, - function(membership, status, xhr, onDone) { - item.expires_at = now + DAP_DEFAULT_TOKEN_TTL; - let exp = dapUtils.dapExtractExpiryFromToken(membership.said) - if (typeof exp == 'number') { - item.expires_at = exp - 10; - } - item.said = membership.said; - item.cohorts = membership.cohorts; - storage.setDataInLocalStorage(DAP_MEMBERSHIP, JSON.stringify(item)); - dapUtils.dapLog('Successfully updated and stored membership:'); - dapUtils.dapLog(item); - - let data = dapUtils.dapGetRtdObj(item, config.segtax) - dapUtils.checkAndAddRealtimeData(ortb2, data, config.segtax); - onDone(); - }, - function(xhr, status, error, onDone) { - logError('ERROR(' + error + '): failed to retrieve membership! ' + status); - if (status == 403 && dapRetryTokenize < DAP_MAX_RETRY_TOKENIZE) { - dapRetryTokenize++; - dapUtils.dapRefreshToken(ortb2, config, true, onDone); - } else { - onDone(); - } - } - ); - }, - - dapGetEncryptedMembershipFromLocalStorage: function() { - let now = Math.round(Date.now() / 1000.0); // in seconds - let encMembership = null; - let item = JSON.parse(storage.getDataFromLocalStorage(DAP_ENCRYPTED_MEMBERSHIP)); - if (item) { - if (now < item.expires_at) { - encMembership = { - encryptedSegments: item.encryptedSegments - }; - } - } - return encMembership; - }, - - dapRefreshEncryptedMembership: function(ortb2, config, token, onDone) { - let now = Math.round(Date.now() / 1000.0); // in seconds - let item = {}; - let configAsync = {...config}; - dapUtils.dapEncryptedMembership(configAsync, token, onDone, - function(encToken, status, xhr, onDone) { - item.expires_at = now + DAP_DEFAULT_TOKEN_TTL; - let exp = dapUtils.dapExtractExpiryFromToken(encToken); - if (typeof exp == 'number') { - item.expires_at = exp - 10; - } - item.encryptedSegments = encToken; - storage.setDataInLocalStorage(DAP_ENCRYPTED_MEMBERSHIP, JSON.stringify(item)); - dapUtils.dapLog('Successfully updated and stored encrypted membership:'); - dapUtils.dapLog(item); - - let encData = dapUtils.dapGetEncryptedRtdObj(item, config.segtax); - dapUtils.checkAndAddRealtimeData(ortb2, encData, config.segtax); - onDone(); - }, - function(xhr, status, error, onDone) { - logError('ERROR(' + error + '): failed to retrieve encrypted membership! ' + status); - if (status == 403 && dapRetryTokenize < DAP_MAX_RETRY_TOKENIZE) { - dapRetryTokenize++; - dapUtils.dapRefreshToken(ortb2, config, true, onDone); - } else { - onDone(); - } - } - ); - }, - - /** - * DESCRIPTION - * Extract expiry value from a token - */ - dapExtractExpiryFromToken: function(token) { - let exp = null; - if (token) { - const tokenArray = token.split('..'); - if (tokenArray && tokenArray.length > 0) { - let decode = atob(tokenArray[0]) - let header = JSON.parse(decode.replace(/"/g, '"')); - exp = header.exp; - } - } - return exp - }, - - /** - * DESCRIPTION - * - * Convert a DAP membership response to an OpenRTB2 segment object suitable - * for insertion into user.data.segment or site.data.segment and add it to the rtd obj. - */ - dapGetRtdObj: function(membership, segtax) { - let segment = { - name: 'dap.akamai.com', - ext: { - 'segtax': segtax - }, - segment: [] - }; - if (membership != null) { - for (const i of membership.cohorts) { - segment.segment.push({ id: i }); - } - } - let data = { - rtd: { - ortb2: { - user: { - data: [ - segment - ] - }, - site: { - ext: { - data: { - dapSAID: membership.said - } - } - } - } - } - }; - return data; - }, - - /** - * DESCRIPTION - * - * Convert a DAP membership response to an OpenRTB2 segment object suitable - * for insertion into user.data.segment or site.data.segment and add it to the rtd obj. - */ - dapGetEncryptedRtdObj: function(encToken, segtax) { - let segment = { - name: 'dap.akamai.com', - ext: { - 'segtax': segtax - }, - segment: [] - }; - if (encToken != null) { - segment.segment.push({ id: encToken.encryptedSegments }); - } - let encData = { - rtd: { - ortb2: { - user: { - data: [ - segment - ] - } - } - } - }; - return encData; - }, - - checkAndAddRealtimeData: function(ortb2, data, segtax) { - if (data.rtd) { - if (segtax == 504 && dapUtils.checkIfSegmentsAlreadyExist(ortb2, data.rtd, 504)) { - logMessage('DEBUG(handleInit): rtb Object already added'); - } else { - addRealTimeData(ortb2, data.rtd); - } - logInfo('DEBUG(checkAndAddRealtimeData) - 1'); - } - }, - - checkIfSegmentsAlreadyExist: function(ortb2, rtd, segtax) { - let segmentsExist = false - if (ortb2.user && ortb2.user.data && ortb2.user.data.length > 0) { - for (let i = 0; i < ortb2.user.data.length; i++) { - let element = ortb2.user.data[i] - if (element.ext && element.ext.segtax == segtax) { - segmentsExist = true - logMessage('DEBUG(checkIfSegmentsAlreadyExist): rtb Object already added: ', ortb2.user.data); - break; - } - } - } - return segmentsExist - }, - - dapLog: function(args) { - let css = ''; - css += 'display: inline-block;'; - css += 'color: #fff;'; - css += 'background: #F28B20;'; - css += 'padding: 1px 4px;'; - css += 'border-radius: 3px'; - - logInfo('%cDAP Client', css, args); - }, - - isValidHttpsUrl: function(urlString) { - let url; - try { - url = new URL(urlString); - } catch (_) { - return false; - } - return url.protocol === 'https:'; - }, - - checkConsent: function(userConsent) { - let consent = true; - - if (userConsent && userConsent.gdpr && userConsent.gdpr.gdprApplies) { - const gdpr = userConsent.gdpr; - const hasGdpr = (gdpr && typeof gdpr.gdprApplies === 'boolean' && gdpr.gdprApplies) ? 1 : 0; - const gdprConsentString = hasGdpr ? gdpr.consentString : ''; - if (hasGdpr && (!gdprConsentString || gdprConsentString === '')) { - logError('akamaiDapRtd submodule requires consent string to call API'); - consent = false; - } - } else if (userConsent && userConsent.usp) { - const usp = userConsent.usp; - consent = usp[1] !== 'N' && usp[2] !== 'Y'; - } - - return consent; - }, - - /******************************************************************************* - * - * V2 (And Beyond) API - * - ******************************************************************************/ - - /** - * SYNOPSIS - * - * dapTokenize( config, identity ); - * - * DESCRIPTION - * - * Tokenize an identity into a secure, privacy safe pseudonymiziation. - * - * PARAMETERS - * - * config: an array of system configuration parameters - * - * identity: an array of identity parameters passed to the tokenizing system - * - * EXAMPLE - * - * config = { - * api_hostname: "prebid.dap.akadns.net", // required - * domain: "prebid.org", // required - * api_version: "x1", // optional, default "x1" - * }; - * - * token = null; - * identity_email = { - * type: "email", - * identity: "obiwan@jedi.com" - * attributes: { cohorts: [ "100:1641013200", "101:1641013200", "102":3:1641013200" ] }, - * }; - * dap_x1_tokenize( config, identity_email, - * function( response, status, xhr ) { token = response; }, - * function( xhr, status, error ) { ; } // handle error - * - * token = null; - * identity_signature = { type: "signature:1.0.0" }; - * dap_x1_tokenize( config, identity_signature, - * function( response, status, xhr } { token = response; }, - * function( xhr, status, error ) { ; } // handle error - */ - dapTokenize: function(config, identity, onDone, onSuccess = null, onError = null) { - if (onError == null) { - onError = function(xhr, status, error, onDone) {}; - } - - if (config == null || typeof (config) == typeof (undefined)) { - onError(null, 'Invalid config object', 'ClientError', onDone); - return; - } - - if (typeof (config.domain) != 'string') { - onError(null, 'Invalid config.domain: must be a string', 'ClientError', onDone); - return; - } - - if (config.domain.length <= 0) { - onError(null, 'Invalid config.domain: must have non-zero length', 'ClientError', onDone); - return; - } - - if (!('api_version' in config) || (typeof (config.api_version) == 'string' && config.api_version.length == 0)) { - config.api_version = 'x1'; - } - - if (typeof (config.api_version) != 'string') { - onError(null, "Invalid api_version: must be a string like 'x1', etc.", 'ClientError', onDone); - return; - } - - if (!(('api_hostname') in config) || typeof (config.api_hostname) != 'string' || config.api_hostname.length == 0) { - onError(null, 'Invalid api_hostname: must be a non-empty string', 'ClientError', onDone); - return; - } - - if (identity == null || typeof (identity) == typeof (undefined)) { - onError(null, 'Invalid identity object', 'ClientError', onDone); - return; - } - - if (!('type' in identity) || typeof (identity.type) != 'string' || identity.type.length <= 0) { - onError(null, "Identity must contain a valid 'type' field", 'ClientError', onDone); - return; - } - - let apiParams = { - 'type': identity.type, - }; - - if (typeof (identity.identity) != typeof (undefined)) { - apiParams.identity = identity.identity; - } - if (typeof (identity.attributes) != typeof (undefined)) { - apiParams.attributes = identity.attributes; - } - - let entropyDict = JSON.parse(storage.getDataFromLocalStorage(DAP_CLIENT_ENTROPY)); - if (entropyDict && entropyDict.entropy) { - apiParams.entropy = entropyDict.entropy; - } - - let method; - let body; - let path; - switch (config.api_version) { - case 'x1': - case 'x1-dev': - method = 'POST'; - path = '/data-activation/' + config.api_version + '/domain/' + config.domain + '/identity/tokenize'; - body = JSON.stringify(apiParams); - break; - default: - onError(null, 'Invalid api_version: ' + config.api_version, 'ClientError', onDone); - return; - } - - let customHeaders = {'Content-Type': 'application/json'}; - let dapSSID = JSON.parse(storage.getDataFromLocalStorage(DAP_SS_ID)); - if (dapSSID) { - customHeaders['Akamai-DAP-SS-ID'] = dapSSID; - } - - let url = 'https://' + config.api_hostname + path; - let cb = { - success: (response, request) => { - let token = null; - switch (config.api_version) { - case 'x1': - case 'x1-dev': - token = request.getResponseHeader('Akamai-DAP-Token'); - break; - } - onSuccess(token, request.status, request, onDone); - }, - error: (request, error) => { - onError(request, request.statusText, error, onDone); - } - }; - - ajax(url, cb, body, { - method: method, - customHeaders: customHeaders - }); - }, - - /** - * SYNOPSIS - * - * dapMembership( config, token, onSuccess, onError ); - * - * DESCRIPTION - * - * Return the audience segment membership along with a new Secure Advertising - * ID for this token. - * - * PARAMETERS - * - * config: an array of system configuration parameters - * - * token: the token previously returned from the tokenize API - * - * EXAMPLE - * - * config = { - * api_hostname: 'api.dap.akadns.net', - * }; - * - * // token from dap_tokenize - * - * dapMembership( config, token, - * function( membership, status, xhr ) { - * // Run auction with membership.segments and membership.said - * }, - * function( xhr, status, error ) { - * // error - * } ); - * - */ - dapMembership: function(config, token, onDone, onSuccess = null, onError = null) { - if (onError == null) { - onError = function(xhr, status, error, onDone) {}; - } - - if (config == null || typeof (config) == typeof (undefined)) { - onError(null, 'Invalid config object', 'ClientError', onDone); - return; - } - - if (!('api_version' in config) || (typeof (config.api_version) == 'string' && config.api_version.length == 0)) { - config.api_version = 'x1'; - } - - if (typeof (config.api_version) != 'string') { - onError(null, "Invalid api_version: must be a string like 'x1', etc.", 'ClientError', onDone); - return; - } - - if (!(('api_hostname') in config) || typeof (config.api_hostname) != 'string' || config.api_hostname.length == 0) { - onError(null, 'Invalid api_hostname: must be a non-empty string', 'ClientError', onDone); - return; - } - - if (token == null || typeof (token) != 'string') { - onError(null, 'Invalid token: must be a non-null string', 'ClientError', onDone); - return; - } - let path = '/data-activation/' + - config.api_version + - '/token/' + token + - '/membership'; - - let url = 'https://' + config.api_hostname + path; - - let cb = { - success: (response, request) => { - onSuccess(JSON.parse(response), request.status, request, onDone); - }, - error: (error, request) => { - onError(request, request.status, error, onDone); - } - }; - - ajax(url, cb, undefined, { - method: 'GET', - customHeaders: {} - }); - }, - - /** - * SYNOPSIS - * - * dapEncryptedMembership( config, token, onSuccess, onError ); - * - * DESCRIPTION - * - * Return the audience segment membership along with a new Secure Advertising - * ID for this token in encrypted format. - * - * PARAMETERS - * - * config: an array of system configuration parameters - * - * token: the token previously returned from the tokenize API - * - * EXAMPLE - * - * config = { - * api_hostname: 'api.dap.akadns.net', - * }; - * - * // token from dap_tokenize - * - * dapEncryptedMembership( config, token, - * function( membership, status, xhr ) { - * // Run auction with membership.segments and membership.said after decryption - * }, - * function( xhr, status, error ) { - * // error - * } ); - * - */ - dapEncryptedMembership: function(config, token, onDone, onSuccess = null, onError = null) { - if (onError == null) { - onError = function(xhr, status, error, onDone) {}; - } - - if (config == null || typeof (config) == typeof (undefined)) { - onError(null, 'Invalid config object', 'ClientError', onDone); - return; - } - - if (!('api_version' in config) || (typeof (config.api_version) == 'string' && config.api_version.length == 0)) { - config.api_version = 'x1'; - } - - if (typeof (config.api_version) != 'string') { - onError(null, "Invalid api_version: must be a string like 'x1', etc.", 'ClientError', onDone); - return; - } - - if (!(('api_hostname') in config) || typeof (config.api_hostname) != 'string' || config.api_hostname.length == 0) { - onError(null, 'Invalid api_hostname: must be a non-empty string', 'ClientError', onDone); - return; - } - - if (token == null || typeof (token) != 'string') { - onError(null, 'Invalid token: must be a non-null string', 'ClientError', onDone); - return; - } - let path = '/data-activation/' + - config.api_version + - '/token/' + token + - '/membership/encrypt'; - - let url = 'https://' + config.api_hostname + path; - - let cb = { - success: (response, request) => { - let encToken = request.getResponseHeader('Akamai-DAP-Token'); - onSuccess(encToken, request.status, request, onDone); - }, - error: (error, request) => { - onError(request, request.status, error, onDone); - } - }; - ajax(url, cb, undefined, { - method: 'GET', - customHeaders: { - 'Content-Type': 'application/json', - 'Pragma': 'akamai-x-get-extracted-values' - } - }); - } -} +import { + createRtdProvider +} from './symitriDapRtdProvider.js'/* eslint prebid/validate-imports: "off" */ + +export const { + addRealTimeData, + getRealTimeData, + generateRealTimeData, + rtdSubmodule: akamaiDapRtdSubmodule, + storage, + dapUtils, + DAP_TOKEN, + DAP_MEMBERSHIP, + DAP_ENCRYPTED_MEMBERSHIP, + DAP_SS_ID, + DAP_DEFAULT_TOKEN_TTL, + DAP_MAX_RETRY_TOKENIZE, + DAP_CLIENT_ENTROPY +} = createRtdProvider('dap', 'akamaidap', 'Akamai'); diff --git a/modules/anonymisedRtdProvider.js b/modules/anonymisedRtdProvider.js index 48ac649f002..c3bb21ce8a5 100644 --- a/modules/anonymisedRtdProvider.js +++ b/modules/anonymisedRtdProvider.js @@ -9,10 +9,13 @@ import {getStorageManager} from '../src/storageManager.js'; import {submodule} from '../src/hook.js'; import {isPlainObject, mergeDeep, logMessage, logError} from '../src/utils.js'; import {MODULE_TYPE_RTD} from '../src/activities/modules.js'; - +/** + * @typedef {import('../modules/rtdModule/index.js').RtdSubmodule} RtdSubmodule + */ export function createRtdProvider(moduleName) { const MODULE_NAME = 'realTimeData'; const SUBMODULE_NAME = moduleName; + const GVLID = 1116; const storage = getStorageManager({ moduleType: MODULE_TYPE_RTD, moduleName: SUBMODULE_NAME }); /** @@ -106,6 +109,7 @@ export function createRtdProvider(moduleName) { /** @type {RtdSubmodule} */ const rtdSubmodule = { name: SUBMODULE_NAME, + gvlid: GVLID, getBidRequestData: getRealTimeData, init: init }; diff --git a/modules/anonymisedRtdProvider.md b/modules/anonymisedRtdProvider.md index 2ff2597690b..936e5fc7437 100644 --- a/modules/anonymisedRtdProvider.md +++ b/modules/anonymisedRtdProvider.md @@ -8,7 +8,7 @@ Anonymised’s Real-time Data Provider automatically obtains segment IDs from th - Build the anonymisedRtd module into the Prebid.js package with: ```bash - gulp build --modules=anonymisedRtdProvider,... + gulp build --modules=rtdModule,anonymisedRtdProvider,... ``` - Use `setConfig` to instruct Prebid.js to initilaize the anonymisedRtdProvider module, as specified below. diff --git a/modules/apacdexBidAdapter.js b/modules/apacdexBidAdapter.js index fce4d16daf6..83119052f3a 100644 --- a/modules/apacdexBidAdapter.js +++ b/modules/apacdexBidAdapter.js @@ -1,7 +1,7 @@ import { deepAccess, isPlainObject, isArray, replaceAuctionPrice, isFn, logError, deepClone } from '../src/utils.js'; import { config } from '../src/config.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; -import {hasPurpose1Consent} from '../src/utils/gpdr.js'; +import {hasPurpose1Consent} from '../src/utils/gdpr.js'; import {parseDomain} from '../src/refererDetection.js'; const BIDDER_CODE = 'apacdex'; const ENDPOINT = 'https://useast.quantumdex.io/auction/pbjs' diff --git a/modules/appnexusBidAdapter.js b/modules/appnexusBidAdapter.js index 3d851c96a1f..387df07a8b4 100644 --- a/modules/appnexusBidAdapter.js +++ b/modules/appnexusBidAdapter.js @@ -15,7 +15,8 @@ import { logError, logInfo, logMessage, - logWarn + logWarn, + mergeDeep } from '../src/utils.js'; import {Renderer} from '../src/Renderer.js'; import {config} from '../src/config.js'; @@ -25,7 +26,7 @@ import {find, includes} from '../src/polyfill.js'; import {INSTREAM, OUTSTREAM} from '../src/video.js'; import {getStorageManager} from '../src/storageManager.js'; import {bidderSettings} from '../src/bidderSettings.js'; -import {hasPurpose1Consent} from '../src/utils/gpdr.js'; +import {hasPurpose1Consent} from '../src/utils/gdpr.js'; import {convertOrtbRequestToProprietaryNative} from '../src/native.js'; import {APPNEXUS_CATEGORY_MAPPING} from '../libraries/categoryTranslationMapping/index.js'; import { @@ -103,6 +104,28 @@ const VIEWABILITY_URL_START = /\/\/cdn\.adnxs\.com\/v|\/\/cdn\.adnxs\-simple\.co const VIEWABILITY_FILE_NAME = 'trk.js'; const GVLID = 32; const storage = getStorageManager({bidderCode: BIDDER_CODE}); +// ORTB2 device types according to the OpenRTB specification +const ORTB2_DEVICE_TYPE = { + MOBILE_TABLET: 1, + PERSONAL_COMPUTER: 2, + CONNECTED_TV: 3, + PHONE: 4, + TABLET: 5, + CONNECTED_DEVICE: 6, + SET_TOP_BOX: 7, + OOH_DEVICE: 8 +}; +// Map of ORTB2 device types to AppNexus device types +const ORTB2_DEVICE_TYPE_MAP = new Map([ + [ORTB2_DEVICE_TYPE.MOBILE_TABLET, 'Mobile/Tablet - General'], + [ORTB2_DEVICE_TYPE.PERSONAL_COMPUTER, 'Personal Computer'], + [ORTB2_DEVICE_TYPE.CONNECTED_TV, 'Connected TV'], + [ORTB2_DEVICE_TYPE.PHONE, 'Phone'], + [ORTB2_DEVICE_TYPE.TABLET, 'Tablet'], + [ORTB2_DEVICE_TYPE.CONNECTED_DEVICE, 'Connected Device'], + [ORTB2_DEVICE_TYPE.SET_TOP_BOX, 'Set Top Box'], + [ORTB2_DEVICE_TYPE.OOH_DEVICE, 'OOH Device'], +]); export const spec = { code: BIDDER_CODE, @@ -247,6 +270,12 @@ export const spec = { payload.app = appIdObj; } + // if present, convert and merge device object from ortb2 into `payload.device` + if (bidderRequest?.ortb2?.device) { + payload.device = payload.device || {}; + mergeDeep(payload.device, convertORTB2DeviceDataToAppNexusDeviceObject(bidderRequest.ortb2.device)); + } + // grab the ortb2 keyword data (if it exists) and convert from the comma list string format to object format let ortb2 = deepClone(bidderRequest && bidderRequest.ortb2); @@ -537,7 +566,7 @@ function newBid(serverBid, rtbBid, bidderRequest) { cpm: rtbBid.cpm, creativeId: rtbBid.creative_id, dealId: rtbBid.deal_id, - currency: rtbBid.publisher_currency_codename || 'USD', + currency: 'USD', netRevenue: true, ttl: 300, adUnitCode: bidRequest.adUnitCode, @@ -1196,4 +1225,29 @@ function getBidFloor(bid) { return null; } +// Convert device data to a format that AppNexus expects +function convertORTB2DeviceDataToAppNexusDeviceObject(ortb2DeviceData) { + const _device = { + useragent: ortb2DeviceData.ua, + devicetype: ORTB2_DEVICE_TYPE_MAP.get(ortb2DeviceData.devicetype), + make: ortb2DeviceData.make, + model: ortb2DeviceData.model, + os: ortb2DeviceData.os, + os_version: ortb2DeviceData.osv, + w: ortb2DeviceData.w, + h: ortb2DeviceData.h, + ppi: ortb2DeviceData.ppi, + pxratio: ortb2DeviceData.pxratio, + }; + + // filter out any empty values and return the object + return Object.keys(_device) + .reduce((r, key) => { + if (_device[key]) { + r[key] = _device[key]; + } + return r; + }, {}); +} + registerBidder(spec); diff --git a/modules/automatadAnalyticsAdapter.js b/modules/automatadAnalyticsAdapter.js index 523e8d558ca..7ed109ab705 100644 --- a/modules/automatadAnalyticsAdapter.js +++ b/modules/automatadAnalyticsAdapter.js @@ -18,6 +18,8 @@ var isLoggingEnabled; var queuePointer = 0; var retryCount = 0; var timer = null const prettyLog = (level, text, isGroup = false, cb = () => {}) => { if (self.isLoggingEnabled === undefined) { + // TODO FIX THIS RULES VIOLATION + // eslint-disable-next-line prebid/no-global if (window.localStorage.getItem('__aggLoggingEnabled')) { self.isLoggingEnabled = true } else { diff --git a/modules/azerionedgeRtdProvider.js b/modules/azerionedgeRtdProvider.js index a162ce074aa..852639972c2 100644 --- a/modules/azerionedgeRtdProvider.js +++ b/modules/azerionedgeRtdProvider.js @@ -19,6 +19,8 @@ const REAL_TIME_MODULE = 'realTimeData'; const SUBREAL_TIME_MODULE = 'azerionedge'; export const STORAGE_KEY = 'ht-pa-v1-a'; +const IMPROVEDIGITAL_GVLID = '253'; + export const storage = getStorageManager({ moduleType: MODULE_TYPE_RTD, moduleName: SUBREAL_TIME_MODULE, @@ -42,14 +44,21 @@ function getScriptURL(config) { * Attach script tag to DOM * * @param {Object} config + * @param {Object} userConsent * * @return {void} */ -export function attachScript(config) { +export function attachScript(config, userConsent) { const script = getScriptURL(config); loadExternalScript(script, SUBREAL_TIME_MODULE, () => { if (typeof window.azerionPublisherAudiences === 'function') { - window.azerionPublisherAudiences(config.params?.process || {}); + const publisherConfig = config.params?.process || {}; + window.azerionPublisherAudiences({ + ...publisherConfig, + gdprApplies: userConsent?.gdpr?.gdprApplies, + gdprConsent: userConsent?.gdpr?.consentString, + uspConsent: userConsent?.usp, + }); } }); } @@ -106,7 +115,7 @@ export function setAudiencesToBidders(reqBidsConfigObj, config, audiences) { * @return {boolean} */ function init(config, userConsent) { - attachScript(config); + attachScript(config, userConsent); return true; } @@ -138,6 +147,7 @@ export const azerionedgeSubmodule = { name: SUBREAL_TIME_MODULE, init: init, getBidRequestData: getBidRequestData, + gvlid: IMPROVEDIGITAL_GVLID, }; submodule(REAL_TIME_MODULE, azerionedgeSubmodule); diff --git a/modules/azerionedgeRtdProvider.md b/modules/azerionedgeRtdProvider.md index 6658907c480..e1bdf792647 100644 --- a/modules/azerionedgeRtdProvider.md +++ b/modules/azerionedgeRtdProvider.md @@ -79,23 +79,6 @@ provided to the module when the user gives the relevant permissions on the publi As Prebid.js utilizes TCF vendor consent for the RTD module to load, the module needs to be labeled within the Vendor Exceptions. -### Instructions - -If the Prebid GDPR enforcement is enabled, the module should be labeled -as exception, as shown below: - -```js -[ - { - purpose: 'storage', - enforcePurpose: true, - enforceVendor: true, - vendorExceptions: ["azerionedge"] - }, - ... -] -``` - ## Testing To view an example: diff --git a/modules/bridBidAdapter.js b/modules/bridBidAdapter.js index f3fe1541886..527cb9d5d5d 100644 --- a/modules/bridBidAdapter.js +++ b/modules/bridBidAdapter.js @@ -1,7 +1,7 @@ -import {createTrackPixelHtml, _each, deepAccess, getDefinedParams, parseGPTSingleSizeArrayToRtbSize} from '../src/utils.js'; +import {_each, deepAccess, getDefinedParams, parseGPTSingleSizeArrayToRtbSize} from '../src/utils.js'; import {VIDEO} from '../src/mediaTypes.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {getRefererInfo} from '../src/refererDetection.js'; +import {getAd, getSiteObj} from '../libraries/targetVideoUtils/bidderUtils.js' /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest @@ -180,50 +180,50 @@ export const spec = { } -/** - * Helper function to get ad - * - * @param {object} bid The bid. - * @return {object} ad object. - */ -function getAd(bid) { - let ad, adUrl, vastXml, vastUrl; - - switch (deepAccess(bid, 'ext.prebid.type')) { - case VIDEO: - if (bid.adm.substr(0, 4) === 'http') { - vastUrl = bid.adm; - } else { - vastXml = bid.adm; - }; - break; - default: - if (bid.adm && bid.nurl) { - ad = bid.adm; - ad += createTrackPixelHtml(decodeURIComponent(bid.nurl)); - } else if (bid.adm) { - ad = bid.adm; - } else if (bid.nurl) { - adUrl = bid.nurl; - }; - } - - return {ad, adUrl, vastXml, vastUrl}; -} - -/** - * Helper function to get site object - * - * @return {object} siteObj. - */ -function getSiteObj() { - const refInfo = (getRefererInfo && getRefererInfo()) || {}; - - return { - page: refInfo.page, - ref: refInfo.ref, - domain: refInfo.domain - }; -} +// /** +// * Helper function to get ad +// * +// * @param {object} bid The bid. +// * @return {object} ad object. +// */ +// function getAd(bid) { +// let ad, adUrl, vastXml, vastUrl; + +// switch (deepAccess(bid, 'ext.prebid.type')) { +// case VIDEO: +// if (bid.adm.substr(0, 4) === 'http') { +// vastUrl = bid.adm; +// } else { +// vastXml = bid.adm; +// }; +// break; +// default: +// if (bid.adm && bid.nurl) { +// ad = bid.adm; +// ad += createTrackPixelHtml(decodeURIComponent(bid.nurl)); +// } else if (bid.adm) { +// ad = bid.adm; +// } else if (bid.nurl) { +// adUrl = bid.nurl; +// }; +// } + +// return {ad, adUrl, vastXml, vastUrl}; +// } + +// /** +// * Helper function to get site object +// * +// * @return {object} siteObj. +// */ +// function getSiteObj() { +// const refInfo = (getRefererInfo && getRefererInfo()) || {}; + +// return { +// page: refInfo.page, +// ref: refInfo.ref, +// domain: refInfo.domain +// }; +// } registerBidder(spec); diff --git a/modules/carodaBidAdapter.js b/modules/carodaBidAdapter.js index cb7b5fbe7c5..8ec260213b6 100644 --- a/modules/carodaBidAdapter.js +++ b/modules/carodaBidAdapter.js @@ -8,7 +8,8 @@ import { deepSetValue, logError, mergeDeep, - parseSizesInput + sizeTupleToRtbSize, + sizesToSizeTuples } from '../src/utils.js'; import { config } from '../src/config.js'; @@ -195,13 +196,7 @@ function getImps (validBidRequests, common) { }; const bannerParams = deepAccess(bid, 'mediaTypes.banner'); if (bannerParams && bannerParams.sizes) { - const sizes = parseSizesInput(bannerParams.sizes); - const format = sizes.map(size => { - const [width, height] = size.split('x'); - const w = parseInt(width, 10); - const h = parseInt(height, 10); - return { w, h }; - }); + const format = sizesToSizeTuples(bannerParams.sizes).map(sizeTupleToRtbSize); imp.banner = { format }; diff --git a/modules/cleanioRtdProvider.js b/modules/cleanioRtdProvider.js index c3f3dd51a61..1a5e64de3cc 100644 --- a/modules/cleanioRtdProvider.js +++ b/modules/cleanioRtdProvider.js @@ -43,6 +43,7 @@ let preloadStatus = 0; * @param {string} scriptURL The script URL to preload */ function pageInitStepPreloadScript(scriptURL) { + // TODO: this bypasses adLoader const linkElement = document.createElement('link'); linkElement.rel = 'preload'; linkElement.as = 'script'; diff --git a/modules/cleanmedianetBidAdapter.js b/modules/cleanmedianetBidAdapter.js index a0e85032798..01178d63872 100644 --- a/modules/cleanmedianetBidAdapter.js +++ b/modules/cleanmedianetBidAdapter.js @@ -157,7 +157,7 @@ export const spec = { maxduration: bidRequest.mediaTypes.video.maxduration, api: bidRequest.mediaTypes.video.api, skip: bidRequest.mediaTypes.video.skip || bidRequest.params.video.skip, - placement: bidRequest.mediaTypes.video.plcmt || bidRequest.params.video.plcmt, + plcmt: bidRequest.mediaTypes.video.plcmt || bidRequest.params.video.plcmt, minduration: bidRequest.mediaTypes.video.minduration || bidRequest.params.video.minduration, playbackmethod: bidRequest.mediaTypes.video.playbackmethod || bidRequest.params.video.playbackmethod, startdelay: bidRequest.mediaTypes.video.startdelay || bidRequest.params.video.startdelay diff --git a/modules/codefuelBidAdapter.js b/modules/codefuelBidAdapter.js index a4accee3ce0..9f85b2b82cb 100644 --- a/modules/codefuelBidAdapter.js +++ b/modules/codefuelBidAdapter.js @@ -1,4 +1,4 @@ -import {deepAccess, isArray} from '../src/utils.js'; +import {isArray, setOnAny} from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER} from '../src/mediaTypes.js'; @@ -148,15 +148,6 @@ function getDeviceType() { return 2; // 'desktop' } -function setOnAny(collection, key) { - for (let i = 0, result; i < collection.length; i++) { - result = deepAccess(collection[i], key); - if (result) { - return result; - } - } -} - function flatten(arr) { return [].concat(...arr); } diff --git a/modules/concertBidAdapter.js b/modules/concertBidAdapter.js index 12dba194844..ec65ba11205 100644 --- a/modules/concertBidAdapter.js +++ b/modules/concertBidAdapter.js @@ -1,7 +1,7 @@ import { logWarn, logMessage, debugTurnedOn, generateUUID, deepAccess } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { getStorageManager } from '../src/storageManager.js'; -import { hasPurpose1Consent } from '../src/utils/gpdr.js'; +import { hasPurpose1Consent } from '../src/utils/gdpr.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest diff --git a/modules/connatixBidAdapter.js b/modules/connatixBidAdapter.js index 0b840db6c26..802ad855e27 100644 --- a/modules/connatixBidAdapter.js +++ b/modules/connatixBidAdapter.js @@ -11,7 +11,9 @@ import { } from '../src/utils.js'; import { + ADPOD, BANNER, + VIDEO, } from '../src/mediaTypes.js'; const BIDDER_CODE = 'connatix'; @@ -41,10 +43,28 @@ export function getBidFloor(bid) { } } +export function validateBanner(mediaTypes) { + if (!mediaTypes[BANNER]) { + return true; + } + + const banner = deepAccess(mediaTypes, BANNER, {}); + return (Boolean(banner.sizes) && isArray(mediaTypes[BANNER].sizes) && mediaTypes[BANNER].sizes.length > 0); +} + +export function validateVideo(mediaTypes) { + const video = mediaTypes[VIDEO]; + if (!video) { + return true; + } + + return video.context !== ADPOD; +} + export const spec = { code: BIDDER_CODE, gvlid: 143, - supportedMediaTypes: [BANNER], + supportedMediaTypes: [BANNER, VIDEO], /* * Validate the bid request. @@ -57,17 +77,24 @@ export const spec = { const params = deepAccess(bid, 'params', {}); const bidder = deepAccess(bid, 'bidder'); - const banner = deepAccess(mediaTypes, BANNER, {}); - const hasBidId = Boolean(bidId); const isValidBidder = (bidder === BIDDER_CODE); - const isValidSize = (Boolean(banner.sizes) && isArray(mediaTypes[BANNER].sizes) && mediaTypes[BANNER].sizes.length > 0); - const hasSizes = mediaTypes[BANNER] ? isValidSize : false; + const hasMediaTypes = Boolean(mediaTypes) && (Boolean(mediaTypes[BANNER]) || Boolean(mediaTypes[VIDEO])); + const isValidBanner = validateBanner(mediaTypes); + const isValidVideo = validateVideo(mediaTypes); const hasRequiredBidParams = Boolean(params.placementId); - const isValid = isValidBidder && hasBidId && hasSizes && hasRequiredBidParams; + const isValid = isValidBidder && hasBidId && hasMediaTypes && isValidBanner && isValidVideo && hasRequiredBidParams; if (!isValid) { - logError(`Invalid bid request: isValidBidder: ${isValidBidder} hasBidId: ${hasBidId}, hasSizes: ${hasSizes}, hasRequiredBidParams: ${hasRequiredBidParams}`); + logError( + `Invalid bid request: + isValidBidder: ${isValidBidder}, + hasBidId: ${hasBidId}, + hasMediaTypes: ${hasMediaTypes}, + isValidBanner: ${isValidBanner}, + isValidVideo: ${isValidVideo}, + hasRequiredBidParams: ${hasRequiredBidParams}` + ); } return isValid; }, @@ -129,12 +156,13 @@ export const spec = { cpm: bidResponse.Cpm, ttl: bidResponse.Ttl || DEFAULT_MAX_TTL, currency: 'USD', - mediaType: BANNER, + mediaType: bidResponse.VastXml ? VIDEO : BANNER, netRevenue: true, width: bidResponse.Width, height: bidResponse.Height, creativeId: bidResponse.CreativeId, ad: bidResponse.Ad, + vastXml: bidResponse.VastXml, referrer: referrer, })); }, diff --git a/modules/connectIdSystem.js b/modules/connectIdSystem.js index 2ebc68baa84..6926c69d453 100644 --- a/modules/connectIdSystem.js +++ b/modules/connectIdSystem.js @@ -313,12 +313,16 @@ export const connectIdSubmodule = { /** * Utility function that returns a boolean flag indicating if the user - * has opeted out via the Yahoo easy-opt-out mechanism. + * has opted out via the Yahoo easy-opt-out mechanism. * @returns {Boolean} */ userHasOptedOut() { try { - return localStorage.getItem(OVERRIDE_OPT_OUT_KEY) === '1'; + if (storage.localStorageIsEnabled()) { + return storage.getDataFromLocalStorage(OVERRIDE_OPT_OUT_KEY) === '1'; + } else { + return true; + } } catch { return false; } diff --git a/modules/contxtfulRtdProvider.js b/modules/contxtfulRtdProvider.js index e2bb1f3b909..03050a6a64f 100644 --- a/modules/contxtfulRtdProvider.js +++ b/modules/contxtfulRtdProvider.js @@ -17,12 +17,19 @@ import { isArray, } from '../src/utils.js'; import { loadExternalScript } from '../src/adloader.js'; +import { getStorageManager } from '../src/storageManager.js'; +import { MODULE_TYPE_RTD } from '../src/activities/modules.js'; const MODULE_NAME = 'contxtful'; const MODULE = `${MODULE_NAME}RtdProvider`; const CONTXTFUL_RECEPTIVITY_DOMAIN = 'api.receptivity.io'; +const storageManager = getStorageManager({ + moduleType: MODULE_TYPE_RTD, + moduleName: MODULE_NAME +}); + let rxApi = null; let isFirstBidRequestCall = true; @@ -35,8 +42,19 @@ function getRxEngineReceptivity(requester) { return rxApi?.receptivity(requester); } +function getItemFromSessionStorage(key) { + let value = null; + try { + // Use the Storage Manager + value = storageManager.getDataFromSessionStorage(key, null); + } catch (error) { + } + + return value; +} + function loadSessionReceptivity(requester) { - let sessionStorageValue = sessionStorage.getItem(requester); + let sessionStorageValue = getItemFromSessionStorage(requester); if (!sessionStorageValue) { return null; } @@ -54,7 +72,7 @@ function loadSessionReceptivity(requester) { } catch { return null; } -}; +} /** * Prepare a receptivity batch diff --git a/modules/contxtfulRtdProvider.md b/modules/contxtfulRtdProvider.md index 71a641db4ad..622b353c27a 100644 --- a/modules/contxtfulRtdProvider.md +++ b/modules/contxtfulRtdProvider.md @@ -63,6 +63,7 @@ pbjs.setConfig({ } }); ``` + ## Parameters | Name | Type | Scope | Description | diff --git a/modules/cpmstarBidAdapter.js b/modules/cpmstarBidAdapter.js index e076fb4b0bb..772cb8c537c 100755 --- a/modules/cpmstarBidAdapter.js +++ b/modules/cpmstarBidAdapter.js @@ -1,8 +1,8 @@ import * as utils from '../src/utils.js'; -import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {BANNER, VIDEO} from '../src/mediaTypes.js'; -import {config} from '../src/config.js'; -import {getBidIdParameter} from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { VIDEO, BANNER } from '../src/mediaTypes.js'; +import { config } from '../src/config.js'; +import { ortbConverter } from '../libraries/ortbConverter/converter.js'; const BIDDER_CODE = 'cpmstar'; @@ -12,15 +12,18 @@ const ENDPOINT_PRODUCTION = 'https://server.cpmstar.com/view.aspx'; const DEFAULT_TTL = 300; const DEFAULT_CURRENCY = 'USD'; +const DEFAULT_NET_REVENUE = true; -function fixedEncodeURIComponent(str) { - return encodeURIComponent(str).replace(/[!'()*]/g, function(c) { - return '%' + c.charCodeAt(0).toString(16); - }); -} +export const converter = ortbConverter({ + context: { + ttl: DEFAULT_TTL, + netRevenue: DEFAULT_NET_REVENUE + } +}); export const spec = { code: BIDDER_CODE, + gvlid: 1317, supportedMediaTypes: [BANNER, VIDEO], pageID: Math.floor(Math.random() * 10e6), @@ -43,22 +46,30 @@ export const spec = { buildRequests: function (validBidRequests, bidderRequest) { var requests = []; - // This reference to window.top can cause issues when loaded in an iframe if not protected with a try/catch. for (var i = 0; i < validBidRequests.length; i++) { var bidRequest = validBidRequests[i]; - var referer = bidderRequest.refererInfo.page ? bidderRequest.refererInfo.page : bidderRequest.refererInfo.domain; - referer = encodeURIComponent(referer); - var e = getBidIdParameter('endpoint', bidRequest.params); - var ENDPOINT = e == 'dev' ? ENDPOINT_DEV : e == 'staging' ? ENDPOINT_STAGING : ENDPOINT_PRODUCTION; - var mediaType = spec.getMediaType(bidRequest); - var playerSize = spec.getPlayerSize(bidRequest); - var videoArgs = '&fv=0' + (playerSize ? ('&w=' + playerSize[0] + '&h=' + playerSize[1]) : ''); - var url = ENDPOINT + '?media=' + mediaType + (mediaType == VIDEO ? videoArgs : '') + - '&json=c_b&mv=1&poolid=' + getBidIdParameter('placementId', bidRequest.params) + - '&reachedTop=' + encodeURIComponent(bidderRequest.refererInfo.reachedTop) + - '&requestid=' + bidRequest.bidId + - '&referer=' + encodeURIComponent(referer); + const referer = bidderRequest.refererInfo.page ? bidderRequest.refererInfo.page : bidderRequest.refererInfo.domain; + const e = utils.getBidIdParameter('endpoint', bidRequest.params); + const ENDPOINT = e == 'dev' ? ENDPOINT_DEV : e == 'staging' ? ENDPOINT_STAGING : ENDPOINT_PRODUCTION; + const url = new URL(ENDPOINT); + const body = {}; + const mediaType = spec.getMediaType(bidRequest); + const playerSize = spec.getPlayerSize(bidRequest); + url.searchParams.set('media', mediaType); + if (mediaType == VIDEO) { + url.searchParams.set('fv', 0); + if (playerSize) { + url.searchParams.set('w', playerSize?.[0]); + url.searchParams.set('h', playerSize?.[1]); + } + } + url.searchParams.set('json', 'c_b'); + url.searchParams.set('mv', 1); + url.searchParams.set('poolid', utils.getBidIdParameter('placementId', bidRequest.params)); + url.searchParams.set('reachedTop', bidderRequest.refererInfo.reachedTop); + url.searchParams.set('requestid', bidRequest.bidId); + url.searchParams.set('referer', referer); if (bidRequest.schain && bidRequest.schain.nodes) { var schain = bidRequest.schain; @@ -67,45 +78,49 @@ export const spec = { for (var i2 = 0; i2 < schain.nodes.length; i2++) { var node = schain.nodes[i2]; schainString += '!' + - fixedEncodeURIComponent(node.asi || '') + ',' + - fixedEncodeURIComponent(node.sid || '') + ',' + - fixedEncodeURIComponent(node.hp || '') + ',' + - fixedEncodeURIComponent(node.rid || '') + ',' + - fixedEncodeURIComponent(node.name || '') + ',' + - fixedEncodeURIComponent(node.domain || ''); + (node.asi || '') + ',' + + (node.sid || '') + ',' + + (node.hp || '') + ',' + + (node.rid || '') + ',' + + (node.name || '') + ',' + + (node.domain || ''); } - url += '&schain=' + schainString; + url.searchParams.set('schain', schainString); } if (bidderRequest.gdprConsent) { if (bidderRequest.gdprConsent.consentString != null) { - url += '&gdpr_consent=' + bidderRequest.gdprConsent.consentString; + url.searchParams.set('gdpr_consent', bidderRequest.gdprConsent.consentString); } if (bidderRequest.gdprConsent.gdprApplies != null) { - url += '&gdpr=' + (bidderRequest.gdprConsent.gdprApplies ? 1 : 0); + url.searchParams.set('gdpr', (bidderRequest.gdprConsent.gdprApplies ? 1 : 0)); } } if (bidderRequest.uspConsent != null) { - url += '&us_privacy=' + bidderRequest.uspConsent; + url.searchParams.set('us_privacy', bidderRequest.uspConsent); } if (config.getConfig('coppa')) { - url += '&tfcd=' + (config.getConfig('coppa') ? 1 : 0); + url.searchParams.set('tfcd', (config.getConfig('coppa') ? 1 : 0)); } - let body = {}; let adUnitCode = bidRequest.adUnitCode; if (adUnitCode) { body.adUnitCode = adUnitCode; } if (mediaType == VIDEO) { body.video = utils.deepAccess(bidRequest, 'mediaTypes.video'); + } else if (mediaType == BANNER) { + body.banner = utils.deepAccess(bidRequest, 'mediaTypes.banner'); } + const ortb = converter.toORTB({ bidderRequest, bidRequests: [bidRequest] }); + Object.assign(body, ortb); + requests.push({ method: 'POST', - url: url, + url: url.toString(), bidRequest: bidRequest, data: body }); @@ -144,7 +159,7 @@ export const spec = { width: rawBid.width || 0, height: rawBid.height || 0, currency: rawBid.currency ? rawBid.currency : DEFAULT_CURRENCY, - netRevenue: rawBid.netRevenue ? rawBid.netRevenue : true, + netRevenue: rawBid.netRevenue ? rawBid.netRevenue : DEFAULT_NET_REVENUE, ttl: rawBid.ttl ? rawBid.ttl : DEFAULT_TTL, creativeId: rawBid.creativeid || 0, meta: { @@ -191,4 +206,5 @@ export const spec = { } }; + registerBidder(spec); diff --git a/modules/cpmstarBidAdapter.md b/modules/cpmstarBidAdapter.md index c227f19bfaf..66f13479c05 100755 --- a/modules/cpmstarBidAdapter.md +++ b/modules/cpmstarBidAdapter.md @@ -3,10 +3,7 @@ ``` Module Name: Cpmstar Bidder Adapter Module Type: Bidder Adapter -Maintainer: josh@cpmstar.com -gdpr_supported: true -usp_supported: true -coppa_supported: true +Maintainer: prebid@cpmstar.com ``` # Description diff --git a/modules/craftBidAdapter.js b/modules/craftBidAdapter.js index c751a18cc84..f8d216f0838 100644 --- a/modules/craftBidAdapter.js +++ b/modules/craftBidAdapter.js @@ -4,7 +4,7 @@ import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; import {find, includes} from '../src/polyfill.js'; import {getStorageManager} from '../src/storageManager.js'; import {ajax} from '../src/ajax.js'; -import {hasPurpose1Consent} from '../src/utils/gpdr.js'; +import {hasPurpose1Consent} from '../src/utils/gdpr.js'; import {convertOrtbRequestToProprietaryNative} from '../src/native.js'; import {getANKeywordParam} from '../libraries/appnexusUtils/anKeywords.js'; diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js index 229acaac01a..053980d04ab 100644 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -3,7 +3,7 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; import {getStorageManager} from '../src/storageManager.js'; import {getRefererInfo} from '../src/refererDetection.js'; -import {hasPurpose1Consent} from '../src/utils/gpdr.js'; +import {hasPurpose1Consent} from '../src/utils/gdpr.js'; import {Renderer} from '../src/Renderer.js'; import {OUTSTREAM} from '../src/video.js'; import {ajax} from '../src/ajax.js'; diff --git a/modules/cwireBidAdapter.js b/modules/cwireBidAdapter.js index f878be5f66a..191ff7758da 100644 --- a/modules/cwireBidAdapter.js +++ b/modules/cwireBidAdapter.js @@ -2,7 +2,7 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; import {getStorageManager} from '../src/storageManager.js'; import {BANNER} from '../src/mediaTypes.js'; import {generateUUID, getParameterByName, isNumber, logError, logInfo} from '../src/utils.js'; -import {hasPurpose1Consent} from '../src/utils/gpdr.js'; +import {hasPurpose1Consent} from '../src/utils/gdpr.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest @@ -224,6 +224,8 @@ export const spec = { bid: bid } } + // TODO FIX THIS RULES VIOLATION + // eslint-disable-next-line prebid/no-member navigator.sendBeacon(EVENT_ENDPOINT, JSON.stringify(event)) }, @@ -236,6 +238,8 @@ export const spec = { bidderRequest: bidderRequest } } + // TODO FIX THIS RULES VIOLATION + // eslint-disable-next-line prebid/no-member navigator.sendBeacon(EVENT_ENDPOINT, JSON.stringify(event)) }, diff --git a/modules/dailymotionBidAdapter.js b/modules/dailymotionBidAdapter.js index b268d497723..4f8f73816fe 100644 --- a/modules/dailymotionBidAdapter.js +++ b/modules/dailymotionBidAdapter.js @@ -130,76 +130,96 @@ export const spec = { * @param {BidderRequest} bidderRequest * @return ServerRequest Info describing the request to the server. */ - buildRequests: (validBidRequests = [], bidderRequest) => validBidRequests.map(bid => ({ - method: 'POST', - url: 'https://pb.dmxleo.com', - data: { - pbv: '$prebid.version$', - bidder_request: { - gdprConsent: { - apiVersion: deepAccess(bidderRequest, 'gdprConsent.apiVersion', 1), - consentString: deepAccess(bidderRequest, 'gdprConsent.consentString', ''), - // Cast boolean in any case (eg: if value is int) to ensure type - gdprApplies: !!deepAccess(bidderRequest, 'gdprConsent.gdprApplies'), - }, - refererInfo: { - page: deepAccess(bidderRequest, 'refererInfo.page', ''), + buildRequests: function(validBidRequests = [], bidderRequest) { + // check consent to be able to read user cookie + const allowCookieReading = + // No GDPR applies + !deepAccess(bidderRequest, 'gdprConsent.gdprApplies') || + // OR GDPR applies and we have global consent + deepAccess(bidderRequest, 'gdprConsent.vendorData.hasGlobalConsent') === true || + ( + // Vendor consent + deepAccess(bidderRequest, 'gdprConsent.vendorData.vendor.consents.573') === true && + // Purposes + [1, 3, 4].every(v => deepAccess(bidderRequest, `gdprConsent.vendorData.purpose.consents.${v}`) === true) && + // Flexible purposes + [2, 7, 9, 10].every(v => + deepAccess(bidderRequest, `gdprConsent.vendorData.purpose.consents.${v}`) === true || + deepAccess(bidderRequest, `gdprConsent.vendorData.purpose.legitimateInterests.${v}`) === true + ) + ); + + return validBidRequests.map(bid => ({ + method: 'POST', + url: 'https://pb.dmxleo.com', + data: { + pbv: '$prebid.version$', + bidder_request: { + gdprConsent: { + apiVersion: deepAccess(bidderRequest, 'gdprConsent.apiVersion', 1), + consentString: deepAccess(bidderRequest, 'gdprConsent.consentString', ''), + // Cast boolean in any case (eg: if value is int) to ensure type + gdprApplies: !!deepAccess(bidderRequest, 'gdprConsent.gdprApplies'), + }, + refererInfo: { + page: deepAccess(bidderRequest, 'refererInfo.page', ''), + }, + uspConsent: deepAccess(bidderRequest, 'uspConsent', ''), + gppConsent: { + gppString: deepAccess(bidderRequest, 'gppConsent.gppString') || + deepAccess(bidderRequest, 'ortb2.regs.gpp', ''), + applicableSections: deepAccess(bidderRequest, 'gppConsent.applicableSections') || + deepAccess(bidderRequest, 'ortb2.regs.gpp_sid', []), + }, }, - uspConsent: deepAccess(bidderRequest, 'uspConsent', ''), - gppConsent: { - gppString: deepAccess(bidderRequest, 'gppConsent.gppString') || - deepAccess(bidderRequest, 'ortb2.regs.gpp', ''), - applicableSections: deepAccess(bidderRequest, 'gppConsent.applicableSections') || - deepAccess(bidderRequest, 'ortb2.regs.gpp_sid', []), + config: { + api_key: bid.params.apiKey }, - }, - config: { - api_key: bid.params.apiKey - }, - // Cast boolean in any case (value should be 0 or 1) to ensure type - coppa: !!deepAccess(bidderRequest, 'ortb2.regs.coppa'), - // In app context, we need to retrieve additional informations - ...(!deepAccess(bidderRequest, 'ortb2.site') && !!deepAccess(bidderRequest, 'ortb2.app') ? { - 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', ''), - bidId: deepAccess(bid, 'bidId', ''), - mediaTypes: { - video: { - api: bid.mediaTypes?.[VIDEO]?.api || [], - 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, - skipmin: bid.mediaTypes?.[VIDEO]?.skipmin || 0, - startdelay: bid.mediaTypes?.[VIDEO]?.startdelay || 0, - w: bid.mediaTypes?.[VIDEO]?.w || 0, - h: bid.mediaTypes?.[VIDEO]?.h || 0, + // Cast boolean in any case (value should be 0 or 1) to ensure type + coppa: !!deepAccess(bidderRequest, 'ortb2.regs.coppa'), + // In app context, we need to retrieve additional informations + ...(!deepAccess(bidderRequest, 'ortb2.site') && !!deepAccess(bidderRequest, 'ortb2.app') ? { + 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', ''), + bidId: deepAccess(bid, 'bidId', ''), + mediaTypes: { + video: { + api: bid.mediaTypes?.[VIDEO]?.api || [], + 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, + protocols: bid.mediaTypes?.[VIDEO]?.protocols || [], + skip: bid.mediaTypes?.[VIDEO]?.skip || 0, + skipafter: bid.mediaTypes?.[VIDEO]?.skipafter || 0, + skipmin: bid.mediaTypes?.[VIDEO]?.skipmin || 0, + startdelay: bid.mediaTypes?.[VIDEO]?.startdelay, + w: bid.mediaTypes?.[VIDEO]?.w || 0, + h: bid.mediaTypes?.[VIDEO]?.h || 0, + }, }, + sizes: bid.sizes || [], }, - sizes: bid.sizes || [], + video_metadata: getVideoMetadata(bid, bidderRequest), }, - video_metadata: getVideoMetadata(bid, bidderRequest), - }, - options: { - withCredentials: true, - crossOrigin: true, - }, - })), + options: { + withCredentials: allowCookieReading, + crossOrigin: true, + }, + })); + }, /** * Map the response from the server into a list of bids. @@ -224,7 +244,7 @@ export const spec = { const pixelSyncs = []; serverResponses.forEach((response) => { - (response.user_syncs || []).forEach((syncUrl) => { + (response?.body?.userSyncs || []).forEach((syncUrl) => { if (syncUrl.type === 'image') { pixelSyncs.push({ url: syncUrl.url, type: 'image' }); } diff --git a/modules/debugging/debugging.js b/modules/debugging/debugging.js index 63887074f04..ced8f7bf4a0 100644 --- a/modules/debugging/debugging.js +++ b/modules/debugging/debugging.js @@ -31,6 +31,7 @@ export function disableDebugging({hook, logger}) { } } +// eslint-disable-next-line prebid/no-global function saveDebuggingConfig(debugConfig, {sessionStorage = window.sessionStorage, DEBUG_KEY} = {}) { if (!debugConfig.enabled) { try { @@ -49,6 +50,7 @@ function saveDebuggingConfig(debugConfig, {sessionStorage = window.sessionStorag } } +// eslint-disable-next-line prebid/no-global export function getConfig(debugging, {getStorage = () => window.sessionStorage, DEBUG_KEY, config, hook, logger} = {}) { if (debugging == null) return; let sessionStorage; @@ -70,6 +72,7 @@ export function getConfig(debugging, {getStorage = () => window.sessionStorage, export function sessionLoader({DEBUG_KEY, storage, config, hook, logger}) { let overrides; try { + // eslint-disable-next-line prebid/no-global storage = storage || window.sessionStorage; overrides = JSON.parse(storage.getItem(DEBUG_KEY)); } catch (e) { diff --git a/modules/deltaprojectsBidAdapter.js b/modules/deltaprojectsBidAdapter.js index 870378a13dd..15e94a5bc36 100644 --- a/modules/deltaprojectsBidAdapter.js +++ b/modules/deltaprojectsBidAdapter.js @@ -8,7 +8,8 @@ import { isFn, isNumber, logError, - logWarn + logWarn, + setOnAny } from '../src/utils.js'; import {config} from '../src/config.js'; @@ -234,16 +235,6 @@ export function getBidFloor(bid, mediaType, size, currency) { } } -/** -- Helper methods -- */ -function setOnAny(collection, key) { - for (let i = 0, result; i < collection.length; i++) { - result = deepAccess(collection[i], key); - if (result) { - return result; - } - } -} - /** -- Register -- */ export const spec = { code: BIDDER_CODE, diff --git a/modules/dfpAdServerVideo.js b/modules/dfpAdServerVideo.js index 8325af56b20..367520870e3 100644 --- a/modules/dfpAdServerVideo.js +++ b/modules/dfpAdServerVideo.js @@ -2,8 +2,18 @@ * This module adds [DFP support]{@link https://www.doubleclickbygoogle.com/} for Video to Prebid. */ -import {registerVideoSupport} from '../src/adServerManager.js'; -import {targeting} from '../src/targeting.js'; +import { DEFAULT_DFP_PARAMS, DFP_ENDPOINT, setGdprConsent } from '../libraries/dfpUtils/dfpUtils.js'; +import { getSignals } from '../libraries/gptUtils/gptUtils.js'; +import { registerVideoSupport } from '../src/adServerManager.js'; +import { gdprDataHandler } from '../src/adapterManager.js'; +import { getPPID } from '../src/adserver.js'; +import { auctionManager } from '../src/auctionManager.js'; +import { config } from '../src/config.js'; +import { EVENTS } from '../src/constants.js'; +import * as events from '../src/events.js'; +import { getHook } from '../src/hook.js'; +import { getRefererInfo } from '../src/refererDetection.js'; +import { targeting } from '../src/targeting.js'; import { buildUrl, deepAccess, @@ -12,19 +22,8 @@ import { isNumber, logError, parseSizesInput, - parseUrl, - uniques + parseUrl } from '../src/utils.js'; -import {config} from '../src/config.js'; -import {getHook} from '../src/hook.js'; -import {auctionManager} from '../src/auctionManager.js'; -import {gdprDataHandler} from '../src/adapterManager.js'; -import * as events from '../src/events.js'; -import {EVENTS} from '../src/constants.js'; -import {getPPID} from '../src/adserver.js'; -import {getRefererInfo} from '../src/refererDetection.js'; -import {CLIENT_SECTIONS} from '../src/fpd/oneClient.js'; -import {DEFAULT_DFP_PARAMS, DFP_ENDPOINT} from '../libraries/dfpUtils/dfpUtils.js'; /** * @typedef {Object} DfpVideoParams * @@ -115,11 +114,7 @@ export function buildDfpVideoUrl(options) { const descriptionUrl = getDescriptionUrl(bid, options, 'params'); if (descriptionUrl) { queryParams.description_url = descriptionUrl; } const gdprConsent = gdprDataHandler.getConsentData(); - if (gdprConsent) { - if (typeof gdprConsent.gdprApplies === 'boolean') { queryParams.gdpr = Number(gdprConsent.gdprApplies); } - if (gdprConsent.consentString) { queryParams.gdpr_consent = gdprConsent.consentString; } - if (gdprConsent.addtlConsent) { queryParams.addtl_consent = gdprConsent.addtlConsent; } - } + setGdprConsent(gdprConsent, queryParams); if (!queryParams.ppid) { const ppid = getPPID(); @@ -171,20 +166,7 @@ export function buildDfpVideoUrl(options) { const fpd = auctionManager.index.getBidRequest(options.bid || {})?.ortb2 ?? auctionManager.index.getAuction(options.bid || {})?.getFPD()?.global; - function getSegments(sections, segtax) { - return sections - .flatMap(section => deepAccess(fpd, section) || []) - .filter(datum => datum.ext?.segtax === segtax) - .flatMap(datum => datum.segment?.map(seg => seg.id)) - .filter(ob => ob) - .filter(uniques) - } - - const signals = Object.entries({ - IAB_AUDIENCE_1_1: getSegments(['user.data'], 4), - IAB_CONTENT_2_2: getSegments(CLIENT_SECTIONS.map(section => `${section}.content.data`), 6) - }).map(([taxonomy, values]) => values.length ? {taxonomy, values} : null) - .filter(ob => ob); + const signals = getSignals(fpd); if (signals.length) { queryParams.ppsj = btoa(JSON.stringify({ diff --git a/modules/dfpAdpod.js b/modules/dfpAdpod.js index a5bd48f60e4..1675954459c 100644 --- a/modules/dfpAdpod.js +++ b/modules/dfpAdpod.js @@ -1,7 +1,7 @@ import {submodule} from '../src/hook.js'; import {buildUrl, deepAccess, formatQS, logError, parseSizesInput} from '../src/utils.js'; import {auctionManager} from '../src/auctionManager.js'; -import {DEFAULT_DFP_PARAMS, DFP_ENDPOINT} from '../libraries/dfpUtils/dfpUtils.js'; +import {DEFAULT_DFP_PARAMS, DFP_ENDPOINT, setGdprConsent} from '../libraries/dfpUtils/dfpUtils.js'; import {gdprDataHandler} from '../src/consentHandler.js'; import {registerVideoSupport} from '../src/adServerManager.js'; @@ -79,11 +79,7 @@ export function buildAdpodVideoUrl({code, params, callback} = {}) { ); const gdprConsent = gdprDataHandler.getConsentData(); - if (gdprConsent) { - if (typeof gdprConsent.gdprApplies === 'boolean') { queryParams.gdpr = Number(gdprConsent.gdprApplies); } - if (gdprConsent.consentString) { queryParams.gdpr_consent = gdprConsent.consentString; } - if (gdprConsent.addtlConsent) { queryParams.addtl_consent = gdprConsent.addtlConsent; } - } + setGdprConsent(gdprConsent, queryParams); const masterTag = buildUrl({ ...DFP_ENDPOINT, diff --git a/modules/dgkeywordRtdProvider.js b/modules/dgkeywordRtdProvider.js index 14519ae2713..c97296f6982 100644 --- a/modules/dgkeywordRtdProvider.js +++ b/modules/dgkeywordRtdProvider.js @@ -101,6 +101,8 @@ export function getProfileApiUrl(customeUrl, enableReadFpid) { export function readFpidFromLocalStrage() { try { + // TODO: use storageManager + // eslint-disable-next-line prebid/no-global const fpid = window.localStorage.getItem('ope_fpid'); if (fpid) { return fpid; diff --git a/modules/dianomiBidAdapter.js b/modules/dianomiBidAdapter.js index d4b2a4a5da5..f4f81f20f87 100644 --- a/modules/dianomiBidAdapter.js +++ b/modules/dianomiBidAdapter.js @@ -10,6 +10,7 @@ import { parseSizesInput, deepSetValue, formatQS, + setOnAny } from '../src/utils.js'; import { config } from '../src/config.js'; import { Renderer } from '../src/Renderer.js'; @@ -355,15 +356,6 @@ function parseNative(bid) { return result; } -function setOnAny(collection, key) { - for (let i = 0, result; i < collection.length; i++) { - result = deepAccess(collection[i], key); - if (result) { - return result; - } - } -} - function flatten(arr) { return [].concat(...arr); } diff --git a/modules/discoveryBidAdapter.js b/modules/discoveryBidAdapter.js index 12f1d7ac1f2..696faa86a0a 100644 --- a/modules/discoveryBidAdapter.js +++ b/modules/discoveryBidAdapter.js @@ -3,6 +3,10 @@ import { getStorageManager } from '../src/storageManager.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, NATIVE } from '../src/mediaTypes.js'; import { getHLen, getHC, getDM } from '../src/fpd/navigator.js'; +import { getPageTitle, getPageDescription, getPageKeywords, getConnectionDownLink, getReferrer } from '../libraries/fpdUtils/pageInfo.js'; +import { getDevice, getScreenSize } from '../libraries/fpdUtils/deviceInfo.js'; +import { getBidFloor } from '../libraries/currencyUtils/floor.js'; +import { transformSizes, normalAdSize } from '../libraries/sizeUtils/tranformSize.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest @@ -22,6 +26,9 @@ const MEDIATYPE = [BANNER, NATIVE]; const COOKIE_KEY_SSPPID = '_ss_pp_id'; export const COOKIE_KEY_MGUID = '__mguid_'; const COOKIE_KEY_PMGUID = '__pmguid_'; +const COOKIE_KEY_PBUID = 'pub_pp_tag'; +const STORAGE_KEY_FTUID = 'fluct_ppUUIDv4'; +const STORAGE_KEY_IMUID = '__im_ppid'; const COOKIE_RETENTION_TIME = 365 * 24 * 60 * 60 * 1000; // 1 year const COOKY_SYNC_IFRAME_URL = 'https://asset.popin.cc/js/cookieSync.html'; export const THIRD_PARTY_COOKIE_ORIGIN = 'https://asset.popin.cc'; @@ -68,64 +75,6 @@ const NATIVERET = { ext: {}, }; -/** - * get page title111 - * @returns {string} - */ - -export function getPageTitle(win = window) { - try { - const ogTitle = win.top.document.querySelector('meta[property="og:title"]') - return win.top.document.title || (ogTitle && ogTitle.content) || ''; - } catch (e) { - const ogTitle = document.querySelector('meta[property="og:title"]') - return document.title || (ogTitle && ogTitle.content) || ''; - } -} - -/** - * get page description - * @returns {string} - */ -export function getPageDescription(win = window) { - let element; - - try { - element = win.top.document.querySelector('meta[name="description"]') || - win.top.document.querySelector('meta[property="og:description"]') - } catch (e) { - element = document.querySelector('meta[name="description"]') || - document.querySelector('meta[property="og:description"]') - } - - return (element && element.content) || ''; -} - -/** - * get page keywords - * @returns {string} - */ -export function getPageKeywords(win = window) { - let element; - - try { - element = win.top.document.querySelector('meta[name="keywords"]'); - } catch (e) { - element = document.querySelector('meta[name="keywords"]'); - } - - return (element && element.content) || ''; -} - -/** - * get connection downlink - * @returns {number} - */ -export function getConnectionDownLink(win = window) { - const nav = win.navigator || {}; - return nav && nav.connection && nav.connection.downlink >= 0 ? nav.connection.downlink.toString() : undefined; -} - /** * get pmg uid * 获取并生成用户的id @@ -140,7 +89,7 @@ export const getPmgUID = () => { } // Extend the expiration time of pmguid try { - storage.setCookie(COOKIE_KEY_PMGUID, pmgUid, getCurrentTimeToUTCString()); + storage.setCookie(COOKIE_KEY_PMGUID, pmgUid, getCookieTimeToUTCString()); } catch (e) {} return pmgUid; }; @@ -166,150 +115,14 @@ function getKv(obj, ...keys) { return o; } -/** - * get device - * @return {boolean} - */ -function getDevice() { - let check = false; - (function (a) { - let reg1 = new RegExp( - [ - '(android|bbd+|meego)', - '.+mobile|avantgo|bada/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)', - '|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone', - '|p(ixi|re)/|plucker|pocket|psp|series(4|6)0|symbian|treo|up.(browser|link)|vodafone|wap', - '|windows ce|xda|xiino|android|ipad|playbook|silk', - ].join(''), - 'i' - ); - let reg2 = new RegExp( - [ - '1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s-)', - '|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|-m|r |s )', - '|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw-(n|u)|c55/|capi|ccwa|cdm-|cell', - '|chtm|cldc|cmd-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc-s|devi|dica|dmob|do(c|p)o|ds(12|-d)', - '|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(-|_)|g1 u|g560|gene', - '|gf-5|g-mo|go(.w|od)|gr(ad|un)|haie|hcit|hd-(m|p|t)|hei-|hi(pt|ta)|hp( i|ip)|hs-c', - '|ht(c(-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i-(20|go|ma)|i230|iac( |-|/)|ibro|idea|ig01|ikom', - '|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |/)|klon|kpt |kwc-|kyo(c|k)', - '|le(no|xi)|lg( g|/(k|l|u)|50|54|-[a-w])|libw|lynx|m1-w|m3ga|m50/|ma(te|ui|xo)|mc(01|21|ca)', - '|m-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]', - '|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)', - '|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|-([1-8]|c))|phil|pire|pl(ay|uc)|pn-2|po(ck|rt|se)|prox|psio', - '|pt-g|qa-a|qc(07|12|21|32|60|-[2-7]|i-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55/|sa(ge|ma|mm|ms', - '|ny|va)|sc(01|h-|oo|p-)|sdk/|se(c(-|0|1)|47|mc|nd|ri)|sgh-|shar|sie(-|m)|sk-0|sl(45|id)|sm(al', - '|ar|b3|it|t5)|so(ft|ny)|sp(01|h-|v-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl-|tdg-|tel(i|m)', - '|tim-|t-mo|to(pl|sh)|ts(70|m-|m3|m5)|tx-9|up(.b|g1|si)|utst|', - 'v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|-v)', - '|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas-', - '|your|zeto|zte-', - ].join(''), - 'i' - ); - if (reg1.test(a) || reg2.test(a.substr(0, 4))) { - check = true; - } - })(navigator.userAgent || navigator.vendor || window.opera); - return check; -} - -/** - * get BidFloor - * @param {*} bid - * @param {*} mediaType - * @param {*} sizes - * @returns - */ -function getBidFloor(bid) { - if (!utils.isFn(bid.getFloor)) { - return utils.deepAccess(bid, 'params.bidfloor', 0); - } - - try { - const bidFloor = bid.getFloor({ - currency: 'USD', - mediaType: '*', - size: '*', - }); - return bidFloor.floor; - } catch (_) { - return 0; - } -} - -/** - * get sizes for rtb - * @param {Array|Object} requestSizes - * @return {Object} - */ -function transformSizes(requestSizes) { - let sizes = []; - let sizeObj = {}; - - if ( - utils.isArray(requestSizes) && - requestSizes.length === 2 && - !utils.isArray(requestSizes[0]) - ) { - sizeObj.width = parseInt(requestSizes[0], 10); - sizeObj.height = parseInt(requestSizes[1], 10); - sizes.push(sizeObj); - } else if (typeof requestSizes === 'object') { - for (let i = 0; i < requestSizes.length; i++) { - let size = requestSizes[i]; - sizeObj = {}; - sizeObj.width = parseInt(size[0], 10); - sizeObj.height = parseInt(size[1], 10); - sizes.push(sizeObj); - } - } - - return sizes; -} - // Support sizes -const popInAdSize = [ - { w: 300, h: 250 }, - { w: 300, h: 600 }, - { w: 728, h: 90 }, - { w: 970, h: 250 }, - { w: 320, h: 50 }, - { w: 160, h: 600 }, - { w: 320, h: 180 }, - { w: 320, h: 100 }, - { w: 336, h: 280 }, -]; - -/** - * get screen size - * - * @returns {Array} eg: "['widthxheight']" - */ -function getScreenSize() { - return utils.parseSizesInput([window.screen.width, window.screen.height]); -} +const popInAdSize = normalAdSize; /** - * @param {BidRequest} bidRequest - * @param bidderRequest - * @returns {string} - */ -function getReferrer(bidRequest = {}, bidderRequest = {}) { - let pageUrl; - if (bidRequest.params && bidRequest.params.referrer) { - pageUrl = bidRequest.params.referrer; - } else { - pageUrl = utils.deepAccess(bidderRequest, 'refererInfo.page'); - } - return pageUrl; -} - -/** - * get current time to UTC string + * get cookie time to UTC string * @returns utc string */ -export function getCurrentTimeToUTCString() { +export function getCookieTimeToUTCString() { const date = new Date(); date.setTime(date.getTime() + COOKIE_RETENTION_TIME); return date.toUTCString(); @@ -382,9 +195,8 @@ function getItems(validBidRequests, bidderRequest) { } } if (!matchSize) { - matchSize = sizes[0] - ? { h: sizes[0].height || 0, w: sizes[0].width || 0 } - : { h: 0, w: 0 }; + const { height = 0, width = 0 } = sizes[0] || {}; + matchSize = { h: height, w: width }; } ret = { id: id, @@ -424,7 +236,7 @@ export const buildUTMTagData = (url) => { }); UTMValue = JSON.parse(storage.getCookie(UTM_KEY) || '{}'); Object.assign(UTMValue, UTMParams); - storage.setCookie(UTM_KEY, JSON.stringify(UTMValue), getCurrentTimeToUTCString()); + storage.setCookie(UTM_KEY, JSON.stringify(UTMValue), getCookieTimeToUTCString()); } /** @@ -435,10 +247,10 @@ export const buildUTMTagData = (url) => { * @return {Object} */ function getParam(validBidRequests, bidderRequest) { - const pubcid = utils.deepAccess(validBidRequests[0], 'crumbs.pubcid'); const sharedid = utils.deepAccess(validBidRequests[0], 'userId.sharedid.id') || - utils.deepAccess(validBidRequests[0], 'userId.pubcid'); + utils.deepAccess(validBidRequests[0], 'userId.pubcid') || + utils.deepAccess(validBidRequests[0], 'crumbs.pubcid'); const eids = validBidRequests[0].userIdAsEids || validBidRequests[0].userId; let isMobile = getDevice() ? 1 : 0; @@ -466,10 +278,13 @@ function getParam(validBidRequests, bidderRequest) { firstPartyData, ssppid: storage.getCookie(COOKIE_KEY_SSPPID) || undefined, pmguid: getPmgUID(), + ssftUid: storage.getDataFromLocalStorage(STORAGE_KEY_FTUID) || undefined, + ssimUid: storage.getDataFromLocalStorage(STORAGE_KEY_IMUID) || undefined, + sspbid: storage.getCookie(COOKIE_KEY_PBUID) || undefined, tpData, utm: storage.getCookie(UTM_KEY), page: { - title: title ? title.slice(0, 100) : undefined, + title: title ? title.slice(0, 150) : undefined, desc: desc ? desc.slice(0, 300) : undefined, keywords: keywords ? keywords.slice(0, 100) : undefined, hLen: getHLen(), @@ -504,7 +319,7 @@ function getParam(validBidRequests, bidderRequest) { ext, user: { buyeruid: storage.getCookie(COOKIE_KEY_MGUID) || undefined, - id: sharedid || pubcid, + id: sharedid, }, tmax: timeout, site: { @@ -565,14 +380,15 @@ export const spec = { * @return ServerRequest Info describing the request to the server. */ buildRequests: function (validBidRequests, bidderRequest) { - if (!globals['token']) return; + const pbToken = globals['token']; + if (!pbToken) return; let payload = getParam(validBidRequests, bidderRequest); - const payloadString = JSON.stringify(payload); + return { method: 'POST', - url: ENDPOINT_URL + globals['token'], + url: `${ENDPOINT_URL}${pbToken}`, data: payloadString, }; }, @@ -696,7 +512,7 @@ export const spec = { const response = event.data; if (!response.optout && response.mguid) { - storage.setCookie(COOKIE_KEY_MGUID, response.mguid, getCurrentTimeToUTCString()); + storage.setCookie(COOKIE_KEY_MGUID, response.mguid, getCookieTimeToUTCString()); } }, true); return [ diff --git a/modules/docereeAdManagerBidAdapter.js b/modules/docereeAdManagerBidAdapter.js index d3765f5a130..f97bfbba6eb 100644 --- a/modules/docereeAdManagerBidAdapter.js +++ b/modules/docereeAdManagerBidAdapter.js @@ -74,16 +74,11 @@ function getPayload(bid, userData) { if (!userData || !bid) { return false; } - const { bidId, params } = bid; const { placementId } = params; const { userid, - email, - firstname, - lastname, specialization, - hcpid, gender, city, state, @@ -94,16 +89,17 @@ function getPayload(bid, userData) { hashedmobile, country, organization, - dob, + platformUid, + mobile } = userData; const data = { - userid: userid || '', - email: email || '', - firstname: firstname || '', - lastname: lastname || '', + userid: platformUid || userid || '', + email: '', + firstname: '', + lastname: '', specialization: specialization || '', - hcpid: hcpid || '', + hcpid: '', gender: gender || '', city: city || '', state: state || '', @@ -117,8 +113,9 @@ function getPayload(bid, userData) { hashedmobile: hashedmobile || '', country: country || '', organization: organization || '', - dob: dob || '', + dob: '', userconsent: 1, + mobile: mobile || '' }; return { data, diff --git a/modules/dspxBidAdapter.js b/modules/dspxBidAdapter.js index 2b819789ec1..b2610610cf2 100644 --- a/modules/dspxBidAdapter.js +++ b/modules/dspxBidAdapter.js @@ -1,4 +1,5 @@ -import {deepAccess, getBidIdParameter, isFn, logError, logMessage, logWarn} from '../src/utils.js'; +import {deepAccess, getBidIdParameter, isFn, logError, logMessage, logWarn, isEmptyStr, isArray} from '../src/utils.js'; + import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; import {Renderer} from '../src/Renderer.js'; @@ -7,7 +8,6 @@ import {includes} from '../src/polyfill.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest */ - const BIDDER_CODE = 'dspx'; const ENDPOINT_URL = 'https://buyer.dspx.tv/request/'; const ENDPOINT_URL_DEV = 'https://dcbuyer.dspx.tv/request/'; @@ -63,24 +63,18 @@ export const spec = { rnd: rnd, ref: referrer, bid_id: bidId, - pbver: '$prebid.version$' + pbver: '$prebid.version$', }; + payload.pfilter = {}; if (params.pfilter !== undefined) { payload.pfilter = params.pfilter; } if (bidderRequest && bidderRequest.gdprConsent) { - if (payload.pfilter !== undefined) { - if (!payload.pfilter.gdpr_consent) { - payload.pfilter.gdpr_consent = bidderRequest.gdprConsent.consentString; - payload.pfilter.gdpr = bidderRequest.gdprConsent.gdprApplies; - } - } else { - payload.pfilter = { - 'gdpr_consent': bidderRequest.gdprConsent.consentString, - 'gdpr': bidderRequest.gdprConsent.gdprApplies - }; + if (!payload.pfilter.gdpr_consent) { + payload.pfilter.gdpr_consent = bidderRequest.gdprConsent.consentString; + payload.pfilter.gdpr = bidderRequest.gdprConsent.gdprApplies; } } @@ -94,48 +88,10 @@ export const spec = { payload.prebidDevMode = 1; } - // fill userId params - if (bidRequest.userId) { - if (bidRequest.userId.netId) { - payload.did_netid = bidRequest.userId.netId; - } - if (bidRequest.userId.id5id) { - payload.did_id5 = bidRequest.userId.id5id.uid || '0'; - if (bidRequest.userId.id5id.ext.linkType !== undefined) { - payload.did_id5_linktype = bidRequest.userId.id5id.ext.linkType; - } - } - let uId2 = deepAccess(bidRequest, 'userId.uid2.id'); - if (uId2) { - payload.did_uid2 = uId2; - } - let sharedId = deepAccess(bidRequest, 'userId.sharedid.id'); - if (sharedId) { - payload.did_sharedid = sharedId; - } - let pubcId = deepAccess(bidRequest, 'userId.pubcid'); - if (pubcId) { - payload.did_pubcid = pubcId; - } - let crumbsPubcid = deepAccess(bidRequest, 'crumbs.pubcid'); - if (crumbsPubcid) { - payload.did_cpubcid = crumbsPubcid; - } - } - - if (bidRequest.schain) { - payload.schain = bidRequest.schain; - } - - if (payload.pfilter === undefined || !payload.pfilter.floorprice) { + if (!payload.pfilter.floorprice) { let bidFloor = getBidFloor(bidRequest); if (bidFloor > 0) { - if (payload.pfilter !== undefined) { - payload.pfilter.floorprice = bidFloor; - } else { - payload.pfilter = { 'floorprice': bidFloor }; - } - // payload.bidFloor = bidFloor; + payload.pfilter.floorprice = bidFloor; } } @@ -146,6 +102,7 @@ export const spec = { payload.pbcode = pbcode; } + // media types payload.media_types = convertMediaInfoForRequest(mediaTypesInfo); if (mediaTypesInfo[VIDEO] !== undefined) { payload.vctx = getVideoContext(bidRequest); @@ -159,6 +116,33 @@ export const spec = { .forEach(key => payload.vpl[key] = videoParams[key]); } + // iab content + let content = deepAccess(bidderRequest, 'ortb2.site.content'); + if (content) { + let stringContent = siteContentToString(content); + if (stringContent) { + payload.pfilter.iab_content = stringContent; + } + } + + // Google Topics + const segments = extractUserSegments(bidderRequest); + if (segments) { + assignDefinedValues(payload, { + segtx: segments.segtax, + segcl: segments.segclass, + segs: segments.segments + }); + } + + // schain + if (bidRequest.schain) { + payload.schain = bidRequest.schain; + } + + // fill userId params + fillUsersIds(bidRequest, payload); + return { method: 'GET', url: endpoint, @@ -257,6 +241,74 @@ export const spec = { } } +/** + * Adds userIds to payload + * + * @param bidRequest + * @param payload + */ +function fillUsersIds(bidRequest, payload) { + if (bidRequest.hasOwnProperty('userId')) { + let didMapping = { + did_netid: 'userId.netId', + did_id5: 'userId.id5id.uid', + did_id5_linktype: 'userId.id5id.ext.linkType', + did_uid2: 'userId.uid2', + did_sharedid: 'userId.sharedid', + did_pubcid: 'userId.pubcid', + did_uqid: 'userId.utiq', + did_cruid: 'userId.criteoid', + did_euid: 'userId.euid', + // did_tdid: 'unifiedId', + did_tdid: 'userId.tdid', + did_ppuid: function() { + let path = 'userId.pubProvidedId'; + let value = deepAccess(bidRequest, path); + if (isArray(value)) { + for (const rec of value) { + if (rec.uids && rec.uids.length > 0) { + for (let i = 0; i < rec.uids.length; i++) { + if ('id' in rec.uids[i] && deepAccess(rec.uids[i], 'ext.stype') === 'ppuid') { + return (rec.uids[i].atype ?? '') + ':' + rec.source + ':' + rec.uids[i].id; + } + } + } + } + } + return undefined; + }, + did_cpubcid: 'crumbs.pubcid' + }; + for (let paramName in didMapping) { + let path = didMapping[paramName]; + + // handle function + if (typeof path == 'function') { + let value = path(paramName); + if (value) { + payload[paramName] = value; + } + continue; + } + // direct access + let value = deepAccess(bidRequest, path); + if (typeof value == 'string' || typeof value == 'number') { + payload[paramName] = value; + } else if (typeof value == 'object') { + // trying to find string ID value + if (typeof deepAccess(bidRequest, path + '.id') == 'string') { + payload[paramName] = deepAccess(bidRequest, path + '.id'); + } else { + if (Object.keys(value).length > 0) { + logError(`DSPx: WARNING: fillUserIds had to use first key in user object to get value for bid.userId key: ${path}.`); + payload[paramName] = value[Object.keys(value)[0]]; + } + } + } + } + } +} + function appendToUrl(url, what) { if (!what) { return url; @@ -276,7 +328,7 @@ function objectToQueryString(obj, prefix) { : encodeURIComponent(k) + '=' + encodeURIComponent(v)); } } - return str.join('&'); + return str.filter(n => n).join('&'); } /** @@ -508,4 +560,74 @@ function createOutstreamEmbedCode(bid) { return fragment; } +/** + * Convert site.content to string + * @param content + */ +function siteContentToString(content) { + if (!content) { + return ''; + } + let stringKeys = ['id', 'title', 'series', 'season', 'artist', 'genre', 'isrc', 'url', 'keywords']; + let intKeys = ['episode', 'context', 'livestream']; + let arrKeys = ['cat']; + let retArr = []; + arrKeys.forEach(k => { + let val = deepAccess(content, k); + if (val && Array.isArray(val)) { + retArr.push(k + ':' + val.join('|')); + } + }); + intKeys.forEach(k => { + let val = deepAccess(content, k); + if (val && typeof val === 'number') { + retArr.push(k + ':' + val); + } + }); + stringKeys.forEach(k => { + let val = deepAccess(content, k); + if (val && typeof val === 'string') { + retArr.push(k + ':' + encodeURIComponent(val)); + } + }); + return retArr.join(','); +} + +/** + * Assigns multiple values to the specified keys on an object if the values are not undefined. + * @param {Object} target - The object to which the values will be assigned. + * @param {Object} values - An object containing key-value pairs to be assigned. + */ +function assignDefinedValues(target, values) { + for (const key in values) { + if (values[key] !== undefined) { + target[key] = values[key]; + } + } +} + +/** + * Extracts user segments/topics from the bid request object + * @param {Object} bid - The bid request object + * @returns {{segclass: *, segtax: *, segments: *}|undefined} - User segments/topics or undefined if not found + */ +function extractUserSegments(bid) { + const userData = deepAccess(bid, 'ortb2.user.data') || []; + for (const dataObj of userData) { + if (dataObj.segment && isArray(dataObj.segment) && dataObj.segment.length > 0) { + const segments = dataObj.segment + .filter(seg => seg.id && !isEmptyStr(seg.id) && isFinite(seg.id)) + .map(seg => Number(seg.id)); + if (segments.length > 0) { + return { + segtax: deepAccess(dataObj, 'ext.segtax'), + segclass: deepAccess(dataObj, 'ext.segclass'), + segments: segments.join(',') + }; + } + } + } + return undefined; +} + registerBidder(spec); diff --git a/modules/eightPodAnalyticsAdapter.js b/modules/eightPodAnalyticsAdapter.js index a1ea76daed1..6dab3b0c107 100644 --- a/modules/eightPodAnalyticsAdapter.js +++ b/modules/eightPodAnalyticsAdapter.js @@ -1,4 +1,4 @@ -import {logError, logInfo} from '../src/utils.js'; +import {logError, logInfo, logMessage} from '../src/utils.js'; import {ajax} from '../src/ajax.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import { EVENTS } from '../src/constants.js'; @@ -9,13 +9,11 @@ import {getStorageManager} from '../src/storageManager.js'; const analyticsType = 'endpoint'; const MODULE_NAME = `eightPod`; const MODULE = `${MODULE_NAME}AnalyticProvider`; -let interval; /** * Custom tracking server that gets internal events from EightPod's ad unit */ const trackerUrl = 'https://demo.8pod.com/tracker/track'; - export const storage = getStorageManager({moduleType: MODULE_TYPE_ANALYTICS, moduleName: MODULE_NAME}) const { @@ -23,12 +21,12 @@ const { } = EVENTS; export let queue = []; -export let context; +let context = {}; /** * Create eightPod Analytic adapter */ -let eightPodAnalytics = Object.assign(adapter({ analyticsType }), { +let eightPodAnalytics = Object.assign(adapter({url: trackerUrl, analyticsType}), { /** * Execute on bid won - setup basic settings, save context about EightPod's bid. We will send it with our events later */ @@ -36,45 +34,47 @@ let eightPodAnalytics = Object.assign(adapter({ analyticsType }), { switch (eventType) { case BID_WON: if (args.bidder === 'eightPod') { + context[args.adUnitCode] = makeContext(args); + eightPodAnalytics.setupPage(args); - context = makeContext(args); break; } } }, /** - * Execute on bid won - subscribe on events from adUnit + * Execute on bid won upload events from local storage */ setupPage() { - eightPodAnalytics.eventSubscribe(); - queue = getEventFromLocalStorage(); + queue = this.getEventFromLocalStorage(); }, + /** * Subscribe on internal ad unit tracking events */ eventSubscribe() { window.addEventListener('message', async (event) => { - const data = event?.data; + const data = event.data; - if (!data?.detail?.name) { - return; - } + const frameElement = event.source?.frameElement; + const parentElement = frameElement?.parentElement; + const adUnitCode = parentElement?.id; - trackEvent(data); + trackEvent(data, adUnitCode); }); - // Send queue of event every 10 seconds - if (!interval) { - interval = setInterval(sendEvents, 10_000); - } + setInterval(sendEvents, 10_000); }, resetQueue() { queue = []; }, getContext() { return context; - } + }, + resetContext() { + context = {}; + }, + getEventFromLocalStorage, }); /** @@ -84,8 +84,8 @@ function makeContext(args) { const params = args?.params?.[0]; return { bidId: args.seatBidId, - variantId: args.creativeId || 'variantId', - campaignId: 'campaignId', + variantId: args.creativeId || '', + campaignId: args.cid || '', publisherId: params.publisherId, placementId: params.placementId, }; @@ -94,12 +94,13 @@ function makeContext(args) { /** * Create event, add context and push it to queue */ -export function trackEvent(event) { +export function trackEvent(event, adUnitCode) { if (!event.detail) { return; } + const fullEvent = { - context: eightPodAnalytics.getContext(), + context: eightPodAnalytics.getContext()[adUnitCode], eventType: event.detail.type, eventClass: 'adunit', timestamp: new Date().getTime(), @@ -107,6 +108,7 @@ export function trackEvent(event) { payload: event.detail.payload }; + logMessage(fullEvent); addEvent(fullEvent); } @@ -158,7 +160,7 @@ function sendEvents() { * Send event to our custom tracking server */ function sendEventsApi(eventList, callbacks) { - ajax(trackerUrl, callbacks, JSON.stringify(eventList)); + ajax(trackerUrl, callbacks, JSON.stringify(eventList), {keepalive: true}); } /** @@ -173,21 +175,13 @@ eightPodAnalytics.originEnableAnalytics = eightPodAnalytics.enableAnalytics; eightPodAnalytics.eventsStorage = []; // override enableAnalytics so we can get access to the config passed in from the page +// Subscribe on events from adUnit eightPodAnalytics.enableAnalytics = function (config) { eightPodAnalytics.originEnableAnalytics(config); logInfo(MODULE, 'init', config); + eightPodAnalytics.eventSubscribe(); }; -eightPodAnalytics.disableAnalytics = (function (orig) { - return function (...args) { - if (interval) { - clearInterval(interval); - interval = null; - } - return orig.apply(this, args); - }; -})(eightPodAnalytics.disableAnalytics); - /** * Register Analytics Adapter */ diff --git a/modules/eightPodBidAdapter.js b/modules/eightPodBidAdapter.js index 02f0954af07..536bc4b4036 100644 --- a/modules/eightPodBidAdapter.js +++ b/modules/eightPodBidAdapter.js @@ -4,7 +4,7 @@ import { BANNER } from '../src/mediaTypes.js' import * as utils from '../src/utils.js' export const BIDDER_CODE = 'eightPod' -const url = 'https://demo.8pod.com/bidder/rtb/eightpod_exchange/bid?trace=true'; +const url = 'https://demo.8pod.com/bidder/rtb/eightpod_exchange/bid'; export const spec = { code: BIDDER_CODE, @@ -49,8 +49,9 @@ function isBidRequestValid(bidRequest) { function buildRequests(bids, bidderRequest) { let bannerBids = bids.filter((bid) => isBannerBid(bid)) let requests = bannerBids.length - ? [createRequest(bannerBids, bidderRequest, BANNER)] + ? createRequest(bannerBids, bidderRequest, BANNER) : [] + return requests } @@ -61,8 +62,10 @@ function bidResponse(buildBidResponse, bid, context) { bidResponse.height = context?.imp?.banner?.format?.[0].h; bidResponse.width = context?.imp?.banner?.format?.[0].w; + bidResponse.cid = bid.cid; bidResponse.burl = replacePriceInUrl(bid.burl, bidResponse.originalCpm || bidResponse.cpm); + return bidResponse; } @@ -119,64 +122,75 @@ export function getPageKeywords(win = window) { } function createRequest(bidRequests, bidderRequest, mediaType) { - const data = converter.toORTB({ - bidRequests, - bidderRequest, - context: { mediaType }, - }); - - data.adSlotPositionOnScreen = 'ABOVE_THE_FOLD'; - data.at = 1; - - const params = getBidderParams(bidRequests); - - data.device = { - ...data.device, - model: parseUserAgent().device, - os: parseUserAgent().platform, - osv: parseUserAgent().version, - geo: { - country: params.country || 'GRB' - }, - language: params.language || data.device.language, - } - data.site = { - ...data.site, - keywords: getPageKeywords(window), - } - data.imp = [ - { - ...data.imp?.[0], - pmp: params.dealId - ? { - ...data.pmp, - deals: [ - { - bidfloor: 0.5, - at: 2, - id: params.dealId, - }, - ], - private_auction: 1, - } - : data.pmp, + const requests = bidRequests.map((bidRequest) => { + const data = converter.toORTB({ + bidRequests: [bidRequest], + bidderRequest, + context: { mediaType }, + }); + + data.adSlotPositionOnScreen = 'ABOVE_THE_FOLD'; + data.at = 1; + + const userId = + utils.deepAccess(bidRequest, 'userId.unifiedId.id') || + utils.deepAccess(bidRequest, 'userId.id5id.uid') || + utils.deepAccess(bidRequest, 'userId.idl_env'); + + const params = getBidderParams(bidRequest); + data.device = { + ...data.device, + devicetype: 4, + geo: { + country: params.country || 'GRB' + }, + language: params.language || data.device.language, + } + data.site = { + ...data.site, + keywords: getPageKeywords(window), + publisher: { + id: params.publisherId + } + } + data.imp = [ + { + ...data.imp?.[0], + secure: 1, + pmp: params.dealId + ? { + ...data.pmp, + deals: [ + { + id: params.dealId, + }, + ], + private_auction: 1, + } + : data.pmp, + } + ] + data.adSlotPlacementId = params.placementId; + + if (userId) { + data.user = { + id: userId + } } - ] - data.adSlotPlacementId = params.placementId; - const req = { - method: 'POST', - url, - data - } - return req -} + const req = { + method: 'POST', + url: url && params.trace ? url + '?trace=true' : url, + options: { withCredentials: false }, + data + } + return req + }) -function getBidderParams(bidRequests) { - const bid = bidRequests.find(bid => { - return bid.bidder === BIDDER_CODE - }); + return requests; +} +function getBidderParams(bid) { return bid?.params ? bid.params : undefined; } @@ -189,5 +203,47 @@ function isBannerBid(bid) { } function interpretResponse(resp, req) { - return converter.fromORTB({ request: req.data, response: resp.body }) + const impressionId = resp.body.seatbid[0].bid[0].impid; + const bidResponses = converter.fromORTB({ request: req.data, response: resp.body }); + const ad = bidResponses[0].ad; + const trackingTag = ` + + + + + ` + + bidResponses[0].ad = ad.replace('', trackingTag + ''); + return bidResponses; } diff --git a/modules/finativeBidAdapter.js b/modules/finativeBidAdapter.js index 87580a209bb..e7613bf9cce 100644 --- a/modules/finativeBidAdapter.js +++ b/modules/finativeBidAdapter.js @@ -3,7 +3,7 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; import {NATIVE} from '../src/mediaTypes.js'; -import {_map, deepAccess, deepSetValue, isEmpty} from '../src/utils.js'; +import {_map, deepSetValue, isEmpty, setOnAny} from '../src/utils.js'; import {config} from '../src/config.js'; import {convertOrtbRequestToProprietaryNative} from '../src/native.js'; @@ -224,15 +224,6 @@ function parseNative(bid) { return result; } -function setOnAny(collection, key) { - for (let i = 0, result; i < collection.length; i++) { - result = deepAccess(collection[i], key); - if (result) { - return result; - } - } -} - function flatten(arr) { return [].concat(...arr); } diff --git a/modules/fintezaAnalyticsAdapter.js b/modules/fintezaAnalyticsAdapter.js index ab41272c85f..78777cd6478 100644 --- a/modules/fintezaAnalyticsAdapter.js +++ b/modules/fintezaAnalyticsAdapter.js @@ -70,7 +70,8 @@ function initFirstVisit() { let cookies; try { - cookies = parseCookies(document.cookie); + // TODO: commented out because of rule violations + cookies = {} // parseCookies(document.cookie); } catch (a) { cookies = {}; } @@ -91,7 +92,8 @@ function initFirstVisit() { return visitDate; } - +// TODO: commented out because of rule violations +/* function trim(string) { if (string.trim) { return string.trim(); @@ -130,6 +132,7 @@ function parseCookies(cookie) { return values; } +*/ function getRandAsStr(digits) { let str = ''; @@ -172,7 +175,8 @@ function initSession() { let isNew = false; try { - cookies = parseCookies(document.cookie); + // TODO: commented out because of rule violations + cookies = {} // parseCookies(document.cookie); } catch (a) { cookies = {}; } @@ -263,7 +267,8 @@ function getTrackRequestLastTime() { ); } - cookie = parseCookies(document.cookie); + // TODO: commented out because of rule violations + cookie = {} // parseCookies(document.cookie); cookie = cookie[ TRACK_TIME_KEY ]; if (cookie) { return parseInt(cookie, 10); diff --git a/modules/gamoshiBidAdapter.js b/modules/gamoshiBidAdapter.js index 6681dc328d0..cfc2e32ca67 100644 --- a/modules/gamoshiBidAdapter.js +++ b/modules/gamoshiBidAdapter.js @@ -157,7 +157,7 @@ export const spec = { maxduration: bidRequest.mediaTypes.video.maxduration, api: bidRequest.mediaTypes.video.api, skip: bidRequest.mediaTypes.video.skip || bidRequest.params.video.skip, - placement: bidRequest.mediaTypes.video.plcmt || bidRequest.params.video.plcmt, + plcmt: bidRequest.mediaTypes.video.plcmt || bidRequest.params.video.plcmt, minduration: bidRequest.mediaTypes.video.minduration || bidRequest.params.video.minduration, playbackmethod: bidRequest.mediaTypes.video.playbackmethod || bidRequest.params.video.playbackmethod, startdelay: bidRequest.mediaTypes.video.startdelay || bidRequest.params.video.startdelay diff --git a/modules/goldbachBidAdapter.js b/modules/goldbachBidAdapter.js index 8f6f3f74cea..07ad6b2fa97 100644 --- a/modules/goldbachBidAdapter.js +++ b/modules/goldbachBidAdapter.js @@ -21,7 +21,7 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; import {ADPOD, BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; import {find, includes} from '../src/polyfill.js'; import {INSTREAM, OUTSTREAM} from '../src/video.js'; -import {hasPurpose1Consent} from '../src/utils/gpdr.js'; +import {hasPurpose1Consent} from '../src/utils/gdpr.js'; import {convertOrtbRequestToProprietaryNative} from '../src/native.js'; import {APPNEXUS_CATEGORY_MAPPING} from '../libraries/categoryTranslationMapping/index.js'; import {getANKeywordParam} from '../libraries/appnexusUtils/anKeywords.js'; diff --git a/modules/gptPreAuction.js b/modules/gptPreAuction.js index 65b1bf24eef..29b9257d325 100644 --- a/modules/gptPreAuction.js +++ b/modules/gptPreAuction.js @@ -1,19 +1,68 @@ +import { getSignals as getSignalsFn, getSegments as getSegmentsFn, taxonomies } from '../libraries/gptUtils/gptUtils.js'; +import { auctionManager } from '../src/auctionManager.js'; +import { config } from '../src/config.js'; +import { TARGETING_KEYS } from '../src/constants.js'; +import { getHook } from '../src/hook.js'; +import { find } from '../src/polyfill.js'; import { deepAccess, + deepSetValue, isAdUnitCodeMatchingSlot, isGptPubadsDefined, logInfo, + logWarn, pick, - deepSetValue, logWarn + uniques } from '../src/utils.js'; -import {config} from '../src/config.js'; -import {getHook} from '../src/hook.js'; -import {find} from '../src/polyfill.js'; const MODULE_NAME = 'GPT Pre-Auction'; export let _currentConfig = {}; let hooksAdded = false; +export function getSegments(fpd, sections, segtax) { + return getSegmentsFn(fpd, sections, segtax); +} + +export function getSignals(fpd) { + return getSignalsFn(fpd); +} + +export function getSignalsArrayByAuctionsIds(auctionIds, index = auctionManager.index) { + const signals = auctionIds + .map(auctionId => index.getAuction({ auctionId })?.getFPD()?.global) + .map(getSignals) + .filter(fpd => fpd); + + return signals; +} + +export function getSignalsIntersection(signals) { + const result = {}; + taxonomies.forEach((taxonomy) => { + const allValues = signals + .flatMap(x => x) + .filter(x => x.taxonomy === taxonomy) + .map(x => x.values); + result[taxonomy] = allValues.length ? ( + allValues.reduce((commonElements, subArray) => { + return commonElements.filter(element => subArray.includes(element)); + }) + ) : [] + result[taxonomy] = { values: result[taxonomy] }; + }) + return result; +} + +export function getAuctionsIdsFromTargeting(targeting, am = auctionManager) { + return Object.values(targeting) + .flatMap(x => Object.entries(x)) + .filter((entry) => entry[0] === TARGETING_KEYS.AD_ID || entry[0].startsWith(TARGETING_KEYS.AD_ID + '_')) + .flatMap(entry => entry[1]) + .map(adId => am.findBidByAdId(adId)?.auctionId) + .filter(id => id != null) + .filter(uniques); +} + export const appendGptSlots = adUnits => { const { customGptSlotMatching } = _currentConfig; @@ -153,6 +202,14 @@ export const makeBidRequestsHook = (fn, adUnits, ...args) => { return fn.call(this, adUnits, ...args); }; +const setPpsConfigFromTargetingSet = (next, targetingSet) => { + // set gpt config + const auctionsIds = getAuctionsIdsFromTargeting(targetingSet); + const signals = getSignalsIntersection(getSignalsArrayByAuctionsIds(auctionsIds)); + window.googletag.setConfig && window.googletag.setConfig({pps: { taxonomies: signals }}); + next(targetingSet); +}; + const handleSetGptConfig = moduleConfig => { _currentConfig = pick(moduleConfig, [ 'enabled', enabled => enabled !== false, @@ -166,12 +223,14 @@ const handleSetGptConfig = moduleConfig => { if (_currentConfig.enabled) { if (!hooksAdded) { getHook('makeBidRequests').before(makeBidRequestsHook); + getHook('targetingDone').after(setPpsConfigFromTargetingSet) hooksAdded = true; } } else { logInfo(`${MODULE_NAME}: Turning off module`); _currentConfig = {}; getHook('makeBidRequests').getHooks({hook: makeBidRequestsHook}).remove(); + getHook('targetingDone').getHooks({hook: setPpsConfigFromTargetingSet}).remove(); hooksAdded = false; } }; diff --git a/modules/gridBidAdapter.js b/modules/gridBidAdapter.js index f7db6d878f1..4c1876dfb6f 100644 --- a/modules/gridBidAdapter.js +++ b/modules/gridBidAdapter.js @@ -15,6 +15,7 @@ import { Renderer } from '../src/Renderer.js'; import { VIDEO, BANNER } from '../src/mediaTypes.js'; import { config } from '../src/config.js'; import { getStorageManager } from '../src/storageManager.js'; +import { getBidFromResponse } from '../libraries/processResponse/index.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest @@ -441,7 +442,7 @@ export const spec = { if (!errorMessage && serverResponse.seatbid) { serverResponse.seatbid.forEach(respItem => { - _addBidResponse(_getBidFromResponse(respItem), bidRequest, bidResponses, RendererConst, bidderCode); + _addBidResponse(getBidFromResponse(respItem, LOG_ERROR_MESS), bidRequest, bidResponses, RendererConst, bidderCode); }); } if (errorMessage) logError(errorMessage); @@ -512,17 +513,6 @@ function _getFloor (mediaTypes, bid) { return floor; } -function _getBidFromResponse(respItem) { - if (!respItem) { - logError(LOG_ERROR_MESS.emptySeatbid); - } else if (!respItem.bid) { - logError(LOG_ERROR_MESS.hasNoArrayOfBids + JSON.stringify(respItem)); - } else if (!respItem.bid[0]) { - logError(LOG_ERROR_MESS.noBid); - } - return respItem && respItem.bid && respItem.bid[0]; -} - function _addBidResponse(serverBid, bidRequest, bidResponses, RendererConst, bidderCode) { if (!serverBid) return; let errorMessage; diff --git a/modules/growthCodeAnalyticsAdapter.js b/modules/growthCodeAnalyticsAdapter.js index 1bd7a80afa7..0b1f343e4dc 100644 --- a/modules/growthCodeAnalyticsAdapter.js +++ b/modules/growthCodeAnalyticsAdapter.js @@ -140,7 +140,7 @@ function logToServer() { if (pid === DEFAULT_PID) return; if (eventQueue.length >= 1) { // Get the correct GCID - let gcid = localStorage.getItem('gcid') + let gcid = storage.getDataFromLocalStorage('gcid'); let data = { session: sessionId, diff --git a/modules/growthCodeRtdProvider.js b/modules/growthCodeRtdProvider.js index b12b25a0951..a8893b9648e 100644 --- a/modules/growthCodeRtdProvider.js +++ b/modules/growthCodeRtdProvider.js @@ -75,7 +75,7 @@ function callServer(configParams, items, expiresAt, userConsent) { storage.removeDataFromLocalStorage(RTD_EXPIRE_KEY, null) } if ((items === null) && (isNaN(expiresAt))) { - let gcid = localStorage.getItem('gcid') + let gcid = storage.getDataFromLocalStorage('gcid') let url = configParams.url ? configParams.url : ENDPOINT_URL; url = tryAppendQueryString(url, 'pid', configParams.pid); diff --git a/modules/gumgumBidAdapter.js b/modules/gumgumBidAdapter.js index 774b4b2f6f7..ecab3d0b970 100644 --- a/modules/gumgumBidAdapter.js +++ b/modules/gumgumBidAdapter.js @@ -215,11 +215,12 @@ function _getVidParams(attributes) { } /** - * Gets bidfloor - * @param {Object} mediaTypes - * @param {Number} bidfloor - * @param {Object} bid - * @returns {Number} floor + * Retrieves the bid floor value, which is the minimum acceptable bid for an ad unit. + * This function calculates the bid floor based on the given media types and other bidding parameters. + * @param {Object} mediaTypes - The media types specified for the bid, which might influence floor calculations. + * @param {number} staticBidFloor - The default or static bid floor set for the bid. + * @param {Object} bid - The bid object which may contain a method to get dynamic floor values. + * @returns {Object} An object containing the calculated bid floor and its currency. */ function _getFloor(mediaTypes, staticBidFloor, bid) { const curMediaType = Object.keys(mediaTypes)[0] || 'banner'; @@ -290,10 +291,10 @@ function getEids(userId) { } /** - * Make a server request from the list of BidRequests. - * - * @param {validBidRequests[]} - an array of bids - * @return ServerRequest Info describing the request to the server. + * Builds requests for bids. + * @param {validBidRequests[]} validBidRequests - An array of valid bid requests. + * @param {Object} bidderRequest - The bidder's request information. + * @returns {Object[]} An array of server requests. */ function buildRequests(validBidRequests, bidderRequest) { const bids = []; @@ -316,6 +317,7 @@ function buildRequests(validBidRequests, bidderRequest) { const { currency, floor } = _getFloor(mediaTypes, params.bidfloor, bidRequest); const eids = getEids(userId); const gpid = deepAccess(ortb2Imp, 'ext.gpid') || deepAccess(ortb2Imp, 'ext.data.pbadslot'); + const paapiEligible = deepAccess(ortb2Imp, 'ext.ae') === 1 let sizes = [1, 1]; let data = {}; data.displaymanager = 'Prebid.js - gumgum'; @@ -402,7 +404,9 @@ function buildRequests(validBidRequests, bidderRequest) { } else { // legacy params data = { ...data, ...handleLegacyParams(params, sizes) }; } - + if (paapiEligible) { + data.ae = paapiEligible + } if (gdprConsent) { data.gdprApplies = gdprConsent.gdprApplies ? 1 : 0; } diff --git a/modules/idImportLibrary.js b/modules/idImportLibrary.js index f6819a485e0..8cfa7e47c7c 100644 --- a/modules/idImportLibrary.js +++ b/modules/idImportLibrary.js @@ -1,15 +1,19 @@ -import { logInfo, logError } from '../src/utils.js'; -import {getGlobal} from '../src/prebidGlobal.js'; -import {ajax} from '../src/ajax.js'; -import {config} from '../src/config.js'; import MD5 from 'crypto-js/md5.js'; +import { ACTIVITY_ENRICH_UFPD } from '../src/activities/activities.js'; +import { activityParams } from '../src/activities/activityParams.js'; +import { MODULE_TYPE_PREBID } from '../src/activities/modules.js'; +import { isActivityAllowed } from '../src/activities/rules.js'; +import { ajax } from '../src/ajax.js'; +import { config } from '../src/config.js'; +import { getGlobal } from '../src/prebidGlobal.js'; +import { logError, logInfo } from '../src/utils.js'; let email; let conf; const LOG_PRE_FIX = 'ID-Library: '; const CONF_DEFAULT_OBSERVER_DEBOUNCE_MS = 250; -const CONF_DEFAULT_FULL_BODY_SCAN = false; -const CONF_DEFAULT_INPUT_SCAN = false; +export const CONF_DEFAULT_FULL_BODY_SCAN = false; +export const CONF_DEFAULT_INPUT_SCAN = false; const OBSERVER_CONFIG = { subtree: true, attributes: true, @@ -257,6 +261,10 @@ export function setConfig(config) { _logError('The required url is not configured'); return; } + if (!isActivityAllowed(ACTIVITY_ENRICH_UFPD, activityParams(MODULE_TYPE_PREBID, 'idImportLibrary'))) { + _logError('Permission for id import was denied by CMP'); + return; + } if (typeof config.debounce !== 'number') { config.debounce = CONF_DEFAULT_OBSERVER_DEBOUNCE_MS; _logInfo('Set default observer debounce to ' + CONF_DEFAULT_OBSERVER_DEBOUNCE_MS); diff --git a/modules/illuminBidAdapter.js b/modules/illuminBidAdapter.js index e830c27a32b..0e76e471f4b 100644 --- a/modules/illuminBidAdapter.js +++ b/modules/illuminBidAdapter.js @@ -1,322 +1,27 @@ -import {_each, deepAccess, parseSizesInput, parseUrl, uniques, isFn} from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; import {getStorageManager} from '../src/storageManager.js'; -import {config} from '../src/config.js'; +import { + isBidRequestValid, createUserSyncGetter, createInterpretResponseFn, createBuildRequestsFn +} from '../libraries/vidazooUtils/bidderUtils.js'; const DEFAULT_SUB_DOMAIN = 'exchange'; const BIDDER_CODE = 'illumin'; const BIDDER_VERSION = '1.0.0'; const GVLID = 149; -const CURRENCY = 'USD'; -const TTL_SECONDS = 60 * 5; -const UNIQUE_DEAL_ID_EXPIRY = 1000 * 60 * 15; -const storage = getStorageManager({bidderCode: BIDDER_CODE}); - -function getTopWindowQueryParams() { - try { - const parsedUrl = parseUrl(window.top.document.URL, {decodeSearchAsString: true}); - return parsedUrl.search; - } catch (e) { - return ''; - } -} +export const storage = getStorageManager({bidderCode: BIDDER_CODE}); export function createDomain(subDomain = DEFAULT_SUB_DOMAIN) { return `https://${subDomain}.illumin.com`; } -export function extractCID(params) { - return params.cId; -} - -export function extractPID(params) { - return params.pId; -} - -export function extractSubDomain(params) { - return params.subDomain; -} - -function isBidRequestValid(bid) { - const params = bid.params || {}; - return !!(extractCID(params) && extractPID(params)); -} - -function buildRequest(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout) { - const { - params, - bidId, - userId, - adUnitCode, - schain, - mediaTypes, - ortb2Imp, - bidderRequestId, - bidRequestsCount, - bidderRequestsCount, - bidderWinsCount - } = bid; - let {bidFloor, ext} = params; - const hashUrl = hashCode(topWindowUrl); - const uniqueDealId = getUniqueDealId(hashUrl); - const cId = extractCID(params); - const pId = extractPID(params); - const subDomain = extractSubDomain(params); - - const gpid = deepAccess(bid, 'ortb2Imp.ext.gpid', deepAccess(bid, 'ortb2Imp.ext.data.pbadslot', '')); - - if (isFn(bid.getFloor)) { - const floorInfo = bid.getFloor({ - currency: 'USD', - mediaType: '*', - size: '*' - }); - - if (floorInfo.currency === 'USD') { - bidFloor = floorInfo.floor; - } - } +const buildRequests = createBuildRequestsFn(createDomain, null, storage, BIDDER_CODE, BIDDER_VERSION, false); - let data = { - url: encodeURIComponent(topWindowUrl), - uqs: getTopWindowQueryParams(), - cb: Date.now(), - bidFloor: bidFloor, - bidId: bidId, - referrer: bidderRequest.refererInfo.ref, - adUnitCode: adUnitCode, - publisherId: pId, - sizes: sizes, - uniqueDealId: uniqueDealId, - bidderVersion: BIDDER_VERSION, - prebidVersion: '$prebid.version$', - res: `${screen.width}x${screen.height}`, - schain: schain, - mediaTypes: mediaTypes, - gpid: gpid, - transactionId: ortb2Imp?.ext?.tid, - bidderRequestId: bidderRequestId, - bidRequestsCount: bidRequestsCount, - bidderRequestsCount: bidderRequestsCount, - bidderWinsCount: bidderWinsCount, - bidderTimeout: bidderTimeout - }; - - appendUserIdsToRequestPayload(data, userId); - - const sua = deepAccess(bidderRequest, 'ortb2.device.sua'); - - if (sua) { - data.sua = sua; - } - - if (bidderRequest.gdprConsent) { - if (bidderRequest.gdprConsent.consentString) { - data.gdprConsent = bidderRequest.gdprConsent.consentString; - } - if (bidderRequest.gdprConsent.gdprApplies !== undefined) { - data.gdpr = bidderRequest.gdprConsent.gdprApplies ? 1 : 0; - } - } - if (bidderRequest.uspConsent) { - data.usPrivacy = bidderRequest.uspConsent; - } - - if (bidderRequest.gppConsent) { - data.gppString = bidderRequest.gppConsent.gppString; - data.gppSid = bidderRequest.gppConsent.applicableSections; - } else if (bidderRequest.ortb2?.regs?.gpp) { - data.gppString = bidderRequest.ortb2.regs.gpp; - data.gppSid = bidderRequest.ortb2.regs.gpp_sid; - } - - const dto = { - method: 'POST', - url: `${createDomain(subDomain)}/prebid/multi/${cId}`, - data: data - }; - - _each(ext, (value, key) => { - dto.data['ext.' + key] = value; - }); - - return dto; -} - -function appendUserIdsToRequestPayload(payloadRef, userIds) { - let key; - _each(userIds, (userId, idSystemProviderName) => { - key = `uid.${idSystemProviderName}`; - - switch (idSystemProviderName) { - case 'lipb': - payloadRef[key] = userId.lipbid; - break; - case 'id5id': - payloadRef[key] = userId.uid; - break; - default: - payloadRef[key] = userId; - } - }); -} +const interpretResponse = createInterpretResponseFn(BIDDER_CODE, false); -function buildRequests(validBidRequests, bidderRequest) { - const topWindowUrl = bidderRequest.refererInfo.page || bidderRequest.refererInfo.topmostLocation; - const bidderTimeout = config.getConfig('bidderTimeout'); - const requests = []; - validBidRequests.forEach(validBidRequest => { - const sizes = parseSizesInput(validBidRequest.sizes); - const request = buildRequest(validBidRequest, topWindowUrl, sizes, bidderRequest, bidderTimeout); - requests.push(request); - }); - return requests; -} - -function interpretResponse(serverResponse, request) { - if (!serverResponse || !serverResponse.body) { - return []; - } - const {bidId} = request.data; - const {results} = serverResponse.body; - - let output = []; - - try { - results.forEach(result => { - const { - creativeId, - ad, - price, - exp, - width, - height, - currency, - metaData, - advertiserDomains, - mediaType = BANNER - } = result; - if (!ad || !price) { - return; - } - - const response = { - requestId: bidId, - cpm: price, - width: width, - height: height, - creativeId: creativeId, - currency: currency || CURRENCY, - netRevenue: true, - ttl: exp || TTL_SECONDS, - }; - - if (metaData) { - Object.assign(response, { - meta: metaData - }) - } else { - Object.assign(response, { - meta: { - advertiserDomains: advertiserDomains || [] - } - }) - } - - if (mediaType === BANNER) { - Object.assign(response, { - ad: ad, - }); - } else { - Object.assign(response, { - vastXml: ad, - mediaType: VIDEO - }); - } - output.push(response); - }); - return output; - } catch (e) { - return []; - } -} - -function getUserSyncs(syncOptions, responses, gdprConsent = {}, uspConsent = '') { - let syncs = []; - const {iframeEnabled, pixelEnabled} = syncOptions; - const {gdprApplies, consentString = ''} = gdprConsent; - - const cidArr = responses.filter(resp => deepAccess(resp, 'body.cid')).map(resp => resp.body.cid).filter(uniques); - const params = `?cid=${encodeURIComponent(cidArr.join(','))}&gdpr=${gdprApplies ? 1 : 0}&gdpr_consent=${encodeURIComponent(consentString || '')}&us_privacy=${encodeURIComponent(uspConsent || '')}` - if (iframeEnabled) { - syncs.push({ - type: 'iframe', - url: `https://sync.illumin.com/api/sync/iframe/${params}` - }); - } - if (pixelEnabled) { - syncs.push({ - type: 'image', - url: `https://sync.illumin.com/api/sync/image/${params}` - }); - } - return syncs; -} - -export function hashCode(s, prefix = '_') { - const l = s.length; - let h = 0 - let i = 0; - if (l > 0) { - while (i < l) { - h = (h << 5) - h + s.charCodeAt(i++) | 0; - } - } - return prefix + h; -} - -export function getUniqueDealId(key, expiry = UNIQUE_DEAL_ID_EXPIRY) { - const storageKey = `u_${key}`; - const now = Date.now(); - const data = getStorageItem(storageKey); - let uniqueId; - - if (!data || !data.value || now - data.created > expiry) { - uniqueId = `${key}_${now.toString()}`; - setStorageItem(storageKey, uniqueId); - } else { - uniqueId = data.value; - } - - return uniqueId; -} - -export function getStorageItem(key) { - try { - return tryParseJSON(storage.getDataFromLocalStorage(key)); - } catch (e) { - } - - return null; -} - -export function setStorageItem(key, value, timestamp) { - try { - const created = timestamp || Date.now(); - const data = JSON.stringify({value, created}); - storage.setDataInLocalStorage(key, data); - } catch (e) { - } -} - -export function tryParseJSON(value) { - try { - return JSON.parse(value); - } catch (e) { - return value; - } -} +const getUserSyncs = createUserSyncGetter({ + iframeSyncUrl: 'https://sync.illumin.com/api/sync/iframe', imageSyncUrl: 'https://sync.illumin.com/api/sync/image' +}); export const spec = { code: BIDDER_CODE, diff --git a/modules/improvedigitalBidAdapter.js b/modules/improvedigitalBidAdapter.js index 2d67caf6a61..ddf13caa833 100644 --- a/modules/improvedigitalBidAdapter.js +++ b/modules/improvedigitalBidAdapter.js @@ -3,7 +3,7 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; import {config} from '../src/config.js'; import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; import {Renderer} from '../src/Renderer.js'; -import {hasPurpose1Consent} from '../src/utils/gpdr.js'; +import {hasPurpose1Consent} from '../src/utils/gdpr.js'; import {ortbConverter} from '../libraries/ortbConverter/converter.js'; /** * See https://github.com/prebid/Prebid.js/pull/8827 for details on linting exception diff --git a/modules/insticatorBidAdapter.js b/modules/insticatorBidAdapter.js index 1ddd9334dc4..4ab7f5927f9 100644 --- a/modules/insticatorBidAdapter.js +++ b/modules/insticatorBidAdapter.js @@ -107,19 +107,8 @@ function buildVideo(bidRequest) { const playerSize = deepAccess(bidRequest, 'mediaTypes.video.playerSize'); const context = deepAccess(bidRequest, 'mediaTypes.video.context'); - if (!w && playerSize) { - if (Array.isArray(playerSize[0])) { - w = parseInt(playerSize[0][0], 10); - } else if (typeof playerSize[0] === 'number' && !isNaN(playerSize[0])) { - w = parseInt(playerSize[0], 10); - } - } - if (!h && playerSize) { - if (Array.isArray(playerSize[0])) { - h = parseInt(playerSize[0][1], 10); - } else if (typeof playerSize[1] === 'number' && !isNaN(playerSize[1])) { - h = parseInt(playerSize[1], 10); - } + if (!h && !w && playerSize) { + ({w, h} = parsePlayerSizeToWidthHeight(playerSize, w, h)); } const bidRequestVideo = deepAccess(bidRequest, 'mediaTypes.video'); @@ -173,6 +162,14 @@ function buildImpression(bidRequest) { }, } + if (bidRequest?.params?.adUnitId) { + deepSetValue(imp, 'ext.prebid.bidder.insticator.adUnitId', bidRequest.params.adUnitId); + } + + if (bidRequest?.params?.publisherId) { + deepSetValue(imp, 'ext.prebid.bidder.insticator.publisherId', bidRequest.params.publisherId); + } + let bidFloor = parseFloat(deepAccess(bidRequest, 'params.floor')); if (!isNaN(bidFloor)) { @@ -247,7 +244,7 @@ function buildDevice(bidRequest) { const device = { w: window.innerWidth, h: window.innerHeight, - js: true, + js: 1, ext: { localStorage: storage.localStorageIsEnabled(), cookies: storage.cookiesAreEnabled(), @@ -569,24 +566,12 @@ function validateVideo(bid) { let w = deepAccess(bid, 'mediaTypes.video.w'); let h = deepAccess(bid, 'mediaTypes.video.h'); const playerSize = deepAccess(bid, 'mediaTypes.video.playerSize'); - if (!w && playerSize) { - if (Array.isArray(playerSize[0])) { - w = parseInt(playerSize[0][0], 10); - } else if (typeof playerSize[0] === 'number' && !isNaN(playerSize[0])) { - w = parseInt(playerSize[0], 10); - } - } - if (!h && playerSize) { - if (Array.isArray(playerSize[0])) { - h = parseInt(playerSize[0][1], 10); - } else if (typeof playerSize[1] === 'number' && !isNaN(playerSize[1])) { - h = parseInt(playerSize[1], 10); - } + + if (!h && !w && playerSize) { + ({w, h} = parsePlayerSizeToWidthHeight(playerSize, w, h)); } - const videoSize = [ - w, - h, - ]; + + const videoSize = [w, h]; if ( !validateSize(videoSize) @@ -625,6 +610,25 @@ function validateVideo(bid) { return true; } +function parsePlayerSizeToWidthHeight(playerSize, w, h) { + if (!w && playerSize) { + if (Array.isArray(playerSize[0])) { + w = parseInt(playerSize[0][0], 10); + } else if (typeof playerSize[0] === 'number' && !isNaN(playerSize[0])) { + w = parseInt(playerSize[0], 10); + } + } + if (!h && playerSize) { + if (Array.isArray(playerSize[0])) { + h = parseInt(playerSize[0][1], 10); + } else if (typeof playerSize[1] === 'number' && !isNaN(playerSize[1])) { + h = parseInt(playerSize[1], 10); + } + } + + return { w, h }; +} + export const spec = { code: BIDDER_CODE, gvlid: GVLID, diff --git a/modules/intentIqAnalyticsAdapter.js b/modules/intentIqAnalyticsAdapter.js new file mode 100644 index 00000000000..10ce8097bf1 --- /dev/null +++ b/modules/intentIqAnalyticsAdapter.js @@ -0,0 +1,234 @@ +import { logInfo, logError } from '../src/utils.js'; +import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; +import adapterManager from '../src/adapterManager.js'; +import { ajax } from '../src/ajax.js'; +import { getStorageManager } from '../src/storageManager.js'; +import { config } from '../src/config.js'; +import { EVENTS } from '../src/constants.js'; +import { MODULE_TYPE_ANALYTICS } from '../src/activities/modules.js'; + +const MODULE_NAME = 'iiqAnalytics' +const analyticsType = 'endpoint'; +const defaultUrl = 'https://reports.intentiq.com/report'; +const storage = getStorageManager({ moduleType: MODULE_TYPE_ANALYTICS, moduleName: MODULE_NAME }); +const prebidVersion = '$prebid.version$'; +export const REPORTER_ID = Date.now() + '_' + getRandom(0, 1000); + +const FIRST_PARTY_KEY = '_iiq_fdata'; +const FIRST_PARTY_DATA_KEY = '_iiq_fdata'; +const JSVERSION = 0.1 + +const PARAMS_NAMES = { + abTestGroup: 'abGroup', + pbPauseUntil: 'pbPauseUntil', + pbMonitoringEnabled: 'pbMonitoringEnabled', + isInTestGroup: 'isInTestGroup', + enhanceRequests: 'enhanceRequests', + wasSubscribedForPrebid: 'wasSubscribedForPrebid', + hadEids: 'hadEids', + ABTestingConfigurationSource: 'ABTestingConfigurationSource', + lateConfiguration: 'lateConfiguration', + jsversion: 'jsversion', + eidsNames: 'eidsNames', + requestRtt: 'rtt', + clientType: 'clientType', + adserverDeviceType: 'AdserverDeviceType', + terminationCause: 'terminationCause', + callCount: 'callCount', + manualCallCount: 'mcc', + pubprovidedidsFailedToregister: 'ppcc', + noDataCount: 'noDataCount', + profile: 'profile', + isProfileDeterministic: 'pidDeterministic', + siteId: 'sid', + hadEidsInLocalStorage: 'idls', + auctionStartTime: 'ast', + eidsReadTime: 'eidt', + agentId: 'aid', + auctionEidsLength: 'aeidln', + wasServerCalled: 'wsrvcll', + referrer: 'vrref', + isInBrowserBlacklist: 'inbbl', + prebidVersion: 'pbjsver', + partnerId: 'partnerId' +}; + +let iiqAnalyticsAnalyticsAdapter = Object.assign(adapter({ defaultUrl, analyticsType }), { + initOptions: { + lsValueInitialized: false, + partner: null, + fpid: null, + currentGroup: null, + dataInLs: null, + eidl: null, + lsIdsInitialized: false, + manualReport: false + }, + track({ eventType, args }) { + switch (eventType) { + case BID_WON: + bidWon(args); + break; + default: + break; + } + } +}); + +// Events needed +const { + BID_WON +} = EVENTS; + +function readData(key) { + try { + if (storage.hasLocalStorage()) { + return storage.getDataFromLocalStorage(key); + } + if (storage.cookiesAreEnabled()) { + return storage.getCookie(key); + } + } catch (error) { + logError(error); + } +} + +function initLsValues() { + if (iiqAnalyticsAnalyticsAdapter.initOptions.lsValueInitialized) return; + iiqAnalyticsAnalyticsAdapter.initOptions.fpid = JSON.parse(readData(FIRST_PARTY_KEY)); + let iiqArr = config.getConfig('userSync.userIds').filter(m => m.name == 'intentIqId'); + if (iiqArr && iiqArr.length > 0) iiqAnalyticsAnalyticsAdapter.initOptions.lsValueInitialized = true; + if (!iiqArr) iiqArr = []; + if (iiqArr.length == 0) { + iiqArr.push({ + 'params': { + 'partner': -1, + 'group': 'U' + } + }) + } + if (iiqArr && iiqArr.length > 0) { + if (iiqArr[0].params && iiqArr[0].params.partner && !isNaN(iiqArr[0].params.partner)) { + iiqAnalyticsAnalyticsAdapter.initOptions.partner = iiqArr[0].params.partner; + iiqAnalyticsAnalyticsAdapter.initOptions.currentGroup = iiqAnalyticsAnalyticsAdapter.initOptions.fpid.group; + } + } +} + +function initReadLsIds() { + if (isNaN(iiqAnalyticsAnalyticsAdapter.initOptions.partner) || iiqAnalyticsAnalyticsAdapter.initOptions.partner == -1) return; + try { + iiqAnalyticsAnalyticsAdapter.initOptions.dataInLs = null; + let iData = readData(FIRST_PARTY_DATA_KEY + '_' + iiqAnalyticsAnalyticsAdapter.initOptions.partner) + if (iData) { + iiqAnalyticsAnalyticsAdapter.initOptions.lsIdsInitialized = true; + let pData = JSON.parse(iData); + iiqAnalyticsAnalyticsAdapter.initOptions.dataInLs = pData.data; + iiqAnalyticsAnalyticsAdapter.initOptions.eidl = pData.eidl || -1; + } + } catch (e) { + logError(e) + } +} + +function bidWon(args) { + if (!iiqAnalyticsAnalyticsAdapter.initOptions.lsValueInitialized) { initLsValues(); } + if (iiqAnalyticsAnalyticsAdapter.initOptions.lsValueInitialized && !iiqAnalyticsAnalyticsAdapter.initOptions.lsIdsInitialized) { initReadLsIds(); } + if (!iiqAnalyticsAnalyticsAdapter.initOptions.manualReport) { + ajax(constructFullUrl(preparePayload(args, true)), undefined, null, { method: 'GET' }); + } + + logInfo('IIQ ANALYTICS -> BID WON') +} + +function getRandom(start, end) { + return Math.floor((Math.random() * (end - start + 1)) + start); +} + +export function preparePayload(data) { + let result = getDefaultDataObject(); + + result[PARAMS_NAMES.partnerId] = iiqAnalyticsAnalyticsAdapter.initOptions.partner; + result[PARAMS_NAMES.prebidVersion] = prebidVersion; + result[PARAMS_NAMES.referrer] = getReferrer(); + + result[PARAMS_NAMES.abTestGroup] = iiqAnalyticsAnalyticsAdapter.initOptions.currentGroup; + + result[PARAMS_NAMES.isInTestGroup] = iiqAnalyticsAnalyticsAdapter.initOptions.currentGroup == 'A'; + + result[PARAMS_NAMES.agentId] = REPORTER_ID; + + fillPrebidEventData(data, result); + + fillEidsData(result); + + return result; +} + +function fillEidsData(result) { + if (iiqAnalyticsAnalyticsAdapter.initOptions.lsIdsInitialized) { + result[PARAMS_NAMES.hadEidsInLocalStorage] = iiqAnalyticsAnalyticsAdapter.initOptions.eidl && iiqAnalyticsAnalyticsAdapter.initOptions.eidl > 0; + result[PARAMS_NAMES.auctionEidsLength] = iiqAnalyticsAnalyticsAdapter.initOptions.eidl || -1; + } +} + +function fillPrebidEventData(eventData, result) { + if (eventData.bidderCode) { result.bidderCode = eventData.bidderCode; } + if (eventData.cpm) { result.cpm = eventData.cpm; } + if (eventData.currency) { result.currency = eventData.currency; } + if (eventData.originalCpm) { result.originalCpm = eventData.originalCpm; } + if (eventData.originalCurrency) { result.originalCurrency = eventData.originalCurrency; } + if (eventData.status) { result.status = eventData.status; } + if (eventData.auctionId) { result.prebidAuctionId = eventData.auctionId; } + + result.biddingPlatformId = 1; + result.partnerAuctionId = 'BW'; +} + +function getDefaultDataObject() { + return { + 'inbbl': false, + 'pbjsver': prebidVersion, + 'partnerAuctionId': 'BW', + 'reportSource': 'pbjs', + 'abGroup': 'U', + 'jsversion': JSVERSION, + 'partnerId': -1, + 'biddingPlatformId': 1, + 'idls': false, + 'ast': -1, + 'aeidln': -1 + } +} + +function constructFullUrl(data) { + let report = [] + data = btoa(JSON.stringify(data)) + report.push(data) + return defaultUrl + '?pid=' + iiqAnalyticsAnalyticsAdapter.initOptions.partner + + '&mct=1' + + ((iiqAnalyticsAnalyticsAdapter.initOptions && iiqAnalyticsAnalyticsAdapter.initOptions.fpid) + ? '&iiqid=' + encodeURIComponent(iiqAnalyticsAnalyticsAdapter.initOptions.fpid.pcid) : '') + + '&agid=' + REPORTER_ID + + '&jsver=' + JSVERSION + + '&vrref=' + getReferrer() + + '&source=pbjs' + + '&payload=' + JSON.stringify(report) +} + +export function getReferrer() { + return document.referrer; +} + +iiqAnalyticsAnalyticsAdapter.originEnableAnalytics = iiqAnalyticsAnalyticsAdapter.enableAnalytics; + +iiqAnalyticsAnalyticsAdapter.enableAnalytics = function (myConfig) { + iiqAnalyticsAnalyticsAdapter.originEnableAnalytics(myConfig); // call the base class function +}; + +adapterManager.registerAnalyticsAdapter({ + adapter: iiqAnalyticsAnalyticsAdapter, + code: MODULE_NAME +}); + +export default iiqAnalyticsAnalyticsAdapter; diff --git a/modules/intentIqAnalyticsAdapter.md b/modules/intentIqAnalyticsAdapter.md new file mode 100644 index 00000000000..905d88a9b21 --- /dev/null +++ b/modules/intentIqAnalyticsAdapter.md @@ -0,0 +1,27 @@ +# Overview + +Module Name: iiqAnalytics +Module Type: Analytics Adapter +Maintainer: julian@intentiq.com + +# Description + +By using this Intent IQ adapter, you will be able to obtain comprehensive analytics and metrics regarding the performance of the Intent IQ Unified ID module. This includes how the module impacts your revenue, CPMs, and fill rates related to bidders and domains. + +## Intent IQ Universal ID Registration + +No registration for this module is required. + +## Intent IQ Universal IDConfiguration + +IMPORTANT: only effective when Intent IQ Universal ID module is installed and configured. [(How-To)](https://docs.prebid.org/dev-docs/modules/userid-submodules/intentiq.html) + +No additional configuration for this module is required. We will use the configuration provided for Intent IQ Universal IQ module. + +#### Example Configuration + +```js +pbjs.enableAnalytics({ + provider: 'iiqAnalytics' +}); +``` diff --git a/modules/intentIqIdSystem.md b/modules/intentIqIdSystem.md old mode 100755 new mode 100644 diff --git a/modules/jwplayerBidAdapter.js b/modules/jwplayerBidAdapter.js index 151d08bf3a6..c58eed8ffb8 100644 --- a/modules/jwplayerBidAdapter.js +++ b/modules/jwplayerBidAdapter.js @@ -2,7 +2,7 @@ import { registerBidder } from '../src/adapters/bidderFactory.js'; import { VIDEO } from '../src/mediaTypes.js'; import { isArray, isFn, deepAccess, deepSetValue, getDNT, logError, logWarn } from '../src/utils.js'; import { config } from '../src/config.js'; -import { hasPurpose1Consent } from '../src/utils/gpdr.js'; +import { hasPurpose1Consent } from '../src/utils/gdpr.js'; const BIDDER_CODE = 'jwplayer'; const BASE_URL = 'https://vpb-server.jwplayer.com/'; diff --git a/modules/jwplayerRtdProvider.js b/modules/jwplayerRtdProvider.js index a06404e52f2..78c26cbda6a 100644 --- a/modules/jwplayerRtdProvider.js +++ b/modules/jwplayerRtdProvider.js @@ -12,7 +12,7 @@ import {submodule} from '../src/hook.js'; import {config} from '../src/config.js'; import {ajaxBuilder} from '../src/ajax.js'; -import {deepAccess, logError} from '../src/utils.js'; +import { deepAccess, logError, logWarn } from '../src/utils.js' import {find} from '../src/polyfill.js'; import {getGlobal} from '../src/prebidGlobal.js'; @@ -429,17 +429,37 @@ export function addTargetingToBid(bid, targeting) { bid.rtd = Object.assign({}, rtd, jwRtd); } -function getPlayer(playerDivId) { +export function getPlayer(playerDivId) { const jwplayer = window.jwplayer; if (!jwplayer) { logError(SUBMODULE_NAME + '.js was not found on page'); return; } - const player = jwplayer(playerDivId); - if (!player || !player.getPlaylist) { - logError('player ID did not match any players'); + let player = jwplayer(playerDivId); + if (player && player.getPlaylist) { + return player; + } + + const playerOnPageCount = document.getElementsByClassName('jwplayer').length; + if (playerOnPageCount === 0) { + logError('No JWPlayer instances have been detected on the page'); return; } - return player; + + let errorMessage = `player Div ID ${playerDivId} did not match any players.`; + + // If there are multiple instances on the page, we cannot guess which one should be targeted. + if (playerOnPageCount > 1) { + logError(errorMessage); + return; + } + + player = jwplayer(); + if (player && player.getPlaylist) { + logWarn(`${errorMessage} Targeting player Div ID ${player.id} instead`); + return player; + } + + logError(errorMessage); } diff --git a/modules/jwplayerVideoProvider.js b/modules/jwplayerVideoProvider.js index ed6b69d756a..54de1949e6f 100644 --- a/modules/jwplayerVideoProvider.js +++ b/modules/jwplayerVideoProvider.js @@ -12,6 +12,12 @@ import stateFactory from '../libraries/video/shared/state.js'; import { JWPLAYER_VENDOR } from '../libraries/video/constants/vendorCodes.js'; import { getEventHandler } from '../libraries/video/shared/eventHandler.js'; import { submodule } from '../src/hook.js'; +/** + * @typedef {import('../libraries/video/constants/ortb.js').OrtbVideoParams} OrtbVideoParams + * @typedef {import('../libraries/video/shared/state.js').State} State + * @typedef {import('../modules/videoModule/coreVideo.js').VideoProvider} VideoProvider + * @typedef {import('../modules/videoModule/coreVideo.js').videoProviderConfig} videoProviderConfig + */ /** * @constructor diff --git a/modules/kargoBidAdapter.js b/modules/kargoBidAdapter.js index 91d067ab67d..8429228d7af 100644 --- a/modules/kargoBidAdapter.js +++ b/modules/kargoBidAdapter.js @@ -48,7 +48,7 @@ const SUA_ATTRIBUTES = [ const CERBERUS = Object.freeze({ KEY: 'krg_crb', - SYNC_URL: 'https://crb.kargo.com/api/v1/initsyncrnd/{UUID}?seed={SEED}&idx={INDEX}&gdpr={GDPR}&gdpr_consent={GDPR_CONSENT}&us_privacy={US_PRIVACY}&gpp={GPP_STRING}&gpp_sid={GPP_SID}', + SYNC_URL: 'https://crb.kargo.com/api/v1/initsyncrnd/{UUID}?seed={SEED}&gdpr={GDPR}&gdpr_consent={GDPR_CONSENT}&us_privacy={US_PRIVACY}&gpp={GPP_STRING}&gpp_sid={GPP_SID}', SYNC_COUNT: 5, PAGE_VIEW_ID: 'pageViewId', PAGE_VIEW_TIMESTAMP: 'pageViewTimestamp', @@ -274,19 +274,16 @@ function getUserSyncs(syncOptions, _, gdprConsent, usPrivacy, gppConsent) { return syncs; } if (syncOptions.iframeEnabled && seed && clientId) { - for (let i = 0; i < CERBERUS.SYNC_COUNT; i++) { - syncs.push({ - type: 'iframe', - url: CERBERUS.SYNC_URL.replace('{UUID}', clientId) - .replace('{SEED}', seed) - .replace('{INDEX}', i) - .replace('{GDPR}', gdpr) - .replace('{GDPR_CONSENT}', gdprConsentString) - .replace('{US_PRIVACY}', usPrivacy || '') - .replace('{GPP_STRING}', gppString) - .replace('{GPP_SID}', gppApplicableSections) - }); - } + syncs.push({ + type: 'iframe', + url: CERBERUS.SYNC_URL.replace('{UUID}', clientId) + .replace('{SEED}', seed) + .replace('{GDPR}', gdpr) + .replace('{GDPR_CONSENT}', gdprConsentString) + .replace('{US_PRIVACY}', usPrivacy || '') + .replace('{GPP_STRING}', gppString) + .replace('{GPP_SID}', gppApplicableSections) + }) } return syncs; } diff --git a/modules/kimberliteBidAdapter.js b/modules/kimberliteBidAdapter.js index 72df921e18f..6ad8b9eda05 100644 --- a/modules/kimberliteBidAdapter.js +++ b/modules/kimberliteBidAdapter.js @@ -1,13 +1,14 @@ import { registerBidder } from '../src/adapters/bidderFactory.js'; -import { BANNER } from '../src/mediaTypes.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; import { ortbConverter } from '../libraries/ortbConverter/converter.js' import { deepSetValue } from '../src/utils.js'; +import {ORTB_MTYPES} from '../libraries/ortbConverter/processors/mediaType.js'; -const VERSION = '1.0.0'; +const VERSION = '1.1.0'; const BIDDER_CODE = 'kimberlite'; const METHOD = 'POST'; -const ENDPOINT_URL = 'https://kimberlite.io/rtb/bid/pbjs'; +export const ENDPOINT_URL = 'https://kimberlite.io/rtb/bid/pbjs'; const VERSION_INFO = { ver: '$prebid.version$', @@ -16,7 +17,6 @@ const VERSION_INFO = { const converter = ortbConverter({ context: { - mediaType: BANNER, netRevenue: true, ttl: 300 }, @@ -35,18 +35,32 @@ const converter = ortbConverter({ const imp = buildImp(bidRequest, context); imp.tagid = bidRequest.params.placementId; return imp; - } + }, + + bidResponse: function (buildBidResponse, bid, context) { + if (!bid.price) return; + + const [type] = Object.keys(context.bidRequest.mediaTypes); + if (Object.values(ORTB_MTYPES).includes(type)) { + context.mediaType = type; + } + + const bidResponse = buildBidResponse(bid, context); + return bidResponse; + }, }); export const spec = { code: BIDDER_CODE, - supportedMediaTypes: [BANNER], + supportedMediaTypes: [BANNER, VIDEO], isBidRequestValid: (bidRequest = {}) => { const { params, mediaTypes } = bidRequest; let isValid = Boolean(params && params.placementId); if (mediaTypes && mediaTypes[BANNER]) { isValid = isValid && Boolean(mediaTypes[BANNER].sizes); + } else if (mediaTypes && mediaTypes[VIDEO]) { + isValid = isValid && Boolean(mediaTypes[VIDEO].mimes); } else { isValid = false; } @@ -58,7 +72,10 @@ export const spec = { return { method: METHOD, url: ENDPOINT_URL, - data: converter.toORTB({ bidderRequest, bidRequests }) + data: converter.toORTB({ + bidRequests, + bidderRequest + }) } }, diff --git a/modules/kimberliteBidAdapter.md b/modules/kimberliteBidAdapter.md index c165f1073aa..06749f2c8e0 100644 --- a/modules/kimberliteBidAdapter.md +++ b/modules/kimberliteBidAdapter.md @@ -20,7 +20,7 @@ var adUnits = [ code: 'test-div', mediaTypes: { banner: { - sizes: [[320, 250], [640, 480]], + sizes: [[320, 250], [640, 480]], // Required. } }, bids: [ @@ -34,3 +34,32 @@ var adUnits = [ } ] ``` + +## Video AdUnit + +```javascript +var adUnits = [ + { + code: 'test-div', + mediaTypes: { + video: { + // ORTB 2.5 options. + mimes: ['video/mp4'], // Required. + // Other options are optional. + placement: 1, + protocols: [3, 6], + linearity: 1, + startdelay: 0 + } + }, + bids: [ + { + bidder: "kimberlite", + params: { + placementId: 'testVideo' + } + } + ] + } +] +``` diff --git a/modules/kueezRtbBidAdapter.js b/modules/kueezRtbBidAdapter.js index ba33f3ade9a..c0fb17672af 100644 --- a/modules/kueezRtbBidAdapter.js +++ b/modules/kueezRtbBidAdapter.js @@ -1,338 +1,43 @@ -import {_each, deepAccess, parseSizesInput, parseUrl, uniques, isFn} from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; import {getStorageManager} from '../src/storageManager.js'; -import {config} from '../src/config.js'; +import { + createBuildRequestsFn, + createInterpretResponseFn, + createUserSyncGetter, + isBidRequestValid +} from '../libraries/vidazooUtils/bidderUtils.js'; const GVLID = 1165; const DEFAULT_SUB_DOMAIN = 'exchange'; const BIDDER_CODE = 'kueezrtb'; const BIDDER_VERSION = '1.0.0'; -const CURRENCY = 'USD'; -const TTL_SECONDS = 60 * 5; -const UNIQUE_DEAL_ID_EXPIRY = 1000 * 60 * 15; -const storage = getStorageManager({bidderCode: BIDDER_CODE}); - -function getTopWindowQueryParams() { - try { - const parsedUrl = parseUrl(window.top.document.URL, {decodeSearchAsString: true}); - return parsedUrl.search; - } catch (e) { - return ''; - } -} +export const storage = getStorageManager({bidderCode: BIDDER_CODE}); export function createDomain(subDomain = DEFAULT_SUB_DOMAIN) { return `https://${subDomain}.kueezrtb.com`; } -export function extractCID(params) { - return params.cId || params.CID || params.cID || params.CId || params.cid || params.ciD || params.Cid || params.CiD; -} - -export function extractPID(params) { - return params.pId || params.PID || params.pID || params.PId || params.pid || params.piD || params.Pid || params.PiD; -} - -export function extractSubDomain(params) { - return params.subDomain || params.SubDomain || params.Subdomain || params.subdomain || params.SUBDOMAIN || params.subDOMAIN; -} - -function isBidRequestValid(bid) { - const params = bid.params || {}; - return !!(extractCID(params) && extractPID(params)); -} - -function buildRequest(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout) { +function createUniqueRequestData(hashUrl, bid) { const { - params, - bidId, - userId, - adUnitCode, - schain, - mediaTypes, auctionId, transactionId, - bidderRequestId, - bidRequestsCount, - bidderRequestsCount, - bidderWinsCount } = bid; - let {bidFloor, ext} = params; - const hashUrl = hashCode(topWindowUrl); - const uniqueDealId = getUniqueDealId(hashUrl); - const cId = extractCID(params); - const pId = extractPID(params); - const subDomain = extractSubDomain(params); - - const gpid = deepAccess(bid, 'ortb2Imp.ext.gpid') || deepAccess(bid, 'ortb2Imp.ext.data.pbadslot', ''); - - if (isFn(bid.getFloor)) { - const floorInfo = bid.getFloor({ - currency: 'USD', - mediaType: '*', - size: '*' - }); - - if (floorInfo.currency === 'USD') { - bidFloor = floorInfo.floor; - } - } - let data = { - url: encodeURIComponent(topWindowUrl), - uqs: getTopWindowQueryParams(), - cb: Date.now(), - bidFloor: bidFloor, - bidId: bidId, - referrer: bidderRequest.refererInfo.ref, - adUnitCode: adUnitCode, - publisherId: pId, - sizes: sizes, - uniqueDealId: uniqueDealId, - bidderVersion: BIDDER_VERSION, - prebidVersion: '$prebid.version$', - res: `${screen.width}x${screen.height}`, - schain: schain, - mediaTypes: mediaTypes, - gpid: gpid, - // TODO: fix auctionId/transactionId leak: https://github.com/prebid/Prebid.js/issues/9781 - auctionId: auctionId, - transactionId: transactionId, - bidderRequestId: bidderRequestId, - bidRequestsCount: bidRequestsCount, - bidderRequestsCount: bidderRequestsCount, - bidderWinsCount: bidderWinsCount, - bidderTimeout: bidderTimeout - }; - - appendUserIdsToRequestPayload(data, userId); - - const sua = deepAccess(bidderRequest, 'ortb2.device.sua'); - - if (sua) { - data.sua = sua; - } - - if (bidderRequest.gdprConsent) { - if (bidderRequest.gdprConsent.consentString) { - data.gdprConsent = bidderRequest.gdprConsent.consentString; - } - if (bidderRequest.gdprConsent.gdprApplies !== undefined) { - data.gdpr = bidderRequest.gdprConsent.gdprApplies ? 1 : 0; - } - } - if (bidderRequest.uspConsent) { - data.usPrivacy = bidderRequest.uspConsent; - } - - if (bidderRequest.gppConsent) { - data.gppString = bidderRequest.gppConsent.gppString; - data.gppSid = bidderRequest.gppConsent.applicableSections; - } else if (bidderRequest.ortb2?.regs?.gpp) { - data.gppString = bidderRequest.ortb2.regs.gpp; - data.gppSid = bidderRequest.ortb2.regs.gpp_sid; - } - - const dto = { - method: 'POST', - url: `${createDomain(subDomain)}/prebid/multi/${cId}`, - data: data + return { + auctionId, + transactionId, }; - - _each(ext, (value, key) => { - dto.data['ext.' + key] = value; - }); - - return dto; } -function appendUserIdsToRequestPayload(payloadRef, userIds) { - let key; - _each(userIds, (userId, idSystemProviderName) => { - key = `uid.${idSystemProviderName}`; +const buildRequests = createBuildRequestsFn(createDomain, createUniqueRequestData, storage, BIDDER_CODE, BIDDER_VERSION, false); - switch (idSystemProviderName) { - case 'digitrustid': - payloadRef[key] = deepAccess(userId, 'data.id'); - break; - case 'lipb': - payloadRef[key] = userId.lipbid; - break; - case 'parrableId': - payloadRef[key] = userId.eid; - break; - case 'id5id': - payloadRef[key] = userId.uid; - break; - default: - payloadRef[key] = userId; - } - }); -} +const interpretResponse = createInterpretResponseFn(BIDDER_CODE, false); -function buildRequests(validBidRequests, bidderRequest) { - const topWindowUrl = bidderRequest.refererInfo.page || bidderRequest.refererInfo.topmostLocation; - const bidderTimeout = bidderRequest.timeout ?? config.getConfig('bidderTimeout'); - const requests = []; - validBidRequests.forEach(validBidRequest => { - const sizes = parseSizesInput(validBidRequest.sizes); - const request = buildRequest(validBidRequest, topWindowUrl, sizes, bidderRequest, bidderTimeout); - requests.push(request); - }); - return requests; -} - -function interpretResponse(serverResponse, request) { - if (!serverResponse || !serverResponse.body) { - return []; - } - const {bidId} = request.data; - const {results} = serverResponse.body; - - let output = []; - - try { - results.forEach(result => { - const { - creativeId, - ad, - price, - exp, - width, - height, - currency, - metaData, - advertiserDomains, - mediaType = BANNER - } = result; - if (!ad || !price) { - return; - } - - const response = { - requestId: bidId, - cpm: price, - width: width, - height: height, - creativeId: creativeId, - currency: currency || CURRENCY, - netRevenue: true, - ttl: exp || TTL_SECONDS, - }; - - if (metaData) { - Object.assign(response, { - meta: metaData - }) - } else { - Object.assign(response, { - meta: { - advertiserDomains: advertiserDomains || [] - } - }) - } - - if (mediaType === BANNER) { - Object.assign(response, { - ad: ad, - }); - } else { - Object.assign(response, { - vastXml: ad, - mediaType: VIDEO - }); - } - output.push(response); - }); - return output; - } catch (e) { - return []; - } -} - -function getUserSyncs(syncOptions, responses, gdprConsent = {}, uspConsent = '', gppConsent = {}) { - let syncs = []; - const {iframeEnabled, pixelEnabled} = syncOptions; - const {gdprApplies, consentString = ''} = gdprConsent; - const {gppString, applicableSections} = gppConsent; - - const cidArr = responses.filter(resp => deepAccess(resp, 'body.cid')).map(resp => resp.body.cid).filter(uniques); - let params = `?cid=${encodeURIComponent(cidArr.join(','))}&gdpr=${gdprApplies ? 1 : 0}&gdpr_consent=${encodeURIComponent(consentString || '')}&us_privacy=${encodeURIComponent(uspConsent || '')}` - - if (gppString && applicableSections?.length) { - params += '&gpp=' + encodeURIComponent(gppString); - params += '&gpp_sid=' + encodeURIComponent(applicableSections.join(',')); - } - - if (iframeEnabled) { - syncs.push({ - type: 'iframe', - url: `https://sync.kueezrtb.com/api/sync/iframe/${params}` - }); - } - if (pixelEnabled) { - syncs.push({ - type: 'image', - url: `https://sync.kueezrtb.com/api/sync/image/${params}` - }); - } - return syncs; -} - -export function hashCode(s, prefix = '_') { - const l = s.length; - let h = 0 - let i = 0; - if (l > 0) { - while (i < l) { - h = (h << 5) - h + s.charCodeAt(i++) | 0; - } - } - return prefix + h; -} - -export function getUniqueDealId(key, expiry = UNIQUE_DEAL_ID_EXPIRY) { - const storageKey = `u_${key}`; - const now = Date.now(); - const data = getStorageItem(storageKey); - let uniqueId; - - if (!data || !data.value || now - data.created > expiry) { - uniqueId = `${key}_${now.toString()}`; - setStorageItem(storageKey, uniqueId); - } else { - uniqueId = data.value; - } - - return uniqueId; -} - -export function getStorageItem(key) { - try { - return tryParseJSON(storage.getDataFromLocalStorage(key)); - } catch (e) { - } - - return null; -} - -export function setStorageItem(key, value, timestamp) { - try { - const created = timestamp || Date.now(); - const data = JSON.stringify({value, created}); - storage.setDataInLocalStorage(key, data); - } catch (e) { - } -} - -export function tryParseJSON(value) { - try { - return JSON.parse(value); - } catch (e) { - return value; - } -} +const getUserSyncs = createUserSyncGetter({ + iframeSyncUrl: 'https://sync.kueezrtb.com/api/sync/iframe', + imageSyncUrl: 'https://sync.kueezrtb.com/api/sync/image' +}); export const spec = { code: BIDDER_CODE, diff --git a/modules/luponmediaBidAdapter.js b/modules/luponmediaBidAdapter.js index 2c08ca3a435..447257f97da 100755 --- a/modules/luponmediaBidAdapter.js +++ b/modules/luponmediaBidAdapter.js @@ -9,7 +9,9 @@ import { logError, logMessage, logWarn, - parseSizesInput + parseSizesInput, + sizeTupleToRtbSize, + sizesToSizeTuples } from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {config} from '../src/config.js'; @@ -271,16 +273,8 @@ function newOrtbBidRequest(bidRequest, bidderRequest, currentImps) { let bannerSizes = []; if (bannerParams && bannerParams.sizes) { - const sizes = parseSizesInput(bannerParams.sizes); - // get banner sizes in form [{ w: , h: }, ...] - const format = sizes.map(size => { - const [ width, height ] = size.split('x'); - const w = parseInt(width, 10); - const h = parseInt(height, 10); - return { w, h }; - }); - + const format = sizesToSizeTuples(bannerParams.sizes).map(sizeTupleToRtbSize); bannerSizes = format; } diff --git a/modules/mediafuseBidAdapter.js b/modules/mediafuseBidAdapter.js index 32eea23c8a6..b70d2bf30a5 100644 --- a/modules/mediafuseBidAdapter.js +++ b/modules/mediafuseBidAdapter.js @@ -24,7 +24,7 @@ import {find, includes} from '../src/polyfill.js'; import {INSTREAM, OUTSTREAM} from '../src/video.js'; import {getStorageManager} from '../src/storageManager.js'; import {bidderSettings} from '../src/bidderSettings.js'; -import {hasPurpose1Consent} from '../src/utils/gpdr.js'; +import {hasPurpose1Consent} from '../src/utils/gdpr.js'; import {convertOrtbRequestToProprietaryNative} from '../src/native.js'; import {APPNEXUS_CATEGORY_MAPPING} from '../libraries/categoryTranslationMapping/index.js'; import { diff --git a/modules/mediagoBidAdapter.js b/modules/mediagoBidAdapter.js index 8f687d30ff3..5c6c62b95fe 100644 --- a/modules/mediagoBidAdapter.js +++ b/modules/mediagoBidAdapter.js @@ -5,6 +5,11 @@ import * as utils from '../src/utils.js'; import { getStorageManager } from '../src/storageManager.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { getPageTitle, getPageDescription, getPageKeywords, getConnectionDownLink, getReferrer } from '../libraries/fpdUtils/pageInfo.js'; +import { getDevice } from '../libraries/fpdUtils/deviceInfo.js'; +import { getBidFloor } from '../libraries/currencyUtils/floor.js'; +import { transformSizes, normalAdSize } from '../libraries/sizeUtils/tranformSize.js'; + // import { config } from '../src/config.js'; // import { isPubcidEnabled } from './pubCommonId.js'; @@ -34,64 +39,6 @@ export const COOKIE_KEY_MGUID = '__mguid_'; const COOKIE_KEY_PMGUID = '__pmguid_'; const COOKIE_RETENTION_TIME = 365 * 24 * 60 * 60 * 1000; // 1 year let reqTimes = 0; -/** - * get page title - * @returns {string} - */ - -export function getPageTitle(win = window) { - try { - const ogTitle = win.top.document.querySelector('meta[property="og:title"]') - return win.top.document.title || (ogTitle && ogTitle.content) || ''; - } catch (e) { - const ogTitle = document.querySelector('meta[property="og:title"]') - return document.title || (ogTitle && ogTitle.content) || ''; - } -} - -/** - * get page description - * - * @returns {string} - */ -export function getPageDescription(win = window) { - let element; - - try { - element = win.top.document.querySelector('meta[name="description"]') || - win.top.document.querySelector('meta[property="og:description"]') - } catch (e) { - element = document.querySelector('meta[name="description"]') || - document.querySelector('meta[property="og:description"]') - } - - return (element && element.content) || ''; -} - -/** - * get page keywords - * @returns {string} - */ -export function getPageKeywords(win = window) { - let element; - - try { - element = win.top.document.querySelector('meta[name="keywords"]'); - } catch (e) { - element = document.querySelector('meta[name="keywords"]'); - } - - return (element && element.content) || ''; -} - -/** - * get connection downlink - * @returns {number} - */ -export function getConnectionDownLink(win = window) { - const nav = win.navigator || {}; - return nav && nav.connection && nav.connection.downlink >= 0 ? nav.connection.downlink.toString() : undefined; -} /** * get pmg uid @@ -135,54 +82,6 @@ function getProperty(obj, ...keys) { return o; } -/** - * 是不是移动设备或者平板 - * @return {boolean} - */ -function isMobileAndTablet() { - let check = false; - (function (a) { - let reg1 = new RegExp( - [ - '(android|bbd+|meego)', - '.+mobile|avantgo|bada/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)', - '|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone', - '|p(ixi|re)/|plucker|pocket|psp|series(4|6)0|symbian|treo|up.(browser|link)|vodafone|wap', - '|windows ce|xda|xiino|android|ipad|playbook|silk' - ].join(''), - 'i' - ); - let reg2 = new RegExp( - [ - '1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s-)', - '|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|-m|r |s )', - '|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw-(n|u)|c55/|capi|ccwa|cdm-|cell', - '|chtm|cldc|cmd-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc-s|devi|dica|dmob|do(c|p)o|ds(12|-d)', - '|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(-|_)|g1 u|g560|gene', - '|gf-5|g-mo|go(.w|od)|gr(ad|un)|haie|hcit|hd-(m|p|t)|hei-|hi(pt|ta)|hp( i|ip)|hs-c', - '|ht(c(-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i-(20|go|ma)|i230|iac( |-|/)|ibro|idea|ig01|ikom', - '|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |/)|klon|kpt |kwc-|kyo(c|k)', - '|le(no|xi)|lg( g|/(k|l|u)|50|54|-[a-w])|libw|lynx|m1-w|m3ga|m50/|ma(te|ui|xo)|mc(01|21|ca)', - '|m-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]', - '|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)', - '|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|-([1-8]|c))|phil|pire|pl(ay|uc)|pn-2|po(ck|rt|se)|prox|psio', - '|pt-g|qa-a|qc(07|12|21|32|60|-[2-7]|i-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55/|sa(ge|ma|mm|ms', - '|ny|va)|sc(01|h-|oo|p-)|sdk/|se(c(-|0|1)|47|mc|nd|ri)|sgh-|shar|sie(-|m)|sk-0|sl(45|id)|sm(al', - '|ar|b3|it|t5)|so(ft|ny)|sp(01|h-|v-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl-|tdg-|tel(i|m)', - '|tim-|t-mo|to(pl|sh)|ts(70|m-|m3|m5)|tx-9|up(.b|g1|si)|utst|', - 'v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|-v)', - '|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas-', - '|your|zeto|zte-' - ].join(''), - 'i' - ); - if (reg1.test(a) || reg2.test(a.substr(0, 4))) { - check = true; - } - })(navigator.userAgent || navigator.vendor || window.opera); - return check; -} - /** * 获取底价 * @param {*} bid @@ -205,62 +104,9 @@ function isMobileAndTablet() { // } // return floor; // } -function getBidFloor(bid) { - if (!utils.isFn(bid.getFloor)) { - return utils.deepAccess(bid, 'params.bidfloor', 0); - } - - try { - const bidFloor = bid.getFloor({ - currency: 'USD', - mediaType: '*', - size: '*' - }); - return bidFloor.floor; - } catch (_) { - return 0; - } -} - -/** - * 将尺寸转为RTB识别的尺寸 - * - * @param {Array|Object} requestSizes 配置尺寸 - * @return {Object} - */ -function transformSizes(requestSizes) { - let sizes = []; - let sizeObj = {}; - - if (utils.isArray(requestSizes) && requestSizes.length === 2 && !utils.isArray(requestSizes[0])) { - sizeObj.width = parseInt(requestSizes[0], 10); - sizeObj.height = parseInt(requestSizes[1], 10); - sizes.push(sizeObj); - } else if (typeof requestSizes === 'object') { - for (let i = 0; i < requestSizes.length; i++) { - let size = requestSizes[i]; - sizeObj = {}; - sizeObj.width = parseInt(size[0], 10); - sizeObj.height = parseInt(size[1], 10); - sizes.push(sizeObj); - } - } - - return sizes; -} // 支持的广告尺寸 -const mediagoAdSize = [ - { w: 300, h: 250 }, - { w: 300, h: 600 }, - { w: 728, h: 90 }, - { w: 970, h: 250 }, - { w: 320, h: 50 }, - { w: 160, h: 600 }, - { w: 320, h: 180 }, - { w: 320, h: 100 }, - { w: 336, h: 280 } -]; +const mediagoAdSize = normalAdSize; /** * 获取广告位配置 @@ -340,21 +186,6 @@ function getItems(validBidRequests, bidderRequest) { return items; } -/** - * @param {BidRequest} bidRequest - * @param bidderRequest - * @returns {string} - */ -function getReferrer(bidRequest = {}, bidderRequest = {}) { - let pageUrl; - if (bidRequest.params && bidRequest.params.referrer) { - pageUrl = bidRequest.params.referrer; - } else { - pageUrl = utils.deepAccess(bidderRequest, 'refererInfo.page'); - } - return pageUrl; -} - /** * get current time to UTC string * @returns utc string @@ -386,7 +217,7 @@ function getParam(validBidRequests, bidderRequest) { const cat = utils.deepAccess(bidderRequest, 'ortb2.site.cat'); reqTimes += 1; - let isMobile = isMobileAndTablet() ? 1 : 0; + let isMobile = getDevice() ? 1 : 0; // input test status by Publisher. more frequently for test true req let isTest = validBidRequests[0].params.test || 0; let auctionId = getProperty(bidderRequest, 'auctionId'); diff --git a/modules/medianetBidAdapter.js b/modules/medianetBidAdapter.js index 73e25379144..c90292a74ac 100644 --- a/modules/medianetBidAdapter.js +++ b/modules/medianetBidAdapter.js @@ -1,6 +1,6 @@ import { - buildUrl, deepAccess, + formatQS, getWindowTop, isArray, isEmpty, @@ -8,7 +8,9 @@ import { isStr, logError, logInfo, - triggerPixel + safeJSONEncode, + deepClone, + deepSetValue } from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {config} from '../src/config.js'; @@ -18,6 +20,7 @@ import {Renderer} from '../src/Renderer.js'; import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; import {getGlobal} from '../src/prebidGlobal.js'; import {getGptSlotInfoForAdUnitCode} from '../libraries/gptUtils/gptUtils.js'; +import {ajax} from '../src/ajax.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest @@ -35,27 +38,20 @@ const SLOT_VISIBILITY = { ABOVE_THE_FOLD: 1, BELOW_THE_FOLD: 2 }; -const EVENTS = { +export const EVENTS = { TIMEOUT_EVENT_NAME: 'client_timeout', - BID_WON_EVENT_NAME: 'client_bid_won' + BID_WON_EVENT_NAME: 'client_bid_won', + SET_TARGETING: 'client_set_targeting', + BIDDER_ERROR: 'client_bidder_error' }; -const EVENT_PIXEL_URL = 'qsearch-a.akamaihd.net/log'; +export const EVENT_PIXEL_URL = 'https://navvy.media.net/log'; const OUTSTREAM = 'outstream'; -// TODO: this should be picked from bidderRequest -let refererInfo = getRefererInfo(); - -let mnData = {}; +let pageMeta; window.mnet = window.mnet || {}; window.mnet.queue = window.mnet.queue || []; -mnData.urlData = { - domain: refererInfo.domain, - page: refererInfo.page, - isTop: refererInfo.reachedTop -}; - const aliases = [ { code: TRUSTEDSTACK_CODE, gvlid: 1288 }, ]; @@ -85,20 +81,20 @@ function siteDetails(site, bidderRequest) { } function getPageMeta() { - if (mnData.pageMeta) { - return mnData.pageMeta; + if (pageMeta) { + return pageMeta; } let canonicalUrl = getUrlFromSelector('link[rel="canonical"]', 'href'); let ogUrl = getUrlFromSelector('meta[property="og:url"]', 'content'); let twitterUrl = getUrlFromSelector('meta[name="twitter:url"]', 'content'); - mnData.pageMeta = Object.assign({}, + pageMeta = Object.assign({}, canonicalUrl && { 'canonical_url': canonicalUrl }, ogUrl && { 'og_url': ogUrl }, twitterUrl && { 'twitter_url': twitterUrl } ); - return mnData.pageMeta; + return pageMeta; } function getUrlFromSelector(selector, attribute) { @@ -338,6 +334,15 @@ function getBidderURL(bidderCode, cid) { return url + '?cid=' + encodeURIComponent(cid); } +function ortb2Data(ortb2, bidRequests) { + const ortb2Object = deepClone(ortb2); + const eids = deepAccess(bidRequests, '0.userIdAsEids'); + if (eids) { + deepSetValue(ortb2Object, 'user.ext.eids', eids) + } + return ortb2Object; +} + function generatePayload(bidRequests, bidderRequests) { return { site: siteDetails(bidRequests[0].params.site, bidderRequests), @@ -345,7 +350,7 @@ function generatePayload(bidRequests, bidderRequests) { // TODO: fix auctionId leak: https://github.com/prebid/Prebid.js/issues/9781 id: bidRequests[0].auctionId, imp: bidRequests.map(request => slotParams(request, bidderRequests)), - ortb2: bidderRequests.ortb2, + ortb2: ortb2Data(bidderRequests.ortb2, bidRequests), tmax: bidderRequests.timeout } } @@ -363,38 +368,71 @@ function fetchCookieSyncUrls(response) { return []; } -function getLoggingData(event, data) { - data = (isArray(data) && data) || []; - - let params = {}; +function getEventData(event) { + const params = {}; + const referrerInfo = getRefererInfo(); params.logid = 'kfk'; params.evtid = 'projectevents'; params.project = 'prebid'; - params.acid = deepAccess(data, '0.auctionId') || ''; + params.pbver = '$prebid.version$'; params.cid = getGlobal().medianetGlobals.cid || ''; - params.crid = data.map((adunit) => deepAccess(adunit, 'params.0.crid') || adunit.adUnitCode).join('|'); - params.adunit_count = data.length || 0; - params.dn = mnData.urlData.domain || ''; - params.requrl = mnData.urlData.page || ''; - params.istop = mnData.urlData.isTop || ''; + params.dn = encodeURIComponent(referrerInfo.domain || ''); + params.requrl = encodeURIComponent(referrerInfo.page || ''); params.event = event.name || ''; params.value = event.value || ''; params.rd = event.related_data || ''; + return params; +} +function getBidData(bid) { + const params = {}; + params.acid = bid.auctionId || ''; + params.crid = deepAccess(bid, 'params.crid') || deepAccess(bid, 'params.0.crid') || bid.adUnitCode || ''; + params.ext = safeJSONEncode(bid.ext) || ''; + + const rawobj = deepClone(bid); + delete rawobj.ad; + delete rawobj.vastXml; + params.rawobj = safeJSONEncode(rawobj); return params; } -function logEvent (event, data) { - let getParams = { - protocol: 'https', - hostname: EVENT_PIXEL_URL, - search: getLoggingData(event, data) - }; - triggerPixel(buildUrl(getParams)); +function getLoggingData(event, bids) { + const logData = {}; + if (!isArray(bids)) { + bids = []; + } + bids.forEach((bid) => { + let bidData = getBidData(bid); + Object.keys(bidData).forEach((key) => { + logData[key] = logData[key] || []; + logData[key].push(encodeURIComponent(bidData[key])); + }); + }); + return Object.assign({}, getEventData(event), logData) +} + +function fireAjaxLog(url, payload) { + ajax(url, + { + success: () => undefined, + error: () => undefined + }, + payload, + { + method: 'POST', + keepalive: true + } + ); } -function clearMnData() { - mnData = {}; +function logEvent(event, data) { + const logData = getLoggingData(event, data); + fireAjaxLog(EVENT_PIXEL_URL, formatQS(logData)); +} + +function clearPageMeta() { + pageMeta = undefined; } function addRenderer(bid) { @@ -550,7 +588,30 @@ export const spec = { } catch (e) {} }, - clearMnData, + onSetTargeting: (bid) => { + try { + let eventData = { + name: EVENTS.SET_TARGETING, + value: bid.cpm + }; + const enableSendAllBids = config.getConfig('enableSendAllBids'); + if (!enableSendAllBids) { + logEvent(eventData, [bid]); + } + } catch (e) {} + }, + + onBidderError: ({error, bidderRequest}) => { + try { + let eventData = { + name: EVENTS.BIDDER_ERROR, + related_data: `timedOut:${error.timedOut}|status:${error.status}|message:${error.reason.message}` + }; + logEvent(eventData, bidderRequest.bids); + } catch (e) {} + }, + + clearPageMeta, getWindowSize, }; diff --git a/modules/mgidBidAdapter.js b/modules/mgidBidAdapter.js index fb3990e97f1..5cfef325d2f 100644 --- a/modules/mgidBidAdapter.js +++ b/modules/mgidBidAdapter.js @@ -12,7 +12,7 @@ import { isFn, isNumber, isBoolean, - isInteger, deepSetValue, getBidIdParameter, + isInteger, deepSetValue, getBidIdParameter, setOnAny } from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, NATIVE} from '../src/mediaTypes.js'; @@ -86,7 +86,7 @@ _each(NATIVE_ASSETS, anAsset => { _NATIVE_ASSET_ID_TO_KEY_MAP[anAsset.ID] = anAs _each(NATIVE_ASSETS, anAsset => { _NATIVE_ASSET_KEY_TO_ASSET_MAP[anAsset.KEY] = anAsset }); export const spec = { - VERSION: '1.6', + VERSION: '1.7', code: BIDDER_CODE, gvlid: GVLID, supportedMediaTypes: [BANNER, NATIVE], @@ -167,6 +167,8 @@ export const spec = { tagid, secure, }; + const gpid = deepAccess(bid, 'ortb2Imp.ext.gpid'); + gpid && isStr(gpid) && deepSetValue(impObj, `ext.gpid`, gpid); const floorData = getBidFloor(bid, cur); if (floorData.floor) { impObj.bidfloor = floorData.floor; @@ -431,15 +433,6 @@ export const spec = { registerBidder(spec); -function setOnAny(collection, key) { - for (let i = 0, result; i < collection.length; i++) { - result = deepAccess(collection[i], key); - if (result) { - return result; - } - } -} - /** * Unpack the Server's Bid into a Prebid-compatible one. * @param serverBid diff --git a/modules/minutemediaBidAdapter.js b/modules/minutemediaBidAdapter.js index a724a0446a4..4e83c5c6db4 100644 --- a/modules/minutemediaBidAdapter.js +++ b/modules/minutemediaBidAdapter.js @@ -2,33 +2,28 @@ import { logWarn, logInfo, isArray, - isFn, deepAccess, - isEmpty, - contains, - timestamp, triggerPixel, - isInteger, - getBidIdParameter } from '../src/utils.js'; -import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {BANNER, VIDEO} from '../src/mediaTypes.js'; -import {config} from '../src/config.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import { + getEndpoint, + generateBidsParams, + generateGeneralParams, + buildBidResponse, +} from '../libraries/riseUtils/index.js'; const SUPPORTED_AD_TYPES = [BANNER, VIDEO]; const BIDDER_CODE = 'minutemedia'; const ADAPTER_VERSION = '6.0.0'; const TTL = 360; const DEFAULT_CURRENCY = 'USD'; -const SELLER_ENDPOINT = 'https://hb.minutemedia-prebid.com/'; +const BASE_URL = 'https://hb.minutemedia-prebid.com/'; const MODES = { PRODUCTION: 'hb-mm-multi', TEST: 'hb-multi-mm-test' -} -const SUPPORTED_SYNC_METHODS = { - IFRAME: 'iframe', - PIXEL: 'pixel' -} +}; export const spec = { code: BIDDER_CODE, @@ -51,50 +46,24 @@ export const spec = { buildRequests: function (validBidRequests, bidderRequest) { const combinedRequestsObject = {}; - // use data from the first bid, to create the general params for all bids const generalObject = validBidRequests[0]; const testMode = generalObject.params.testMode; - combinedRequestsObject.params = generateGeneralParams(generalObject, bidderRequest); + combinedRequestsObject.params = generateGeneralParams(generalObject, bidderRequest, ADAPTER_VERSION); combinedRequestsObject.bids = generateBidsParams(validBidRequests, bidderRequest); return { method: 'POST', - url: getEndpoint(testMode), + url: getEndpoint(testMode, BASE_URL, MODES), data: combinedRequestsObject - } + }; }, - interpretResponse: function ({body}) { + interpretResponse: function ({ body }) { const bidResponses = []; if (body.bids) { body.bids.forEach(adUnit => { - const bidResponse = { - requestId: adUnit.requestId, - cpm: adUnit.cpm, - currency: adUnit.currency || DEFAULT_CURRENCY, - width: adUnit.width, - height: adUnit.height, - ttl: adUnit.ttl || TTL, - creativeId: adUnit.creativeId, - netRevenue: adUnit.netRevenue || true, - nurl: adUnit.nurl, - mediaType: adUnit.mediaType, - meta: { - mediaType: adUnit.mediaType - } - }; - - if (adUnit.mediaType === VIDEO) { - bidResponse.vastXml = adUnit.vastXml; - } else if (adUnit.mediaType === BANNER) { - bidResponse.ad = adUnit.ad; - } - - if (adUnit.adomain && adUnit.adomain.length) { - bidResponse.meta.advertiserDomains = adUnit.adomain; - } - + const bidResponse = buildBidResponse(adUnit, DEFAULT_CURRENCY, TTL, VIDEO, BANNER); bidResponses.push(bidResponse); }); } @@ -104,20 +73,20 @@ export const spec = { getUserSyncs: function (syncOptions, serverResponses) { const syncs = []; for (const response of serverResponses) { - if (syncOptions.iframeEnabled && response.body.params.userSyncURL) { + if (syncOptions.iframeEnabled && deepAccess(response, 'body.params.userSyncURL')) { syncs.push({ type: 'iframe', - url: response.body.params.userSyncURL + url: deepAccess(response, 'body.params.userSyncURL') }); } - if (syncOptions.pixelEnabled && isArray(response.body.params.userSyncPixels)) { + if (syncOptions.pixelEnabled && isArray(deepAccess(response, 'body.params.userSyncPixels'))) { const pixels = response.body.params.userSyncPixels.map(pixel => { return { type: 'image', url: pixel - } - }) - syncs.push(...pixels) + }; + }); + syncs.push(...pixels); } } return syncs; @@ -135,349 +104,3 @@ export const spec = { }; registerBidder(spec); - -/** - * Get floor price - * @param bid {bid} - * @returns {Number} - */ -function getFloor(bid, mediaType) { - if (!isFn(bid.getFloor)) { - return 0; - } - let floorResult = bid.getFloor({ - currency: DEFAULT_CURRENCY, - mediaType: mediaType, - size: '*' - }); - return floorResult.currency === DEFAULT_CURRENCY && floorResult.floor ? floorResult.floor : 0; -} - -/** - * Get the the ad sizes array from the bid - * @param bid {bid} - * @returns {Array} - */ -function getSizesArray(bid, mediaType) { - let sizesArray = [] - - if (deepAccess(bid, `mediaTypes.${mediaType}.sizes`)) { - sizesArray = bid.mediaTypes[mediaType].sizes; - } else if (Array.isArray(bid.sizes) && bid.sizes.length > 0) { - sizesArray = bid.sizes; - } - - return sizesArray; -} - -/** - * Get schain string value - * @param schainObject {Object} - * @returns {string} - */ -function getSupplyChain(schainObject) { - if (isEmpty(schainObject)) { - return ''; - } - let scStr = `${schainObject.ver},${schainObject.complete}`; - schainObject.nodes.forEach((node) => { - scStr += '!'; - scStr += `${getEncodedValIfNotEmpty(node.asi)},`; - scStr += `${getEncodedValIfNotEmpty(node.sid)},`; - scStr += `${node.hp ? encodeURIComponent(node.hp) : ''},`; - scStr += `${getEncodedValIfNotEmpty(node.rid)},`; - scStr += `${getEncodedValIfNotEmpty(node.name)},`; - scStr += `${getEncodedValIfNotEmpty(node.domain)}`; - }); - return scStr; -} - -/** - * Get encoded node value - * @param val {string} - * @returns {string} - */ -function getEncodedValIfNotEmpty(val) { - return !isEmpty(val) ? encodeURIComponent(val) : ''; -} - -/** - * Get preferred user-sync method based on publisher configuration - * @param bidderCode {string} - * @returns {string} - */ -function getAllowedSyncMethod(filterSettings, bidderCode) { - const iframeConfigsToCheck = ['all', 'iframe']; - const pixelConfigToCheck = 'image'; - if (filterSettings && iframeConfigsToCheck.some(config => isSyncMethodAllowed(filterSettings[config], bidderCode))) { - return SUPPORTED_SYNC_METHODS.IFRAME; - } - if (!filterSettings || !filterSettings[pixelConfigToCheck] || isSyncMethodAllowed(filterSettings[pixelConfigToCheck], bidderCode)) { - return SUPPORTED_SYNC_METHODS.PIXEL; - } -} - -/** - * Check if sync rule is supported - * @param syncRule {Object} - * @param bidderCode {string} - * @returns {boolean} - */ -function isSyncMethodAllowed(syncRule, bidderCode) { - if (!syncRule) { - return false; - } - const isInclude = syncRule.filter === 'include'; - const bidders = isArray(syncRule.bidders) ? syncRule.bidders : [bidderCode]; - return isInclude && contains(bidders, bidderCode); -} - -/** - * Get the seller endpoint - * @param testMode {boolean} - * @returns {string} - */ -function getEndpoint(testMode) { - return testMode - ? SELLER_ENDPOINT + MODES.TEST - : SELLER_ENDPOINT + MODES.PRODUCTION; -} - -/** - * get device type - * @param uad {ua} - * @returns {string} - */ -function getDeviceType(ua) { - if (/ipad|android 3.0|xoom|sch-i800|playbook|tablet|kindle/i - .test(ua.toLowerCase())) { - return '5'; - } - if (/iphone|ipod|android|blackberry|opera|mini|windows\sce|palm|smartphone|iemobile/i - .test(ua.toLowerCase())) { - return '4'; - } - if (/smart[-_\s]?tv|hbbtv|appletv|googletv|hdmi|netcast|viera|nettv|roku|\bdtv\b|sonydtv|inettvbrowser|\btv\b/i - .test(ua.toLowerCase())) { - return '3'; - } - return '1'; -} - -function generateBidsParams(validBidRequests, bidderRequest) { - const bidsArray = []; - - if (validBidRequests.length) { - validBidRequests.forEach(bid => { - bidsArray.push(generateBidParameters(bid, bidderRequest)); - }); - } - - return bidsArray; -} - -/** - * Generate bid specific parameters - * @param {bid} bid - * @param {bidderRequest} bidderRequest - * @returns {Object} bid specific params object - */ -function generateBidParameters(bid, bidderRequest) { - const {params} = bid; - const mediaType = isBanner(bid) ? BANNER : VIDEO; - const sizesArray = getSizesArray(bid, mediaType); - - // fix floor price in case of NAN - if (isNaN(params.floorPrice)) { - params.floorPrice = 0; - } - - const bidObject = { - mediaType, - adUnitCode: getBidIdParameter('adUnitCode', bid), - sizes: sizesArray, - floorPrice: Math.max(getFloor(bid, mediaType), params.floorPrice), - bidId: getBidIdParameter('bidId', bid), - loop: getBidIdParameter('bidderRequestsCount', bid), - bidderRequestId: getBidIdParameter('bidderRequestId', bid), - transactionId: bid.ortb2Imp?.ext?.tid || '', - coppa: 0, - }; - - const pos = deepAccess(bid, `mediaTypes.${mediaType}.pos`); - if (pos) { - bidObject.pos = pos; - } - - const gpid = deepAccess(bid, `ortb2Imp.ext.gpid`); - if (gpid) { - bidObject.gpid = gpid; - } - - const placementId = params.placementId || deepAccess(bid, `mediaTypes.${mediaType}.name`); - if (placementId) { - bidObject.placementId = placementId; - } - - const mimes = deepAccess(bid, `mediaTypes.${mediaType}.mimes`); - if (mimes) { - bidObject.mimes = mimes; - } - const api = deepAccess(bid, `mediaTypes.${mediaType}.api`); - if (api) { - bidObject.api = api; - } - - const sua = deepAccess(bid, `ortb2.device.sua`); - if (sua) { - bidObject.sua = sua; - } - - const coppa = deepAccess(bid, `ortb2.regs.coppa`) - if (coppa) { - bidObject.coppa = 1; - } - - if (mediaType === VIDEO) { - const playbackMethod = deepAccess(bid, `mediaTypes.video.playbackmethod`); - let playbackMethodValue; - - // verify playbackMethod is of type integer array, or integer only. - if (Array.isArray(playbackMethod) && isInteger(playbackMethod[0])) { - // only the first playbackMethod in the array will be used, according to OpenRTB 2.5 recommendation - playbackMethodValue = playbackMethod[0]; - } else if (isInteger(playbackMethod)) { - playbackMethodValue = playbackMethod; - } - - if (playbackMethodValue) { - bidObject.playbackMethod = playbackMethodValue; - } - - const placement = deepAccess(bid, `mediaTypes.video.placement`); - if (placement) { - bidObject.placement = placement; - } - - const minDuration = deepAccess(bid, `mediaTypes.video.minduration`); - if (minDuration) { - bidObject.minDuration = minDuration; - } - - const maxDuration = deepAccess(bid, `mediaTypes.video.maxduration`); - if (maxDuration) { - bidObject.maxDuration = maxDuration; - } - - const skip = deepAccess(bid, `mediaTypes.video.skip`); - if (skip) { - bidObject.skip = skip; - } - - const linearity = deepAccess(bid, `mediaTypes.video.linearity`); - if (linearity) { - bidObject.linearity = linearity; - } - - const protocols = deepAccess(bid, `mediaTypes.video.protocols`); - if (protocols) { - bidObject.protocols = protocols; - } - - const plcmt = deepAccess(bid, `mediaTypes.video.plcmt`); - if (plcmt) { - bidObject.plcmt = plcmt; - } - } - - return bidObject; -} - -function isBanner(bid) { - return bid.mediaTypes && bid.mediaTypes.banner; -} - -/** - * Generate params that are common between all bids - * @param {single bid object} generalObject - * @param {bidderRequest} bidderRequest - * @returns {object} the common params object - */ -function generateGeneralParams(generalObject, bidderRequest) { - const domain = window.location.hostname; - const {syncEnabled, filterSettings} = config.getConfig('userSync') || {}; - const {bidderCode} = bidderRequest; - const generalBidParams = generalObject.params; - const timeout = bidderRequest.timeout; - - // these params are snake_case instead of camelCase to allow backwards compatability on the server. - // in the future, these will be converted to camelCase to match our convention. - const generalParams = { - wrapper_type: 'prebidjs', - wrapper_vendor: '$$PREBID_GLOBAL$$', - wrapper_version: '$prebid.version$', - adapter_version: ADAPTER_VERSION, - auction_start: timestamp(), - publisher_id: generalBidParams.org, - publisher_name: domain, - site_domain: domain, - dnt: (navigator.doNotTrack == 'yes' || navigator.doNotTrack == '1' || navigator.msDoNotTrack == '1') ? 1 : 0, - device_type: getDeviceType(navigator.userAgent), - ua: navigator.userAgent, - is_wrapper: !!generalBidParams.isWrapper, - session_id: generalBidParams.sessionId || getBidIdParameter('bidderRequestId', generalObject), - tmax: timeout - } - - const userIdsParam = getBidIdParameter('userId', generalObject); - if (userIdsParam) { - generalParams.userIds = JSON.stringify(userIdsParam); - } - - const ortb2Metadata = bidderRequest.ortb2 || {}; - if (ortb2Metadata.site) { - generalParams.site_metadata = JSON.stringify(ortb2Metadata.site); - } - if (ortb2Metadata.user) { - generalParams.user_metadata = JSON.stringify(ortb2Metadata.user); - } - - if (syncEnabled) { - const allowedSyncMethod = getAllowedSyncMethod(filterSettings, bidderCode); - if (allowedSyncMethod) { - generalParams.cs_method = allowedSyncMethod; - } - } - - if (bidderRequest.uspConsent) { - generalParams.us_privacy = bidderRequest.uspConsent; - } - - if (bidderRequest && bidderRequest.gdprConsent && bidderRequest.gdprConsent.gdprApplies) { - generalParams.gdpr = bidderRequest.gdprConsent.gdprApplies; - generalParams.gdpr_consent = bidderRequest.gdprConsent.consentString; - } - - if (bidderRequest.gppConsent) { - generalParams.gpp = bidderRequest.gppConsent.gppString; - generalParams.gpp_sid = bidderRequest.gppConsent.applicableSections; - } else if (bidderRequest.ortb2?.regs?.gpp) { - generalParams.gpp = bidderRequest.ortb2.regs.gpp; - generalParams.gpp_sid = bidderRequest.ortb2.regs.gpp_sid; - } - - if (generalBidParams.ifa) { - generalParams.ifa = generalBidParams.ifa; - } - - if (generalObject.schain) { - generalParams.schain = getSupplyChain(generalObject.schain); - } - - if (bidderRequest && bidderRequest.refererInfo) { - generalParams.referrer = deepAccess(bidderRequest, 'refererInfo.ref'); - generalParams.page_url = deepAccess(bidderRequest, 'refererInfo.page') || deepAccess(window, 'location.href'); - } - - return generalParams -} diff --git a/modules/mobianRtdProvider.js b/modules/mobianRtdProvider.js index 09a338c9bb0..76626a7c020 100644 --- a/modules/mobianRtdProvider.js +++ b/modules/mobianRtdProvider.js @@ -1,10 +1,20 @@ +/** + * This module adds the Mobian RTD provider to the real time data module + * The {@link module:modules/realTimeData} module is required + */ import { submodule } from '../src/hook.js'; import { ajaxBuilder } from '../src/ajax.js'; +import { deepSetValue, safeJSONParse } from '../src/utils.js'; + +/** + * @typedef {import('../modules/rtdModule/index.js').RtdSubmodule} RtdSubmodule + */ + export const MOBIAN_URL = 'https://impact-api-prod.themobian.com/brand_safety'; +/** @type {RtdSubmodule} */ export const mobianBrandSafetySubmodule = { name: 'mobianBrandSafety', - gvlid: null, init: init, getBidRequestData: getBidRequestData }; @@ -12,6 +22,7 @@ export const mobianBrandSafetySubmodule = { function init() { return true; } + function getBidRequestData(bidReqConfig, callback, config) { const { site: ortb2Site } = bidReqConfig.ortb2Fragments.global; const pageUrl = encodeURIComponent(getPageUrl()); @@ -21,25 +32,54 @@ function getBidRequestData(bidReqConfig, callback, config) { return new Promise((resolve) => { ajax(requestUrl, { - success: function(response) { - const risks = ['garm_high_risk', 'garm_medium_risk', 'garm_low_risk', 'garm_no_risk']; - const riskLevels = ['high_risk', 'medium_risk', 'low_risk', 'no_risk']; - - let mobianGarmRisk = 'unknown'; - for (let i = 0; i < risks.length; i++) { - if (response[risks[i]]) { - mobianGarmRisk = riskLevels[i]; - break; + success: function(responseData) { + let response = safeJSONParse(responseData); + if (!response) { + resolve({}); + callback(); + return; + } + + let mobianGarmRisk = response.garm_risk || 'unknown'; + + if (mobianGarmRisk === 'unknown') { + const risks = ['garm_high_risk', 'garm_medium_risk', 'garm_low_risk', 'garm_no_risk']; + const riskLevels = ['high', 'medium', 'low', 'none']; + + for (let i = 0; i < risks.length; i++) { + if (response[risks[i]]) { + mobianGarmRisk = riskLevels[i]; + break; + } } } + + const garmCategories = Object.keys(response) + .filter(key => key.startsWith('garm_content_category_') && response[key]) + .map(key => key.replace('garm_content_category_', '')); + + const sentiment = Object.keys(response) + .find(key => key.startsWith('sentiment_') && response[key]) + ?.replace('sentiment_', '') || 'unknown'; + + const emotions = Object.keys(response) + .filter(key => key.startsWith('emotion_') && response[key]) + .map(key => key.replace('emotion_', '')); + const risk = { - 'mobianGarmRisk': mobianGarmRisk + 'mobianGarmRisk': mobianGarmRisk, + 'garmContentCategories': garmCategories, + 'sentiment': sentiment, + 'emotions': emotions }; + resolve(risk); - ortb2Site.ext.data['mobian'] = risk + deepSetValue(ortb2Site.ext, 'data.mobian', risk); + callback() }, error: function () { resolve({}); + callback() } }); }); diff --git a/modules/nextMillenniumBidAdapter.js b/modules/nextMillenniumBidAdapter.js index 65f530d9e58..5e9be67c6bb 100644 --- a/modules/nextMillenniumBidAdapter.js +++ b/modules/nextMillenniumBidAdapter.js @@ -1,6 +1,5 @@ import { _each, - createTrackPixelHtml, deepAccess, deepSetValue, getBidIdParameter, @@ -12,6 +11,7 @@ import { parseUrl, triggerPixel, } from '../src/utils.js'; +import {getAd} from '../libraries/targetVideoUtils/bidderUtils.js'; import {getGlobal} from '../src/prebidGlobal.js'; import { EVENTS } from '../src/constants.js'; @@ -455,32 +455,6 @@ function getTopWindow(curWindow, nesting = 0) { }; } -function getAd(bid) { - let ad, adUrl, vastXml, vastUrl; - - switch (deepAccess(bid, 'ext.prebid.type')) { - case VIDEO: - if (bid.adm.substr(0, 4) === 'http') { - vastUrl = bid.adm; - } else { - vastXml = bid.adm; - }; - - break; - default: - if (bid.adm && bid.nurl) { - ad = bid.adm; - ad += createTrackPixelHtml(decodeURIComponent(bid.nurl)); - } else if (bid.adm) { - ad = bid.adm; - } else if (bid.nurl) { - adUrl = bid.nurl; - }; - }; - - return {ad, adUrl, vastXml, vastUrl}; -} - function getSiteObj() { const refInfo = (getRefererInfo && getRefererInfo()) || {}; diff --git a/modules/nexx360BidAdapter.js b/modules/nexx360BidAdapter.js index b4f7cf50ffe..69032fb151b 100644 --- a/modules/nexx360BidAdapter.js +++ b/modules/nexx360BidAdapter.js @@ -22,7 +22,7 @@ const OUTSTREAM_RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstre const BIDDER_CODE = 'nexx360'; const REQUEST_URL = 'https://fast.nexx360.io/booster'; const PAGE_VIEW_ID = generateUUID(); -const BIDDER_VERSION = '4.1'; +const BIDDER_VERSION = '4.2'; const GVLID = 965; const NEXXID_KEY = 'nexx360_storage'; @@ -33,6 +33,7 @@ const ALIASES = [ { code: 'league-m', gvlid: 965 }, { code: 'prjads' }, { code: 'pubtech' }, + { code: '1accord', gvlid: 965 }, ]; export const storage = getStorageManager({ @@ -125,7 +126,7 @@ const converter = ortbConverter({ deepSetValue(request, 'ext.localStorage.nexx360Id', nexx360LocalStorage.nexx360Id); } const amxId = getAmxId(); - if (amxId) deepSetValue(request, 'ext.localStorage.amxId', amxId()); + if (amxId) deepSetValue(request, 'ext.localStorage.amxId', amxId); deepSetValue(request, 'ext.version', '$prebid.version$'); deepSetValue(request, 'ext.source', 'prebid.js'); deepSetValue(request, 'ext.pageViewId', PAGE_VIEW_ID); diff --git a/modules/nobidBidAdapter.js b/modules/nobidBidAdapter.js index 77e5a1c6fed..4865ea3bc9c 100644 --- a/modules/nobidBidAdapter.js +++ b/modules/nobidBidAdapter.js @@ -3,7 +3,7 @@ import { config } from '../src/config.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; import { getStorageManager } from '../src/storageManager.js'; -import { hasPurpose1Consent } from '../src/utils/gpdr.js'; +import { hasPurpose1Consent } from '../src/utils/gdpr.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest diff --git a/modules/openwebBidAdapter.js b/modules/openwebBidAdapter.js index f083647c480..60364f41d3c 100644 --- a/modules/openwebBidAdapter.js +++ b/modules/openwebBidAdapter.js @@ -2,33 +2,28 @@ import { logWarn, logInfo, isArray, - isFn, deepAccess, - isEmpty, - contains, - triggerPixel, - isInteger, - getBidIdParameter, - getDNT + triggerPixel } from '../src/utils.js'; -import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {BANNER, VIDEO} from '../src/mediaTypes.js'; -import {config} from '../src/config.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import { + getEndpoint, + generateBidsParams, + generateGeneralParams, + buildBidResponse, +} from '../libraries/riseUtils/index.js'; const SUPPORTED_AD_TYPES = [BANNER, VIDEO]; const BIDDER_CODE = 'openweb'; const ADAPTER_VERSION = '6.0.0'; const TTL = 360; const DEFAULT_CURRENCY = 'USD'; -const SELLER_ENDPOINT = 'https://hb.openwebmp.com/'; +const BASE_URL = 'https://hb.openwebmp.com/'; const MODES = { PRODUCTION: 'hb-multi', TEST: 'hb-multi-test' -} -const SUPPORTED_SYNC_METHODS = { - IFRAME: 'iframe', - PIXEL: 'pixel' -} +}; export const spec = { code: BIDDER_CODE, @@ -65,7 +60,7 @@ export const spec = { return { method: 'POST', - url: getEndpoint(testMode), + url: getEndpoint(testMode, BASE_URL, MODES), data: combinedRequestsObject } }, @@ -74,32 +69,7 @@ export const spec = { if (body && body.bids && body.bids.length) { body.bids.forEach(adUnit => { - const bidResponse = { - requestId: adUnit.requestId, - cpm: adUnit.cpm, - currency: adUnit.currency || DEFAULT_CURRENCY, - width: adUnit.width, - height: adUnit.height, - ttl: adUnit.ttl || TTL, - creativeId: adUnit.creativeId, - netRevenue: adUnit.netRevenue || true, - nurl: adUnit.nurl, - mediaType: adUnit.mediaType, - meta: { - mediaType: adUnit.mediaType - } - }; - - if (adUnit.mediaType === VIDEO) { - bidResponse.vastXml = adUnit.vastXml; - } else if (adUnit.mediaType === BANNER) { - bidResponse.ad = adUnit.ad; - } - - if (adUnit.adomain && adUnit.adomain.length) { - bidResponse.meta.advertiserDomains = adUnit.adomain; - } - + const bidResponse = buildBidResponse(adUnit, DEFAULT_CURRENCY, TTL, VIDEO, BANNER); bidResponses.push(bidResponse); }); } @@ -109,20 +79,20 @@ export const spec = { getUserSyncs: function (syncOptions, serverResponses) { const syncs = []; for (const response of serverResponses) { - if (syncOptions.iframeEnabled && response.body.params.userSyncURL) { + if (syncOptions.iframeEnabled && deepAccess(response, 'body.params.userSyncURL')) { syncs.push({ type: 'iframe', - url: response.body.params.userSyncURL + url: deepAccess(response, 'body.params.userSyncURL') }); } - if (syncOptions.pixelEnabled && isArray(response.body.params.userSyncPixels)) { + if (syncOptions.pixelEnabled && isArray(deepAccess(response, 'body.params.userSyncPixels'))) { const pixels = response.body.params.userSyncPixels.map(pixel => { return { type: 'image', url: pixel } - }) - syncs.push(...pixels) + }); + syncs.push(...pixels); } } return syncs; @@ -140,351 +110,3 @@ export const spec = { }; registerBidder(spec); - -/** - * Get floor price - * @param bid {bid} - * @returns {Number} - */ -function getFloor(bid, mediaType) { - if (!isFn(bid.getFloor)) { - return 0; - } - let floorResult = bid.getFloor({ - currency: DEFAULT_CURRENCY, - mediaType: mediaType, - size: '*' - }); - return floorResult.currency === DEFAULT_CURRENCY && floorResult.floor ? floorResult.floor : 0; -} - -/** - * Get the the ad sizes array from the bid - * @param bid {bid} - * @returns {Array} - */ -function getSizesArray(bid, mediaType) { - let sizesArray = [] - - if (deepAccess(bid, `mediaTypes.${mediaType}.sizes`)) { - sizesArray = bid.mediaTypes[mediaType].sizes; - } else if (Array.isArray(bid.sizes) && bid.sizes.length > 0) { - sizesArray = bid.sizes; - } - - return sizesArray; -} - -/** - * Get schain string value - * @param schainObject {Object} - * @returns {string} - */ -function getSupplyChain(schainObject) { - if (isEmpty(schainObject)) { - return ''; - } - let scStr = `${schainObject.ver},${schainObject.complete}`; - schainObject.nodes.forEach((node) => { - scStr += '!'; - scStr += `${getEncodedValIfNotEmpty(node.asi)},`; - scStr += `${getEncodedValIfNotEmpty(node.sid)},`; - scStr += `${node.hp ? encodeURIComponent(node.hp) : ''},`; - scStr += `${getEncodedValIfNotEmpty(node.rid)},`; - scStr += `${getEncodedValIfNotEmpty(node.name)},`; - scStr += `${getEncodedValIfNotEmpty(node.domain)}`; - }); - return scStr; -} - -/** - * Get encoded node value - * @param val {string} - * @returns {string} - */ -function getEncodedValIfNotEmpty(val) { - return !isEmpty(val) ? encodeURIComponent(val) : ''; -} - -/** - * Get preferred user-sync method based on publisher configuration - * @param bidderCode {string} - * @returns {string} - */ -function getAllowedSyncMethod(filterSettings, bidderCode) { - const iframeConfigsToCheck = ['all', 'iframe']; - const pixelConfigToCheck = 'image'; - if (filterSettings && iframeConfigsToCheck.some(config => isSyncMethodAllowed(filterSettings[config], bidderCode))) { - return SUPPORTED_SYNC_METHODS.IFRAME; - } - if (!filterSettings || !filterSettings[pixelConfigToCheck] || isSyncMethodAllowed(filterSettings[pixelConfigToCheck], bidderCode)) { - return SUPPORTED_SYNC_METHODS.PIXEL; - } -} - -/** - * Check if sync rule is supported - * @param syncRule {Object} - * @param bidderCode {string} - * @returns {boolean} - */ -function isSyncMethodAllowed(syncRule, bidderCode) { - if (!syncRule) { - return false; - } - const isInclude = syncRule.filter === 'include'; - const bidders = isArray(syncRule.bidders) ? syncRule.bidders : [bidderCode]; - return isInclude && contains(bidders, bidderCode); -} - -/** - * Get the seller endpoint - * @param testMode {boolean} - * @returns {string} - */ -function getEndpoint(testMode) { - return testMode - ? SELLER_ENDPOINT + MODES.TEST - : SELLER_ENDPOINT + MODES.PRODUCTION; -} - -/** - * get device type - * @param uad {ua} - * @returns {string} - */ -function getDeviceType(ua) { - if (/ipad|android 3.0|xoom|sch-i800|playbook|tablet|kindle/i - .test(ua.toLowerCase())) { - return '5'; - } - if (/iphone|ipod|android|blackberry|opera|mini|windows\sce|palm|smartphone|iemobile/i - .test(ua.toLowerCase())) { - return '4'; - } - if (/smart[-_\s]?tv|hbbtv|appletv|googletv|hdmi|netcast|viera|nettv|roku|\bdtv\b|sonydtv|inettvbrowser|\btv\b/i - .test(ua.toLowerCase())) { - return '3'; - } - return '1'; -} - -function generateBidsParams(validBidRequests, bidderRequest) { - const bidsArray = []; - - if (validBidRequests.length) { - validBidRequests.forEach(bid => { - bidsArray.push(generateBidParameters(bid, bidderRequest)); - }); - } - - return bidsArray; -} - -/** - * Generate bid specific parameters - * @param {bid} bid - * @param {bidderRequest} bidderRequest - * @returns {Object} bid specific params object - */ -function generateBidParameters(bid, bidderRequest) { - const {params} = bid; - const mediaType = isBanner(bid) ? BANNER : VIDEO; - const sizesArray = getSizesArray(bid, mediaType); - - // fix floor price in case of NAN - if (isNaN(params.floorPrice)) { - params.floorPrice = 0; - } - - const bidObject = { - mediaType, - adUnitCode: getBidIdParameter('adUnitCode', bid), - sizes: sizesArray, - floorPrice: Math.max(getFloor(bid, mediaType), params.floorPrice), - bidId: getBidIdParameter('bidId', bid), - loop: getBidIdParameter('bidderRequestsCount', bid), - bidderRequestId: getBidIdParameter('bidderRequestId', bid), - transactionId: bid.ortb2Imp?.ext?.tid || '', - coppa: 0, - }; - - const pos = deepAccess(bid, `mediaTypes.${mediaType}.pos`); - if (pos) { - bidObject.pos = pos; - } - - const gpid = deepAccess(bid, `ortb2Imp.ext.gpid`); - if (gpid) { - bidObject.gpid = gpid; - } - - const placementId = params.placementId || deepAccess(bid, `mediaTypes.${mediaType}.name`); - if (placementId) { - bidObject.placementId = placementId; - } - - const mimes = deepAccess(bid, `mediaTypes.${mediaType}.mimes`); - if (mimes) { - bidObject.mimes = mimes; - } - const api = deepAccess(bid, `mediaTypes.${mediaType}.api`); - if (api) { - bidObject.api = api; - } - - const sua = deepAccess(bid, `ortb2.device.sua`); - if (sua) { - bidObject.sua = sua; - } - - const coppa = deepAccess(bid, `ortb2.regs.coppa`); - if (coppa) { - bidObject.coppa = 1; - } - - if (mediaType === VIDEO) { - const playbackMethod = deepAccess(bid, `mediaTypes.video.playbackmethod`); - let playbackMethodValue; - - // verify playbackMethod is of type integer array, or integer only. - if (Array.isArray(playbackMethod) && isInteger(playbackMethod[0])) { - // only the first playbackMethod in the array will be used, according to OpenRTB 2.5 recommendation - playbackMethodValue = playbackMethod[0]; - } else if (isInteger(playbackMethod)) { - playbackMethodValue = playbackMethod; - } - - if (playbackMethodValue) { - bidObject.playbackMethod = playbackMethodValue; - } - - const placement = deepAccess(bid, `mediaTypes.video.placement`); - if (placement) { - bidObject.placement = placement; - } - - const minDuration = deepAccess(bid, `mediaTypes.video.minduration`); - if (minDuration) { - bidObject.minDuration = minDuration; - } - - const maxDuration = deepAccess(bid, `mediaTypes.video.maxduration`); - if (maxDuration) { - bidObject.maxDuration = maxDuration; - } - - const skip = deepAccess(bid, `mediaTypes.video.skip`); - if (skip) { - bidObject.skip = skip; - } - - const linearity = deepAccess(bid, `mediaTypes.video.linearity`); - if (linearity) { - bidObject.linearity = linearity; - } - - const protocols = deepAccess(bid, `mediaTypes.video.protocols`); - if (protocols) { - bidObject.protocols = protocols; - } - - const plcmt = deepAccess(bid, `mediaTypes.video.plcmt`); - if (plcmt) { - bidObject.plcmt = plcmt; - } - } - - return bidObject; -} - -function isBanner(bid) { - return bid.mediaTypes && bid.mediaTypes.banner; -} - -/** - * Generate params that are common between all bids - * @param {single bid object} generalObject - * @param {bidderRequest} bidderRequest - * @returns {object} the common params object - */ -function generateGeneralParams(generalObject, bidderRequest) { - const domain = deepAccess(bidderRequest, 'refererInfo.domain') || window.location.hostname; - const {syncEnabled, filterSettings} = config.getConfig('userSync') || {}; - const {bidderCode, timeout} = bidderRequest; - const generalBidParams = generalObject.params; - - // these params are snake_case instead of camelCase to allow backwards compatability on the server. - // in the future, these will be converted to camelCase to match our convention. - const generalParams = { - wrapper_type: 'prebidjs', - wrapper_vendor: '$$PREBID_GLOBAL$$', - wrapper_version: '$prebid.version$', - adapter_version: ADAPTER_VERSION, - publisher_id: generalBidParams.org, - publisher_name: domain, - site_domain: domain, - dnt: getDNT() ? 1 : 0, - device_type: getDeviceType(navigator.userAgent), - ua: navigator.userAgent, - is_wrapper: !!generalBidParams.isWrapper, - session_id: generalBidParams.sessionId || getBidIdParameter('bidderRequestId', generalObject), - tmax: timeout - } - - const userIdsParam = getBidIdParameter('userId', generalObject); - if (userIdsParam) { - generalParams.userIds = JSON.stringify(userIdsParam); - } - - const ortb2Metadata = bidderRequest.ortb2 || {}; - if (ortb2Metadata.site) { - generalParams.site_metadata = JSON.stringify(ortb2Metadata.site); - } - if (ortb2Metadata.user) { - generalParams.user_metadata = JSON.stringify(ortb2Metadata.user); - } - - if (syncEnabled) { - const allowedSyncMethod = getAllowedSyncMethod(filterSettings, bidderCode); - if (allowedSyncMethod) { - generalParams.cs_method = allowedSyncMethod; - } - } - - if (bidderRequest.auctionStart) { - generalParams.auction_start = bidderRequest.auctionStart; - } - - if (bidderRequest.uspConsent) { - generalParams.us_privacy = bidderRequest.uspConsent; - } - - if (bidderRequest && bidderRequest.gdprConsent && bidderRequest.gdprConsent.gdprApplies) { - generalParams.gdpr = bidderRequest.gdprConsent.gdprApplies; - generalParams.gdpr_consent = bidderRequest.gdprConsent.consentString; - } - - if (bidderRequest.gppConsent) { - generalParams.gpp = bidderRequest.gppConsent.gppString; - generalParams.gpp_sid = bidderRequest.gppConsent.applicableSections; - } else if (bidderRequest.ortb2?.regs?.gpp) { - generalParams.gpp = bidderRequest.ortb2.regs.gpp; - generalParams.gpp_sid = bidderRequest.ortb2.regs.gpp_sid; - } - - if (generalBidParams.ifa) { - generalParams.ifa = generalBidParams.ifa; - } - - if (generalObject.schain) { - generalParams.schain = getSupplyChain(generalObject.schain); - } - - if (bidderRequest && bidderRequest.refererInfo) { - generalParams.referrer = deepAccess(bidderRequest, 'refererInfo.ref'); - generalParams.page_url = deepAccess(bidderRequest, 'refererInfo.page') || deepAccess(window, 'location.href'); - } - - return generalParams; -} diff --git a/modules/optoutBidAdapter.js b/modules/optoutBidAdapter.js index f7b5934665c..f0010d54833 100644 --- a/modules/optoutBidAdapter.js +++ b/modules/optoutBidAdapter.js @@ -1,7 +1,7 @@ import { deepAccess } from '../src/utils.js'; import {config} from '../src/config.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {hasPurpose1Consent} from '../src/utils/gpdr.js'; +import {hasPurpose1Consent} from '../src/utils/gdpr.js'; const BIDDER_CODE = 'optout'; diff --git a/modules/outbrainBidAdapter.js b/modules/outbrainBidAdapter.js index 9690b79fea5..5ce514a46d7 100644 --- a/modules/outbrainBidAdapter.js +++ b/modules/outbrainBidAdapter.js @@ -5,7 +5,7 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; import { getStorageManager } from '../src/storageManager.js'; import {OUTSTREAM} from '../src/video.js'; -import {_map, deepAccess, deepSetValue, isArray, logWarn, replaceAuctionPrice} from '../src/utils.js'; +import {_map, deepAccess, deepSetValue, logWarn, replaceAuctionPrice, setOnAny, parseGPTSingleSizeArrayToRtbSize} from '../src/utils.js'; import {ajax} from '../src/ajax.js'; import {config} from '../src/config.js'; import {convertOrtbRequestToProprietaryNative} from '../src/native.js'; @@ -94,7 +94,7 @@ export const spec = { imp.video = getVideoAsset(bid); } else { imp.banner = { - format: transformSizes(bid.sizes) + format: bid.sizes?.map((size) => parseGPTSingleSizeArrayToRtbSize(size)) } } @@ -111,7 +111,7 @@ export const spec = { const request = { id: bidderRequest.bidderRequestId, site: { page, publisher }, - device: { ua }, + device: ortb2?.device || { ua }, source: { fd: 1 }, cur: [cur], tmax: timeout, @@ -174,7 +174,7 @@ export const spec = { } const { seatbid, cur } = serverResponse.body; - const bidResponses = flatten(seatbid.map(seat => seat.bid)).reduce((result, bid) => { + const bidResponses = seatbid.map(seat => seat.bid).flat().reduce((result, bid) => { result[bid.impid - 1] = bid; return result; }, []); @@ -288,19 +288,6 @@ function parseNative(bid) { return result; } -function setOnAny(collection, key) { - for (let i = 0, result; i < collection.length; i++) { - result = deepAccess(collection[i], key); - if (result) { - return result; - } - } -} - -function flatten(arr) { - return [].concat(...arr); -} - function getNativeAssets(bid) { return _map(bid.nativeParams, (bidParams, key) => { const props = NATIVE_PARAMS[key]; @@ -319,7 +306,7 @@ function getNativeAssets(bid) { } if (bidParams.sizes) { - const sizes = flatten(bidParams.sizes); + const sizes = bidParams.sizes.flat(); w = parseInt(sizes[0], 10); h = parseInt(sizes[1], 10); } @@ -339,7 +326,7 @@ function getNativeAssets(bid) { } function getVideoAsset(bid) { - const sizes = flatten(bid.mediaTypes.video.playerSize); + const sizes = bid.mediaTypes.video.playerSize.flat(); return { w: parseInt(sizes[0], 10), h: parseInt(sizes[1], 10), @@ -354,34 +341,12 @@ function getVideoAsset(bid) { minduration: bid.mediaTypes.video.minduration, maxduration: bid.mediaTypes.video.maxduration, startdelay: bid.mediaTypes.video.startdelay, - placement: bid.mediaTypes.video.plcmt ?? bid.mediaTypes.video.placement, + placement: bid.mediaTypes.video.placement, + plcmt: bid.mediaTypes.video.plcmt, linearity: bid.mediaTypes.video.linearity }; } -/* Turn bid request sizes into ut-compatible format */ -function transformSizes(requestSizes) { - if (!isArray(requestSizes)) { - return []; - } - - if (requestSizes.length === 2 && !isArray(requestSizes[0])) { - return [{ - w: parseInt(requestSizes[0], 10), - h: parseInt(requestSizes[1], 10) - }]; - } else if (isArray(requestSizes[0])) { - return requestSizes.map(item => - ({ - w: parseInt(item[0], 10), - h: parseInt(item[1], 10) - }) - ); - } - - return []; -} - function _getFloor(bid, type) { const floorInfo = bid.getFloor({ currency: CURRENCY, diff --git a/modules/ownadxBidAdapter.js b/modules/ownadxBidAdapter.js new file mode 100644 index 00000000000..5843735f314 --- /dev/null +++ b/modules/ownadxBidAdapter.js @@ -0,0 +1,99 @@ +import { parseSizesInput, isEmpty } from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER } from '../src/mediaTypes.js' + +/** + * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest + * @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid + * @typedef {import('../src/adapters/bidderFactory.js').ServerResponse} ServerResponse + */ + +const BIDDER_CODE = 'ownadx'; +const CUR = 'USD'; +const CREATIVE_TTL = 300; + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER], + + /** + * Determines whether or not the given bid request is valid. + * + * @param {BidRequest} bid The bid params to validate. + * @return boolean True if this is a valid bid, and false otherwise. + */ + isBidRequestValid: function (bid) { + return !!(bid.params.tokenId && bid.params.sspId && bid.params.seatId); + }, + + /** + * Make a server request from the list of BidRequests. + * + * @param validBidRequests + * @param bidderRequest + * @return Array Info describing the request to the server. + */ + buildRequests: function (validBidRequests, bidderRequest) { + return validBidRequests.map(bidRequest => { + const sizes = parseSizesInput(bidRequest.params.size || bidRequest.sizes); + let mtype = 0; + if (bidRequest.mediaTypes[BANNER]) { + mtype = 1; + } else { + mtype = 2; + } + + let tkn = bidRequest.params.tokenId; + let seatid = bidRequest.params.seatId; + let sspid = bidRequest.params.sspId; + + const payload = { + sizes: sizes, + slotBidId: bidRequest.bidId, + PageUrl: bidderRequest.refererInfo.page, + mediaChannel: mtype + }; + return { + method: 'POST', + url: `https://pbs-js.prebid-ownadx.com/publisher/prebid/${seatid}/${sspid}?token=${tkn}`, + data: payload + }; + }); + }, + + /** + * Unpack the response from the server into a list of bids. + * + * @param {ServerResponse} serverResponse A successful response from the server. + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: function (serverResponse) { + const response = serverResponse.body; + const bids = []; + if (isEmpty(response)) { + return bids; + } + const responseBid = { + width: response.width, + height: response.height, + token: response.tokenId, + ttl: CREATIVE_TTL, + requestId: response.slotBidId, + aType: response.adType || '1', + cpm: response.cpm, + creativeId: response.creativeId || 0, + netRevenue: response.netRevenue || false, + currency: response.currency || CUR, + meta: { + mediaType: response.mediaType || BANNER, + advertiserDomains: response.advertiserDomains || [] + }, + ad: response.adm + }; + bids.push(responseBid); + return bids; + } + +}; + +registerBidder(spec); diff --git a/modules/ozoneBidAdapter.js b/modules/ozoneBidAdapter.js index 9968072eff4..7a4a5a9717c 100644 --- a/modules/ozoneBidAdapter.js +++ b/modules/ozoneBidAdapter.js @@ -22,7 +22,7 @@ const AUCTIONURI = '/openrtb2/auction'; const OZONECOOKIESYNC = '/static/load-cookie.html'; const OZONE_RENDERER_URL = 'https://prebid.the-ozone-project.com/ozone-renderer.js'; const ORIGIN_DEV = 'https://test.ozpr.net'; -const OZONEVERSION = '2.9.2'; +const OZONEVERSION = '2.9.3'; export const spec = { gvlid: 524, aliases: [{code: 'lmc', gvlid: 524}, {code: 'venatus', gvlid: 524}], @@ -535,7 +535,7 @@ export const spec = { for (let j = 0; j < sb.bid.length; j++) { let thisRequestBid = this.getBidRequestForBidId(sb.bid[j].impid, request.bidderRequest.bids); logInfo(`seatbid:${i}, bid:${j} Going to set default w h for seatbid/bidRequest`, sb.bid[j], thisRequestBid); - const {defaultWidth, defaultHeight} = defaultSize(thisRequestBid); + let {defaultWidth, defaultHeight} = defaultSize(thisRequestBid); let thisBid = ozoneAddStandardProperties(sb.bid[j], defaultWidth, defaultHeight); thisBid.meta = {advertiserDomains: thisBid.adomain || []}; let videoContext = null; @@ -567,8 +567,8 @@ export const spec = { this.setBidMediaTypeIfNotExist(thisBid, BANNER); } if (enhancedAdserverTargeting) { - let allBidsForThisBidid = ozoneGetAllBidsForBidId(thisBid.bidId, serverResponse.seatbid); - logInfo('Going to iterate allBidsForThisBidId', allBidsForThisBidid); + let allBidsForThisBidid = ozoneGetAllBidsForBidId(thisBid.bidId, serverResponse.seatbid, defaultWidth, defaultHeight); + logInfo('Going to iterate allBidsForThisBidId', deepClone(allBidsForThisBidid)); Object.keys(allBidsForThisBidid).forEach((bidderName, index, ar2) => { logInfo(`adding adserverTargeting for ${bidderName} for bidId ${thisBid.bidId}`); adserverTargeting[whitelabelPrefix + '_' + bidderName] = bidderName; @@ -606,6 +606,7 @@ export const spec = { } } let {seat: winningSeat, bid: winningBid} = ozoneGetWinnerForRequestBid(thisBid.bidId, serverResponse.seatbid); + winningBid = ozoneAddStandardProperties(winningBid, defaultWidth, defaultHeight); adserverTargeting[whitelabelPrefix + '_auc_id'] = String(aucId); // was request.bidderRequest.auctionId adserverTargeting[whitelabelPrefix + '_winner'] = String(winningSeat); adserverTargeting[whitelabelPrefix + '_bid'] = 'true'; @@ -899,7 +900,7 @@ export const spec = { } }; export function injectAdIdsIntoAllBidResponses(seatbid) { - logInfo('injectAdIdsIntoAllBidResponses', seatbid); + logInfo('injectAdIdsIntoAllBidResponses', deepClone(seatbid)); for (let i = 0; i < seatbid.length; i++) { let sb = seatbid[i]; for (let j = 0; j < sb.bid.length; j++) { @@ -951,7 +952,7 @@ export function ozoneGetWinnerForRequestBid(requestBidId, serverResponseSeatBid) } return {'seat': winningSeat, 'bid': thisBidWinner}; } -export function ozoneGetAllBidsForBidId(matchBidId, serverResponseSeatBid) { +export function ozoneGetAllBidsForBidId(matchBidId, serverResponseSeatBid, defaultWidth, defaultHeight) { let objBids = {}; for (let j = 0; j < serverResponseSeatBid.length; j++) { let theseBids = serverResponseSeatBid[j].bid; @@ -960,10 +961,11 @@ export function ozoneGetAllBidsForBidId(matchBidId, serverResponseSeatBid) { if (theseBids[k].impid === matchBidId) { if (objBids.hasOwnProperty(thisSeat)) { // > 1 bid for an adunit from a bidder - only use the one with the highest bid if (objBids[thisSeat]['price'] < theseBids[k].price) { - objBids[thisSeat] = theseBids[k]; + objBids[thisSeat] = ozoneAddStandardProperties(theseBids[k], defaultWidth, defaultHeight); } } else { objBids[thisSeat] = theseBids[k]; + objBids[thisSeat] = ozoneAddStandardProperties(theseBids[k], defaultWidth, defaultHeight); } } } diff --git a/modules/paapi.js b/modules/paapi.js index 8ddd1912c29..9ae2c870e5d 100644 --- a/modules/paapi.js +++ b/modules/paapi.js @@ -54,6 +54,7 @@ export function init(cfg) { } getHook('addPaapiConfig').before(addPaapiConfigHook); +getHook('makeBidRequests').before(addPaapiData); getHook('makeBidRequests').after(markForFledge); events.on(EVENTS.AUCTION_END, onAuctionEnd); @@ -332,38 +333,50 @@ function getRequestedSize(adUnit) { })(); } +export function addPaapiData(next, adUnits, ...args) { + if (isFledgeSupported() && moduleConfig.enabled) { + adUnits.forEach(adUnit => { + // https://github.com/InteractiveAdvertisingBureau/openrtb/blob/main/extensions/community_extensions/Protected%20Audience%20Support.md + const igsAe = adUnit.ortb2Imp?.ext?.igs != null + ? adUnit.ortb2Imp.ext.igs.ae || 1 + : null; + const extAe = adUnit.ortb2Imp?.ext?.ae; + if (igsAe !== extAe && igsAe != null && extAe != null) { + logWarn(MODULE, `Ad unit defines conflicting ortb2Imp.ext.ae and ortb2Imp.ext.igs, using the latter`, adUnit); + } + const ae = igsAe ?? extAe ?? moduleConfig.defaultForSlots; + if (ae) { + deepSetValue(adUnit, 'ortb2Imp.ext.ae', ae); + adUnit.ortb2Imp.ext.igs = Object.assign({ + ae: ae, + biddable: 1 + }, adUnit.ortb2Imp.ext.igs); + const requestedSize = getRequestedSize(adUnit); + if (requestedSize) { + deepSetValue(adUnit, 'ortb2Imp.ext.paapi.requestedSize', requestedSize); + } + adUnit.bids.forEach(bidReq => { + if (!getFledgeConfig(bidReq.bidder).enabled) { + deepSetValue(bidReq, 'ortb2Imp.ext.ae', 0); + bidReq.ortb2Imp.ext.igs = {ae: 0, biddable: 0}; + } + }) + } + }) + } + next(adUnits, ...args); +} + export function markForFledge(next, bidderRequests) { if (isFledgeSupported()) { bidderRequests.forEach((bidderReq) => { - const {enabled, ae} = getFledgeConfig(bidderReq.bidderCode); + const {enabled} = getFledgeConfig(bidderReq.bidderCode); Object.assign(bidderReq, { paapi: { enabled, componentSeller: !!moduleConfig.componentSeller?.auctionConfig } }); - bidderReq.bids.forEach(bidReq => { - // https://github.com/InteractiveAdvertisingBureau/openrtb/blob/main/extensions/community_extensions/Protected%20Audience%20Support.md - const igsAe = bidReq.ortb2Imp?.ext?.igs != null - ? bidReq.ortb2Imp.ext.igs.ae || 1 - : null; - const extAe = bidReq.ortb2Imp?.ext?.ae; - if (igsAe !== extAe && igsAe != null && extAe != null) { - logWarn(MODULE, `Bid request defines conflicting ortb2Imp.ext.ae and ortb2Imp.ext.igs, using the latter`, bidReq); - } - const bidAe = igsAe ?? extAe ?? ae; - if (bidAe) { - deepSetValue(bidReq, 'ortb2Imp.ext.ae', bidAe); - bidReq.ortb2Imp.ext.igs = Object.assign({ - ae: bidAe, - biddable: 1 - }, bidReq.ortb2Imp.ext.igs); - const requestedSize = getRequestedSize(bidReq); - if (requestedSize) { - deepSetValue(bidReq, 'ortb2Imp.ext.paapi.requestedSize', requestedSize); - } - } - }); }); } next(bidderRequests); @@ -378,18 +391,6 @@ export function setImpExtAe(imp, bidRequest, context) { registerOrtbProcessor({type: IMP, name: 'impExtAe', fn: setImpExtAe}); -function paapiResponseParser(configs, response, context) { - configs.forEach((config) => { - const impCtx = context.impContext[config.impid]; - if (!impCtx?.imp?.ext?.ae) { - logWarn(MODULE, 'Received auction configuration for an impression that was not in the request or did not ask for it', config, impCtx?.imp); - } else { - impCtx.paapiConfigs = impCtx.paapiConfigs || []; - impCtx.paapiConfigs.push(config); - } - }); -} - export function parseExtIgi(response, ortbResponse, context) { paapiResponseParser( (ortbResponse.ext?.igi || []).flatMap(igi => { @@ -411,6 +412,18 @@ export function parseExtIgi(response, ortbResponse, context) { ) } +function paapiResponseParser(configs, response, context) { + configs.forEach((config) => { + const impCtx = context.impContext[config.impid]; + if (!impCtx?.imp?.ext?.ae) { + logWarn(MODULE, 'Received auction configuration for an impression that was not in the request or did not ask for it', config, impCtx?.imp); + } else { + impCtx.paapiConfigs = impCtx.paapiConfigs || []; + impCtx.paapiConfigs.push(config); + } + }); +} + // to make it easier to share code between the PBS adapter and adapters whose backend is PBS, break up // fledge response processing in two steps: first aggregate all the auction configs by their imp... diff --git a/modules/permutiveRtdProvider.js b/modules/permutiveRtdProvider.js index c42a15d9197..bb2dff6189e 100644 --- a/modules/permutiveRtdProvider.js +++ b/modules/permutiveRtdProvider.js @@ -95,7 +95,8 @@ export function getModuleConfig(customModuleConfig) { /** * Sets ortb2 config for ac bidders * @param {Object} bidderOrtb2 - The ortb2 object for the all bidders - * @param {Object} customModuleConfig - Publisher config for module + * @param {Object} moduleConfig - Publisher config for module + * @param {Object} segmentData - Segment data grouped by bidder or type */ export function setBidderRtb (bidderOrtb2, moduleConfig, segmentData) { const acBidders = deepAccess(moduleConfig, 'params.acBidders') @@ -129,13 +130,13 @@ export function setBidderRtb (bidderOrtb2, moduleConfig, segmentData) { /** * Updates `user.data` object in existing bidder config with Permutive segments - * @param string bidder - The bidder + * @param {string} bidder - The bidder identifier * @param {Object} currConfig - Current bidder config - * @param {Object[]} transformationConfigs - array of objects with `id` and `config` properties, used to determine - * the transformations on user data to include the ORTB2 object * @param {string[]} segmentIDs - Permutive segment IDs * @param {string[]} sspSegmentIDs - Permutive SSP segment IDs * @param {Object} topics - Privacy Sandbox Topics, keyed by IAB taxonomy version (600, 601, etc.) + * @param {Object[]} transformationConfigs - array of objects with `id` and `config` properties, used to determine + * the transformations on user data to include the ORTB2 object * @param {Object} segmentData - The segments available for targeting * @return {Object} Merged ortb2 object */ @@ -270,7 +271,7 @@ function setSegments (reqBidsConfigObj, moduleConfig, segmentData) { */ function makeSafe (fn) { try { - fn() + return fn() } catch (e) { logError(e) } @@ -310,23 +311,71 @@ export function isPermutiveOnPage () { * @param {number} maxSegs - Maximum number of segments to be included * @return {Object} */ -export function getSegments (maxSegs) { - const legacySegs = readSegments('_psegs', []).map(Number).filter(seg => seg >= 1000000).map(String) - const _ppam = readSegments('_ppam', []) - const _pcrprs = readSegments('_pcrprs', []) - +export function getSegments(maxSegs) { const segments = { - ac: [..._pcrprs, ..._ppam, ...legacySegs], - ix: readSegments('_pindexs', []), - rubicon: readSegments('_prubicons', []), - appnexus: readSegments('_papns', []), - gam: readSegments('_pdfps', []), - ssp: readSegments('_pssps', { - cohorts: [], - ssps: [] + ac: + makeSafe(() => { + const legacySegs = + makeSafe(() => + readSegments('_psegs', []) + .map(Number) + .filter((seg) => seg >= 1000000) + .map(String), + ) || []; + const _ppam = makeSafe(() => readSegments('_ppam', []).map(String)) || []; + const _pcrprs = makeSafe(() => readSegments('_pcrprs', []).map(String)) || []; + + return [..._pcrprs, ..._ppam, ...legacySegs]; + }) || [], + + ix: + makeSafe(() => { + const _pindexs = readSegments('_pindexs', []); + return _pindexs.map(String); + }) || [], + + rubicon: + makeSafe(() => { + const _prubicons = readSegments('_prubicons', []); + return _prubicons.map(String); + }) || [], + + appnexus: + makeSafe(() => { + const _papns = readSegments('_papns', []); + return _papns.map(String); + }) || [], + + gam: + makeSafe(() => { + const _pdfps = readSegments('_pdfps', []); + return _pdfps.map(String); + }) || [], + + ssp: makeSafe(() => { + const _pssps = readSegments('_pssps', { + cohorts: [], + ssps: [], + }); + + return { + cohorts: makeSafe(() => _pssps.cohorts.map(String)) || [], + ssps: makeSafe(() => _pssps.ssps.map(String)) || [], + }; }), - topics: readSegments('_ppsts', {}), - } + + topics: + makeSafe(() => { + const _ppsts = readSegments('_ppsts', {}); + + const topics = {}; + for (const [k, value] of Object.entries(_ppsts)) { + topics[k] = makeSafe(() => value.map(String)) || []; + } + + return topics; + }) || {}, + }; for (const bidder in segments) { if (bidder === 'ssp') { @@ -342,7 +391,8 @@ export function getSegments (maxSegs) { } } - return segments + logger.logInfo(`Read segments`, segments) + return segments; } /** @@ -393,7 +443,7 @@ function iabSegmentId(permutiveSegmentId, iabIds) { * Pull the latest configuration and cohort information and update accordingly. * * @param reqBidsConfigObj - Bidder provided config for request - * @param customModuleConfig - Publisher provide config + * @param moduleConfig - Publisher provided config */ export function readAndSetCohorts(reqBidsConfigObj, moduleConfig) { const segmentData = getSegments(deepAccess(moduleConfig, 'params.maxSegs')) diff --git a/modules/playdigoBidAdapter.js b/modules/playdigoBidAdapter.js index 4fc7addc0a0..e41e86c4c47 100644 --- a/modules/playdigoBidAdapter.js +++ b/modules/playdigoBidAdapter.js @@ -1,9 +1,10 @@ import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; -import { isBidRequestValid, buildRequests, interpretResponse } from '../libraries/teqblazeUtils/bidderUtils.js'; +import { isBidRequestValid, buildRequests, interpretResponse, getUserSyncs } from '../libraries/teqblazeUtils/bidderUtils.js'; const BIDDER_CODE = 'playdigo'; const AD_URL = 'https://server.playdigo.com/pbjs'; +const SYNC_URL = 'https://cs.playdigo.com'; export const spec = { code: BIDDER_CODE, @@ -11,7 +12,8 @@ export const spec = { isBidRequestValid: isBidRequestValid(), buildRequests: buildRequests(AD_URL), - interpretResponse + interpretResponse, + getUserSyncs: getUserSyncs(SYNC_URL) }; registerBidder(spec); diff --git a/modules/prebidServerBidAdapter/index.js b/modules/prebidServerBidAdapter/index.js index 2256e788e7e..edae21e97a7 100644 --- a/modules/prebidServerBidAdapter/index.js +++ b/modules/prebidServerBidAdapter/index.js @@ -25,7 +25,7 @@ import {includes} from '../../src/polyfill.js'; import {S2S_VENDORS} from './config.js'; import {ajax} from '../../src/ajax.js'; import {hook} from '../../src/hook.js'; -import {hasPurpose1Consent} from '../../src/utils/gpdr.js'; +import {hasPurpose1Consent} from '../../src/utils/gdpr.js'; import {buildPBSRequest, interpretPBSResponse} from './ortbConverter.js'; import {useMetrics} from '../../src/utils/perfMetrics.js'; import {isActivityAllowed} from '../../src/activities/rules.js'; @@ -515,7 +515,9 @@ export function PrebidServer() { } }, onFledge: (params) => { - addPaapiConfig({auctionId: bidRequests[0].auctionId, ...params}, {config: params.config}); + config.runWithBidder(params.bidder, () => { + addPaapiConfig({auctionId: bidRequests[0].auctionId, ...params}, {config: params.config}); + }) } }) } diff --git a/modules/prebidServerBidAdapter/ortbConverter.js b/modules/prebidServerBidAdapter/ortbConverter.js index bb033271b3c..242c65c7dfa 100644 --- a/modules/prebidServerBidAdapter/ortbConverter.js +++ b/modules/prebidServerBidAdapter/ortbConverter.js @@ -241,6 +241,7 @@ const PBS_CONVERTER = ortbConverter({ adUnitCode: impCtx.adUnit.code, ortb2: bidderReq?.ortb2, ortb2Imp: bidReq?.ortb2Imp, + bidder: cfg.bidder, config: cfg.config }; })); diff --git a/modules/programmaticaBidAdapter.js b/modules/programmaticaBidAdapter.js index 7d52e305189..aeca74120d6 100644 --- a/modules/programmaticaBidAdapter.js +++ b/modules/programmaticaBidAdapter.js @@ -1,6 +1,6 @@ import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; -import { hasPurpose1Consent } from '../src/utils/gpdr.js'; +import { hasPurpose1Consent } from '../src/utils/gdpr.js'; import { deepAccess, parseSizesInput, isArray } from '../src/utils.js'; const BIDDER_CODE = 'programmatica'; diff --git a/modules/publirBidAdapter.js b/modules/publirBidAdapter.js index 432e123458c..2cf55aa86cb 100644 --- a/modules/publirBidAdapter.js +++ b/modules/publirBidAdapter.js @@ -2,32 +2,26 @@ import { logWarn, logInfo, isArray, - isFn, deepAccess, - isEmpty, - contains, timestamp, triggerPixel, - getDNT, - getBidIdParameter } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; -import { config } from '../src/config.js'; import { getStorageManager } from '../src/storageManager.js'; import { ajax } from '../src/ajax.js'; +import { + generateBidsParams, + generateGeneralParams, +} from '../libraries/riseUtils/index.js'; const SUPPORTED_AD_TYPES = [BANNER, VIDEO]; const BIDDER_CODE = 'publir'; const ADAPTER_VERSION = '1.0.0'; const TTL = 360; const CURRENCY = 'USD'; -const DEFAULT_SELLER_ENDPOINT = 'https://prebid.publir.com/publirPrebidEndPoint'; +const BASE_URL = 'https://prebid.publir.com/publirPrebidEndPoint'; const DEFAULT_IMPS_ENDPOINT = 'https://prebidimpst.publir.com/publirPrebidImpressionTracker'; -const SUPPORTED_SYNC_METHODS = { - IFRAME: 'iframe', - PIXEL: 'pixel' -} export const storage = getStorageManager({ bidderCode: BIDDER_CODE }); export const spec = { @@ -40,25 +34,26 @@ export const spec = { logWarn('pubId is a mandatory param for Publir adapter'); return false; } - return true; }, buildRequests: function (validBidRequests, bidderRequest) { - const reqObj = {}; + const combinedRequestsObject = {}; + const generalObject = validBidRequests[0]; - reqObj.params = generatePubGeneralsParams(generalObject, bidderRequest); - reqObj.bids = generatePubBidParams(validBidRequests, bidderRequest); - reqObj.bids.timestamp = timestamp(); + combinedRequestsObject.params = generateGeneralParams(generalObject, bidderRequest, ADAPTER_VERSION); + combinedRequestsObject.bids = generateBidsParams(validBidRequests, bidderRequest); + combinedRequestsObject.bids.timestamp = timestamp(); + let options = { withCredentials: false }; return { method: 'POST', - url: DEFAULT_SELLER_ENDPOINT, - data: reqObj, + url: BASE_URL, + data: combinedRequestsObject, options - } + }; }, interpretResponse: function ({ body }) { const bidResponses = []; @@ -109,20 +104,20 @@ export const spec = { const syncs = []; for (const response of serverResponses) { if (response.body && response.body.params) { - if (syncOptions.iframeEnabled && response.body.params.userSyncURL) { + if (syncOptions.iframeEnabled && deepAccess(response, 'body.params.userSyncURL')) { syncs.push({ type: 'iframe', - url: response.body.params.userSyncURL + url: deepAccess(response, 'body.params.userSyncURL') }); } - if (syncOptions.pixelEnabled && isArray(response.body.params.userSyncPixels)) { + if (syncOptions.pixelEnabled && isArray(deepAccess(response, 'body.params.userSyncPixels'))) { const pixels = response.body.params.userSyncPixels.map(pixel => { return { type: 'image', url: pixel - } - }) - syncs.push(...pixels) + }; + }); + syncs.push(...pixels); } } } @@ -141,251 +136,3 @@ export const spec = { }; registerBidder(spec); - -/** - * Get floor price - * @param bid {bid} - * @returns {Number} - */ -function getFloor(bid, mediaType) { - if (!isFn(bid.getFloor)) { - return 0; - } - let floorResult = bid.getFloor({ - currency: CURRENCY, - mediaType: mediaType, - size: '*' - }); - return floorResult.currency === CURRENCY && floorResult.floor ? floorResult.floor : 0; -} - -/** - * Get the the ad sizes array from the bid - * @param bid {bid} - * @returns {Array} - */ -function getSizesArray(bid, mediaType) { - let sizesArray = [] - - if (deepAccess(bid, `mediaTypes.${mediaType}.sizes`)) { - sizesArray = bid.mediaTypes[mediaType].sizes; - } else if (Array.isArray(bid.sizes) && bid.sizes.length > 0) { - sizesArray = bid.sizes; - } - - return sizesArray; -} - -/** - * Get schain string value - * @param schainObject {Object} - * @returns {string} - */ -function getSupplyChain(schainObject) { - if (isEmpty(schainObject)) { - return ''; - } - let scStr = `${schainObject.ver},${schainObject.complete}`; - schainObject.nodes.forEach((node) => { - scStr += '!'; - scStr += `${getEncodedValIfNotEmpty(node.asi)},`; - scStr += `${getEncodedValIfNotEmpty(node.sid)},`; - scStr += `${node.hp ? encodeURIComponent(node.hp) : ''},`; - scStr += `${getEncodedValIfNotEmpty(node.rid)},`; - scStr += `${getEncodedValIfNotEmpty(node.name)},`; - scStr += `${getEncodedValIfNotEmpty(node.domain)}`; - }); - return scStr; -} - -/** - * Get encoded node value - * @param val {string} - * @returns {string} - */ -function getEncodedValIfNotEmpty(val) { - return !isEmpty(val) ? encodeURIComponent(val) : ''; -} - -function getAllowedSyncMethod(filterSettings, bidderCode) { - const iframeConfigsToCheck = ['all', 'iframe']; - const pixelConfigToCheck = 'image'; - if (filterSettings && iframeConfigsToCheck.some(config => isSyncMethodAllowed(filterSettings[config], bidderCode))) { - return SUPPORTED_SYNC_METHODS.IFRAME; - } - if (!filterSettings || !filterSettings[pixelConfigToCheck] || isSyncMethodAllowed(filterSettings[pixelConfigToCheck], bidderCode)) { - return SUPPORTED_SYNC_METHODS.PIXEL; - } -} - -/** - * Check if sync rule is supported - * @param syncRule {Object} - * @param bidderCode {string} - * @returns {boolean} - */ -function isSyncMethodAllowed(syncRule, bidderCode) { - if (!syncRule) { - return false; - } - const isInclude = syncRule.filter === 'include'; - const bidders = isArray(syncRule.bidders) ? syncRule.bidders : [bidderCode]; - return isInclude && contains(bidders, bidderCode); -} - -/** - * get device type - * @param ua {ua} - * @returns {string} - */ -function getDeviceType(ua) { - if (/ipad|android 3.0|xoom|sch-i800|playbook|tablet|kindle/i.test(ua.toLowerCase())) { - return '5'; - } - if (/iphone|ipod|android|blackberry|opera|mini|windows\sce|palm|smartphone|iemobile/i.test(ua.toLowerCase())) { - return '4'; - } - if (/smart[-_\s]?tv|hbbtv|appletv|googletv|hdmi|netcast|viera|nettv|roku|\bdtv\b|sonydtv|inettvbrowser|\btv\b/i.test(ua.toLowerCase())) { - return '3'; - } - return '1'; -} - -function generatePubBidParams(validBidRequests, bidderRequest) { - const bidsArray = []; - - if (validBidRequests.length) { - validBidRequests.forEach(bid => { - bidsArray.push(generateBidParameters(bid, bidderRequest)); - }); - } - return bidsArray; -} - -/** - * Generate bid specific parameters - * @param {bid} bid - * @param {bidderRequest} bidderRequest - * @returns {Object} bid specific params object - */ -function generateBidParameters(bid, bidderRequest) { - const { params } = bid; - const mediaType = isBanner(bid) ? BANNER : VIDEO; - const sizesArray = getSizesArray(bid, mediaType); - - // fix floor price in case of NAN - if (isNaN(params.floorPrice)) { - params.floorPrice = 0; - } - - const bidObject = { - mediaType, - adUnitCode: getBidIdParameter('adUnitCode', bid), - sizes: sizesArray, - floorPrice: Math.max(getFloor(bid, mediaType), params.floorPrice), - bidId: getBidIdParameter('bidId', bid), - bidderRequestId: getBidIdParameter('bidderRequestId', bid), - loop: getBidIdParameter('bidderRequestsCount', bid), - transactionId: bid.ortb2Imp?.ext?.tid, - coppa: 0 - }; - - const pubId = params.pubId; - if (pubId) { - bidObject.pubId = pubId; - } - - const sua = deepAccess(bid, `ortb2.device.sua`); - if (sua) { - bidObject.sua = sua; - } - - const coppa = deepAccess(bid, `ortb2.regs.coppa`) - if (coppa) { - bidObject.coppa = 1; - } - - return bidObject; -} - -function isBanner(bid) { - return bid.mediaTypes && bid.mediaTypes.banner; -} - -function getLocalStorage(cookieObjName) { - if (storage.localStorageIsEnabled()) { - const lstData = storage.getDataFromLocalStorage(cookieObjName); - return lstData; - } - return ''; -} - -/** - * Generate params that are common between all bids - * @param generalObject - * @param {bidderRequest} bidderRequest - * @returns {object} the common params object - */ -function generatePubGeneralsParams(generalObject, bidderRequest) { - const domain = bidderRequest.refererInfo; - const { syncEnabled, filterSettings } = config.getConfig('userSync') || {}; - const { bidderCode } = bidderRequest; - const generalBidParams = generalObject.params; - const timeout = bidderRequest.timeout; - const generalParams = { - wrapper_type: 'prebidjs', - wrapper_vendor: '$$PREBID_GLOBAL$$', - wrapper_version: '$prebid.version$', - adapter_version: ADAPTER_VERSION, - auction_start: bidderRequest.auctionStart, - publisher_id: generalBidParams.pubId, - publisher_name: domain, - site_domain: domain, - dnt: getDNT() ? 1 : 0, - device_type: getDeviceType(navigator.userAgent), - ua: navigator.userAgent, - is_wrapper: !!generalBidParams.isWrapper, - session_id: generalBidParams.sessionId || getBidIdParameter('bidderRequestId', generalObject), - tmax: timeout, - user_cookie: getLocalStorage('_publir_prebid_creative') - }; - - const userIdsParam = getBidIdParameter('userId', generalObject); - if (userIdsParam) { - generalParams.userIds = JSON.stringify(userIdsParam); - } - - const ortb2Metadata = bidderRequest.ortb2 || {}; - if (ortb2Metadata.site) { - generalParams.site_metadata = JSON.stringify(ortb2Metadata.site); - } - if (ortb2Metadata.user) { - generalParams.user_metadata = JSON.stringify(ortb2Metadata.user); - } - - if (syncEnabled) { - const allowedSyncMethod = getAllowedSyncMethod(filterSettings, bidderCode); - if (allowedSyncMethod) { - generalParams.cs_method = allowedSyncMethod; - } - } - - if (bidderRequest.uspConsent) { - generalParams.us_privacy = bidderRequest.uspConsent; - } - - if (bidderRequest && bidderRequest.gdprConsent && bidderRequest.gdprConsent.gdprApplies) { - generalParams.gdpr = bidderRequest.gdprConsent.gdprApplies; - generalParams.gdpr_consent = bidderRequest.gdprConsent.consentString; - } - - if (generalObject.schain) { - generalParams.schain = getSupplyChain(generalObject.schain); - } - - if (bidderRequest && bidderRequest.refererInfo) { - generalParams.page_url = deepAccess(bidderRequest, 'refererInfo.page') || deepAccess(window, 'location.href'); - } - - return generalParams; -} diff --git a/modules/pubmaticBidAdapter.js b/modules/pubmaticBidAdapter.js index 5add3fb9be1..85018a73a54 100644 --- a/modules/pubmaticBidAdapter.js +++ b/modules/pubmaticBidAdapter.js @@ -68,6 +68,10 @@ const NATIVE_ASSET_IMAGE_TYPE = { 'IMAGE': 3 } +const BANNER_CUSTOM_PARAMS = { + 'battr': DATA_TYPES.ARRAY +} + const NET_REVENUE = true; const dealChannelValues = { 1: 'PMP', @@ -551,6 +555,14 @@ function _createBannerRequest(bid) { } bannerObj.pos = 0; bannerObj.topframe = inIframe() ? 0 : 1; + + // Adding Banner custom params + const bannerCustomParams = {...deepAccess(bid, 'ortb2Imp.banner')}; + for (let key in BANNER_CUSTOM_PARAMS) { + if (bannerCustomParams.hasOwnProperty(key)) { + bannerObj[key] = _checkParamDataType(key, bannerCustomParams[key], BANNER_CUSTOM_PARAMS[key]); + } + } } else { logWarn(LOG_WARN_PREFIX + 'Error: mediaTypes.banner.size missing for adunit: ' + bid.params.adUnit + '. Ignoring the banner impression in the adunit.'); bannerObj = UNDEFINED; diff --git a/modules/pubxaiAnalyticsAdapter.js b/modules/pubxaiAnalyticsAdapter.js index 3b9aee3ecb7..afa8b01bfca 100644 --- a/modules/pubxaiAnalyticsAdapter.js +++ b/modules/pubxaiAnalyticsAdapter.js @@ -1,204 +1,346 @@ -import { deepAccess, parseSizesInput, getWindowLocation, buildUrl } from '../src/utils.js'; -import { ajax } from '../src/ajax.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; +import { + getGptSlotInfoForAdUnitCode, getGptSlotForAdUnitCode +} from '../libraries/gptUtils/gptUtils.js'; +import { getDeviceType, getBrowser, getOS } from '../libraries/userAgentUtils/index.js'; +import { MODULE_TYPE_ANALYTICS } from '../src/activities/modules.js'; import adapterManager from '../src/adapterManager.js'; +import { sendBeacon } from '../src/ajax.js' import { EVENTS } from '../src/constants.js'; -import {getGlobal} from '../src/prebidGlobal.js'; -import {getGptSlotInfoForAdUnitCode} from '../libraries/gptUtils/gptUtils.js'; +import { getGlobal } from '../src/prebidGlobal.js'; +import { getStorageManager } from '../src/storageManager.js'; +import { + deepAccess, parseSizesInput, getWindowLocation, buildUrl, cyrb53Hash +} from '../src/utils.js'; + +let initOptions; const emptyUrl = ''; const analyticsType = 'endpoint'; -const pubxaiAnalyticsVersion = 'v1.2.0'; +const adapterCode = 'pubxai'; +const pubxaiAnalyticsVersion = 'v2.0.0'; const defaultHost = 'api.pbxai.com'; const auctionPath = '/analytics/auction'; const winningBidPath = '/analytics/bidwon'; +const storage = getStorageManager({ moduleType: MODULE_TYPE_ANALYTICS, moduleName: adapterCode }) -let initOptions; -let auctionTimestamp; -let auctionCache = []; -let events = { - bids: [], - floorDetail: {}, - pageDetail: {}, - deviceDetail: {} -}; - -function getStorage() { - return null; -} - -var pubxaiAnalyticsAdapter = Object.assign(adapter( +/** + * The sendCache is a global cache object which tracks the pending sends + * back to pubx.ai. The data may be removed from this cache, post send. + */ +export const sendCache = new Proxy( + {}, { - emptyUrl, - analyticsType - }), { - track({ eventType, args }) { - if (typeof args !== 'undefined') { - if (eventType === EVENTS.BID_TIMEOUT) { - args.forEach(item => { mapBidResponse(item, 'timeout'); }); - } else if (eventType === EVENTS.AUCTION_INIT) { - events.auctionInit = args; - events.floorDetail = {}; - events.bids = []; - const floorData = deepAccess(args, 'bidderRequests.0.bids.0.floorData'); - if (typeof floorData !== 'undefined') { - Object.assign(events.floorDetail, floorData); - } - auctionTimestamp = args.timestamp; - } else if (eventType === EVENTS.BID_RESPONSE) { - mapBidResponse(args, 'response'); - } else if (eventType === EVENTS.BID_WON) { - send({ - winningBid: mapBidResponse(args, 'bidwon') - }, 'bidwon'); + get: (target, name) => { + if (!target.hasOwnProperty(name)) { + target[name] = []; } - } - if (eventType === EVENTS.AUCTION_END) { - send(events, 'auctionEnd'); - } + return target[name]; + }, } -}); +); -function mapBidResponse(bidResponse, status) { - if (typeof bidResponse !== 'undefined') { - let bid = { - adUnitCode: bidResponse.adUnitCode, - gptSlotCode: getGptSlotInfoForAdUnitCode(bidResponse.adUnitCode).gptSlot || null, - auctionId: bidResponse.auctionId, - bidderCode: bidResponse.bidder, - cpm: bidResponse.cpm, - creativeId: bidResponse.creativeId, - currency: bidResponse.currency, - floorData: bidResponse.floorData, - mediaType: bidResponse.mediaType, - netRevenue: bidResponse.netRevenue, - requestTimestamp: bidResponse.requestTimestamp, - responseTimestamp: bidResponse.responseTimestamp, - status: bidResponse.status, - statusMessage: bidResponse.statusMessage, - timeToRespond: bidResponse.timeToRespond, - transactionId: bidResponse.transactionId - }; - if (status !== 'bidwon') { - Object.assign(bid, { - bidId: status === 'timeout' ? bidResponse.bidId : bidResponse.requestId, - renderStatus: status === 'timeout' ? 3 : 2, - sizes: parseSizesInput(bidResponse.size).toString(), - }); - events.bids.push(bid); - } else { - Object.assign(bid, { - bidId: bidResponse.requestId, - floorProvider: events.floorDetail?.floorProvider || null, - floorFetchStatus: events.floorDetail?.fetchStatus || null, - floorLocation: events.floorDetail?.location || null, - floorModelVersion: events.floorDetail?.modelVersion || null, - floorSkipRate: events.floorDetail?.skipRate || 0, - isFloorSkipped: events.floorDetail?.skipped || false, - isWinningBid: true, - placementId: bidResponse.params ? deepAccess(bidResponse, 'params.0.placementId') : null, - renderedSize: bidResponse.size, - renderStatus: 4 - }); - return bid; - } +/** + * auctionCache is a global cache object which stores all auction histories + * for the session. When getting a key from the auction cache, any + * information already known about the auction or associated data (floor + * data configured by prebid, browser data, user data etc) is added to + * the cache automatically. + */ +export const auctionCache = new Proxy( + {}, + { + get: (target, name) => { + if (!target.hasOwnProperty(name)) { + target[name] = { + bids: [], + auctionDetail: { + refreshRank: Object.keys(target).length, + auctionId: name, + }, + floorDetail: {}, + pageDetail: { + host: getWindowLocation().host, + path: getWindowLocation().pathname, + search: getWindowLocation().search, + }, + deviceDetail: { + platform: navigator.platform, + deviceType: getDeviceType(), + deviceOS: getOS(), + browser: getBrowser(), + }, + userDetail: { + userIdTypes: Object.keys(getGlobal().getUserIds?.() || {}), + }, + consentDetail: { + consentTypes: Object.keys(getGlobal().getConsentMetadata?.() || {}), + }, + pmacDetail: JSON.parse(storage.getDataFromLocalStorage('pubx:pmac')) || {}, // {auction_1: {floor:0.23,maxBid:0.34,bidCount:3},auction_2:{floor:0.13,maxBid:0.14,bidCount:2} + initOptions: { + ...initOptions, + auctionId: name, // back-compat + }, + sendAs: [], + }; + } + return target[name]; + }, } -} +); -export function getDeviceType() { - if ((/ipad|android 3.0|xoom|sch-i800|playbook|tablet|kindle/i.test(navigator.userAgent.toLowerCase()))) { - return 'tablet'; +/** + * Fetch extra ad server data for a specific ad slot (bid) + * @param {object} bid an output from extractBid + * @returns {object} key value pairs from the adserver + */ +const getAdServerDataForBid = (bid) => { + const gptSlot = getGptSlotForAdUnitCode(bid); + if (gptSlot) { + return Object.fromEntries( + gptSlot + .getTargetingKeys() + .filter( + (key) => + key.startsWith('pubx-') || + (key.startsWith('hb_') && (key.match(/_/g) || []).length === 1) + ) + .map((key) => [key, gptSlot.getTargeting(key)]) + ); } - if ((/iphone|ipod|android|blackberry|opera|mini|windows\sce|palm|smartphone|iemobile/i.test(navigator.userAgent.toLowerCase()))) { - return 'mobile'; - } - return 'desktop'; -} + return {}; // TODO: support more ad servers +}; -export function getBrowser() { - if (/Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor)) return 'Chrome'; - else if (navigator.userAgent.match('CriOS')) return 'Chrome'; - else if (/Firefox/.test(navigator.userAgent)) return 'Firefox'; - else if (/Edg/.test(navigator.userAgent)) return 'Microsoft Edge'; - else if (/Safari/.test(navigator.userAgent) && /Apple Computer/.test(navigator.vendor)) return 'Safari'; - else if (/Trident/.test(navigator.userAgent) || /MSIE/.test(navigator.userAgent)) return 'Internet Explorer'; - else return 'Others'; -} +/** + * extracts and derives valuable data from a prebid bidder bidResponse object + * @param {object} bidResponse a prebid bidder bidResponse (see + * https://docs.prebid.org/dev-docs/publisher-api-reference/getBidResponses.html) + * @returns {object} + */ +const extractBid = (bidResponse) => { + return { + adUnitCode: bidResponse.adUnitCode, + gptSlotCode: + getGptSlotInfoForAdUnitCode(bidResponse.adUnitCode).gptSlot || null, + auctionId: bidResponse.auctionId, + bidderCode: bidResponse.bidder, + cpm: bidResponse.cpm, + creativeId: bidResponse.creativeId, + dealId: bidResponse.dealId, + currency: bidResponse.currency, + floorData: bidResponse.floorData, + mediaType: bidResponse.mediaType, + netRevenue: bidResponse.netRevenue, + requestTimestamp: bidResponse.requestTimestamp, + responseTimestamp: bidResponse.responseTimestamp, + status: bidResponse.status, + sizes: parseSizesInput(bidResponse.size).toString(), + statusMessage: bidResponse.statusMessage, + timeToRespond: bidResponse.timeToRespond, + transactionId: bidResponse.transactionId, + bidId: bidResponse.bidId || bidResponse.requestId, + placementId: bidResponse.params + ? deepAccess(bidResponse, 'params.0.placementId') + : null, + source: bidResponse.source || 'null', + }; +}; -export function getOS() { - if (navigator.userAgent.indexOf('Android') != -1) return 'Android'; - if (navigator.userAgent.indexOf('like Mac') != -1) return 'iOS'; - if (navigator.userAgent.indexOf('Win') != -1) return 'Windows'; - if (navigator.userAgent.indexOf('Mac') != -1) return 'Macintosh'; - if (navigator.userAgent.indexOf('Linux') != -1) return 'Linux'; - if (navigator.appVersion.indexOf('X11') != -1) return 'Unix'; - return 'Others'; -} +/** + * Track the events emitted by prebid and handle each case. See https://docs.prebid.org/dev-docs/publisher-api-reference/getEvents.html for more info + * @param {object} event the prebid event emmitted + * @param {string} event.eventType the type of the event + * @param {object} event.args the arguments of the emitted event + */ +const track = ({ eventType, args }) => { + switch (eventType) { + // handle invalid bids, and remove them from the adUnit cache + case EVENTS.BID_TIMEOUT: + args.map(extractBid).forEach((bid) => { + bid.renderStatus = 3; + auctionCache[bid.auctionId].bids.push(bid); + }); + break; + // handle valid bid responses and record them as part of an auction + case EVENTS.BID_RESPONSE: + const bid = Object.assign(extractBid(args), { renderStatus: 2 }); + auctionCache[bid.auctionId].bids.push(bid); + break; + // capture extra information from the auction, and if there were no bids + // (and so no chance of a win) send the auction + case EVENTS.AUCTION_END: + Object.assign( + auctionCache[args.auctionId].floorDetail, + args.adUnits + .map((i) => i?.bids.length && i.bids[0]?.floorData) + .find((i) => i) || {} + ); + auctionCache[args.auctionId].deviceDetail.cdep = args.bidderRequests + .map((bidRequest) => bidRequest.ortb2?.device?.ext?.cdep) + .find((i) => i); + Object.assign(auctionCache[args.auctionId].auctionDetail, { + adUnitCodes: args.adUnits.map((i) => i.code), + timestamp: args.timestamp, + }); + if ( + auctionCache[args.auctionId].bids.every((bid) => bid.renderStatus === 3) + ) { + prepareSend(args.auctionId); + } + break; + // send the prebid winning bid back to pubx + case EVENTS.BID_WON: + const winningBid = extractBid(args); + const floorDetail = auctionCache[winningBid.auctionId].floorDetail; + Object.assign(winningBid, { + floorProvider: floorDetail?.floorProvider || null, + floorFetchStatus: floorDetail?.fetchStatus || null, + floorLocation: floorDetail?.location || null, + floorModelVersion: floorDetail?.modelVersion || null, + floorSkipRate: floorDetail?.skipRate || 0, + isFloorSkipped: floorDetail?.skipped || false, + isWinningBid: true, + renderedSize: args.size, + renderStatus: 4, + }); + winningBid.adServerData = getAdServerDataForBid(winningBid); + auctionCache[winningBid.auctionId].winningBid = winningBid; + prepareSend(winningBid.auctionId); + break; + // do nothing + default: + break; + } +}; -// add sampling rate -pubxaiAnalyticsAdapter.shouldFireEventRequest = function (samplingRate = 1) { - return (Math.floor((Math.random() * samplingRate + 1)) === parseInt(samplingRate)); +/** + * If true, send data back to pubxai + * @param {string} auctionId + * @param {number} samplingRate + * @returns {boolean} + */ +const shouldFireEventRequest = (auctionId, samplingRate = 1) => { + return parseInt(cyrb53Hash(auctionId)) % samplingRate === 0; }; -function send(data, status) { - if (pubxaiAnalyticsAdapter.shouldFireEventRequest(initOptions.samplingRate)) { - let location = getWindowLocation(); - const storage = getStorage(); - data.initOptions = initOptions; - data.pageDetail = {}; - Object.assign(data.pageDetail, { - host: location.host, - path: location.pathname, - search: location.search - }); - if (typeof data !== 'undefined' && typeof data.auctionInit !== 'undefined') { - data.pageDetail.adUnits = data.auctionInit.adUnitCodes; - data.initOptions.auctionId = data.auctionInit.auctionId; - delete data.auctionInit; - - data.pmcDetail = {}; - Object.assign(data.pmcDetail, { - bidDensity: storage ? storage.getItem('pbx:dpbid') : null, - maxBid: storage ? storage.getItem('pbx:mxbid') : null, - auctionId: storage ? storage.getItem('pbx:aucid') : null, - }); +/** + * prepare the payload for sending auction data back to pubx.ai + * @param {string} auctionId the auction to send + */ +const prepareSend = (auctionId) => { + const auctionData = Object.assign({}, auctionCache[auctionId]); + if (!shouldFireEventRequest(auctionId, initOptions.samplingRate)) { + return; + } + [ + { + path: winningBidPath, + requiredKeys: [ + 'winningBid', + 'pageDetail', + 'deviceDetail', + 'floorDetail', + 'auctionDetail', + 'userDetail', + 'consentDetail', + 'pmacDetail', + 'initOptions', + ], + eventType: 'win', + }, + { + path: auctionPath, + requiredKeys: [ + 'bids', + 'pageDetail', + 'deviceDetail', + 'floorDetail', + 'auctionDetail', + 'userDetail', + 'consentDetail', + 'pmacDetail', + 'initOptions', + ], + eventType: 'auction', + }, + ].forEach(({ path, requiredKeys, eventType }) => { + const data = Object.fromEntries( + requiredKeys.map((key) => [key, auctionData[key]]) + ); + if ( + auctionCache[auctionId].sendAs.includes(eventType) || + !requiredKeys.every((key) => !!auctionData[key]) + ) { + return; } - data.deviceDetail = {}; - Object.assign(data.deviceDetail, { - platform: navigator.platform, - deviceType: getDeviceType(), - deviceOS: getOS(), - browser: getBrowser() - }); - - let pubxaiAnalyticsRequestUrl = buildUrl({ + const pubxaiAnalyticsRequestUrl = buildUrl({ protocol: 'https', - hostname: (initOptions && initOptions.hostName) || defaultHost, - pathname: status == 'bidwon' ? winningBidPath : auctionPath, + hostname: + (auctionData.initOptions && auctionData.initOptions.hostName) || + defaultHost, + pathname: path, search: { - auctionTimestamp: auctionTimestamp, + auctionTimestamp: auctionData.auctionDetail.timestamp, pubxaiAnalyticsVersion: pubxaiAnalyticsVersion, - prebidVersion: getGlobal().version + prebidVersion: '$prebid.version$', + }, + }); + sendCache[pubxaiAnalyticsRequestUrl].push(data); + auctionCache[auctionId].sendAs.push(eventType); + }); +}; + +const send = () => { + const toBlob = (d) => new Blob([JSON.stringify(d)], { type: 'text/json' }); + + Object.entries(sendCache).forEach(([requestUrl, events]) => { + let payloadStart = 0; + + events.forEach((event, index, arr) => { + const payload = arr.slice(payloadStart, index + 2); + const payloadTooLarge = toBlob(payload).size > 65536; + + if (payloadTooLarge || index + 1 === arr.length) { + sendBeacon( + requestUrl, + toBlob(payloadTooLarge ? payload.slice(0, -1) : payload) + ); + payloadStart = index; } }); - if (status == 'bidwon') { - ajax(pubxaiAnalyticsRequestUrl, undefined, JSON.stringify(data), { method: 'POST', contentType: 'text/json' }); - } else if (status == 'auctionEnd' && auctionCache.indexOf(data.initOptions.auctionId) === -1) { - ajax(pubxaiAnalyticsRequestUrl, undefined, JSON.stringify(data), { method: 'POST', contentType: 'text/json' }); - auctionCache.push(data.initOptions.auctionId); + + events.splice(0); + }); +}; + +// register event listener to send logs when user leaves page +if (document.visibilityState) { + document.addEventListener('visibilitychange', () => { + if (document.visibilityState === 'hidden') { + send(); } - } + }); } -pubxaiAnalyticsAdapter.originEnableAnalytics = pubxaiAnalyticsAdapter.enableAnalytics; -pubxaiAnalyticsAdapter.enableAnalytics = function (config) { +// declare the analytics adapter +var pubxaiAnalyticsAdapter = Object.assign( + adapter({ + emptyUrl, + analyticsType, + }), + { track } +); + +pubxaiAnalyticsAdapter.originEnableAnalytics = + pubxaiAnalyticsAdapter.enableAnalytics; +pubxaiAnalyticsAdapter.enableAnalytics = (config) => { initOptions = config.options; pubxaiAnalyticsAdapter.originEnableAnalytics(config); }; adapterManager.registerAnalyticsAdapter({ adapter: pubxaiAnalyticsAdapter, - code: 'pubxai' + code: adapterCode, }); export default pubxaiAnalyticsAdapter; diff --git a/modules/relevatehealthBidAdapter.js b/modules/relevatehealthBidAdapter.js index 1d60e7f67cc..e010f3d8fcd 100644 --- a/modules/relevatehealthBidAdapter.js +++ b/modules/relevatehealthBidAdapter.js @@ -142,7 +142,8 @@ function buildUser(bid) { if (bid && bid.params) { return { id: bid.params.user_id && typeof bid.params.user_id == 'string' ? bid.params.user_id : '', - buyeruid: localStorage.getItem('adx_profile_guid') ? localStorage.getItem('adx_profile_guid') : '', + // TODO: commented out because of rule violations + buyeruid: '', // localStorage.getItem('adx_profile_guid') ? localStorage.getItem('adx_profile_guid') : '', keywords: bid.params.keywords && typeof bid.params.keywords == 'string' ? bid.params.keywords : '', customdata: bid.params.customdata && typeof bid.params.customdata == 'string' ? bid.params.customdata : '' }; diff --git a/modules/resetdigitalBidAdapter.md b/modules/resetdigitalBidAdapter.md index a368c7f5633..64b600a7cc0 100644 --- a/modules/resetdigitalBidAdapter.md +++ b/modules/resetdigitalBidAdapter.md @@ -3,7 +3,7 @@ ``` Module Name: ResetDigital Bidder Adapter Module Type: Bidder Adapter -Maintainer: bruce@resetdigital.co +Maintainer: BidderSupport@resetdigital.co ``` # Description @@ -15,49 +15,58 @@ Video is supported but requires a publisher supplied renderer at this time. ## Web ``` - var adUnits = [ - { - code: 'your-div', - mediaTypes: { - banner: { - sizes: [[300,250]] - }, - - }, - bids: [ - { - bidder: "resetdigital", - params: { - pubId: "your-pub-id", - site_id: "your-site-id", - forceBid: true, - } - } - ] - } - ]; - - - var videoAdUnits = [ - { - code: 'your-div', - mediaTypes: { - video: { - playerSize: [640, 480] - }, - - }, - bids: [ - { - bidder: "resetdigital", - params: { - pubId: "your-pub-id", - site_id: "your-site-id", - forceBid: true, - } - } - ] - } - ]; +// Define the ad units for banner ads +var adUnits = [ + { + code: 'your-div', // Replace with the actual ad unit code + mediaTypes: { + banner: { + sizes: [[300, 250]] // Define the sizes for banner ads + } + }, + bids: [ + { + bidder: "resetdigital", + params: { + pubId: "your-pub-id", // (required) Replace with your publisher ID + site_id: "your-site-id", // Replace with your site ID + endpoint: 'https://ads.resetsrv.com', // (optional) Endpoint URL for the ad server + forceBid: true, // Optional parameter to force the bid + zoneId: { // (optional) Zone ID parameters + placementId: "", // Optional ID used for reports + deals: "", // Optional string of deal IDs, comma-separated + test: 1 // Set to 1 to force the bidder to respond with a creative + } + } + } + ] + } +]; +// Define the ad units for video ads +var videoAdUnits = [ + { + code: 'your-div', // Replace with the actual video ad unit code + mediaTypes: { + video: { + playerSize: [640, 480] // Define the player size for video ads + } + }, + bids: [ + { + bidder: "resetdigital", + params: { + pubId: "your-pub-id", // (required) Replace with your publisher ID + site_id: "your-site-id", // Replace with your site ID + forceBid: true, // Optional parameter to force the bid + zoneId: { // (optional) Zone ID parameters + placementId: "", // Optional ID used for reports + deals: "", // Optional string of deal IDs, comma-separated + test: 1 // Set to 1 to force the bidder to respond with a creative + } + } + } + ] + } +]; ``` diff --git a/modules/richaudienceBidAdapter.js b/modules/richaudienceBidAdapter.js index 98d628df181..c6a3a5427bd 100644 --- a/modules/richaudienceBidAdapter.js +++ b/modules/richaudienceBidAdapter.js @@ -151,7 +151,7 @@ export const spec = { * * @param {syncOptions} Publisher prebid configuration * @param {serverResponses} Response from the server - * @param {gdprConsent} GPDR consent object + * @param {gdprConsent} GDPR consent object * @returns {Array} */ getUserSyncs: function (syncOptions, responses, gdprConsent, uspConsent, gppConsent) { diff --git a/modules/riseBidAdapter.js b/modules/riseBidAdapter.js index 72170706fc0..236c048982a 100644 --- a/modules/riseBidAdapter.js +++ b/modules/riseBidAdapter.js @@ -2,18 +2,17 @@ import { logWarn, logInfo, isArray, - isFn, deepAccess, - isEmpty, - contains, - timestamp, triggerPixel, - isInteger, - getBidIdParameter } from '../src/utils.js'; -import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {BANNER, VIDEO} from '../src/mediaTypes.js'; -import {config} from '../src/config.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import { + getEndpoint, + generateBidsParams, + generateGeneralParams, + buildBidResponse, +} from '../libraries/riseUtils/index.js'; const SUPPORTED_AD_TYPES = [BANNER, VIDEO]; const BIDDER_CODE = 'rise'; @@ -21,15 +20,11 @@ const ADAPTER_VERSION = '6.0.0'; const TTL = 360; const DEFAULT_CURRENCY = 'USD'; const DEFAULT_GVLID = 1043; -const DEFAULT_SELLER_ENDPOINT = 'https://hb.yellowblue.io/'; +const BASE_URL = 'https://hb.yellowblue.io/'; const MODES = { PRODUCTION: 'hb-multi', TEST: 'hb-multi-test' -} -const SUPPORTED_SYNC_METHODS = { - IFRAME: 'iframe', - PIXEL: 'pixel' -} +}; export const spec = { code: BIDDER_CODE, @@ -59,48 +54,23 @@ export const spec = { // use data from the first bid, to create the general params for all bids const generalObject = validBidRequests[0]; const testMode = generalObject.params.testMode; - const rtbDomain = generalObject.params.rtbDomain; + const rtbDomain = generalObject.params.rtbDomain || BASE_URL; combinedRequestsObject.params = generateGeneralParams(generalObject, bidderRequest); combinedRequestsObject.bids = generateBidsParams(validBidRequests, bidderRequest); return { method: 'POST', - url: getEndpoint(testMode, rtbDomain), + url: getEndpoint(testMode, rtbDomain, MODES), data: combinedRequestsObject } }, - interpretResponse: function ({body}) { + interpretResponse: function ({ body }) { const bidResponses = []; if (body.bids) { body.bids.forEach(adUnit => { - const bidResponse = { - requestId: adUnit.requestId, - cpm: adUnit.cpm, - currency: adUnit.currency || DEFAULT_CURRENCY, - width: adUnit.width, - height: adUnit.height, - ttl: adUnit.ttl || TTL, - creativeId: adUnit.creativeId, - netRevenue: adUnit.netRevenue || true, - nurl: adUnit.nurl, - mediaType: adUnit.mediaType, - meta: { - mediaType: adUnit.mediaType - } - }; - - if (adUnit.mediaType === VIDEO) { - bidResponse.vastXml = adUnit.vastXml; - } else if (adUnit.mediaType === BANNER) { - bidResponse.ad = adUnit.ad; - } - - if (adUnit.adomain && adUnit.adomain.length) { - bidResponse.meta.advertiserDomains = adUnit.adomain; - } - + const bidResponse = buildBidResponse(adUnit, DEFAULT_CURRENCY, TTL, VIDEO, BANNER); bidResponses.push(bidResponse); }); } @@ -110,20 +80,20 @@ export const spec = { getUserSyncs: function (syncOptions, serverResponses) { const syncs = []; for (const response of serverResponses) { - if (syncOptions.iframeEnabled && response.body.params.userSyncURL) { + if (syncOptions.iframeEnabled && deepAccess(response, 'body.params.userSyncURL')) { syncs.push({ type: 'iframe', - url: response.body.params.userSyncURL + url: deepAccess(response, 'body.params.userSyncURL') }); } - if (syncOptions.pixelEnabled && isArray(response.body.params.userSyncPixels)) { + if (syncOptions.pixelEnabled && isArray(deepAccess(response, 'body.params.userSyncPixels'))) { const pixels = response.body.params.userSyncPixels.map(pixel => { return { type: 'image', url: pixel } - }) - syncs.push(...pixels) + }); + syncs.push(...pixels); } } return syncs; @@ -141,354 +111,3 @@ export const spec = { }; registerBidder(spec); - -/** - * Get floor price - * @param bid {bid} - * @param mediaType {string} - * @returns {Number} - */ -function getFloor(bid, mediaType) { - if (!isFn(bid.getFloor)) { - return 0; - } - let floorResult = bid.getFloor({ - currency: DEFAULT_CURRENCY, - mediaType: mediaType, - size: '*' - }); - return floorResult.currency === DEFAULT_CURRENCY && floorResult.floor ? floorResult.floor : 0; -} - -/** - * Get the the ad sizes array from the bid - * @param bid {bid} - * @returns {Array} - */ -function getSizesArray(bid, mediaType) { - let sizesArray = [] - - if (deepAccess(bid, `mediaTypes.${mediaType}.sizes`)) { - sizesArray = bid.mediaTypes[mediaType].sizes; - } else if (Array.isArray(bid.sizes) && bid.sizes.length > 0) { - sizesArray = bid.sizes; - } - - return sizesArray; -} - -/** - * Get schain string value - * @param schainObject {Object} - * @returns {string} - */ -function getSupplyChain(schainObject) { - if (isEmpty(schainObject)) { - return ''; - } - let scStr = `${schainObject.ver},${schainObject.complete}`; - schainObject.nodes.forEach((node) => { - scStr += '!'; - scStr += `${getEncodedValIfNotEmpty(node.asi)},`; - scStr += `${getEncodedValIfNotEmpty(node.sid)},`; - scStr += `${node.hp ? encodeURIComponent(node.hp) : ''},`; - scStr += `${getEncodedValIfNotEmpty(node.rid)},`; - scStr += `${getEncodedValIfNotEmpty(node.name)},`; - scStr += `${getEncodedValIfNotEmpty(node.domain)}`; - }); - return scStr; -} - -/** - * Get encoded node value - * @param val {string} - * @returns {string} - */ -function getEncodedValIfNotEmpty(val) { - return !isEmpty(val) ? encodeURIComponent(val) : ''; -} - -/** - * Get preferred user-sync method based on publisher configuration - * @param bidderCode {string} - * @returns {string} - */ -function getAllowedSyncMethod(filterSettings, bidderCode) { - const iframeConfigsToCheck = ['all', 'iframe']; - const pixelConfigToCheck = 'image'; - if (filterSettings && iframeConfigsToCheck.some(config => isSyncMethodAllowed(filterSettings[config], bidderCode))) { - return SUPPORTED_SYNC_METHODS.IFRAME; - } - if (!filterSettings || !filterSettings[pixelConfigToCheck] || isSyncMethodAllowed(filterSettings[pixelConfigToCheck], bidderCode)) { - return SUPPORTED_SYNC_METHODS.PIXEL; - } -} - -/** - * Check if sync rule is supported - * @param syncRule {Object} - * @param bidderCode {string} - * @returns {boolean} - */ -function isSyncMethodAllowed(syncRule, bidderCode) { - if (!syncRule) { - return false; - } - const isInclude = syncRule.filter === 'include'; - const bidders = isArray(syncRule.bidders) ? syncRule.bidders : [bidderCode]; - return isInclude && contains(bidders, bidderCode); -} - -/** - * Get the seller endpoint - * @param testMode {boolean} - * @param rtbDomain {string} - * @returns {string} - */ -function getEndpoint(testMode, rtbDomain) { - const SELLER_ENDPOINT = rtbDomain ? `https://${rtbDomain}/` : DEFAULT_SELLER_ENDPOINT; - return testMode - ? SELLER_ENDPOINT + MODES.TEST - : SELLER_ENDPOINT + MODES.PRODUCTION; -} - -/** - * get device type - * @param uad {ua} - * @returns {string} - */ -function getDeviceType(ua) { - if (/ipad|android 3.0|xoom|sch-i800|playbook|tablet|kindle/i - .test(ua.toLowerCase())) { - return '5'; - } - if (/iphone|ipod|android|blackberry|opera|mini|windows\sce|palm|smartphone|iemobile/i - .test(ua.toLowerCase())) { - return '4'; - } - if (/smart[-_\s]?tv|hbbtv|appletv|googletv|hdmi|netcast|viera|nettv|roku|\bdtv\b|sonydtv|inettvbrowser|\btv\b/i - .test(ua.toLowerCase())) { - return '3'; - } - return '1'; -} - -function generateBidsParams(validBidRequests, bidderRequest) { - const bidsArray = []; - - if (validBidRequests.length) { - validBidRequests.forEach(bid => { - bidsArray.push(generateBidParameters(bid, bidderRequest)); - }); - } - - return bidsArray; -} - -/** - * Generate bid specific parameters - * @param {bid} bid - * @param {bidderRequest} bidderRequest - * @returns {Object} bid specific params object - */ -function generateBidParameters(bid, bidderRequest) { - const {params} = bid; - const mediaType = isBanner(bid) ? BANNER : VIDEO; - const sizesArray = getSizesArray(bid, mediaType); - // fix floor price in case of NAN - if (isNaN(params.floorPrice)) { - params.floorPrice = 0; - } - - const bidObject = { - mediaType, - adUnitCode: getBidIdParameter('adUnitCode', bid), - sizes: sizesArray, - floorPrice: Math.max(getFloor(bid, mediaType), params.floorPrice), - bidId: getBidIdParameter('bidId', bid), - bidderRequestId: getBidIdParameter('bidderRequestId', bid), - loop: getBidIdParameter('bidderRequestsCount', bid), - transactionId: bid.ortb2Imp?.ext?.tid, - coppa: 0, - }; - - const pos = deepAccess(bid, `mediaTypes.${mediaType}.pos`); - if (pos) { - bidObject.pos = pos; - } - - const gpid = deepAccess(bid, `ortb2Imp.ext.gpid`); - if (gpid) { - bidObject.gpid = gpid; - } - - const placementId = params.placementId || deepAccess(bid, `mediaTypes.${mediaType}.name`); - if (placementId) { - bidObject.placementId = placementId; - } - - const mimes = deepAccess(bid, `mediaTypes.${mediaType}.mimes`); - if (mimes) { - bidObject.mimes = mimes; - } - - const api = deepAccess(bid, `mediaTypes.${mediaType}.api`); - if (api) { - bidObject.api = api; - } - - const sua = deepAccess(bid, `ortb2.device.sua`); - if (sua) { - bidObject.sua = sua; - } - - const coppa = deepAccess(bid, `ortb2.regs.coppa`) - if (coppa) { - bidObject.coppa = 1; - } - - if (mediaType === VIDEO) { - const playbackMethod = deepAccess(bid, `mediaTypes.video.playbackmethod`); - let playbackMethodValue; - - // verify playbackMethod is of type integer array, or integer only. - if (Array.isArray(playbackMethod) && isInteger(playbackMethod[0])) { - // only the first playbackMethod in the array will be used, according to OpenRTB 2.5 recommendation - playbackMethodValue = playbackMethod[0]; - } else if (isInteger(playbackMethod)) { - playbackMethodValue = playbackMethod; - } - - if (playbackMethodValue) { - bidObject.playbackMethod = playbackMethodValue; - } - - const placement = deepAccess(bid, `mediaTypes.video.placement`); - if (placement) { - bidObject.placement = placement; - } - - const minDuration = deepAccess(bid, `mediaTypes.video.minduration`); - if (minDuration) { - bidObject.minDuration = minDuration; - } - - const maxDuration = deepAccess(bid, `mediaTypes.video.maxduration`); - if (maxDuration) { - bidObject.maxDuration = maxDuration; - } - - const skip = deepAccess(bid, `mediaTypes.video.skip`); - if (skip) { - bidObject.skip = skip; - } - - const linearity = deepAccess(bid, `mediaTypes.video.linearity`); - if (linearity) { - bidObject.linearity = linearity; - } - - const protocols = deepAccess(bid, `mediaTypes.video.protocols`); - if (protocols) { - bidObject.protocols = protocols; - } - - const plcmt = deepAccess(bid, `mediaTypes.video.plcmt`); - if (plcmt) { - bidObject.plcmt = plcmt; - } - } - - return bidObject; -} - -function isBanner(bid) { - return bid.mediaTypes && bid.mediaTypes.banner; -} - -/** - * Generate params that are common between all bids - * @param {single bid object} generalObject - * @param {bidderRequest} bidderRequest - * @returns {object} the common params object - */ -function generateGeneralParams(generalObject, bidderRequest) { - const domain = window.location.hostname; - const {syncEnabled, filterSettings} = config.getConfig('userSync') || {}; - const {bidderCode} = bidderRequest; - const generalBidParams = generalObject.params; - const timeout = bidderRequest.timeout; - - // these params are snake_case instead of camelCase to allow backwards compatability on the server. - // in the future, these will be converted to camelCase to match our convention. - const generalParams = { - wrapper_type: 'prebidjs', - wrapper_vendor: '$$PREBID_GLOBAL$$', - wrapper_version: '$prebid.version$', - adapter_version: ADAPTER_VERSION, - auction_start: timestamp(), - publisher_id: generalBidParams.org, - publisher_name: domain, - site_domain: domain, - dnt: (navigator.doNotTrack == 'yes' || navigator.doNotTrack == '1' || navigator.msDoNotTrack == '1') ? 1 : 0, - device_type: getDeviceType(navigator.userAgent), - ua: navigator.userAgent, - is_wrapper: !!generalBidParams.isWrapper, - session_id: generalBidParams.sessionId || getBidIdParameter('bidderRequestId', generalObject), - tmax: timeout - }; - - const userIdsParam = getBidIdParameter('userId', generalObject); - if (userIdsParam) { - generalParams.userIds = JSON.stringify(userIdsParam); - } - - const ortb2Metadata = bidderRequest.ortb2 || {}; - if (ortb2Metadata.site) { - generalParams.site_metadata = JSON.stringify(ortb2Metadata.site); - } - if (ortb2Metadata.user) { - generalParams.user_metadata = JSON.stringify(ortb2Metadata.user); - } - - if (syncEnabled) { - const allowedSyncMethod = getAllowedSyncMethod(filterSettings, bidderCode); - if (allowedSyncMethod) { - generalParams.cs_method = allowedSyncMethod; - } - } - - if (bidderRequest.uspConsent) { - generalParams.us_privacy = bidderRequest.uspConsent; - } - - if (bidderRequest && bidderRequest.gdprConsent && bidderRequest.gdprConsent.gdprApplies) { - generalParams.gdpr = bidderRequest.gdprConsent.gdprApplies; - generalParams.gdpr_consent = bidderRequest.gdprConsent.consentString; - } - - if (bidderRequest && bidderRequest.gppConsent) { - generalParams.gpp = bidderRequest.gppConsent.gppString; - generalParams.gpp_sid = bidderRequest.gppConsent.applicableSections; - } else if (bidderRequest.ortb2?.regs?.gpp) { - generalParams.gpp = bidderRequest.ortb2.regs.gpp; - generalParams.gpp_sid = bidderRequest.ortb2.regs.gpp_sid; - } - - if (generalBidParams.ifa) { - generalParams.ifa = generalBidParams.ifa; - } - - if (generalObject.schain) { - generalParams.schain = getSupplyChain(generalObject.schain); - } - - if (bidderRequest && bidderRequest.refererInfo) { - // TODO: is 'ref' the right value here? - generalParams.referrer = deepAccess(bidderRequest, 'refererInfo.ref'); - // TODO: does the fallback make sense here? - generalParams.page_url = deepAccess(bidderRequest, 'refererInfo.page') || deepAccess(window, 'location.href'); - } - - return generalParams; -} diff --git a/modules/rtdModule/index.js b/modules/rtdModule/index.js index 0c654fc28b0..18736c6b0ec 100644 --- a/modules/rtdModule/index.js +++ b/modules/rtdModule/index.js @@ -188,10 +188,12 @@ let _dataProviders = []; let _userConsent; /** - * Register a RTD submodule. + * Register a Real-Time Data (RTD) submodule. * - * @param {RtdSubmodule} submodule - * @returns {function()} a de-registration function that will unregister the module when called. + * @param {Object} submodule The RTD submodule to register. + * @param {string} submodule.name The name of the RTD submodule. + * @param {number} [submodule.gvlid] The Global Vendor List ID (GVLID) of the RTD submodule. + * @returns {function(): void} A de-registration function that will unregister the module when called. */ export function attachRealTimeDataProvider(submodule) { registeredSubModules.push(submodule); diff --git a/modules/shinezBidAdapter.js b/modules/shinezBidAdapter.js index 993c069ded0..89f39284bed 100644 --- a/modules/shinezBidAdapter.js +++ b/modules/shinezBidAdapter.js @@ -2,33 +2,28 @@ import { logWarn, logInfo, isArray, - isFn, deepAccess, - isEmpty, - contains, - timestamp, triggerPixel, - isInteger, - getBidIdParameter } from '../src/utils.js'; -import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {BANNER, VIDEO} from '../src/mediaTypes.js'; -import {config} from '../src/config.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import { + getEndpoint, + generateBidsParams, + generateGeneralParams, + buildBidResponse, +} from '../libraries/riseUtils/index.js'; const SUPPORTED_AD_TYPES = [BANNER, VIDEO]; const BIDDER_CODE = 'shinez'; const ADAPTER_VERSION = '1.0.0'; const TTL = 360; const CURRENCY = 'USD'; -const SELLER_ENDPOINT = 'https://hb.sweetgum.io/'; +const BASE_URL = 'https://hb.sweetgum.io/'; const MODES = { PRODUCTION: 'hb-sz-multi', TEST: 'hb-multi-sz-test' -} -const SUPPORTED_SYNC_METHODS = { - IFRAME: 'iframe', - PIXEL: 'pixel' -} +}; export const spec = { code: BIDDER_CODE, @@ -59,7 +54,7 @@ export const spec = { return { method: 'POST', - url: getEndpoint(testMode), + url: getEndpoint(testMode, BASE_URL, MODES), data: combinedRequestsObject } }, @@ -68,32 +63,7 @@ export const spec = { if (body.bids) { body.bids.forEach(adUnit => { - const bidResponse = { - requestId: adUnit.requestId, - cpm: adUnit.cpm, - currency: adUnit.currency || CURRENCY, - width: adUnit.width, - height: adUnit.height, - ttl: adUnit.ttl || TTL, - creativeId: adUnit.requestId, - netRevenue: adUnit.netRevenue || true, - nurl: adUnit.nurl, - mediaType: adUnit.mediaType, - meta: { - mediaType: adUnit.mediaType - } - }; - - if (adUnit.mediaType === VIDEO) { - bidResponse.vastXml = adUnit.vastXml; - } else if (adUnit.mediaType === BANNER) { - bidResponse.ad = adUnit.ad; - } - - if (adUnit.adomain && adUnit.adomain.length) { - bidResponse.meta.advertiserDomains = adUnit.adomain; - } - + const bidResponse = buildBidResponse(adUnit, CURRENCY, TTL, VIDEO, BANNER); bidResponses.push(bidResponse); }); } @@ -103,20 +73,20 @@ export const spec = { getUserSyncs: function (syncOptions, serverResponses) { const syncs = []; for (const response of serverResponses) { - if (syncOptions.iframeEnabled && response.body.params.userSyncURL) { + if (syncOptions.iframeEnabled && deepAccess(response, 'body.params.userSyncURL')) { syncs.push({ type: 'iframe', - url: response.body.params.userSyncURL + url: deepAccess(response, 'body.params.userSyncURL') }); } - if (syncOptions.pixelEnabled && isArray(response.body.params.userSyncPixels)) { + if (syncOptions.pixelEnabled && isArray(deepAccess(response, 'body.params.userSyncPixels'))) { const pixels = response.body.params.userSyncPixels.map(pixel => { return { type: 'image', url: pixel } - }) - syncs.push(...pixels) + }); + syncs.push(...pixels); } } return syncs; @@ -134,317 +104,3 @@ export const spec = { }; registerBidder(spec); - -/** - * Get floor price - * @param bid {bid} - * @returns {Number} - */ -function getFloor(bid, mediaType) { - if (!isFn(bid.getFloor)) { - return 0; - } - let floorResult = bid.getFloor({ - currency: CURRENCY, - mediaType: mediaType, - size: '*' - }); - return floorResult.currency === CURRENCY && floorResult.floor ? floorResult.floor : 0; -} - -/** - * Get the the ad sizes array from the bid - * @param bid {bid} - * @returns {Array} - */ -function getSizesArray(bid, mediaType) { - let sizesArray = [] - - if (deepAccess(bid, `mediaTypes.${mediaType}.sizes`)) { - sizesArray = bid.mediaTypes[mediaType].sizes; - } else if (Array.isArray(bid.sizes) && bid.sizes.length > 0) { - sizesArray = bid.sizes; - } - - return sizesArray; -} - -/** - * Get schain string value - * @param schainObject {Object} - * @returns {string} - */ -function getSupplyChain(schainObject) { - if (isEmpty(schainObject)) { - return ''; - } - let scStr = `${schainObject.ver},${schainObject.complete}`; - schainObject.nodes.forEach((node) => { - scStr += '!'; - scStr += `${getEncodedValIfNotEmpty(node.asi)},`; - scStr += `${getEncodedValIfNotEmpty(node.sid)},`; - scStr += `${node.hp ? encodeURIComponent(node.hp) : ''},`; - scStr += `${getEncodedValIfNotEmpty(node.rid)},`; - scStr += `${getEncodedValIfNotEmpty(node.name)},`; - scStr += `${getEncodedValIfNotEmpty(node.domain)}`; - }); - return scStr; -} - -/** - * Get encoded node value - * @param val {string} - * @returns {string} - */ -function getEncodedValIfNotEmpty(val) { - return !isEmpty(val) ? encodeURIComponent(val) : ''; -} - -/** - * Get preferred user-sync method based on publisher configuration - * @param bidderCode {string} - * @returns {string} - */ -function getAllowedSyncMethod(filterSettings, bidderCode) { - const iframeConfigsToCheck = ['all', 'iframe']; - const pixelConfigToCheck = 'image'; - if (filterSettings && iframeConfigsToCheck.some(config => isSyncMethodAllowed(filterSettings[config], bidderCode))) { - return SUPPORTED_SYNC_METHODS.IFRAME; - } - if (!filterSettings || !filterSettings[pixelConfigToCheck] || isSyncMethodAllowed(filterSettings[pixelConfigToCheck], bidderCode)) { - return SUPPORTED_SYNC_METHODS.PIXEL; - } -} - -/** - * Check if sync rule is supported - * @param syncRule {Object} - * @param bidderCode {string} - * @returns {boolean} - */ -function isSyncMethodAllowed(syncRule, bidderCode) { - if (!syncRule) { - return false; - } - const isInclude = syncRule.filter === 'include'; - const bidders = isArray(syncRule.bidders) ? syncRule.bidders : [bidderCode]; - return isInclude && contains(bidders, bidderCode); -} - -/** - * Get the seller endpoint - * @param testMode {boolean} - * @returns {string} - */ -function getEndpoint(testMode) { - return testMode - ? SELLER_ENDPOINT + MODES.TEST - : SELLER_ENDPOINT + MODES.PRODUCTION; -} - -/** - * get device type - * @param uad {ua} - * @returns {string} - */ -function getDeviceType(ua) { - if (/ipad|android 3.0|xoom|sch-i800|playbook|tablet|kindle/i - .test(ua.toLowerCase())) { - return '5'; - } - if (/iphone|ipod|android|blackberry|opera|mini|windows\sce|palm|smartphone|iemobile/i - .test(ua.toLowerCase())) { - return '4'; - } - if (/smart[-_\s]?tv|hbbtv|appletv|googletv|hdmi|netcast|viera|nettv|roku|\bdtv\b|sonydtv|inettvbrowser|\btv\b/i - .test(ua.toLowerCase())) { - return '3'; - } - return '1'; -} - -function generateBidsParams(validBidRequests, bidderRequest) { - const bidsArray = []; - - if (validBidRequests.length) { - validBidRequests.forEach(bid => { - bidsArray.push(generateBidParameters(bid, bidderRequest)); - }); - } - - return bidsArray; -} - -/** - * Generate bid specific parameters - * @param {bid} bid - * @param {bidderRequest} bidderRequest - * @returns {Object} bid specific params object - */ -function generateBidParameters(bid, bidderRequest) { - const {params} = bid; - const mediaType = isBanner(bid) ? BANNER : VIDEO; - const sizesArray = getSizesArray(bid, mediaType); - - // fix floor price in case of NAN - if (isNaN(params.floorPrice)) { - params.floorPrice = 0; - } - - const bidObject = { - mediaType, - adUnitCode: getBidIdParameter('adUnitCode', bid), - sizes: sizesArray, - floorPrice: Math.max(getFloor(bid, mediaType), params.floorPrice), - bidId: getBidIdParameter('bidId', bid), - bidderRequestId: getBidIdParameter('bidderRequestId', bid), - transactionId: bid.ortb2Imp?.ext?.tid || '', - }; - - const pos = deepAccess(bid, `mediaTypes.${mediaType}.pos`); - if (pos) { - bidObject.pos = pos; - } - - const gpid = deepAccess(bid, `ortb2Imp.ext.gpid`); - if (gpid) { - bidObject.gpid = gpid; - } - - const placementId = params.placementId || deepAccess(bid, `mediaTypes.${mediaType}.name`); - if (placementId) { - bidObject.placementId = placementId; - } - - if (mediaType === VIDEO) { - const playbackMethod = deepAccess(bid, `mediaTypes.video.playbackmethod`); - let playbackMethodValue; - - // verify playbackMethod is of type integer array, or integer only. - if (Array.isArray(playbackMethod) && isInteger(playbackMethod[0])) { - // only the first playbackMethod in the array will be used, according to OpenRTB 2.5 recommendation - playbackMethodValue = playbackMethod[0]; - } else if (isInteger(playbackMethod)) { - playbackMethodValue = playbackMethod; - } - - if (playbackMethodValue) { - bidObject.playbackMethod = playbackMethodValue; - } - - const placement = deepAccess(bid, `mediaTypes.video.placement`); - if (placement) { - bidObject.placement = placement; - } - const plcmt = deepAccess(bid, `mediaTypes.video.plcmt`); - if (plcmt) { - bidObject.plcmt = plcmt; - } - const minDuration = deepAccess(bid, `mediaTypes.video.minduration`); - if (minDuration) { - bidObject.minDuration = minDuration; - } - - const maxDuration = deepAccess(bid, `mediaTypes.video.maxduration`); - if (maxDuration) { - bidObject.maxDuration = maxDuration; - } - - const skip = deepAccess(bid, `mediaTypes.video.skip`); - if (skip) { - bidObject.skip = skip; - } - - const linearity = deepAccess(bid, `mediaTypes.video.linearity`); - if (linearity) { - bidObject.linearity = linearity; - } - } - - return bidObject; -} - -function isBanner(bid) { - return bid.mediaTypes && bid.mediaTypes.banner; -} - -/** - * Generate params that are common between all bids - * @param {single bid object} generalObject - * @param {bidderRequest} bidderRequest - * @returns {object} the common params object - */ -function generateGeneralParams(generalObject, bidderRequest) { - const domain = window.location.hostname; - const {syncEnabled, filterSettings} = config.getConfig('userSync') || {}; - const {bidderCode} = bidderRequest; - const generalBidParams = generalObject.params; - const timeout = bidderRequest.timeout; - - // these params are snake_case instead of camelCase to allow backwards compatability on the server. - // in the future, these will be converted to camelCase to match our convention. - const generalParams = { - wrapper_type: 'prebidjs', - wrapper_vendor: '$$PREBID_GLOBAL$$', - wrapper_version: '$prebid.version$', - adapter_version: ADAPTER_VERSION, - auction_start: timestamp(), - publisher_id: generalBidParams.org, - publisher_name: domain, - site_domain: domain, - dnt: (navigator.doNotTrack == 'yes' || navigator.doNotTrack == '1' || navigator.msDoNotTrack == '1') ? 1 : 0, - device_type: getDeviceType(navigator.userAgent), - ua: navigator.userAgent, - session_id: getBidIdParameter('auctionId', generalObject), - tmax: timeout - }; - - const userIdsParam = getBidIdParameter('userId', generalObject); - if (userIdsParam) { - generalParams.userIds = JSON.stringify(userIdsParam); - } - - const ortb2Metadata = bidderRequest.ortb2 || {}; - if (ortb2Metadata.site) { - generalParams.site_metadata = JSON.stringify(ortb2Metadata.site); - } - if (ortb2Metadata.user) { - generalParams.user_metadata = JSON.stringify(ortb2Metadata.user); - } - - if (syncEnabled) { - const allowedSyncMethod = getAllowedSyncMethod(filterSettings, bidderCode); - if (allowedSyncMethod) { - generalParams.cs_method = allowedSyncMethod; - } - } - - if (bidderRequest.uspConsent) { - generalParams.us_privacy = bidderRequest.uspConsent; - } - - if (bidderRequest && bidderRequest.gdprConsent && bidderRequest.gdprConsent.gdprApplies) { - generalParams.gdpr = bidderRequest.gdprConsent.gdprApplies; - generalParams.gdpr_consent = bidderRequest.gdprConsent.consentString; - } - - if (generalBidParams.ifa) { - generalParams.ifa = generalBidParams.ifa; - } - - if (generalObject.schain) { - generalParams.schain = getSupplyChain(generalObject.schain); - } - - if (bidderRequest.ortb2 && bidderRequest.ortb2.site) { - generalParams.referrer = bidderRequest.ortb2.site.ref; - generalParams.page_url = bidderRequest.ortb2.site.page; - } - - if (bidderRequest && bidderRequest.refererInfo) { - generalParams.referrer = generalParams.referrer || deepAccess(bidderRequest, 'refererInfo.referer'); - generalParams.page_url = generalParams.page_url || config.getConfig('pageUrl') || deepAccess(window, 'location.href'); - } - - return generalParams; -} diff --git a/modules/shinezRtbBidAdapter.js b/modules/shinezRtbBidAdapter.js index 490ea908960..f2034bd1992 100644 --- a/modules/shinezRtbBidAdapter.js +++ b/modules/shinezRtbBidAdapter.js @@ -1,321 +1,29 @@ -import {_each, deepAccess, parseSizesInput, parseUrl, uniques, isFn} from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; import {getStorageManager} from '../src/storageManager.js'; -import {config} from '../src/config.js'; +import { + isBidRequestValid, + createBuildRequestsFn, + createInterpretResponseFn, createUserSyncGetter +} from '../libraries/vidazooUtils/bidderUtils.js'; const DEFAULT_SUB_DOMAIN = 'exchange'; const BIDDER_CODE = 'shinezRtb'; const BIDDER_VERSION = '1.0.0'; -const CURRENCY = 'USD'; -const TTL_SECONDS = 60 * 5; -const UNIQUE_DEAL_ID_EXPIRY = 1000 * 60 * 15; -const storage = getStorageManager({bidderCode: BIDDER_CODE}); - -function getTopWindowQueryParams() { - try { - const parsedUrl = parseUrl(window.top.document.URL, {decodeSearchAsString: true}); - return parsedUrl.search; - } catch (e) { - return ''; - } -} +export const storage = getStorageManager({bidderCode: BIDDER_CODE}); export function createDomain(subDomain = DEFAULT_SUB_DOMAIN) { return `https://${subDomain}.sweetgum.io`; } -export function extractCID(params) { - return params.cId || params.CID || params.cID || params.CId || params.cid || params.ciD || params.Cid || params.CiD; -} - -export function extractPID(params) { - return params.pId || params.PID || params.pID || params.PId || params.pid || params.piD || params.Pid || params.PiD; -} - -export function extractSubDomain(params) { - return params.subDomain || params.SubDomain || params.Subdomain || params.subdomain || params.SUBDOMAIN || params.subDOMAIN; -} - -function isBidRequestValid(bid) { - const params = bid.params || {}; - return !!(extractCID(params) && extractPID(params)); -} - -function buildRequest(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout) { - const { - params, - bidId, - userId, - adUnitCode, - schain, - mediaTypes, - ortb2Imp, - bidderRequestId, - bidRequestsCount, - bidderRequestsCount, - bidderWinsCount - } = bid; - let {bidFloor, ext} = params; - const hashUrl = hashCode(topWindowUrl); - const uniqueDealId = getUniqueDealId(hashUrl); - const cId = extractCID(params); - const pId = extractPID(params); - const subDomain = extractSubDomain(params); - - const gpid = deepAccess(bid, 'ortb2Imp.ext.gpid', deepAccess(bid, 'ortb2Imp.ext.data.pbadslot', '')); - - if (isFn(bid.getFloor)) { - const floorInfo = bid.getFloor({ - currency: 'USD', - mediaType: '*', - size: '*' - }); - - if (floorInfo.currency === 'USD') { - bidFloor = floorInfo.floor; - } - } - - let data = { - url: encodeURIComponent(topWindowUrl), - uqs: getTopWindowQueryParams(), - cb: Date.now(), - bidFloor: bidFloor, - bidId: bidId, - referrer: bidderRequest.refererInfo.ref, - adUnitCode: adUnitCode, - publisherId: pId, - sizes: sizes, - uniqueDealId: uniqueDealId, - bidderVersion: BIDDER_VERSION, - prebidVersion: '$prebid.version$', - res: `${screen.width}x${screen.height}`, - schain: schain, - mediaTypes: mediaTypes, - gpid: gpid, - transactionId: ortb2Imp?.ext?.tid, - bidderRequestId: bidderRequestId, - bidRequestsCount: bidRequestsCount, - bidderRequestsCount: bidderRequestsCount, - bidderWinsCount: bidderWinsCount, - bidderTimeout: bidderTimeout - }; - - appendUserIdsToRequestPayload(data, userId); - - const sua = deepAccess(bidderRequest, 'ortb2.device.sua'); - - if (sua) { - data.sua = sua; - } - - if (bidderRequest.gdprConsent) { - if (bidderRequest.gdprConsent.consentString) { - data.gdprConsent = bidderRequest.gdprConsent.consentString; - } - if (bidderRequest.gdprConsent.gdprApplies !== undefined) { - data.gdpr = bidderRequest.gdprConsent.gdprApplies ? 1 : 0; - } - } - if (bidderRequest.uspConsent) { - data.usPrivacy = bidderRequest.uspConsent; - } - - if (bidderRequest.gppConsent) { - data.gppString = bidderRequest.gppConsent.gppString; - data.gppSid = bidderRequest.gppConsent.applicableSections; - } else if (bidderRequest.ortb2?.regs?.gpp) { - data.gppString = bidderRequest.ortb2.regs.gpp; - data.gppSid = bidderRequest.ortb2.regs.gpp_sid; - } - - const dto = { - method: 'POST', - url: `${createDomain(subDomain)}/prebid/multi/${cId}`, - data: data - }; - - _each(ext, (value, key) => { - dto.data['ext.' + key] = value; - }); - - return dto; -} - -function appendUserIdsToRequestPayload(payloadRef, userIds) { - let key; - _each(userIds, (userId, idSystemProviderName) => { - key = `uid.${idSystemProviderName}`; +const buildRequests = createBuildRequestsFn(createDomain, null, storage, BIDDER_CODE, BIDDER_VERSION, false); - switch (idSystemProviderName) { - case 'lipb': - payloadRef[key] = userId.lipbid; - break; - case 'id5id': - payloadRef[key] = userId.uid; - break; - default: - payloadRef[key] = userId; - } - }); -} - -function buildRequests(validBidRequests, bidderRequest) { - const topWindowUrl = bidderRequest.refererInfo.page || bidderRequest.refererInfo.topmostLocation; - const bidderTimeout = config.getConfig('bidderTimeout'); - const requests = []; - validBidRequests.forEach(validBidRequest => { - const sizes = parseSizesInput(validBidRequest.sizes); - const request = buildRequest(validBidRequest, topWindowUrl, sizes, bidderRequest, bidderTimeout); - requests.push(request); - }); - return requests; -} - -function interpretResponse(serverResponse, request) { - if (!serverResponse || !serverResponse.body) { - return []; - } - const {bidId} = request.data; - const {results} = serverResponse.body; - - let output = []; - - try { - results.forEach(result => { - const { - creativeId, - ad, - price, - exp, - width, - height, - currency, - metaData, - advertiserDomains, - mediaType = BANNER - } = result; - if (!ad || !price) { - return; - } - - const response = { - requestId: bidId, - cpm: price, - width: width, - height: height, - creativeId: creativeId, - currency: currency || CURRENCY, - netRevenue: true, - ttl: exp || TTL_SECONDS, - }; - - if (metaData) { - Object.assign(response, { - meta: metaData - }) - } else { - Object.assign(response, { - meta: { - advertiserDomains: advertiserDomains || [] - } - }) - } - - if (mediaType === BANNER) { - Object.assign(response, { - ad: ad, - }); - } else { - Object.assign(response, { - vastXml: ad, - mediaType: VIDEO - }); - } - output.push(response); - }); - return output; - } catch (e) { - return []; - } -} - -function getUserSyncs(syncOptions, responses, gdprConsent = {}, uspConsent = '') { - let syncs = []; - const {iframeEnabled, pixelEnabled} = syncOptions; - const {gdprApplies, consentString = ''} = gdprConsent; - - const cidArr = responses.filter(resp => deepAccess(resp, 'body.cid')).map(resp => resp.body.cid).filter(uniques); - const params = `?cid=${encodeURIComponent(cidArr.join(','))}&gdpr=${gdprApplies ? 1 : 0}&gdpr_consent=${encodeURIComponent(consentString || '')}&us_privacy=${encodeURIComponent(uspConsent || '')}` - if (iframeEnabled) { - syncs.push({ - type: 'iframe', - url: `https://sync.sweetgum.io/api/sync/iframe/${params}` - }); - } - if (pixelEnabled) { - syncs.push({ - type: 'image', - url: `https://sync.sweetgum.io/api/sync/image/${params}` - }); - } - return syncs; -} +const interpretResponse = createInterpretResponseFn(BIDDER_CODE, false); -export function hashCode(s, prefix = '_') { - const l = s.length; - let h = 0 - let i = 0; - if (l > 0) { - while (i < l) { - h = (h << 5) - h + s.charCodeAt(i++) | 0; - } - } - return prefix + h; -} - -export function getUniqueDealId(key, expiry = UNIQUE_DEAL_ID_EXPIRY) { - const storageKey = `u_${key}`; - const now = Date.now(); - const data = getStorageItem(storageKey); - let uniqueId; - - if (!data || !data.value || now - data.created > expiry) { - uniqueId = `${key}_${now.toString()}`; - setStorageItem(storageKey, uniqueId); - } else { - uniqueId = data.value; - } - - return uniqueId; -} - -export function getStorageItem(key) { - try { - return tryParseJSON(storage.getDataFromLocalStorage(key)); - } catch (e) { - } - - return null; -} - -export function setStorageItem(key, value, timestamp) { - try { - const created = timestamp || Date.now(); - const data = JSON.stringify({value, created}); - storage.setDataInLocalStorage(key, data); - } catch (e) { - } -} - -export function tryParseJSON(value) { - try { - return JSON.parse(value); - } catch (e) { - return value; - } -} +const getUserSyncs = createUserSyncGetter({ + iframeSyncUrl: 'https://sync.sweetgum.io/api/sync/iframe', + imageSyncUrl: 'https://sync.sweetgum.io/api/sync/image', +}); export const spec = { code: BIDDER_CODE, diff --git a/modules/sirdataRtdProvider.js b/modules/sirdataRtdProvider.js index 9a222e20f9d..507d8d982f2 100644 --- a/modules/sirdataRtdProvider.js +++ b/modules/sirdataRtdProvider.js @@ -219,6 +219,8 @@ export function postContentForSemanticAnalysis(postContentToken, actualUrl) { // Use the Beacon API if supported to send the payload if ('sendBeacon' in navigator) { + // TODO FIX RULES VIOLATION + // eslint-disable-next-line prebid/no-member navigator.sendBeacon(url, payload); } else { // Fallback to using AJAX if Beacon API is not supported diff --git a/modules/sizeMapping.js b/modules/sizeMapping.js index eab85aa3d93..9b2a37d0235 100644 --- a/modules/sizeMapping.js +++ b/modules/sizeMapping.js @@ -4,7 +4,6 @@ import {includes} from '../src/polyfill.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; import {setupAdUnitMediaTypes} from '../src/adapterManager.js'; -let installed = false; let sizeConfig = []; /** @@ -24,11 +23,9 @@ let sizeConfig = []; */ export function setSizeConfig(config) { sizeConfig = config; - if (!installed) { - setupAdUnitMediaTypes.before((next, adUnit, labels) => next(processAdUnitsForLabels(adUnit, labels), labels)); - installed = true; - } } + +setupAdUnitMediaTypes.before((next, adUnit, labels) => next(processAdUnitsForLabels(adUnit, labels), labels)); config.getConfig('sizeConfig', config => setSizeConfig(config.sizeConfig)); /** diff --git a/modules/smaatoBidAdapter.js b/modules/smaatoBidAdapter.js index f6dbcfe6071..f8a363cb084 100644 --- a/modules/smaatoBidAdapter.js +++ b/modules/smaatoBidAdapter.js @@ -19,10 +19,11 @@ import {ortbConverter} from '../libraries/ortbConverter/converter.js'; const BIDDER_CODE = 'smaato'; const SMAATO_ENDPOINT = 'https://prebid.ad.smaato.net/oapi/prebid'; -const SMAATO_CLIENT = 'prebid_js_$prebid.version$_3.1' +const SMAATO_CLIENT = 'prebid_js_$prebid.version$_3.2' const TTL = 300; const CURRENCY = 'USD'; const SUPPORTED_MEDIA_TYPES = [BANNER, VIDEO, NATIVE]; +const SYNC_URL = 'https://s.ad.smaato.net/c/?adExInit=p' export const spec = { code: BIDDER_CODE, @@ -196,6 +197,22 @@ export const spec = { * @return {UserSync[]} The user syncs which should be dropped. */ getUserSyncs: (syncOptions, serverResponses, gdprConsent, uspConsent) => { + if (syncOptions && syncOptions.pixelEnabled) { + let gdprParams = ''; + if (gdprConsent && gdprConsent.consentString) { + if (typeof gdprConsent.gdprApplies === 'boolean') { + gdprParams = `&gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`; + } else { + gdprParams = `&gdpr_consent=${gdprConsent.consentString}`; + } + } + + return [{ + type: 'image', + url: SYNC_URL + gdprParams + }]; + } + return []; } } diff --git a/modules/smarthubBidAdapter.js b/modules/smarthubBidAdapter.js index b5970fbb9ee..baf4c358736 100644 --- a/modules/smarthubBidAdapter.js +++ b/modules/smarthubBidAdapter.js @@ -1,23 +1,28 @@ -import {deepAccess, isFn, logError, logMessage} from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; -import {config} from '../src/config.js'; -import {convertOrtbRequestToProprietaryNative} from '../src/native.js'; +import { + buildPlacementProcessingFunction, + buildRequestsBase, + interpretResponseBuilder, + isBidRequestValid +} from '../libraries/teqblazeUtils/bidderUtils.js'; const BIDDER_CODE = 'smarthub'; const ALIASES = [ {code: 'markapp', skipPbsAliasing: true}, {code: 'jdpmedia', skipPbsAliasing: true}, {code: 'tredio', skipPbsAliasing: true}, + {code: 'vimayx', skipPbsAliasing: true}, ]; const BASE_URLS = { smarthub: 'https://prebid.smart-hub.io/pbjs', markapp: 'https://markapp-prebid.smart-hub.io/pbjs', jdpmedia: 'https://jdpmedia-prebid.smart-hub.io/pbjs', - tredio: 'https://tredio-prebid.smart-hub.io/pbjs' + tredio: 'https://tredio-prebid.smart-hub.io/pbjs', + vimayx: 'https://vimayx-prebid.smart-hub.io/pbjs', }; -function getUrl(partnerName) { +const _getUrl = (partnerName) => { const aliases = ALIASES.map(el => el.code); if (aliases.includes(partnerName)) { return BASE_URLS[partnerName]; @@ -26,187 +31,50 @@ function getUrl(partnerName) { return `${BASE_URLS[BIDDER_CODE]}?partnerName=${partnerName}`; } -function isBidResponseValid(bid) { - if (!bid.requestId || !bid.cpm || !bid.creativeId || !bid.ttl || !bid.currency || !bid.hasOwnProperty('netRevenue')) { - return false; - } - switch (bid.mediaType) { - case BANNER: - return Boolean(bid.width && bid.height && bid.ad); - case VIDEO: - return Boolean(bid.width && bid.height && (bid.vastUrl || bid.vastXml)); - case NATIVE: - return Boolean(bid.native && bid.native.impressionTrackers && bid.native.impressionTrackers.length); - default: - return false; - } -} - -function getPlacementReqData(bid) { - const { params, bidId, mediaTypes, bidder } = bid; - const schain = bid.schain || {}; - const { partnerName, seat, token, iabCat, minBidfloor, pos } = params; - const bidfloor = getBidFloor(bid); - - const plcmt = { - partnerName: String(partnerName || bidder).toLowerCase(), - seat, - token, - iabCat, - minBidfloor, - pos, - bidId, - schain, - bidfloor, - }; - - if (mediaTypes && mediaTypes[BANNER]) { - plcmt.adFormat = BANNER; - plcmt.sizes = mediaTypes[BANNER].sizes; - } else if (mediaTypes && mediaTypes[VIDEO]) { - plcmt.adFormat = VIDEO; - plcmt.playerSize = mediaTypes[VIDEO].playerSize; - plcmt.minduration = mediaTypes[VIDEO].minduration; - plcmt.maxduration = mediaTypes[VIDEO].maxduration; - plcmt.mimes = mediaTypes[VIDEO].mimes; - plcmt.protocols = mediaTypes[VIDEO].protocols; - plcmt.startdelay = mediaTypes[VIDEO].startdelay; - plcmt.placement = mediaTypes[VIDEO].plcmt; - plcmt.plcmt = mediaTypes[VIDEO].plcmt; // https://github.com/prebid/Prebid.js/issues/10452 - plcmt.skip = mediaTypes[VIDEO].skip; - plcmt.skipafter = mediaTypes[VIDEO].skipafter; - plcmt.minbitrate = mediaTypes[VIDEO].minbitrate; - plcmt.maxbitrate = mediaTypes[VIDEO].maxbitrate; - plcmt.delivery = mediaTypes[VIDEO].delivery; - plcmt.playbackmethod = mediaTypes[VIDEO].playbackmethod; - plcmt.api = mediaTypes[VIDEO].api; - plcmt.linearity = mediaTypes[VIDEO].linearity; - } else if (mediaTypes && mediaTypes[NATIVE]) { - plcmt.native = mediaTypes[NATIVE]; - plcmt.adFormat = NATIVE; - } - - return plcmt; -} - -function getBidFloor(bid) { - if (!isFn(bid.getFloor)) { - return deepAccess(bid, 'params.bidfloor', 0); - } - - try { - const bidFloor = bid.getFloor({ - currency: 'USD', - mediaType: '*', - size: '*', +const getPartnerName = (bid) => String(bid.params?.partnerName || bid.bidder).toLowerCase(); + +const getPlacementReqData = buildPlacementProcessingFunction({ + addPlacementType() {}, + addCustomFieldsToPlacement(bid, bidderRequest, placement) { + const { seat, token, iabCat, minBidfloor, pos } = bid.params; + Object.assign(placement, { + partnerName: getPartnerName(bid), + seat, + token, + iabCat, + minBidfloor, + pos, }); - return bidFloor.floor; - } catch (e) { - logError(e); - return 0; - } -} - -function buildRequestParams(bidderRequest = {}, placements = []) { - let deviceWidth = 0; - let deviceHeight = 0; - - let winLocation; - try { - const winTop = window.top; - deviceWidth = winTop.screen.width; - deviceHeight = winTop.screen.height; - winLocation = winTop.location; - } catch (e) { - logMessage(e); - winLocation = window.location; - } - - const refferUrl = bidderRequest.refererInfo && bidderRequest.refererInfo.page; - let refferLocation; - try { - refferLocation = refferUrl && new URL(refferUrl); - } catch (e) { - logMessage(e); } - - let location = refferLocation || winLocation; - const language = (navigator && navigator.language) ? navigator.language.split('-')[0] : ''; - const host = location.host; - const page = location.pathname; - const secure = location.protocol === 'https:' ? 1 : 0; - return { - deviceWidth, - deviceHeight, - language, - secure, - host, - page, - placements, - coppa: config.getConfig('coppa') === true ? 1 : 0, - ccpa: bidderRequest.uspConsent || undefined, - gdpr: bidderRequest.gdprConsent || undefined, - tmax: bidderRequest.timeout - }; +}) + +const buildRequests = (validBidRequests = [], bidderRequest = {}) => { + const bidsByPartner = validBidRequests.reduce((bidsByPartner, bid) => { + const partner = getPartnerName(bid); + (bidsByPartner[partner] = bidsByPartner[partner] || []).push(bid); + return bidsByPartner; + }, {}); + return Object.entries(bidsByPartner).map(([partner, validBidRequests]) => { + return buildRequestsBase({ + adUrl: _getUrl(partner), + bidderRequest, + validBidRequests, + placementProcessingFunction: getPlacementReqData + }) + }) } export const spec = { code: BIDDER_CODE, aliases: ALIASES, supportedMediaTypes: [BANNER, VIDEO, NATIVE], - - isBidRequestValid: (bid = {}) => { - const { params, bidId, mediaTypes } = bid; - let valid = Boolean(bidId && params && params.seat && params.token); - - if (mediaTypes && mediaTypes[BANNER]) { - valid = valid && Boolean(mediaTypes[BANNER] && mediaTypes[BANNER].sizes); - } else if (mediaTypes && mediaTypes[VIDEO]) { - valid = valid && Boolean(mediaTypes[VIDEO] && mediaTypes[VIDEO].playerSize); - } else if (mediaTypes && mediaTypes[NATIVE]) { - valid = valid && Boolean(mediaTypes[NATIVE]); - } else { - valid = false; + isBidRequestValid: isBidRequestValid(['seat', 'token'], 'every'), + buildRequests, + interpretResponse: interpretResponseBuilder({ + addtlBidValidation(bid) { + return bid.hasOwnProperty('netRevenue') } - return valid; - }, - - buildRequests: (validBidRequests = [], bidderRequest = {}) => { - // convert Native ORTB definition to old-style prebid native definition - validBidRequests = convertOrtbRequestToProprietaryNative(validBidRequests); - const tempObj = {}; - - const len = validBidRequests.length; - for (let i = 0; i < len; i++) { - const bid = validBidRequests[i]; - const data = getPlacementReqData(bid); - tempObj[data.partnerName] = tempObj[data.partnerName] || []; - tempObj[data.partnerName].push(data); - } - - return Object.keys(tempObj).map(key => { - const request = buildRequestParams(bidderRequest, tempObj[key]); - return { - method: 'POST', - url: getUrl(key), - data: request, - } - }); - }, - - interpretResponse: (serverResponse) => { - let response = []; - for (let i = 0; i < serverResponse.body.length; i++) { - let resItem = serverResponse.body[i]; - if (isBidResponseValid(resItem)) { - const advertiserDomains = resItem.adomain && resItem.adomain.length ? resItem.adomain : []; - resItem.meta = { ...resItem.meta, advertiserDomains }; - - response.push(resItem); - } - } - return response; - } + }) }; registerBidder(spec); diff --git a/modules/smilewantedBidAdapter.js b/modules/smilewantedBidAdapter.js index 7d4a4bca615..7f83dc025cb 100644 --- a/modules/smilewantedBidAdapter.js +++ b/modules/smilewantedBidAdapter.js @@ -4,6 +4,7 @@ import {config} from '../src/config.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; import {INSTREAM, OUTSTREAM} from '../src/video.js'; +import {serializeSupplyChain} from '../libraries/schainSerializer/schainSerializer.js' import {convertOrtbRequestToProprietaryNative, toOrtbNativeRequest, toLegacyResponse} from '../src/native.js'; const BIDDER_CODE = 'smilewanted'; @@ -82,7 +83,8 @@ export const spec = { or from mediaTypes.banner.pos */ positionType: bid.params.positionType || '', - prebidVersion: '$prebid.version$' + prebidVersion: '$prebid.version$', + schain: serializeSupplyChain(bid.schain, ['asi', 'sid', 'hp', 'rid', 'name', 'domain', 'ext']), }; const floor = getBidFloor(bid); @@ -154,16 +156,16 @@ export const spec = { if (response) { const dealId = response.dealId || ''; const bidResponse = { - requestId: bidRequestData.bidId, + ad: response.ad, cpm: response.cpm, - width: response.width, - height: response.height, creativeId: response.creativeId, - dealId: response.dealId, currency: response.currency, + dealId: response.dealId, + height: response.height, netRevenue: response.isNetCpm, + requestId: bidRequestData.bidId, ttl: response.ttl, - ad: response.ad, + width: response.width, }; if (response.formatTypeSw === 'video_instream' || response.formatTypeSw === 'video_outstream') { @@ -209,28 +211,30 @@ export const spec = { * @param {Object} uspConsent The USP consent parameters * @return {UserSync[]} The user syncs which should be dropped. */ - getUserSyncs: function(syncOptions, responses, gdprConsent, uspConsent) { - let params = ''; - - if (gdprConsent && typeof gdprConsent.consentString === 'string') { - // add 'gdpr' only if 'gdprApplies' is defined - if (typeof gdprConsent.gdprApplies === 'boolean') { - params += `?gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`; - } else { - params += `?gdpr_consent=${gdprConsent.consentString}`; + getUserSyncs: function (syncOptions, responses, gdprConsent, uspConsent) { + const syncs = []; + + if (syncOptions.iframeEnabled) { + let params = []; + + if (gdprConsent && typeof gdprConsent.consentString === 'string') { + // add 'gdpr' only if 'gdprApplies' is defined + if (typeof gdprConsent.gdprApplies === 'boolean') { + params.push(`gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`); + } else { + params.push(`gdpr_consent=${gdprConsent.consentString}`); + } } - } - if (uspConsent) { - params += `${params ? '&' : '?'}us_privacy=${encodeURIComponent(uspConsent)}`; - } + if (uspConsent) { + params.push(`us_privacy=${encodeURIComponent(uspConsent)}`); + } - const syncs = [] + const paramsStr = params.length > 0 ? '?' + params.join('&') : ''; - if (syncOptions.iframeEnabled) { syncs.push({ type: 'iframe', - url: 'https://csync.smilewanted.com' + params + url: 'https://csync.smilewanted.com' + paramsStr }); } diff --git a/modules/snigelBidAdapter.js b/modules/snigelBidAdapter.js index e8a8b4005c5..4e0de53ca0d 100644 --- a/modules/snigelBidAdapter.js +++ b/modules/snigelBidAdapter.js @@ -2,7 +2,7 @@ import {config} from '../src/config.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER} from '../src/mediaTypes.js'; import {deepAccess, isArray, isFn, isPlainObject, inIframe, getDNT, generateUUID} from '../src/utils.js'; -import {hasPurpose1Consent} from '../src/utils/gpdr.js'; +import {hasPurpose1Consent} from '../src/utils/gdpr.js'; import {getStorageManager} from '../src/storageManager.js'; const BIDDER_CODE = 'snigel'; diff --git a/modules/sonobiBidAdapter.js b/modules/sonobiBidAdapter.js index edc4f255d18..720ce8ee269 100644 --- a/modules/sonobiBidAdapter.js +++ b/modules/sonobiBidAdapter.js @@ -414,8 +414,6 @@ export function _getPlatform(context = window) { * @return {object} firstPartyData - Data object containing first party information */ function loadOrCreateFirstPartyData() { - var localStorageEnabled; - var FIRST_PARTY_KEY = '_iiq_fdata'; var tryParse = function (data) { try { @@ -426,19 +424,14 @@ function loadOrCreateFirstPartyData() { }; var readData = function (key) { if (hasLocalStorage()) { + // TODO FIX RULES VIOLATION + // eslint-disable-next-line prebid/no-global return window.localStorage.getItem(key); } return null; }; + // TODO FIX RULES VIOLATION - USE STORAGE MANAGER var hasLocalStorage = function () { - if (typeof localStorageEnabled != 'undefined') { return localStorageEnabled; } else { - try { - localStorageEnabled = !!window.localStorage; - return localStorageEnabled; - } catch (e) { - localStorageEnabled = false; - } - } return false; }; var generateGUID = function () { @@ -452,6 +445,8 @@ function loadOrCreateFirstPartyData() { var storeData = function (key, value) { try { if (hasLocalStorage()) { + // TODO FIX RULES VIOLATION + // eslint-disable-next-line prebid/no-global window.localStorage.setItem(key, value); } } catch (error) { diff --git a/modules/stnBidAdapter.js b/modules/stnBidAdapter.js index af4f4c45d38..ba922c0fd57 100644 --- a/modules/stnBidAdapter.js +++ b/modules/stnBidAdapter.js @@ -2,33 +2,32 @@ import { logWarn, logInfo, isArray, - isFn, deepAccess, - isEmpty, - contains, - timestamp, triggerPixel, - isInteger, - getBidIdParameter } from '../src/utils.js'; -import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {BANNER, VIDEO} from '../src/mediaTypes.js'; -import {config} from '../src/config.js'; - -const SUPPORTED_AD_TYPES = [BANNER, VIDEO]; -const BIDDER_CODE = 'stn'; -const ADAPTER_VERSION = '6.0.0'; -const TTL = 360; -const DEFAULT_CURRENCY = 'USD'; -const SELLER_ENDPOINT = 'https://hb.stngo.com/'; -const MODES = { +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import { + getEndpoint, + generateBidsParams, + generateGeneralParams, + buildBidResponse, +} from '../libraries/riseUtils/index.js'; + +export const SUPPORTED_AD_TYPES = [BANNER, VIDEO]; +export const BIDDER_CODE = 'stn'; +export const ADAPTER_VERSION = '6.1.0'; +export const TTL = 360; +export const DEFAULT_CURRENCY = 'USD'; +export const SELLER_ENDPOINT = 'https://hb.stngo.com/'; +export const MODES = { PRODUCTION: 'hb-multi', TEST: 'hb-multi-test' -} -const SUPPORTED_SYNC_METHODS = { +}; +export const SUPPORTED_SYNC_METHODS = { IFRAME: 'iframe', PIXEL: 'pixel' -} +}; export const spec = { code: BIDDER_CODE, @@ -50,7 +49,6 @@ export const spec = { buildRequests: function (validBidRequests, bidderRequest) { const combinedRequestsObject = {}; - // use data from the first bid, to create the general params for all bids const generalObject = validBidRequests[0]; const testMode = generalObject.params.testMode; @@ -59,41 +57,16 @@ export const spec = { return { method: 'POST', - url: getEndpoint(testMode), + url: getEndpoint(testMode, SELLER_ENDPOINT, MODES), data: combinedRequestsObject } }, - interpretResponse: function ({body}) { + interpretResponse: function ({ body }) { const bidResponses = []; if (body.bids) { body.bids.forEach(adUnit => { - const bidResponse = { - requestId: adUnit.requestId, - cpm: adUnit.cpm, - currency: adUnit.currency || DEFAULT_CURRENCY, - width: adUnit.width, - height: adUnit.height, - ttl: adUnit.ttl || TTL, - creativeId: adUnit.creativeId, - netRevenue: adUnit.netRevenue || true, - nurl: adUnit.nurl, - mediaType: adUnit.mediaType, - meta: { - mediaType: adUnit.mediaType - } - }; - - if (adUnit.mediaType === VIDEO) { - bidResponse.vastXml = adUnit.vastXml; - } else if (adUnit.mediaType === BANNER) { - bidResponse.ad = adUnit.ad; - } - - if (adUnit.adomain && adUnit.adomain.length) { - bidResponse.meta.advertiserDomains = adUnit.adomain; - } - + const bidResponse = buildBidResponse(adUnit, DEFAULT_CURRENCY, TTL, VIDEO, BANNER); bidResponses.push(bidResponse); }); } @@ -134,352 +107,3 @@ export const spec = { }; registerBidder(spec); - -/** - * Get floor price - * @param bid {bid} - * @param mediaType {String} - * @returns {Number} - */ -function getFloor(bid, mediaType) { - if (!isFn(bid.getFloor)) { - return 0; - } - let floorResult = bid.getFloor({ - currency: DEFAULT_CURRENCY, - mediaType: mediaType, - size: '*' - }); - return floorResult.currency === DEFAULT_CURRENCY && floorResult.floor ? floorResult.floor : 0; -} - -/** - * Get the ad sizes array from the bid - * @param bid {bid} - * @param mediaType {String} - * @returns {Array} - */ -function getSizesArray(bid, mediaType) { - let sizesArray = [] - - if (deepAccess(bid, `mediaTypes.${mediaType}.sizes`)) { - sizesArray = bid.mediaTypes[mediaType].sizes; - } else if (Array.isArray(bid.sizes) && bid.sizes.length > 0) { - sizesArray = bid.sizes; - } - - return sizesArray; -} - -/** - * Get schain string value - * @param schainObject {Object} - * @returns {string} - */ -function getSupplyChain(schainObject) { - if (isEmpty(schainObject)) { - return ''; - } - let scStr = `${schainObject.ver},${schainObject.complete}`; - schainObject.nodes.forEach((node) => { - scStr += '!'; - scStr += `${getEncodedValIfNotEmpty(node.asi)},`; - scStr += `${getEncodedValIfNotEmpty(node.sid)},`; - scStr += `${getEncodedValIfNotEmpty(node.hp)},`; - scStr += `${getEncodedValIfNotEmpty(node.rid)},`; - scStr += `${getEncodedValIfNotEmpty(node.name)},`; - scStr += `${getEncodedValIfNotEmpty(node.domain)}`; - }); - return scStr; -} - -/** - * Get encoded node value - * @param val {string} - * @returns {string} - */ -function getEncodedValIfNotEmpty(val) { - return (val !== '' && val !== undefined) ? encodeURIComponent(val) : ''; -} - -/** - * Get preferred user-sync method based on publisher configuration - * @param filterSettings {Object} - * @param bidderCode {string} - * @returns {string} - */ -function getAllowedSyncMethod(filterSettings, bidderCode) { - const iframeConfigsToCheck = ['all', 'iframe']; - const pixelConfigToCheck = 'image'; - if (filterSettings && iframeConfigsToCheck.some(config => isSyncMethodAllowed(filterSettings[config], bidderCode))) { - return SUPPORTED_SYNC_METHODS.IFRAME; - } - if (!filterSettings || !filterSettings[pixelConfigToCheck] || isSyncMethodAllowed(filterSettings[pixelConfigToCheck], bidderCode)) { - return SUPPORTED_SYNC_METHODS.PIXEL; - } -} - -/** - * Check if sync rule is supported - * @param syncRule {Object} - * @param bidderCode {string} - * @returns {boolean} - */ -function isSyncMethodAllowed(syncRule, bidderCode) { - if (!syncRule) { - return false; - } - const isInclude = syncRule.filter === 'include'; - const bidders = isArray(syncRule.bidders) ? syncRule.bidders : [bidderCode]; - return isInclude && contains(bidders, bidderCode); -} - -/** - * Get the seller endpoint - * @param testMode {boolean} - * @returns {string} - */ -function getEndpoint(testMode) { - return testMode - ? SELLER_ENDPOINT + MODES.TEST - : SELLER_ENDPOINT + MODES.PRODUCTION; -} - -/** - * get device type - * @param ua {ua} - * @returns {string} - */ -function getDeviceType(ua) { - if (/ipad|android 3.0|xoom|sch-i800|playbook|tablet|kindle/i - .test(ua.toLowerCase())) { - return '5'; - } - if (/iphone|ipod|android|blackberry|opera|mini|windows\sce|palm|smartphone|iemobile/i - .test(ua.toLowerCase())) { - return '4'; - } - if (/smart[-_\s]?tv|hbbtv|appletv|googletv|hdmi|netcast|viera|nettv|roku|\bdtv\b|sonydtv|inettvbrowser|\btv\b/i - .test(ua.toLowerCase())) { - return '3'; - } - return '1'; -} - -function generateBidsParams(validBidRequests, bidderRequest) { - const bidsArray = []; - - if (validBidRequests.length) { - validBidRequests.forEach(bid => { - bidsArray.push(generateBidParameters(bid, bidderRequest)); - }); - } - - return bidsArray; -} - -/** - * Generate bid specific parameters - * @param {bid} bid - * @param {bidderRequest} bidderRequest - * @returns {Object} bid specific params object - */ -function generateBidParameters(bid, bidderRequest) { - const {params} = bid; - const mediaType = isBanner(bid) ? BANNER : VIDEO; - const sizesArray = getSizesArray(bid, mediaType); - - // fix floor price in case of NAN - if (isNaN(params.floorPrice)) { - params.floorPrice = 0; - } - - const bidObject = { - mediaType, - adUnitCode: getBidIdParameter('adUnitCode', bid), - sizes: sizesArray, - floorPrice: Math.max(getFloor(bid, mediaType), params.floorPrice), - bidId: getBidIdParameter('bidId', bid), - loop: getBidIdParameter('bidderRequestsCount', bid), - bidderRequestId: getBidIdParameter('bidderRequestId', bid), - transactionId: bid.ortb2Imp?.ext?.tid || '', - coppa: 0, - }; - - const pos = deepAccess(bid, `mediaTypes.${mediaType}.pos`); - if (pos) { - bidObject.pos = pos; - } - - const gpid = deepAccess(bid, `ortb2Imp.ext.gpid`); - if (gpid) { - bidObject.gpid = gpid; - } - - const placementId = params.placementId || deepAccess(bid, `mediaTypes.${mediaType}.name`); - if (placementId) { - bidObject.placementId = placementId; - } - - const mimes = deepAccess(bid, `mediaTypes.${mediaType}.mimes`); - if (mimes) { - bidObject.mimes = mimes; - } - const api = deepAccess(bid, `mediaTypes.${mediaType}.api`); - if (api) { - bidObject.api = api; - } - - const sua = deepAccess(bid, `ortb2.device.sua`); - if (sua) { - bidObject.sua = sua; - } - - const coppa = deepAccess(bid, `ortb2.regs.coppa`) - if (coppa) { - bidObject.coppa = 1; - } - - if (mediaType === VIDEO) { - const playbackMethod = deepAccess(bid, `mediaTypes.video.playbackmethod`); - let playbackMethodValue; - - // verify playbackMethod is of type integer array, or integer only. - if (Array.isArray(playbackMethod) && isInteger(playbackMethod[0])) { - // only the first playbackMethod in the array will be used, according to OpenRTB 2.5 recommendation - playbackMethodValue = playbackMethod[0]; - } else if (isInteger(playbackMethod)) { - playbackMethodValue = playbackMethod; - } - - if (playbackMethodValue) { - bidObject.playbackMethod = playbackMethodValue; - } - - const placement = deepAccess(bid, `mediaTypes.video.placement`); - if (placement) { - bidObject.placement = placement; - } - - const minDuration = deepAccess(bid, `mediaTypes.video.minduration`); - if (minDuration) { - bidObject.minDuration = minDuration; - } - - const maxDuration = deepAccess(bid, `mediaTypes.video.maxduration`); - if (maxDuration) { - bidObject.maxDuration = maxDuration; - } - - const skip = deepAccess(bid, `mediaTypes.video.skip`); - if (skip) { - bidObject.skip = skip; - } - - const linearity = deepAccess(bid, `mediaTypes.video.linearity`); - if (linearity) { - bidObject.linearity = linearity; - } - - const protocols = deepAccess(bid, `mediaTypes.video.protocols`); - if (protocols) { - bidObject.protocols = protocols; - } - - const plcmt = deepAccess(bid, `mediaTypes.video.plcmt`); - if (plcmt) { - bidObject.plcmt = plcmt; - } - } - - return bidObject; -} - -function isBanner(bid) { - return bid.mediaTypes && bid.mediaTypes.banner; -} - -/** - * Generate params that are common between all bids - * @param {single bid object} generalObject - * @param {bidderRequest} bidderRequest - * @returns {object} the common params object - */ -function generateGeneralParams(generalObject, bidderRequest) { - const domain = window.location.hostname; - const {syncEnabled, filterSettings} = config.getConfig('userSync') || {}; - const {bidderCode} = bidderRequest; - const generalBidParams = generalObject.params; - const timeout = bidderRequest.timeout; - - // these params are snake_case instead of camelCase to allow backwards compatability on the server. - // in the future, these will be converted to camelCase to match our convention. - const generalParams = { - wrapper_type: 'prebidjs', - wrapper_vendor: '$$PREBID_GLOBAL$$', - wrapper_version: '$prebid.version$', - adapter_version: ADAPTER_VERSION, - auction_start: timestamp(), - publisher_id: generalBidParams.org, - publisher_name: domain, - site_domain: domain, - dnt: (navigator.doNotTrack === 'yes' || navigator.doNotTrack === '1' || navigator.msDoNotTrack === '1') ? 1 : 0, - device_type: getDeviceType(navigator.userAgent), - ua: navigator.userAgent, - is_wrapper: !!generalBidParams.isWrapper, - session_id: generalBidParams.sessionId || getBidIdParameter('bidderRequestId', generalObject), - tmax: timeout - } - - const userIdsParam = getBidIdParameter('userId', generalObject); - if (userIdsParam) { - generalParams.userIds = JSON.stringify(userIdsParam); - } - - const ortb2Metadata = bidderRequest.ortb2 || {}; - if (ortb2Metadata.site) { - generalParams.site_metadata = JSON.stringify(ortb2Metadata.site); - } - if (ortb2Metadata.user) { - generalParams.user_metadata = JSON.stringify(ortb2Metadata.user); - } - - if (syncEnabled) { - const allowedSyncMethod = getAllowedSyncMethod(filterSettings, bidderCode); - if (allowedSyncMethod) { - generalParams.cs_method = allowedSyncMethod; - } - } - - if (bidderRequest.uspConsent) { - generalParams.us_privacy = bidderRequest.uspConsent; - } - - if (bidderRequest && bidderRequest.gdprConsent && bidderRequest.gdprConsent.gdprApplies) { - generalParams.gdpr = bidderRequest.gdprConsent.gdprApplies; - generalParams.gdpr_consent = bidderRequest.gdprConsent.consentString; - } - - if (bidderRequest.gppConsent) { - generalParams.gpp = bidderRequest.gppConsent.gppString; - generalParams.gpp_sid = bidderRequest.gppConsent.applicableSections; - } else if (bidderRequest.ortb2?.regs?.gpp) { - generalParams.gpp = bidderRequest.ortb2.regs.gpp; - generalParams.gpp_sid = bidderRequest.ortb2.regs.gpp_sid; - } - - if (generalBidParams.ifa) { - generalParams.ifa = generalBidParams.ifa; - } - - if (generalObject.schain) { - generalParams.schain = getSupplyChain(generalObject.schain); - } - - if (bidderRequest && bidderRequest.refererInfo) { - generalParams.referrer = deepAccess(bidderRequest, 'refererInfo.ref'); - generalParams.page_url = deepAccess(bidderRequest, 'refererInfo.page') || deepAccess(window, 'location.href'); - } - - return generalParams -} diff --git a/modules/symitriDapRtdProvider.js b/modules/symitriDapRtdProvider.js new file mode 100644 index 00000000000..1921bbddf4c --- /dev/null +++ b/modules/symitriDapRtdProvider.js @@ -0,0 +1,812 @@ +/** + * This module adds the Symitri DAP RTD provider to the real time data module + * The {@link module:modules/realTimeData} module is required + * The module will fetch real-time data from DAP + * @module modules/symitriDapRtdProvider + * @requires module:modules/realTimeData + */ +import {ajax} from '../src/ajax.js'; +import {getStorageManager} from '../src/storageManager.js'; +import {submodule} from '../src/hook.js'; +import {isPlainObject, mergeDeep, logMessage, logInfo, logError} from '../src/utils.js'; +import { loadExternalScript } from '../src/adloader.js'; +import {MODULE_TYPE_RTD} from '../src/activities/modules.js'; + +/** + * @typedef {import('../modules/rtdModule/index.js').RtdSubmodule} RtdSubmodule + */ +export function createRtdProvider(moduleName, moduleCode, headerPrefix) { + const MODULE_NAME = 'realTimeData'; + const SUBMODULE_NAME = moduleName; + const MODULE_CODE = moduleCode; + + const DAP_TOKEN = 'async_dap_token'; + const DAP_MEMBERSHIP = 'async_dap_membership'; + const DAP_ENCRYPTED_MEMBERSHIP = 'encrypted_dap_membership'; + const DAP_SS_ID = 'dap_ss_id'; + const DAP_DEFAULT_TOKEN_TTL = 3600; // in seconds + const DAP_MAX_RETRY_TOKENIZE = 1; + const DAP_CLIENT_ENTROPY = 'dap_client_entropy' + + const storage = getStorageManager({moduleType: MODULE_TYPE_RTD, moduleName: SUBMODULE_NAME}); + let dapRetryTokenize = 0; + + /** + * Lazy merge objects. + * @param {String} target + * @param {String} source + */ + function mergeLazy(target, source) { + if (!isPlainObject(target)) { + target = {}; + } + if (!isPlainObject(source)) { + source = {}; + } + return mergeDeep(target, source); + } + + /** + * Add real-time data & merge segments. + * @param {Object} ortb2 destination object to merge RTD into + * @param {Object} rtd + */ + function addRealTimeData(ortb2, rtd) { + logInfo('DEBUG(addRealTimeData) - ENTER'); + if (isPlainObject(rtd.ortb2)) { + logMessage('DEBUG(addRealTimeData): merging original: ', ortb2); + logMessage('DEBUG(addRealTimeData): merging in: ', rtd.ortb2); + mergeLazy(ortb2, rtd.ortb2); + } + logInfo('DEBUG(addRealTimeData) - EXIT'); + } + + /** + * Real-time data retrieval from Audigent + * @param {Object} bidConfig + * @param {function} onDone + * @param {Object} rtdConfig + * @param {Object} userConsent + */ + function getRealTimeData(bidConfig, onDone, rtdConfig, userConsent) { + let entropyDict = JSON.parse(storage.getDataFromLocalStorage(DAP_CLIENT_ENTROPY)); + let loadScriptPromise = new Promise((resolve, reject) => { + if (rtdConfig && rtdConfig.params && rtdConfig.params.dapEntropyTimeout && Number.isInteger(rtdConfig.params.dapEntropyTimeout)) { + setTimeout(reject, rtdConfig.params.dapEntropyTimeout, Error('DapEntropy script could not be loaded')); + } + if (entropyDict && entropyDict.expires_at > Math.round(Date.now() / 1000.0)) { + logMessage('Using cached entropy'); + resolve(); + } else { + if (typeof window.dapCalculateEntropy === 'function') { + window.dapCalculateEntropy(resolve, reject); + } else { + if (rtdConfig && rtdConfig.params && dapUtils.isValidHttpsUrl(rtdConfig.params.dapEntropyUrl)) { + loadExternalScript(rtdConfig.params.dapEntropyUrl, MODULE_CODE, () => { dapUtils.dapGetEntropy(resolve, reject) }); + } else { + reject(Error('Please check if dapEntropyUrl is specified and is valid under config.params')); + } + } + } + }); + loadScriptPromise + .catch((error) => { + logError('Entropy could not be calculated due to: ', error.message); + }) + .finally(() => { + generateRealTimeData(bidConfig, onDone, rtdConfig, userConsent); + }); + } + + function generateRealTimeData(bidConfig, onDone, rtdConfig, userConsent) { + logInfo('DEBUG(generateRealTimeData) - ENTER'); + logMessage(' - apiHostname: ' + rtdConfig.params.apiHostname); + logMessage(' - apiVersion: ' + rtdConfig.params.apiVersion); + dapRetryTokenize = 0; + var jsonData = null; + if (rtdConfig && isPlainObject(rtdConfig.params)) { + if (rtdConfig.params.segtax == 504) { + let encMembership = dapUtils.dapGetEncryptedMembershipFromLocalStorage(); + if (encMembership) { + jsonData = dapUtils.dapGetEncryptedRtdObj(encMembership, rtdConfig.params.segtax) + } + } else { + let membership = dapUtils.dapGetMembershipFromLocalStorage(); + if (membership) { + jsonData = dapUtils.dapGetRtdObj(membership, rtdConfig.params.segtax) + } + } + } + if (jsonData) { + if (jsonData.rtd) { + addRealTimeData(bidConfig.ortb2Fragments?.global, jsonData.rtd); + onDone(); + logInfo('DEBUG(generateRealTimeData) - 1'); + // Don't return - ensure the data is always fresh. + } + } + // Calling setTimeout to release the main thread so that the bid request could be sent. + setTimeout(dapUtils.callDapAPIs, 0, bidConfig, onDone, rtdConfig, userConsent); + } + + /** + * Module init + * @param {Object} provider + * @param {Object} userConsent + * @return {boolean} + */ + function init(provider, userConsent) { + if (dapUtils.checkConsent(userConsent) === false) { + return false; + } + return true; + } + + /** @type {RtdSubmodule} */ + const rtdSubmodule = { + name: SUBMODULE_NAME, + getBidRequestData: getRealTimeData, + init: init + }; + + submodule(MODULE_NAME, rtdSubmodule); + const dapUtils = { + + callDapAPIs: function(bidConfig, onDone, rtdConfig, userConsent) { + if (rtdConfig && isPlainObject(rtdConfig.params)) { + let config = { + api_hostname: rtdConfig.params.apiHostname, + api_version: rtdConfig.params.apiVersion, + domain: rtdConfig.params.domain, + segtax: rtdConfig.params.segtax, + identity: {type: rtdConfig.params.identityType} + }; + let refreshMembership = true; + let token = dapUtils.dapGetTokenFromLocalStorage(); + const ortb2 = bidConfig.ortb2Fragments.global; + logMessage('token is: ', token); + if (token !== null) { // If token is not null then check the membership in storage and add the RTD object + if (config.segtax == 504) { // Follow the encrypted membership path + dapUtils.dapRefreshEncryptedMembership(ortb2, config, token, onDone) // Get the encrypted membership from server + refreshMembership = false; + } else { + dapUtils.dapRefreshMembership(ortb2, config, token, onDone) // Get the membership from server + refreshMembership = false; + } + } + dapUtils.dapRefreshToken(ortb2, config, refreshMembership, onDone) // Refresh Token and membership in all the cases + } + }, + dapGetEntropy: function(resolve, reject) { + if (typeof window.dapCalculateEntropy === 'function') { + window.dapCalculateEntropy(resolve, reject); + } else { + reject(Error('window.dapCalculateEntropy function is not defined')) + } + }, + + dapGetTokenFromLocalStorage: function(ttl) { + let now = Math.round(Date.now() / 1000.0); // in seconds + let token = null; + let item = JSON.parse(storage.getDataFromLocalStorage(DAP_TOKEN)); + if (item) { + if (now < item.expires_at) { + token = item.token; + } + } + return token; + }, + + dapRefreshToken: function(ortb2, config, refreshMembership, onDone) { + dapUtils.dapLog('Token missing or expired, fetching a new one...'); + // Trigger a refresh + let now = Math.round(Date.now() / 1000.0); // in seconds + let item = {} + let configAsync = {...config}; + dapUtils.dapTokenize(configAsync, config.identity, onDone, + function(token, status, xhr, onDone) { + item.expires_at = now + DAP_DEFAULT_TOKEN_TTL; + let exp = dapUtils.dapExtractExpiryFromToken(token); + if (typeof exp == 'number') { + item.expires_at = exp - 10; + } + item.token = token; + storage.setDataInLocalStorage(DAP_TOKEN, JSON.stringify(item)); + dapUtils.dapLog('Successfully updated and stored token; expires at ' + item.expires_at); + let dapSSID = xhr.getResponseHeader(headerPrefix + '-DAP-SS-ID'); + if (dapSSID) { + storage.setDataInLocalStorage(DAP_SS_ID, JSON.stringify(dapSSID)); + } + let deviceId100 = xhr.getResponseHeader(headerPrefix + '-DAP-100'); + if (deviceId100 != null) { + storage.setDataInLocalStorage('dap_deviceId100', deviceId100); + dapUtils.dapLog('Successfully stored DAP 100 Device ID: ' + deviceId100); + } + if (refreshMembership) { + if (config.segtax == 504) { + dapUtils.dapRefreshEncryptedMembership(ortb2, config, token, onDone); + } else { + dapUtils.dapRefreshMembership(ortb2, config, token, onDone); + } + } + }, + function(xhr, status, error, onDone) { + logError('ERROR(' + error + '): failed to retrieve token! ' + status); + onDone() + } + ); + }, + + dapGetMembershipFromLocalStorage: function() { + let now = Math.round(Date.now() / 1000.0); // in seconds + let membership = null; + let item = JSON.parse(storage.getDataFromLocalStorage(DAP_MEMBERSHIP)); + if (item) { + if (now < item.expires_at) { + membership = { + said: item.said, + cohorts: item.cohorts, + attributes: null + }; + } + } + return membership; + }, + + dapRefreshMembership: function(ortb2, config, token, onDone) { + let now = Math.round(Date.now() / 1000.0); // in seconds + let item = {} + let configAsync = {...config}; + dapUtils.dapMembership(configAsync, token, onDone, + function(membership, status, xhr, onDone) { + item.expires_at = now + DAP_DEFAULT_TOKEN_TTL; + let exp = dapUtils.dapExtractExpiryFromToken(membership.said) + if (typeof exp == 'number') { + item.expires_at = exp - 10; + } + item.said = membership.said; + item.cohorts = membership.cohorts; + storage.setDataInLocalStorage(DAP_MEMBERSHIP, JSON.stringify(item)); + dapUtils.dapLog('Successfully updated and stored membership:'); + dapUtils.dapLog(item); + + let data = dapUtils.dapGetRtdObj(item, config.segtax) + dapUtils.checkAndAddRealtimeData(ortb2, data, config.segtax); + onDone(); + }, + function(xhr, status, error, onDone) { + logError('ERROR(' + error + '): failed to retrieve membership! ' + status); + if (status == 403 && dapRetryTokenize < DAP_MAX_RETRY_TOKENIZE) { + dapRetryTokenize++; + dapUtils.dapRefreshToken(ortb2, config, true, onDone); + } else { + onDone(); + } + } + ); + }, + + dapGetEncryptedMembershipFromLocalStorage: function() { + let now = Math.round(Date.now() / 1000.0); // in seconds + let encMembership = null; + let item = JSON.parse(storage.getDataFromLocalStorage(DAP_ENCRYPTED_MEMBERSHIP)); + if (item) { + if (now < item.expires_at) { + encMembership = { + encryptedSegments: item.encryptedSegments + }; + } + } + return encMembership; + }, + + dapRefreshEncryptedMembership: function(ortb2, config, token, onDone) { + let now = Math.round(Date.now() / 1000.0); // in seconds + let item = {}; + let configAsync = {...config}; + dapUtils.dapEncryptedMembership(configAsync, token, onDone, + function(encToken, status, xhr, onDone) { + item.expires_at = now + DAP_DEFAULT_TOKEN_TTL; + let exp = dapUtils.dapExtractExpiryFromToken(encToken); + if (typeof exp == 'number') { + item.expires_at = exp - 10; + } + item.encryptedSegments = encToken; + storage.setDataInLocalStorage(DAP_ENCRYPTED_MEMBERSHIP, JSON.stringify(item)); + dapUtils.dapLog('Successfully updated and stored encrypted membership:'); + dapUtils.dapLog(item); + + let encData = dapUtils.dapGetEncryptedRtdObj(item, config.segtax); + dapUtils.checkAndAddRealtimeData(ortb2, encData, config.segtax); + onDone(); + }, + function(xhr, status, error, onDone) { + logError('ERROR(' + error + '): failed to retrieve encrypted membership! ' + status); + if (status == 403 && dapRetryTokenize < DAP_MAX_RETRY_TOKENIZE) { + dapRetryTokenize++; + dapUtils.dapRefreshToken(ortb2, config, true, onDone); + } else { + onDone(); + } + } + ); + }, + + /** + * DESCRIPTION + * Extract expiry value from a token + */ + dapExtractExpiryFromToken: function(token) { + let exp = null; + if (token) { + const tokenArray = token.split('..'); + if (tokenArray && tokenArray.length > 0) { + let decode = atob(tokenArray[0]) + let header = JSON.parse(decode.replace(/"/g, '"')); + exp = header.exp; + } + } + return exp + }, + + /** + * DESCRIPTION + * + * Convert a DAP membership response to an OpenRTB2 segment object suitable + * for insertion into user.data.segment or site.data.segment and add it to the rtd obj. + */ + dapGetRtdObj: function(membership, segtax) { + let segment = { + name: 'dap.symitri.com', + ext: { + 'segtax': segtax + }, + segment: [] + }; + if (membership != null) { + for (const i of membership.cohorts) { + segment.segment.push({ id: i }); + } + } + let data = { + rtd: { + ortb2: { + user: { + data: [ + segment + ] + }, + site: { + ext: { + data: { + dapSAID: membership.said + } + } + } + } + } + }; + return data; + }, + + /** + * DESCRIPTION + * + * Convert a DAP membership response to an OpenRTB2 segment object suitable + * for insertion into user.data.segment or site.data.segment and add it to the rtd obj. + */ + dapGetEncryptedRtdObj: function(encToken, segtax) { + let segment = { + name: 'dap.symitri.com', + ext: { + 'segtax': segtax + }, + segment: [] + }; + if (encToken != null) { + segment.segment.push({ id: encToken.encryptedSegments }); + } + let encData = { + rtd: { + ortb2: { + user: { + data: [ + segment + ] + } + } + } + }; + return encData; + }, + + checkAndAddRealtimeData: function(ortb2, data, segtax) { + if (data.rtd) { + if (segtax == 504 && dapUtils.checkIfSegmentsAlreadyExist(ortb2, data.rtd, 504)) { + logMessage('DEBUG(handleInit): rtb Object already added'); + } else { + addRealTimeData(ortb2, data.rtd); + } + logInfo('DEBUG(checkAndAddRealtimeData) - 1'); + } + }, + + checkIfSegmentsAlreadyExist: function(ortb2, rtd, segtax) { + let segmentsExist = false + if (ortb2.user && ortb2.user.data && ortb2.user.data.length > 0) { + for (let i = 0; i < ortb2.user.data.length; i++) { + let element = ortb2.user.data[i] + if (element.ext && element.ext.segtax == segtax) { + segmentsExist = true + logMessage('DEBUG(checkIfSegmentsAlreadyExist): rtb Object already added: ', ortb2.user.data); + break; + } + } + } + return segmentsExist + }, + + dapLog: function(args) { + let css = ''; + css += 'display: inline-block;'; + css += 'color: #fff;'; + css += 'background: #F28B20;'; + css += 'padding: 1px 4px;'; + css += 'border-radius: 3px'; + + logInfo('%cDAP Client', css, args); + }, + + isValidHttpsUrl: function(urlString) { + let url; + try { + url = new URL(urlString); + } catch (_) { + return false; + } + return url.protocol === 'https:'; + }, + + checkConsent: function(userConsent) { + let consent = true; + + if (userConsent && userConsent.gdpr && userConsent.gdpr.gdprApplies) { + const gdpr = userConsent.gdpr; + const hasGdpr = (gdpr && typeof gdpr.gdprApplies === 'boolean' && gdpr.gdprApplies) ? 1 : 0; + const gdprConsentString = hasGdpr ? gdpr.consentString : ''; + if (hasGdpr && (!gdprConsentString || gdprConsentString === '')) { + logError('symitriDapRtd submodule requires consent string to call API'); + consent = false; + } + } else if (userConsent && userConsent.usp) { + const usp = userConsent.usp; + consent = usp[1] !== 'N' && usp[2] !== 'Y'; + } + + return consent; + }, + + /******************************************************************************* + * + * V2 (And Beyond) API + * + ******************************************************************************/ + + dapValidationHelper: function(config, onDone, token, onError) { + if (onError == null) { + onError = function(xhr, status, error, onDone) {}; + } + + if (config == null || typeof (config) == typeof (undefined)) { + onError(null, 'Invalid config object', 'ClientError', onDone); + return [ config, true ]; + } + + if (!('api_version' in config) || (typeof (config.api_version) == 'string' && config.api_version.length == 0)) { + config.api_version = 'x1'; + } + + if (typeof (config.api_version) != 'string') { + onError(null, "Invalid api_version: must be a string like 'x1', etc.", 'ClientError', onDone); + return [ config, true ]; + } + + if (!(('api_hostname') in config) || typeof (config.api_hostname) != 'string' || config.api_hostname.length == 0) { + onError(null, 'Invalid api_hostname: must be a non-empty string', 'ClientError', onDone); + return [ config, true ]; + } + + if (token) { + if (typeof (token) != 'string') { + onError(null, 'Invalid token: must be a non-null string', 'ClientError', onDone); + return [ config, true ]; + } + } + + return [ config, false ]; + }, + + /** + * SYNOPSIS + * + * dapTokenize( config, identity ); + * + * DESCRIPTION + * + * Tokenize an identity into a secure, privacy safe pseudonymiziation. + * + * PARAMETERS + * + * config: an array of system configuration parameters + * + * identity: an array of identity parameters passed to the tokenizing system + * + * EXAMPLE + * + * config = { + * api_hostname: "prebid.dap.akadns.net", // required + * domain: "prebid.org", // required + * api_version: "x1", // optional, default "x1" + * }; + * + * token = null; + * identity_email = { + * type: "email", + * identity: "obiwan@jedi.com" + * attributes: { cohorts: [ "100:1641013200", "101:1641013200", "102":3:1641013200" ] }, + * }; + * dap_x1_tokenize( config, identity_email, + * function( response, status, xhr ) { token = response; }, + * function( xhr, status, error ) { ; } // handle error + * + * token = null; + * identity_signature = { type: "signature:1.0.0" }; + * dap_x1_tokenize( config, identity_signature, + * function( response, status, xhr } { token = response; }, + * function( xhr, status, error ) { ; } // handle error + */ + dapTokenize: function(config, identity, onDone, onSuccess = null, onError = null) { + let hasTokenizeError; + [ config, hasTokenizeError ] = this.dapValidationHelper(config, onDone, null, onError); + if (hasTokenizeError) { return; } + + if (typeof (config.domain) != 'string') { + onError(null, 'Invalid config.domain: must be a string', 'ClientError', onDone); + return; + } + + if (config.domain.length <= 0) { + onError(null, 'Invalid config.domain: must have non-zero length', 'ClientError', onDone); + return; + } + + if (identity == null || typeof (identity) == typeof (undefined)) { + onError(null, 'Invalid identity object', 'ClientError', onDone); + return; + } + + if (!('type' in identity) || typeof (identity.type) != 'string' || identity.type.length <= 0) { + onError(null, "Identity must contain a valid 'type' field", 'ClientError', onDone); + return; + } + + let apiParams = { + 'type': identity.type, + }; + + if (typeof (identity.identity) != typeof (undefined)) { + apiParams.identity = identity.identity; + } + if (typeof (identity.attributes) != typeof (undefined)) { + apiParams.attributes = identity.attributes; + } + + let entropyDict = JSON.parse(storage.getDataFromLocalStorage(DAP_CLIENT_ENTROPY)); + if (entropyDict && entropyDict.entropy) { + apiParams.entropy = entropyDict.entropy; + } + + let method; + let body; + let path; + switch (config.api_version) { + case 'x1': + case 'x1-dev': + method = 'POST'; + path = '/data-activation/' + config.api_version + '/domain/' + config.domain + '/identity/tokenize'; + body = JSON.stringify(apiParams); + break; + default: + onError(null, 'Invalid api_version: ' + config.api_version, 'ClientError', onDone); + return; + } + + let customHeaders = {'Content-Type': 'application/json'}; + let dapSSID = JSON.parse(storage.getDataFromLocalStorage(DAP_SS_ID)); + if (dapSSID) { + customHeaders[headerPrefix + '-DAP-SS-ID'] = dapSSID; + } + + let url = 'https://' + config.api_hostname + path; + let cb = { + success: (response, request) => { + let token = null; + switch (config.api_version) { + case 'x1': + case 'x1-dev': + token = request.getResponseHeader(headerPrefix + '-DAP-Token'); + break; + } + onSuccess(token, request.status, request, onDone); + }, + error: (request, error) => { + onError(request, request.statusText, error, onDone); + } + }; + + ajax(url, cb, body, { + method: method, + customHeaders: customHeaders + }); + }, + + /** + * SYNOPSIS + * + * dapMembership( config, token, onSuccess, onError ); + * + * DESCRIPTION + * + * Return the audience segment membership along with a new Secure Advertising + * ID for this token. + * + * PARAMETERS + * + * config: an array of system configuration parameters + * + * token: the token previously returned from the tokenize API + * + * EXAMPLE + * + * config = { + * api_hostname: 'api.dap.akadns.net', + * }; + * + * // token from dap_tokenize + * + * dapMembership( config, token, + * function( membership, status, xhr ) { + * // Run auction with membership.segments and membership.said + * }, + * function( xhr, status, error ) { + * // error + * } ); + * + */ + dapMembership: function(config, token, onDone, onSuccess = null, onError = null) { + let hasMembershipError; + [ config, hasMembershipError ] = this.dapValidationHelper(config, onDone, token, onError); + if (hasMembershipError) { return; } + + if (typeof (config.domain) != 'string') { + onError(null, 'Invalid config.domain: must be a string', 'ClientError', onDone); + return; + } + + let path = '/data-activation/' + + config.api_version + + '/token/' + token + + '/membership'; + + let url = 'https://' + config.api_hostname + path; + + let cb = { + success: (response, request) => { + onSuccess(JSON.parse(response), request.status, request, onDone); + }, + error: (error, request) => { + onError(request, request.status, error, onDone); + } + }; + + ajax(url, cb, undefined, { + method: 'GET', + customHeaders: {} + }); + }, + + /** + * SYNOPSIS + * + * dapEncryptedMembership( config, token, onSuccess, onError ); + * + * DESCRIPTION + * + * Return the audience segment membership along with a new Secure Advertising + * ID for this token in encrypted format. + * + * PARAMETERS + * + * config: an array of system configuration parameters + * + * token: the token previously returned from the tokenize API + * + * EXAMPLE + * + * config = { + * api_hostname: 'api.dap.akadns.net', + * }; + * + * // token from dap_tokenize + * + * dapEncryptedMembership( config, token, + * function( membership, status, xhr ) { + * // Run auction with membership.segments and membership.said after decryption + * }, + * function( xhr, status, error ) { + * // error + * } ); + * + */ + dapEncryptedMembership: function(config, token, onDone, onSuccess = null, onError = null) { + let hasEncryptedMembershipError; + [ config, hasEncryptedMembershipError ] = this.dapValidationHelper(config, onDone, token, onError); + if (hasEncryptedMembershipError) { return; } + + let cb = { + success: (response, request) => { + let encToken = request.getResponseHeader(headerPrefix + '-DAP-Token'); + onSuccess(encToken, request.status, request, onDone); + }, + error: (error, request) => { onError(request, request.status, error, onDone); } + }; + + let path = '/data-activation/' + + config.api_version + + '/token/' + token + + '/membership/encrypt'; + + let url = 'https://' + config.api_hostname + path; + + ajax(url, cb, undefined, { + method: 'GET', + customHeaders: { + 'Content-Type': 'application/json', + 'Pragma': 'akamai-x-get-extracted-values' + } + }); + } + } + + return { + addRealTimeData, + getRealTimeData, + generateRealTimeData, + rtdSubmodule, + storage, + dapUtils, + DAP_TOKEN, + DAP_MEMBERSHIP, + DAP_ENCRYPTED_MEMBERSHIP, + DAP_SS_ID, + DAP_DEFAULT_TOKEN_TTL, + DAP_MAX_RETRY_TOKENIZE, + DAP_CLIENT_ENTROPY + }; +} + +export const { + addRealTimeData, + getRealTimeData, + generateRealTimeData, + rtdSubmodule: symitriDapRtdSubmodule, + storage, + dapUtils, + DAP_TOKEN, + DAP_MEMBERSHIP, + DAP_ENCRYPTED_MEMBERSHIP, + DAP_SS_ID, + DAP_DEFAULT_TOKEN_TTL, + DAP_MAX_RETRY_TOKENIZE, + DAP_CLIENT_ENTROPY +} = createRtdProvider('symitriDap', 'symitridap', 'Symitri'); diff --git a/modules/symitriDapRtdProvider.md b/modules/symitriDapRtdProvider.md new file mode 100644 index 00000000000..654f7b25bfd --- /dev/null +++ b/modules/symitriDapRtdProvider.md @@ -0,0 +1,49 @@ +### Overview + + Symitri DAP Real time data Provider automatically invokes the DAP APIs and submit audience segments and the SAID to the bid-stream. + +### Integration + + 1) Build the symitriDapRTD module into the Prebid.js package with: + + ``` + gulp build --modules=symitriDapRtdProvider,... + ``` + + 2) Use `setConfig` to instruct Prebid.js to initilaize the symitriDapRtdProvider module, as specified below. + +### Configuration + +``` + pbjs.setConfig({ + realTimeData: { + auctionDelay: 2000, + dataProviders: [ + { + name: "dap", + waitForIt: true, + params: { + apiHostname: '', + apiVersion: "x1", + domain: 'your-domain.com', + identityType: 'email' | 'mobile' | ... | 'dap-signature:1.3.0', + segtax: 504, + dapEntropyUrl: 'https://sym-dist.symitri.net/dapentropy.js', + dapEntropyTimeout: 1500 // Maximum time for dapentropy to run + } + } + ] + } + }); + ``` + +Please reach out to your Symitri account representative(Prebid@symitri.com) to get provisioned on the DAP platform. + + +### Testing +To view an example of available segments returned by dap: +``` +‘gulp serve --modules=rtdModule,symitriDapRtdProvider,appnexusBidAdapter,sovrnBidAdapter’ +``` +and then point your browser at: +"http://localhost:9999/integrationExamples/gpt/symitridap_segments_example.html" diff --git a/modules/tagorasBidAdapter.js b/modules/tagorasBidAdapter.js index 0138ba3daf9..6ce54a5a895 100644 --- a/modules/tagorasBidAdapter.js +++ b/modules/tagorasBidAdapter.js @@ -1,333 +1,30 @@ -import {_each, deepAccess, parseSizesInput, parseUrl, uniques, isFn} from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; import {getStorageManager} from '../src/storageManager.js'; -import {config} from '../src/config.js'; +import { + createBuildRequestsFn, + createInterpretResponseFn, + createUserSyncGetter, + isBidRequestValid +} from '../libraries/vidazooUtils/bidderUtils.js'; const DEFAULT_SUB_DOMAIN = 'exchange'; const BIDDER_CODE = 'tagoras'; const BIDDER_VERSION = '1.0.0'; -const CURRENCY = 'USD'; -const TTL_SECONDS = 60 * 5; -const UNIQUE_DEAL_ID_EXPIRY = 1000 * 60 * 15; -const storage = getStorageManager({bidderCode: BIDDER_CODE}); - -function getTopWindowQueryParams() { - try { - const parsedUrl = parseUrl(window.top.document.URL, {decodeSearchAsString: true}); - return parsedUrl.search; - } catch (e) { - return ''; - } -} +export const storage = getStorageManager({bidderCode: BIDDER_CODE}); export function createDomain(subDomain = DEFAULT_SUB_DOMAIN) { return `https://${subDomain}.tagoras.io`; } -export function extractCID(params) { - return params.cId || params.CID || params.cID || params.CId || params.cid || params.ciD || params.Cid || params.CiD; -} - -export function extractPID(params) { - return params.pId || params.PID || params.pID || params.PId || params.pid || params.piD || params.Pid || params.PiD; -} - -export function extractSubDomain(params) { - return params.subDomain || params.SubDomain || params.Subdomain || params.subdomain || params.SUBDOMAIN || params.subDOMAIN; -} - -function isBidRequestValid(bid) { - const params = bid.params || {}; - return !!(extractCID(params) && extractPID(params)); -} - -function buildRequest(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout) { - const { - params, - bidId, - userId, - adUnitCode, - schain, - mediaTypes, - ortb2Imp, - bidderRequestId, - bidRequestsCount, - bidderRequestsCount, - bidderWinsCount - } = bid; - let {bidFloor, ext} = params; - const hashUrl = hashCode(topWindowUrl); - const uniqueDealId = getUniqueDealId(hashUrl); - const cId = extractCID(params); - const pId = extractPID(params); - const subDomain = extractSubDomain(params); - - const gpid = deepAccess(bid, 'ortb2Imp.ext.gpid', deepAccess(bid, 'ortb2Imp.ext.data.pbadslot', '')); - - if (isFn(bid.getFloor)) { - const floorInfo = bid.getFloor({ - currency: 'USD', - mediaType: '*', - size: '*' - }); - - if (floorInfo.currency === 'USD') { - bidFloor = floorInfo.floor; - } - } - - let data = { - url: encodeURIComponent(topWindowUrl), - uqs: getTopWindowQueryParams(), - cb: Date.now(), - bidFloor: bidFloor, - bidId: bidId, - referrer: bidderRequest.refererInfo.ref, - adUnitCode: adUnitCode, - publisherId: pId, - sizes: sizes, - uniqueDealId: uniqueDealId, - bidderVersion: BIDDER_VERSION, - prebidVersion: '$prebid.version$', - res: `${screen.width}x${screen.height}`, - schain: schain, - mediaTypes: mediaTypes, - gpid: gpid, - transactionId: ortb2Imp?.ext?.tid, - bidderRequestId: bidderRequestId, - bidRequestsCount: bidRequestsCount, - bidderRequestsCount: bidderRequestsCount, - bidderWinsCount: bidderWinsCount, - bidderTimeout: bidderTimeout - }; - - appendUserIdsToRequestPayload(data, userId); - - const sua = deepAccess(bidderRequest, 'ortb2.device.sua'); - - if (sua) { - data.sua = sua; - } - - if (bidderRequest.gdprConsent) { - if (bidderRequest.gdprConsent.consentString) { - data.gdprConsent = bidderRequest.gdprConsent.consentString; - } - if (bidderRequest.gdprConsent.gdprApplies !== undefined) { - data.gdpr = bidderRequest.gdprConsent.gdprApplies ? 1 : 0; - } - } - if (bidderRequest.uspConsent) { - data.usPrivacy = bidderRequest.uspConsent; - } - - if (bidderRequest.gppConsent) { - data.gppString = bidderRequest.gppConsent.gppString; - data.gppSid = bidderRequest.gppConsent.applicableSections; - } else if (bidderRequest.ortb2?.regs?.gpp) { - data.gppString = bidderRequest.ortb2.regs.gpp; - data.gppSid = bidderRequest.ortb2.regs.gpp_sid; - } - - const dto = { - method: 'POST', - url: `${createDomain(subDomain)}/prebid/multi/${cId}`, - data: data - }; - - _each(ext, (value, key) => { - dto.data['ext.' + key] = value; - }); - - return dto; -} - -function appendUserIdsToRequestPayload(payloadRef, userIds) { - let key; - _each(userIds, (userId, idSystemProviderName) => { - key = `uid.${idSystemProviderName}`; +const buildRequests = createBuildRequestsFn(createDomain, null, storage, BIDDER_CODE, BIDDER_VERSION, false); - switch (idSystemProviderName) { - case 'digitrustid': - payloadRef[key] = deepAccess(userId, 'data.id'); - break; - case 'lipb': - payloadRef[key] = userId.lipbid; - break; - case 'parrableId': - payloadRef[key] = userId.eid; - break; - case 'id5id': - payloadRef[key] = userId.uid; - break; - default: - payloadRef[key] = userId; - } - }); -} +const interpretResponse = createInterpretResponseFn(BIDDER_CODE, false); -function buildRequests(validBidRequests, bidderRequest) { - const topWindowUrl = bidderRequest.refererInfo.page || bidderRequest.refererInfo.topmostLocation; - const bidderTimeout = config.getConfig('bidderTimeout'); - const requests = []; - validBidRequests.forEach(validBidRequest => { - const sizes = parseSizesInput(validBidRequest.sizes); - const request = buildRequest(validBidRequest, topWindowUrl, sizes, bidderRequest, bidderTimeout); - requests.push(request); - }); - return requests; -} - -function interpretResponse(serverResponse, request) { - if (!serverResponse || !serverResponse.body) { - return []; - } - const {bidId} = request.data; - const {results} = serverResponse.body; - - let output = []; - - try { - results.forEach(result => { - const { - creativeId, - ad, - price, - exp, - width, - height, - currency, - metaData, - advertiserDomains, - mediaType = BANNER - } = result; - if (!ad || !price) { - return; - } - - const response = { - requestId: bidId, - cpm: price, - width: width, - height: height, - creativeId: creativeId, - currency: currency || CURRENCY, - netRevenue: true, - ttl: exp || TTL_SECONDS, - }; - - if (metaData) { - Object.assign(response, { - meta: metaData - }) - } else { - Object.assign(response, { - meta: { - advertiserDomains: advertiserDomains || [] - } - }) - } - - if (mediaType === BANNER) { - Object.assign(response, { - ad: ad, - }); - } else { - Object.assign(response, { - vastXml: ad, - mediaType: VIDEO - }); - } - output.push(response); - }); - return output; - } catch (e) { - return []; - } -} - -function getUserSyncs(syncOptions, responses, gdprConsent = {}, uspConsent = '', gppConsent = {}) { - let syncs = []; - const {iframeEnabled, pixelEnabled} = syncOptions; - const {gdprApplies, consentString = ''} = gdprConsent; - const {gppString, applicableSections} = gppConsent; - - const cidArr = responses.filter(resp => deepAccess(resp, 'body.cid')).map(resp => resp.body.cid).filter(uniques); - let params = `?cid=${encodeURIComponent(cidArr.join(','))}&gdpr=${gdprApplies ? 1 : 0}&gdpr_consent=${encodeURIComponent(consentString || '')}&us_privacy=${encodeURIComponent(uspConsent || '')}` - - if (gppString && applicableSections?.length) { - params += '&gpp=' + encodeURIComponent(gppString); - params += '&gpp_sid=' + encodeURIComponent(applicableSections.join(',')); - } - - if (iframeEnabled) { - syncs.push({ - type: 'iframe', - url: `https://sync.tagoras.io/api/sync/iframe/${params}` - }); - } else if (pixelEnabled) { - syncs.push({ - type: 'image', - url: `https://sync.tagoras.io/api/sync/image/${params}` - }); - } - return syncs; -} - -export function hashCode(s, prefix = '_') { - const l = s.length; - let h = 0 - let i = 0; - if (l > 0) { - while (i < l) { - h = (h << 5) - h + s.charCodeAt(i++) | 0; - } - } - return prefix + h; -} - -export function getUniqueDealId(key, expiry = UNIQUE_DEAL_ID_EXPIRY) { - const storageKey = `u_${key}`; - const now = Date.now(); - const data = getStorageItem(storageKey); - let uniqueId; - - if (!data || !data.value || now - data.created > expiry) { - uniqueId = `${key}_${now.toString()}`; - setStorageItem(storageKey, uniqueId); - } else { - uniqueId = data.value; - } - - return uniqueId; -} - -export function getStorageItem(key) { - try { - return tryParseJSON(storage.getDataFromLocalStorage(key)); - } catch (e) { - } - - return null; -} - -export function setStorageItem(key, value, timestamp) { - try { - const created = timestamp || Date.now(); - const data = JSON.stringify({value, created}); - storage.setDataInLocalStorage(key, data); - } catch (e) { - } -} - -export function tryParseJSON(value) { - try { - return JSON.parse(value); - } catch (e) { - return value; - } -} +const getUserSyncs = createUserSyncGetter({ + iframeSyncUrl: 'https://sync.tagoras.io/api/sync/iframe', + imageSyncUrl: 'https://sync.tagoras.io/api/sync/image' +}); export const spec = { code: BIDDER_CODE, diff --git a/modules/targetVideoBidAdapter.js b/modules/targetVideoBidAdapter.js index 282f322c36a..fd5d79d08b7 100644 --- a/modules/targetVideoBidAdapter.js +++ b/modules/targetVideoBidAdapter.js @@ -1,24 +1,19 @@ -import {find} from '../src/polyfill.js'; -import {getBidRequest} from '../src/utils.js'; +import {_each, getDefinedParams, parseGPTSingleSizeArrayToRtbSize} from '../src/utils.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {formatRequest, getRtbBid, getSiteObj, videoBid, bannerBid, createVideoTag} from '../libraries/targetVideoUtils/bidderUtils.js'; +import {SOURCE, GVLID, BIDDER_CODE, VIDEO_PARAMS, BANNER_ENDPOINT_URL, VIDEO_ENDPOINT_URL, MARGIN, TIME_TO_LIVE} from '../libraries/targetVideoUtils/constants.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest * @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid */ -const SOURCE = 'pbjs'; -const BIDDER_CODE = 'targetVideo'; -const ENDPOINT_URL = 'https://ib.adnxs.com/ut/v3/prebid'; -const MARGIN = 1.35; -const GVLID = 786; - export const spec = { code: BIDDER_CODE, gvlid: GVLID, - supportedMediaTypes: [BANNER], + supportedMediaTypes: [BANNER, VIDEO], /** * Determines whether or not the given bid request is valid. @@ -37,35 +32,114 @@ export const spec = { * @return ServerRequest Info describing the request to the server. */ buildRequests: function(bidRequests, bidderRequest) { - const tags = bidRequests.map(createVideoTag); - const schain = bidRequests[0].schain; - const payload = { - tags: tags, - sdk: { - source: SOURCE, - version: '$prebid.version$' - }, - schain: schain + const requests = []; + const sdk = { + source: SOURCE, + version: '$prebid.version$' }; - if (bidderRequest && bidderRequest.gdprConsent) { - payload.gdpr_consent = { - consent_string: bidderRequest.gdprConsent.consentString, - consent_required: bidderRequest.gdprConsent.gdprApplies - }; - - if (bidderRequest.gdprConsent.addtlConsent && bidderRequest.gdprConsent.addtlConsent.indexOf('~') !== -1) { - let ac = bidderRequest.gdprConsent.addtlConsent; - let acStr = ac.substring(ac.indexOf('~') + 1); - payload.gdpr_consent.addtl_consent = acStr.split('.').map(id => parseInt(id, 10)); + for (let {params, bidId, sizes, mediaTypes} of bidRequests) { + for (const mediaType in mediaTypes) { + switch (mediaType) { + case VIDEO: { + const video = mediaTypes[VIDEO]; + const placementId = params.placementId; + const site = getSiteObj(); + + if (sizes && !Array.isArray(sizes[0])) sizes = [sizes]; + + const payload = { + sdk, + id: bidderRequest.bidderRequestId, + site, + imp: [] + } + + const imp = { + ext: { + prebid: { + storedrequest: { id: placementId } + } + }, + video: getDefinedParams(video, VIDEO_PARAMS) + } + + if (video.playerSize) { + imp.video = Object.assign( + imp.video, parseGPTSingleSizeArrayToRtbSize(video.playerSize[0]) || {} + ); + } else if (video.w && video.h) { + imp.video.w = video.w; + imp.video.h = video.h; + } + + payload.imp.push(imp); + + const gdprConsent = bidderRequest && bidderRequest.gdprConsent; + const uspConsent = bidderRequest && bidderRequest.uspConsent; + + if (gdprConsent || uspConsent) { + payload.regs = { ext: {} }; + + if (uspConsent) { + payload.regs.ext.us_privacy = uspConsent; + }; + + if (gdprConsent) { + if (typeof gdprConsent.gdprApplies !== 'undefined') { + payload.regs.ext.gdpr = gdprConsent.gdprApplies ? 1 : 0; + }; + + if (typeof gdprConsent.consentString !== 'undefined') { + payload.user = { + ext: { consent: gdprConsent.consentString } + }; + }; + }; + }; + + if (bidRequests[0].schain) { + payload.schain = bidRequests[0].schain; + } + + requests.push(formatRequest({ payload, url: VIDEO_ENDPOINT_URL, bidId })); + break; + } + + case BANNER: { + const tags = bidRequests.map(createVideoTag); + const schain = bidRequests[0].schain; + + const payload = { + tags, + sdk, + schain, + }; + + if (bidderRequest && bidderRequest.gdprConsent) { + payload.gdpr_consent = { + consent_string: bidderRequest.gdprConsent.consentString, + consent_required: bidderRequest.gdprConsent.gdprApplies + }; + + if (bidderRequest.gdprConsent.addtlConsent && bidderRequest.gdprConsent.addtlConsent.indexOf('~') !== -1) { + let ac = bidderRequest.gdprConsent.addtlConsent; + let acStr = ac.substring(ac.indexOf('~') + 1); + payload.gdpr_consent.addtl_consent = acStr.split('.').map(id => parseInt(id, 10)); + } + } + + if (bidderRequest && bidderRequest.uspConsent) { + payload.us_privacy = bidderRequest.uspConsent + } + + return formatRequest({ payload, url: BANNER_ENDPOINT_URL, bidderRequest }); + } + } } } - if (bidderRequest && bidderRequest.uspConsent) { - payload.us_privacy = bidderRequest.uspConsent - } - - return formatRequest(payload, bidderRequest); + return requests; }, /** @@ -74,139 +148,33 @@ export const spec = { * @param {*} serverResponse A successful response from the server. * @return {Bid[]} An array of bids which were nested inside the server. */ - interpretResponse: function(serverResponse, { bidderRequest }) { + interpretResponse: function(serverResponse, { bidderRequest, ...bidRequest }) { serverResponse = serverResponse.body; + const currency = serverResponse.cur; const bids = []; if (serverResponse.tags) { serverResponse.tags.forEach(serverBid => { const rtbBid = getRtbBid(serverBid); if (rtbBid && rtbBid.cpm !== 0 && rtbBid.ad_type == VIDEO) { - bids.push(newBid(serverBid, rtbBid, bidderRequest)); + bids.push(bannerBid(serverBid, rtbBid, bidderRequest, MARGIN)); } }); } - return bids; - } - -} - -function getSizes(request) { - let sizes = request.sizes; - if (!sizes && request.mediaTypes && request.mediaTypes.banner && request.mediaTypes.banner.sizes) { - sizes = request.mediaTypes.banner.sizes; - } - if (Array.isArray(sizes) && !Array.isArray(sizes[0])) { - sizes = [sizes[0], sizes[1]]; - } - if (!Array.isArray(sizes) || !Array.isArray(sizes[0])) { - sizes = [[0, 0]]; - } - - return sizes; -} + if (serverResponse.seatbid) { + _each(serverResponse.seatbid, (resp) => { + _each(resp.bid, (bid) => { + const requestId = bidRequest.bidId; + const params = bidRequest.params; -function formatRequest(payload, bidderRequest) { - const options = { - withCredentials: true - }; - const request = { - method: 'POST', - url: ENDPOINT_URL, - data: JSON.stringify(payload), - bidderRequest, - options - }; - - return request; -} - -/** - * Create video auction. - * - * @param {*} serverResponse A successful response from the server. - * @return {Bid[]} An array of bids which were nested inside the server. - */ -function createVideoTag(bid) { - const tag = {}; - tag.id = parseInt(bid.params.placementId, 10); - tag.gpid = 'targetVideo'; - tag.sizes = getSizes(bid); - tag.primary_size = tag.sizes[0]; - tag.ad_types = [VIDEO]; - tag.uuid = bid.bidId; - tag.allow_smaller_sizes = false; - tag.use_pmt_rule = false; - tag.prebid = true; - tag.disable_psa = true; - tag.hb_source = 1; - tag.require_asset_url = true; - tag.video = { - playback_method: 2, - skippable: true - }; - - return tag; -} - -/** - * Unpack the Server's Bid into a Prebid-compatible one. - * @param serverBid - * @param rtbBid - * @param bidderRequest - * @return Bid - */ -function newBid(serverBid, rtbBid, bidderRequest) { - const bidRequest = getBidRequest(serverBid.uuid, [bidderRequest]); - const sizes = getSizes(bidRequest); - const bid = { - requestId: serverBid.uuid, - cpm: rtbBid.cpm / MARGIN, - creativeId: rtbBid.creative_id, - dealId: rtbBid.deal_id, - currency: 'USD', - netRevenue: true, - width: sizes[0][0], - height: sizes[0][1], - ttl: 300, - adUnitCode: bidRequest.adUnitCode, - appnexus: { - buyerMemberId: rtbBid.buyer_member_id, - dealPriority: rtbBid.deal_priority, - dealCode: rtbBid.deal_code + bids.push(videoBid(bid, requestId, currency, params, TIME_TO_LIVE)); + }); + }); } - }; - - if (rtbBid.rtb.video) { - Object.assign(bid, { - vastImpUrl: rtbBid.notify_url, - ad: getBannerHtml(rtbBid.notify_url + '&redir=' + encodeURIComponent(rtbBid.rtb.video.asset_url)), - ttl: 3600 - }); - } - - return bid; -} -function getRtbBid(tag) { - return tag && tag.ads && tag.ads.length && find(tag.ads, ad => ad.rtb); -} - -function getBannerHtml(vastUrl) { - return ` - - - - - - - -
- - - - `; + return bids; + } } registerBidder(spec); diff --git a/modules/targetVideoBidAdapter.md b/modules/targetVideoBidAdapter.md index 557c9f94410..a34ad0aff27 100644 --- a/modules/targetVideoBidAdapter.md +++ b/modules/targetVideoBidAdapter.md @@ -3,17 +3,17 @@ ``` Module Name: Target Video Bid Adapter Module Type: Bidder Adapter -Maintainer: grajzer@gmail.com +Maintainers: grajzer@gmail.com, danijel.ristic@target-video.com ``` # Description Connects to Appnexus exchange for bids. -TargetVideo bid adapter supports Banner. +TargetVideo bid adapter supports Banner and Video. # Test Parameters -``` +```js var adUnits = [ // Banner adUnit { @@ -29,6 +29,23 @@ var adUnits = [ placementId: 13232361 } }] + }, + // Video adUnit + { + mediaTypes: { + video: { + playerSize: [[640, 360]], + context: 'instream', + playbackmethod: [1, 2, 3, 4] + } + }, + bids: [{ + bidder: 'targetVideo', + params: { + placementId: 12345, + reserve: 0, + } + }] } ]; ``` diff --git a/modules/telariaBidAdapter.js b/modules/telariaBidAdapter.js index 38eefd447a8..4ad544aaa50 100644 --- a/modules/telariaBidAdapter.js +++ b/modules/telariaBidAdapter.js @@ -1,6 +1,7 @@ import { logError, isEmpty, deepAccess, triggerPixel, logWarn, isArray } from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {VIDEO} from '../src/mediaTypes.js'; +import {getSupplyChain} from '../libraries/riseUtils/index.js'; const BIDDER_CODE = 'telaria'; const DOMAIN = 'tremorhub.com'; @@ -127,37 +128,6 @@ function getDefaultSrcPageUrl() { return encodeURIComponent(document.location.href); } -function getEncodedValIfNotEmpty(val) { - return (val !== '' && val !== undefined) ? encodeURIComponent(val) : ''; -} - -/** - * Converts the schain object to a url param value. Please refer to - * https://github.com/InteractiveAdvertisingBureau/openrtb/blob/master/supplychainobject.md - * (schain for non ORTB section) for more information - * @param schainObject - * @returns {string} - */ -function getSupplyChainAsUrlParam(schainObject) { - if (isEmpty(schainObject)) { - return ''; - } - - let scStr = `&schain=${schainObject.ver},${schainObject.complete}`; - - schainObject.nodes.forEach((node) => { - scStr += '!'; - scStr += `${getEncodedValIfNotEmpty(node.asi)},`; - scStr += `${getEncodedValIfNotEmpty(node.sid)},`; - scStr += `${getEncodedValIfNotEmpty(node.hp)},`; - scStr += `${getEncodedValIfNotEmpty(node.rid)},`; - scStr += `${getEncodedValIfNotEmpty(node.name)},`; - scStr += `${getEncodedValIfNotEmpty(node.domain)}`; - }); - - return scStr; -} - function getUrlParams(params, schainFromBidRequest) { let urlSuffix = ''; @@ -167,7 +137,7 @@ function getUrlParams(params, schainFromBidRequest) { urlSuffix += `&${key}=${params[key]}`; } } - urlSuffix += getSupplyChainAsUrlParam(!isEmpty(schainFromBidRequest) ? schainFromBidRequest : params['schain']); + urlSuffix += getSupplyChain(!isEmpty(schainFromBidRequest) ? schainFromBidRequest : params['schain']); } return urlSuffix; diff --git a/modules/twistDigitalBidAdapter.js b/modules/twistDigitalBidAdapter.js index 8a5f3c0ed56..bed9e531a26 100644 --- a/modules/twistDigitalBidAdapter.js +++ b/modules/twistDigitalBidAdapter.js @@ -1,441 +1,28 @@ -import { - _each, - deepAccess, - isFn, - parseSizesInput, - parseUrl, - uniques, - isArray, - formatQS, - triggerPixel -} from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; import {getStorageManager} from '../src/storageManager.js'; -import {bidderSettings} from '../src/bidderSettings.js'; -import {config} from '../src/config.js'; -import {chunk} from '../libraries/chunk/chunk.js'; -import {extractCID, extractPID, extractSubDomain} from '../libraries/vidazooUtils/bidderUtils.js'; +import { + isBidRequestValid, createInterpretResponseFn, createUserSyncGetter, createBuildRequestsFn, onBidWon +} from '../libraries/vidazooUtils/bidderUtils.js'; const GVLID = 1292; const DEFAULT_SUB_DOMAIN = 'exchange'; const BIDDER_CODE = 'twistdigital'; const BIDDER_VERSION = '1.0.0'; -const CURRENCY = 'USD'; -const TTL_SECONDS = 60 * 5; -const UNIQUE_DEAL_ID_EXPIRY = 1000 * 60 * 60; -export const webSessionId = 'wsid_' + parseInt(Date.now() * Math.random()); -const storage = getStorageManager({bidderCode: BIDDER_CODE}); - -function getTopWindowQueryParams() { - try { - const parsedUrl = parseUrl(window.top.document.URL, {decodeSearchAsString: true}); - return parsedUrl.search; - } catch (e) { - return ''; - } -} +export const storage = getStorageManager({bidderCode: BIDDER_CODE}); export function createDomain(subDomain = DEFAULT_SUB_DOMAIN) { return `https://${subDomain}.twist.win`; } -function isBidRequestValid(bid) { - const params = bid.params || {}; - return !!(extractCID(params) && extractPID(params)); -} - -function buildRequestData(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout) { - const { - params, - bidId, - userId, - adUnitCode, - schain, - mediaTypes, - ortb2Imp, - bidderRequestId, - bidRequestsCount, - bidderRequestsCount, - bidderWinsCount - } = bid; - const {ext} = params; - let {bidFloor} = params; - const hashUrl = hashCode(topWindowUrl); - const uniqueDealId = getUniqueDealId(hashUrl); - const pId = extractPID(params); - const isStorageAllowed = bidderSettings.get(BIDDER_CODE, 'storageAllowed'); - - const gpid = deepAccess(bid, 'ortb2Imp.ext.gpid', deepAccess(bid, 'ortb2Imp.ext.data.pbadslot', '')); - const cat = deepAccess(bidderRequest, 'ortb2.site.cat', []); - const pagecat = deepAccess(bidderRequest, 'ortb2.site.pagecat', []); - const contentData = deepAccess(bidderRequest, 'ortb2.site.content.data', []); - const userData = deepAccess(bidderRequest, 'ortb2.user.data', []); - - if (isFn(bid.getFloor)) { - const floorInfo = bid.getFloor({ - currency: 'USD', - mediaType: '*', - size: '*' - }); - - if (floorInfo.currency === 'USD') { - bidFloor = floorInfo.floor; - } - } - - let data = { - url: encodeURIComponent(topWindowUrl), - uqs: getTopWindowQueryParams(), - cb: Date.now(), - bidFloor: bidFloor, - bidId: bidId, - referrer: bidderRequest.refererInfo.ref, - adUnitCode: adUnitCode, - publisherId: pId, - sizes: sizes, - uniqueDealId: uniqueDealId, - bidderVersion: BIDDER_VERSION, - prebidVersion: '$prebid.version$', - res: `${screen.width}x${screen.height}`, - schain: schain, - mediaTypes: mediaTypes, - isStorageAllowed: isStorageAllowed, - gpid: gpid, - cat: cat, - contentData, - userData: userData, - pagecat: pagecat, - transactionId: ortb2Imp?.ext?.tid, - bidderRequestId: bidderRequestId, - bidRequestsCount: bidRequestsCount, - bidderRequestsCount: bidderRequestsCount, - bidderWinsCount: bidderWinsCount, - bidderTimeout: bidderTimeout, - webSessionId: webSessionId - }; - - appendUserIdsToRequestPayload(data, userId); - - const sua = deepAccess(bidderRequest, 'ortb2.device.sua'); - - if (sua) { - data.sua = sua; - } - - if (bidderRequest.gdprConsent) { - if (bidderRequest.gdprConsent.consentString) { - data.gdprConsent = bidderRequest.gdprConsent.consentString; - } - if (bidderRequest.gdprConsent.gdprApplies !== undefined) { - data.gdpr = bidderRequest.gdprConsent.gdprApplies ? 1 : 0; - } - } - if (bidderRequest.uspConsent) { - data.usPrivacy = bidderRequest.uspConsent; - } - - if (bidderRequest.gppConsent) { - data.gppString = bidderRequest.gppConsent.gppString; - data.gppSid = bidderRequest.gppConsent.applicableSections; - } else if (bidderRequest.ortb2?.regs?.gpp) { - data.gppString = bidderRequest.ortb2.regs.gpp; - data.gppSid = bidderRequest.ortb2.regs.gpp_sid; - } - - if (bidderRequest.paapi?.enabled) { - const fledge = deepAccess(bidderRequest, 'ortb2Imp.ext.ae'); - if (fledge) { - data.fledge = fledge; - } - } +const buildRequests = createBuildRequestsFn(createDomain, null, storage, BIDDER_CODE, BIDDER_VERSION, true); - _each(ext, (value, key) => { - data['ext.' + key] = value; - }); +const interpretResponse = createInterpretResponseFn(BIDDER_CODE, true); - return data; -} - -function buildRequest(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout) { - const {params} = bid; - const cId = extractCID(params); - const subDomain = extractSubDomain(params); - const data = buildRequestData(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout); - const dto = { - method: 'POST', - url: `${createDomain(subDomain)}/prebid/multi/${cId}`, - data: data - }; - return dto; -} - -function buildSingleRequest(bidRequests, bidderRequest, topWindowUrl, bidderTimeout) { - const {params} = bidRequests[0]; - const cId = extractCID(params); - const subDomain = extractSubDomain(params); - const data = bidRequests.map(bid => { - const sizes = parseSizesInput(bid.sizes); - return buildRequestData(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout) - }); - const chunkSize = Math.min(20, config.getConfig('twistdigital.chunkSize') || 10); - - const chunkedData = chunk(data, chunkSize); - return chunkedData.map(chunk => { - return { - method: 'POST', - url: `${createDomain(subDomain)}/prebid/multi/${cId}`, - data: { - bids: chunk - } - }; - }); -} - -function appendUserIdsToRequestPayload(payloadRef, userIds) { - let key; - _each(userIds, (userId, idSystemProviderName) => { - key = `uid.${idSystemProviderName}`; - switch (idSystemProviderName) { - case 'digitrustid': - payloadRef[key] = deepAccess(userId, 'data.id'); - break; - case 'lipb': - payloadRef[key] = userId.lipbid; - break; - case 'parrableId': - payloadRef[key] = userId.eid; - break; - case 'id5id': - payloadRef[key] = userId.uid; - break; - default: - payloadRef[key] = userId; - } - }); -} - -function buildRequests(validBidRequests, bidderRequest) { - const topWindowUrl = bidderRequest.refererInfo.page || bidderRequest.refererInfo.topmostLocation; - const bidderTimeout = config.getConfig('bidderTimeout'); - - const singleRequestMode = config.getConfig('twistdigital.singleRequest'); - - const requests = []; - - if (singleRequestMode) { - // banner bids are sent as a single request - const bannerBidRequests = validBidRequests.filter(bid => isArray(bid.mediaTypes) ? bid.mediaTypes.includes(BANNER) : bid.mediaTypes[BANNER] !== undefined); - if (bannerBidRequests.length > 0) { - const singleRequests = buildSingleRequest(bannerBidRequests, bidderRequest, topWindowUrl, bidderTimeout); - requests.push(...singleRequests); - } - - // video bids are sent as a single request for each bid - - const videoBidRequests = validBidRequests.filter(bid => bid.mediaTypes[VIDEO] !== undefined); - videoBidRequests.forEach(validBidRequest => { - const sizes = parseSizesInput(validBidRequest.sizes); - const request = buildRequest(validBidRequest, topWindowUrl, sizes, bidderRequest, bidderTimeout); - requests.push(request); - }); - } else { - validBidRequests.forEach(validBidRequest => { - const sizes = parseSizesInput(validBidRequest.sizes); - const request = buildRequest(validBidRequest, topWindowUrl, sizes, bidderRequest, bidderTimeout); - requests.push(request); - }); - } - return requests; -} - -function interpretResponse(serverResponse, request) { - if (!serverResponse || !serverResponse.body) { - return []; - } - - const singleRequestMode = config.getConfig('twistdigital.singleRequest'); - const reqBidId = deepAccess(request, 'data.bidId'); - const {results} = serverResponse.body; - - let output = []; - - try { - results.forEach((result, i) => { - const { - creativeId, - ad, - price, - exp, - width, - height, - currency, - bidId, - nurl, - advertiserDomains, - metaData, - mediaType = BANNER - } = result; - if (!ad || !price) { - return; - } - - const response = { - requestId: (singleRequestMode && bidId) ? bidId : reqBidId, - cpm: price, - width: width, - height: height, - creativeId: creativeId, - currency: currency || CURRENCY, - netRevenue: true, - ttl: exp || TTL_SECONDS, - }; - - if (nurl) { - response.nurl = nurl; - } - - if (metaData) { - Object.assign(response, { - meta: metaData - }) - } else { - Object.assign(response, { - meta: { - advertiserDomains: advertiserDomains || [] - } - }) - } - - if (mediaType === BANNER) { - Object.assign(response, { - ad: ad, - }); - } else { - Object.assign(response, { - vastXml: ad, - mediaType: VIDEO - }); - } - output.push(response); - }); - - return output; - } catch (e) { - return []; - } -} - -function getUserSyncs(syncOptions, responses, gdprConsent = {}, uspConsent = '', gppConsent = {}) { - let syncs = []; - const {iframeEnabled, pixelEnabled} = syncOptions; - const {gdprApplies, consentString = ''} = gdprConsent; - const {gppString, applicableSections} = gppConsent; - - const cidArr = responses.filter(resp => deepAccess(resp, 'body.cid')).map(resp => resp.body.cid).filter(uniques); - let params = `?cid=${encodeURIComponent(cidArr.join(','))}&gdpr=${gdprApplies ? 1 : 0}&gdpr_consent=${encodeURIComponent(consentString || '')}&us_privacy=${encodeURIComponent(uspConsent || '')}`; - - if (gppString && applicableSections?.length) { - params += '&gpp=' + encodeURIComponent(gppString); - params += '&gpp_sid=' + encodeURIComponent(applicableSections.join(',')); - } - - if (iframeEnabled) { - syncs.push({ - type: 'iframe', - url: `https://sync.twist.win/api/sync/iframe/${params}` - }); - } - if (pixelEnabled) { - syncs.push({ - type: 'image', - url: `https://sync.twist.win/api/sync/image/${params}` - }); - } - return syncs; -} - -/** - * @param {Bid} bid - */ -function onBidWon(bid) { - if (!bid.nurl) { - return; - } - const wonBid = { - adId: bid.adId, - creativeId: bid.creativeId, - auctionId: bid.auctionId, - transactionId: bid.transactionId, - adUnitCode: bid.adUnitCode, - cpm: bid.cpm, - currency: bid.currency, - originalCpm: bid.originalCpm, - originalCurrency: bid.originalCurrency, - netRevenue: bid.netRevenue, - mediaType: bid.mediaType, - timeToRespond: bid.timeToRespond, - status: bid.status, - }; - const qs = formatQS(wonBid); - const url = bid.nurl + (bid.nurl.indexOf('?') === -1 ? '?' : '&') + qs; - triggerPixel(url); -} - -export function hashCode(s, prefix = '_') { - const l = s.length; - let h = 0 - let i = 0; - if (l > 0) { - while (i < l) { - h = (h << 5) - h + s.charCodeAt(i++) | 0; - } - } - return prefix + h; -} - -export function getUniqueDealId(key, expiry = UNIQUE_DEAL_ID_EXPIRY) { - const storageKey = `u_${key}`; - const now = Date.now(); - const data = getStorageItem(storageKey); - let uniqueId; - - if (!data || !data.value || now - data.created > expiry) { - uniqueId = `${key}_${now.toString()}`; - setStorageItem(storageKey, uniqueId); - } else { - uniqueId = data.value; - } - - return uniqueId; -} - -export function getStorageItem(key) { - try { - return tryParseJSON(storage.getDataFromLocalStorage(key)); - } catch (e) { - } - - return null; -} - -export function setStorageItem(key, value, timestamp) { - try { - const created = timestamp || Date.now(); - const data = JSON.stringify({value, created}); - storage.setDataInLocalStorage(key, data); - } catch (e) { - } -} - -export function tryParseJSON(value) { - try { - return JSON.parse(value); - } catch (e) { - return value; - } -} +const getUserSyncs = createUserSyncGetter({ + iframeSyncUrl: 'https://sync.twist.win/api/sync/iframe', imageSyncUrl: 'https://sync.twist.win/api/sync/image' +}); export const spec = { code: BIDDER_CODE, diff --git a/modules/uid2IdSystem_shared.js b/modules/uid2IdSystem_shared.js index 36e5d414941..a9acfd6291e 100644 --- a/modules/uid2IdSystem_shared.js +++ b/modules/uid2IdSystem_shared.js @@ -7,12 +7,22 @@ function isValidIdentity(identity) { return !!(typeof identity === 'object' && identity !== null && identity.advertising_token && identity.identity_expires && identity.refresh_from && identity.refresh_token && identity.refresh_expires); } +// Helper function to prepend message +function prependMessage(message) { + return `UID2 shared library - ${message}`; +} + +// Wrapper function for logInfo +function logInfoWrapper(logInfo, ...args) { + logInfo(prependMessage(args[0]), ...args.slice(1)); +} + // This is extracted from an in-progress API client. Once it's available via NPM, this class should be replaced with the NPM package. export class Uid2ApiClient { constructor(opts, clientId, logInfo, logWarn) { this._baseUrl = opts.baseUrl; this._clientVersion = clientId; - this._logInfo = logInfo; + this._logInfo = (...args) => logInfoWrapper(logInfo, ...args); this._logWarn = logWarn; } @@ -35,7 +45,7 @@ export class Uid2ApiClient { if (this.isValidRefreshResponse(response)) { if (response.status === 'success') { return { status: response.status, identity: response.body }; } return response; - } else { return `Response didn't contain a valid status`; } + } else { return prependMessage(`Response didn't contain a valid status`); } } callRefreshApi(refreshDetails) { const url = this._baseUrl + '/v2/token/refresh'; @@ -53,7 +63,7 @@ export class Uid2ApiClient { this._logInfo('No response decryption key available, assuming unencrypted JSON'); const response = JSON.parse(responseText); const result = this.ResponseToRefreshResult(response); - if (typeof result === 'string') { rejectPromise(result); } else { resolvePromise(result); } + if (typeof result === 'string') { rejectPromise(prependMessage(result)); } else { resolvePromise(result); } } else { this._logInfo('Decrypting refresh API response'); const encodeResp = this.createArrayBuffer(atob(responseText)); @@ -69,12 +79,12 @@ export class Uid2ApiClient { this._logInfo('Decrypted to:', decryptedResponse); const response = JSON.parse(decryptedResponse); const result = this.ResponseToRefreshResult(response); - if (typeof result === 'string') { rejectPromise(result); } else { resolvePromise(result); } - }, (reason) => this._logWarn(`Call to UID2 API failed`, reason)); - }, (reason) => this._logWarn(`Call to UID2 API failed`, reason)); + if (typeof result === 'string') { rejectPromise(prependMessage(result)); } else { resolvePromise(result); } + }, (reason) => this._logWarn(prependMessage(`Call to UID2 API failed`), reason)); + }, (reason) => this._logWarn(prependMessage(`Call to UID2 API failed`), reason)); } } catch (_err) { - rejectPromise(responseText); + rejectPromise(prependMessage(responseText)); } }, error: (error, xhr) => { @@ -82,9 +92,9 @@ export class Uid2ApiClient { this._logInfo('Error status, assuming unencrypted JSON'); const response = JSON.parse(xhr.responseText); const result = this.ResponseToRefreshResult(response); - if (typeof result === 'string') { rejectPromise(result); } else { resolvePromise(result); } + if (typeof result === 'string') { rejectPromise(prependMessage(result)); } else { resolvePromise(result); } } catch (_e) { - rejectPromise(error) + rejectPromise(prependMessage(error)); } } }, refreshDetails.refresh_token, { method: 'POST', @@ -99,7 +109,7 @@ export class Uid2StorageManager { this._storage = storage; this._preferLocalStorage = preferLocalStorage; this._storageName = storageName; - this._logInfo = logInfo; + this._logInfo = (...args) => logInfoWrapper(logInfo, ...args); } readCookie(cookieName) { return this._storage.cookiesAreEnabled() ? this._storage.getCookie(cookieName) : null; @@ -392,7 +402,7 @@ if (FEATURES.UID2_CSTG) { this._baseUrl = opts.baseUrl; this._serverPublicKey = opts.cstg.serverPublicKey; this._subscriptionId = opts.cstg.subscriptionId; - this._logInfo = logInfo; + this._logInfo = (...args) => logInfoWrapper(logInfo, ...args); this._logWarn = logWarn; } @@ -512,11 +522,11 @@ if (FEATURES.UID2_CSTG) { // A 200 should always be a success response. // Something has gone wrong. rejectPromise( - `API error: Response body was invalid for HTTP status 200: ${decryptedResponse}` + prependMessage(`API error: Response body was invalid for HTTP status 200: ${decryptedResponse}`) ); } } catch (err) { - rejectPromise(err); + rejectPromise(prependMessage(err)); } }, error: (error, xhr) => { @@ -524,32 +534,32 @@ if (FEATURES.UID2_CSTG) { if (xhr.status === 400) { const response = JSON.parse(xhr.responseText); if (this.isCstgApiClientErrorResponse(response)) { - rejectPromise(`Client error: ${response.message}`); + rejectPromise(prependMessage(`Client error: ${response.message}`)); } else { // A 400 should always be a client error. // Something has gone wrong. rejectPromise( - `API error: Response body was invalid for HTTP status 400: ${xhr.responseText}` + prependMessage(`UID2 API error: Response body was invalid for HTTP status 400: ${xhr.responseText}`) ); } } else if (xhr.status === 403) { const response = JSON.parse(xhr.responseText); if (this.isCstgApiForbiddenResponse(xhr)) { - rejectPromise(`Forbidden: ${response.message}`); + rejectPromise(prependMessage(`Forbidden: ${response.message}`)); } else { // A 403 should always be a forbidden response. // Something has gone wrong. rejectPromise( - `API error: Response body was invalid for HTTP status 403: ${xhr.responseText}` + prependMessage(`UID2 API error: Response body was invalid for HTTP status 403: ${xhr.responseText}`) ); } } else { rejectPromise( - `API error: Unexpected HTTP status ${xhr.status}: ${error}` + prependMessage(`UID2 API error: Unexpected HTTP status ${xhr.status}: ${error}`) ); } } catch (_e) { - rejectPromise(error); + rejectPromise(prependMessage(error)); } }, }, @@ -678,43 +688,45 @@ if (FEATURES.UID2_CSTG) { } export function Uid2GetId(config, prebidStorageManager, _logInfo, _logWarn) { + const logInfo = (...args) => logInfoWrapper(_logInfo, ...args); + let suppliedToken = null; const preferLocalStorage = (config.storage !== 'cookie'); - const storageManager = new Uid2StorageManager(prebidStorageManager, preferLocalStorage, config.internalStorage, _logInfo); - _logInfo(`Module is using ${preferLocalStorage ? 'local storage' : 'cookies'} for internal storage.`); + const storageManager = new Uid2StorageManager(prebidStorageManager, preferLocalStorage, config.internalStorage, logInfo); + logInfo(`Module is using ${preferLocalStorage ? 'local storage' : 'cookies'} for internal storage.`); const isCstgEnabled = clientSideTokenGenerator && clientSideTokenGenerator.isCSTGOptionsValid(config.cstg, _logWarn); if (isCstgEnabled) { - _logInfo(`Module is using client-side token generation.`); + logInfo(`Module is using client-side token generation.`); // Ignores config.paramToken and config.serverCookieName if any is provided suppliedToken = null; } else if (config.paramToken) { suppliedToken = config.paramToken; - _logInfo('Read token from params', suppliedToken); + logInfo('Read token from params', suppliedToken); } else if (config.serverCookieName) { suppliedToken = storageManager.readProvidedCookie(config.serverCookieName); - _logInfo('Read token from server-supplied cookie', suppliedToken); + logInfo('Read token from server-supplied cookie', suppliedToken); } let storedTokens = storageManager.getStoredValueWithFallback(); - _logInfo('Loaded module-stored tokens:', storedTokens); + logInfo('Loaded module-stored tokens:', storedTokens); if (storedTokens && typeof storedTokens === 'string') { // Stored value is a plain token - if no token is supplied, just use the stored value. if (!suppliedToken && !isCstgEnabled) { - _logInfo('Returning legacy cookie value.'); + logInfo('Returning legacy cookie value.'); return { id: storedTokens }; } // Otherwise, ignore the legacy value - it should get over-written later anyway. - _logInfo('Discarding superseded legacy cookie.'); + logInfo('Discarding superseded legacy cookie.'); storedTokens = null; } if (suppliedToken && storedTokens) { if (storedTokens.originalToken?.advertising_token !== suppliedToken.advertising_token) { - _logInfo('Server supplied new token - ignoring stored value.', storedTokens.originalToken?.advertising_token, suppliedToken.advertising_token); + logInfo('Server supplied new token - ignoring stored value.', storedTokens.originalToken?.advertising_token, suppliedToken.advertising_token); // Stored token wasn't originally sourced from the provided token - ignore the stored value. A new user has logged in? storedTokens = null; } @@ -723,16 +735,16 @@ export function Uid2GetId(config, prebidStorageManager, _logInfo, _logWarn) { if (FEATURES.UID2_CSTG && isCstgEnabled) { const cstgIdentity = clientSideTokenGenerator.getValidIdentity(config.cstg, _logWarn); if (cstgIdentity) { - if (storedTokens && clientSideTokenGenerator.isStoredTokenInvalid(cstgIdentity, storedTokens, _logInfo, _logWarn)) { + if (storedTokens && clientSideTokenGenerator.isStoredTokenInvalid(cstgIdentity, storedTokens, logInfo, _logWarn)) { storedTokens = null; } if (!storedTokens || Date.now() > storedTokens.latestToken.refresh_expires) { - const promise = clientSideTokenGenerator.generateTokenAndStore(config.apiBaseUrl, config.cstg, cstgIdentity, storageManager, _logInfo, _logWarn); - _logInfo('Generate token using CSTG'); + const promise = clientSideTokenGenerator.generateTokenAndStore(config.apiBaseUrl, config.cstg, cstgIdentity, storageManager, logInfo, _logWarn); + logInfo('Generate token using CSTG'); return { callback: (cb) => { promise.then((result) => { - _logInfo('Token generation responded, passing the new token on.', result); + logInfo('Token generation responded, passing the new token on.', result); cb(result); }); } }; @@ -742,25 +754,25 @@ export function Uid2GetId(config, prebidStorageManager, _logInfo, _logWarn) { const useSuppliedToken = !(storedTokens?.latestToken) || (suppliedToken && suppliedToken.identity_expires > storedTokens.latestToken.identity_expires); const newestAvailableToken = useSuppliedToken ? suppliedToken : storedTokens.latestToken; - _logInfo('UID2 module selected latest token', useSuppliedToken, newestAvailableToken); + logInfo('UID2 module selected latest token', useSuppliedToken, newestAvailableToken); if ((!newestAvailableToken || Date.now() > newestAvailableToken.refresh_expires)) { - _logInfo('Newest available token is expired and not refreshable.'); + logInfo('Newest available token is expired and not refreshable.'); return { id: null }; } if (Date.now() > newestAvailableToken.identity_expires) { - const promise = refreshTokenAndStore(config.apiBaseUrl, newestAvailableToken, config.clientId, storageManager, _logInfo, _logWarn); - _logInfo('Token is expired but can be refreshed, attempting refresh.'); + const promise = refreshTokenAndStore(config.apiBaseUrl, newestAvailableToken, config.clientId, storageManager, logInfo, _logWarn); + logInfo('Token is expired but can be refreshed, attempting refresh.'); return { callback: (cb) => { promise.then((result) => { - _logInfo('Refresh reponded, passing the updated token on.', result); + logInfo('Refresh reponded, passing the updated token on.', result); cb(result); }); } }; } // If should refresh (but don't need to), refresh in the background. if (Date.now() > newestAvailableToken.refresh_from) { - _logInfo(`Refreshing token in background with low priority.`); - refreshTokenAndStore(config.apiBaseUrl, newestAvailableToken, config.clientId, storageManager, _logInfo, _logWarn); + logInfo(`Refreshing token in background with low priority.`); + refreshTokenAndStore(config.apiBaseUrl, newestAvailableToken, config.clientId, storageManager, logInfo, _logWarn); } const tokens = { originalToken: suppliedToken ?? storedTokens?.originalToken, diff --git a/modules/userId/eids.js b/modules/userId/eids.js index e5f7e3b8fb2..930dd34b23d 100644 --- a/modules/userId/eids.js +++ b/modules/userId/eids.js @@ -1,4 +1,7 @@ import {deepAccess, deepClone, isFn, isPlainObject, isStr} from '../../src/utils.js'; +/* + * @typedef {import('../modules/userId/index.js').SubmoduleContainer} SubmoduleContainer + */ export const EID_CONFIG = new Map(); diff --git a/modules/utiqIdSystem.js b/modules/utiqIdSystem.js index 8228da3a629..d6b8aae44a3 100644 --- a/modules/utiqIdSystem.js +++ b/modules/utiqIdSystem.js @@ -27,11 +27,6 @@ function getUtiqFromStorage() { let utiqPassStorage = JSON.parse( storage.getDataFromLocalStorage('utiqPass') ); - logInfo( - `${LOG_PREFIX}: Local storage utiqPass: ${JSON.stringify( - utiqPassStorage - )}` - ); if ( utiqPassStorage && @@ -40,12 +35,19 @@ function getUtiqFromStorage() { utiqPassStorage.connectId.idGraph.length > 0 ) { utiqPass = utiqPassStorage.connectId.idGraph[0]; + + logInfo( + `${LOG_PREFIX}: Local storage utiqPass: ${JSON.stringify( + utiqPassStorage + )}` + ); + + logInfo( + `${LOG_PREFIX}: Graph of utiqPass: ${JSON.stringify( + utiqPass + )}` + ); } - logInfo( - `${LOG_PREFIX}: Graph of utiqPass: ${JSON.stringify( - utiqPass - )}` - ); return { utiq: diff --git a/modules/validationFpdModule/index.js b/modules/validationFpdModule/index.js index 70af9d30ec3..2330c41099c 100644 --- a/modules/validationFpdModule/index.js +++ b/modules/validationFpdModule/index.js @@ -13,8 +13,8 @@ let optout; /** * Check if data passed is empty - * @param {*} value to test against - * @returns {Boolean} is value empty + * @param {*} data to test against + * @returns {Boolean} is data empty */ function isEmptyData(data) { let check = true; @@ -30,10 +30,10 @@ function isEmptyData(data) { /** * Check if required keys exist in data object - * @param {Object} data object - * @param {Array} array of required keys - * @param {String} object path (for printing warning) - * @param {Number} index of object value in the data array (for printing warning) + * @param {Object} obj data object + * @param {Array} required array of required keys + * @param {String} parent object path (for printing warning) + * @param {Number} i index of object value in the data array (for printing warning) * @returns {Boolean} is requirements fulfilled */ function getRequiredData(obj, required, parent, i) { @@ -51,8 +51,8 @@ function getRequiredData(obj, required, parent, i) { /** * Check if data type is valid - * @param {*} value to test against - * @param {Object} object containing type definition and if should be array bool + * @param {*} data value to test against + * @param {Object} mapping object containing type definition and if should be array bool * @returns {Boolean} is type fulfilled */ function typeValidation(data, mapping) { @@ -77,10 +77,10 @@ function typeValidation(data, mapping) { /** * Validates ortb2 data arrays and filters out invalid data - * @param {Array} ortb2 data array - * @param {Object} object defining child type and if array - * @param {String} config path of data array - * @param {String} parent path for logging warnings + * @param {Array} arr ortb2 data array + * @param {Object} child object defining child type and if array + * @param {String} path config path of data array + * @param {String} parent parent path for logging warnings * @returns {Array} validated/filtered data */ export function filterArrayData(arr, child, path, parent) { @@ -136,9 +136,9 @@ export function filterArrayData(arr, child, path, parent) { /** * Validates ortb2 object and filters out invalid data - * @param {Object} ortb2 object - * @param {String} config path of data array - * @param {String} parent path for logging warnings + * @param {Object} fpd ortb2 object + * @param {String} path config path of data array + * @param {String} parent parent path for logging warnings * @returns {Object} validated/filtered data */ export function validateFpd(fpd, path = '', parent = '') { @@ -190,6 +190,8 @@ export function validateFpd(fpd, path = '', parent = '') { /** * Run validation on global and bidder config data for ortb2 + * @param {Object} data global and bidder config data + * @returns {Object} validated data */ function runValidations(data) { return { @@ -200,6 +202,9 @@ function runValidations(data) { /** * Sets default values to ortb2 if exists and adds currency and ortb2 setConfig callbacks on init + * @param {Object} fpdConf configuration object + * @param {Object} data ortb2 data + * @returns {Object} processed data */ export function processFpd(fpdConf, data) { // Checks for existsnece of pubcid optout cookie/storage @@ -210,11 +215,11 @@ export function processFpd(fpdConf, data) { return (!fpdConf.skipValidations) ? runValidations(data) : data; } -/** @type {firstPartyDataSubmodule} */ +/** @type {{name: string, queue: number, processFpd: function}} */ export const validationSubmodule = { name: 'validation', queue: 1, processFpd } -submodule('firstPartyData', validationSubmodule) +submodule('firstPartyData', validationSubmodule); diff --git a/modules/viantOrtbBidAdapter.js b/modules/viantOrtbBidAdapter.js index d056dfeb2eb..cfc4c450db8 100644 --- a/modules/viantOrtbBidAdapter.js +++ b/modules/viantOrtbBidAdapter.js @@ -5,7 +5,8 @@ import {ortbConverter} from '../libraries/ortbConverter/converter.js' import {deepAccess, getBidIdParameter, logError} from '../src/utils.js'; const BIDDER_CODE = 'viant'; -const ENDPOINT = 'https://bidders-us-east-1.adelphic.net/d/rtb/v25/prebid/bidder' +const ENDPOINT = 'https://bidders-us.adelphic.net/d/rtb/v25/prebid/bidder' +const ADAPTER_VERSION = '2.0.0'; const DEFAULT_BID_TTL = 300; const DEFAULT_CURRENCY = 'USD'; @@ -85,6 +86,25 @@ function createRequest(bidRequests, bidderRequest, mediaType) { if (!data.regs.ext) data.regs.ext = {}; data.regs.ext.us_privacy = bidderRequest.uspConsent; } + let imp = data.imp || []; + let dealsMap = new Map(); + if (bidderRequest.bids) { + bidderRequest.bids.forEach(bid => { + if (bid.ortb2Imp && bid.ortb2Imp.pmp) { + dealsMap.set(bid.bidId, bid.ortb2Imp.pmp); + } + }); + } + imp.forEach((element) => { + let deals = dealsMap.get(element.id); + if (deals) { + element.pmp = deals; + } + }); + data.ext = data.ext || {}; + data.ext.viant = { + adapterVersion: ADAPTER_VERSION + }; return { method: 'POST', url: ENDPOINT, diff --git a/modules/vidazooBidAdapter.js b/modules/vidazooBidAdapter.js index 21ba444c69c..ed732a4814a 100644 --- a/modules/vidazooBidAdapter.js +++ b/modules/vidazooBidAdapter.js @@ -32,12 +32,12 @@ function createUniqueRequestData(hashUrl) { const vdzhum = getCacheOpt(storage, OPT_TIME_KEY); return { - dealId: dealId, sessionId: sessionId, ptrace: ptrace, vdzhum: vdzhum + dealId: dealId, sessionId: sessionId, ptrace: ptrace, vdzhum: vdzhum, webSessionId: webSessionId }; } -const buildRequests = createBuildRequestsFn(createDomain, createUniqueRequestData, webSessionId, storage, BIDDER_CODE, BIDDER_VERSION); -const interpretResponse = createInterpretResponseFn(BIDDER_CODE); +const buildRequests = createBuildRequestsFn(createDomain, createUniqueRequestData, storage, BIDDER_CODE, BIDDER_VERSION, true); +const interpretResponse = createInterpretResponseFn(BIDDER_CODE, true); const getUserSyncs = createUserSyncGetter({ iframeSyncUrl: 'https://sync.cootlogix.com/api/sync/iframe', imageSyncUrl: 'https://sync.cootlogix.com/api/sync/image' }); diff --git a/modules/videojsVideoProvider.js b/modules/videojsVideoProvider.js index efe518ea495..0be4c6feede 100644 --- a/modules/videojsVideoProvider.js +++ b/modules/videojsVideoProvider.js @@ -13,6 +13,9 @@ import { submodule } from '../src/hook.js'; import stateFactory from '../libraries/video/shared/state.js'; import { PLAYBACK_MODE } from '../libraries/video/constants/constants.js'; import { getEventHandler } from '../libraries/video/shared/eventHandler.js'; +/** + * @typedef {import('../libraries/video/shared/state.js').State} State + */ /* Plugins of interest: diff --git a/modules/visxBidAdapter.js b/modules/visxBidAdapter.js index c7f415e4dac..217cab48cee 100644 --- a/modules/visxBidAdapter.js +++ b/modules/visxBidAdapter.js @@ -1,10 +1,11 @@ -import {deepAccess, logError, parseSizesInput, triggerPixel} from '../src/utils.js'; +import {deepAccess, logError, mergeDeep, parseSizesInput, sizeTupleToRtbSize, sizesToSizeTuples, triggerPixel} from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {config} from '../src/config.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; import {INSTREAM as VIDEO_INSTREAM} from '../src/video.js'; import {getStorageManager} from '../src/storageManager.js'; import {getGptSlotInfoForAdUnitCode} from '../libraries/gptUtils/gptUtils.js'; +import { getBidFromResponse } from '../libraries/processResponse/index.js'; const BIDDER_CODE = 'visx'; const GVLID = 154; @@ -32,7 +33,7 @@ const LOG_ERROR_MESS = { onlyVideoInstream: `Only video ${VIDEO_INSTREAM} supported`, videoMissing: 'Bid request videoType property is missing - ' }; -const currencyWhiteList = ['EUR', 'USD', 'GBP', 'PLN']; +const currencyWhiteList = ['EUR', 'USD', 'GBP', 'PLN', 'CHF', 'SEK']; export const storage = getStorageManager({bidderCode: BIDDER_CODE}); const _bidResponseTimeLogged = []; export const spec = { @@ -69,6 +70,7 @@ export const spec = { let payloadSite; let payloadRegs; let payloadContent; + let payloadUser; if (currencyWhiteList.indexOf(currency) === -1) { logError(LOG_ERROR_MESS.notAllowedCurrency + currency); @@ -116,6 +118,24 @@ export const spec = { const { ortb2 } = bidderRequest; const { device, site, regs, content } = ortb2; + const userOrtb2 = ortb2.user; + let user; + let userReq; + const vads = _getUserId(); + if (payloadUserEids || payload.gdpr_consent || vads) { + user = { + ext: { + ...(payloadUserEids && { eids: payloadUserEids }), + ...(payload.gdpr_consent && { consent: payload.gdpr_consent }), + ...(vads && { vads }) + } + }; + } + if (user) { + userReq = mergeDeep(user, userOrtb2); + } else { + userReq = userOrtb2; + } if (device) { payloadDevice = device; } @@ -128,6 +148,9 @@ export const spec = { if (content) { payloadContent = content; } + if (userReq) { + payloadUser = userReq; + } } const tmax = timeout; @@ -139,14 +162,6 @@ export const spec = { } }; - const vads = _getUserId(); - const user = { - ext: { - ...(payloadUserEids && { eids: payloadUserEids }), - ...(payload.gdpr_consent && { consent: payload.gdpr_consent }), - ...(vads && { vads }) - } - }; if (payloadRegs === undefined) { payloadRegs = ('gdpr_applies' in payload) && { ext: { @@ -161,7 +176,7 @@ export const spec = { tmax, cur: [currency], source, - ...(Object.keys(user.ext).length && { user }), + ...(payloadUser && { user: payloadUser }), ...(payloadRegs && {regs: payloadRegs}), ...(payloadDevice && { device: payloadDevice }), ...(payloadSite && { site: payloadSite }), @@ -190,7 +205,7 @@ export const spec = { if (!errorMessage && serverResponse.seatbid) { serverResponse.seatbid.forEach(respItem => { - _addBidResponse(_getBidFromResponse(respItem), bidsMap, currency, bidResponses); + _addBidResponse(getBidFromResponse(respItem, LOG_ERROR_MESS), bidsMap, currency, bidResponses); }); } if (errorMessage) logError(errorMessage); @@ -260,13 +275,7 @@ function makeBanner(bannerParams) { if (bannerSizes) { const sizes = parseSizesInput(bannerSizes); if (sizes.length) { - const format = sizes.map(size => { - const [ width, height ] = size.split('x'); - const w = parseInt(width, 10); - const h = parseInt(height, 10); - return { w, h }; - }); - + const format = sizesToSizeTuples(bannerSizes).map(sizeTupleToRtbSize); return { format }; } } @@ -306,17 +315,6 @@ function buildImpObject(bid) { } } -function _getBidFromResponse(respItem) { - if (!respItem) { - logError(LOG_ERROR_MESS.emptySeatbid); - } else if (!respItem.bid) { - logError(LOG_ERROR_MESS.hasNoArrayOfBids + JSON.stringify(respItem)); - } else if (!respItem.bid[0]) { - logError(LOG_ERROR_MESS.noBid); - } - return respItem && respItem.bid && respItem.bid[0]; -} - function _addBidResponse(serverBid, bidsMap, currency, bidResponses) { if (!serverBid) return; let errorMessage; diff --git a/modules/winrBidAdapter.js b/modules/winrBidAdapter.js index d81227d3606..b29a854cbab 100644 --- a/modules/winrBidAdapter.js +++ b/modules/winrBidAdapter.js @@ -13,9 +13,10 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER} from '../src/mediaTypes.js'; import {find, includes} from '../src/polyfill.js'; import {getStorageManager} from '../src/storageManager.js'; -import {hasPurpose1Consent} from '../src/utils/gpdr.js'; +import {hasPurpose1Consent} from '../src/utils/gdpr.js'; import {getANKeywordParam} from '../libraries/appnexusUtils/anKeywords.js'; import {convertCamelToUnderscore} from '../libraries/appnexusUtils/anUtils.js'; +import { transformSizes } from '../libraries/sizeUtils/tranformSize.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest @@ -470,32 +471,6 @@ function bidToTag(bid) { return tag; } -/* Turn bid request sizes into ut-compatible format */ -function transformSizes(requestSizes) { - let sizes = []; - let sizeObj = {}; - - if ( - isArray(requestSizes) && - requestSizes.length === 2 && - !isArray(requestSizes[0]) - ) { - sizeObj.width = parseInt(requestSizes[0], 10); - sizeObj.height = parseInt(requestSizes[1], 10); - sizes.push(sizeObj); - } else if (typeof requestSizes === 'object') { - for (let i = 0; i < requestSizes.length; i++) { - let size = requestSizes[i]; - sizeObj = {}; - sizeObj.width = parseInt(size[0], 10); - sizeObj.height = parseInt(size[1], 10); - sizes.push(sizeObj); - } - } - - return sizes; -} - function hasUserInfo(bid) { return !!bid.params.user; } diff --git a/modules/yahooAdsBidAdapter.js b/modules/yahooAdsBidAdapter.js index f50aa9cf002..49efb7c20cb 100644 --- a/modules/yahooAdsBidAdapter.js +++ b/modules/yahooAdsBidAdapter.js @@ -3,7 +3,7 @@ import { BANNER, VIDEO } from '../src/mediaTypes.js'; import { deepAccess, isFn, isStr, isNumber, isArray, isEmpty, isPlainObject, generateUUID, logInfo, logWarn } from '../src/utils.js'; import { config } from '../src/config.js'; import { Renderer } from '../src/Renderer.js'; -import {hasPurpose1Consent} from '../src/utils/gpdr.js'; +import {hasPurpose1Consent} from '../src/utils/gdpr.js'; const INTEGRATION_METHOD = 'prebid.js'; const BIDDER_CODE = 'yahooAds'; diff --git a/modules/yandexIdSystem.js b/modules/yandexIdSystem.js index f24e33a8c44..24b1f611ccd 100644 --- a/modules/yandexIdSystem.js +++ b/modules/yandexIdSystem.js @@ -128,7 +128,7 @@ class YandexUidGenerator { } _getRandomGenerator() { - if (crypto) { + if (window.crypto) { return () => { const buffer = new Uint32Array(1); crypto.getRandomValues(buffer); diff --git a/modules/zeta_global_sspBidAdapter.js b/modules/zeta_global_sspBidAdapter.js index a273927e1ec..2ea6d745096 100644 --- a/modules/zeta_global_sspBidAdapter.js +++ b/modules/zeta_global_sspBidAdapter.js @@ -128,8 +128,8 @@ export const spec = { id: bidderRequest.bidderRequestId, cur: [DEFAULT_CUR], imp: imps, - site: params.site ? params.site : {}, - device: {...(bidderRequest.ortb2?.device || {}), ...params.device}, + site: {...bidderRequest?.ortb2?.site, ...params?.site}, + device: {...bidderRequest?.ortb2?.device, ...params?.device}, user: params.user ? params.user : {}, app: params.app ? params.app : {}, ext: { diff --git a/package-lock.json b/package-lock.json index 343bc1f8867..3ca36a169ae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "prebid.js", - "version": "9.4.0-pre", + "version": "9.7.0-pre", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "prebid.js", - "version": "9.4.0-pre", + "version": "9.7.0-pre", "license": "Apache-2.0", "dependencies": { "@babel/core": "^7.24.6", @@ -46,7 +46,7 @@ "eslint": "^7.27.0", "eslint-config-standard": "^10.2.1", "eslint-plugin-import": "^2.20.2", - "eslint-plugin-jsdoc": "^38.1.6", + "eslint-plugin-jsdoc": "^48.5.0", "eslint-plugin-node": "^11.1.0", "eslint-plugin-prebid": "file:./plugins/eslint", "eslint-plugin-promise": "^5.1.0", @@ -54,7 +54,7 @@ "execa": "^1.0.0", "faker": "^5.5.3", "fs.extra": "^1.3.2", - "gulp": "^4.0.0", + "gulp": "^4.0.2", "gulp-clean": "^0.4.0", "gulp-concat": "^2.6.0", "gulp-connect": "^5.7.0", @@ -95,7 +95,7 @@ "opn": "^5.4.0", "querystring": "^0.2.1", "resolve-from": "^5.0.0", - "sinon": "^4.1.3", + "sinon": "^4.5.0", "through2": "^4.0.2", "url": "^0.11.0", "url-parse": "^1.0.5", @@ -1756,17 +1756,20 @@ } }, "node_modules/@es-joy/jsdoccomment": { - "version": "0.22.2", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.22.2.tgz", - "integrity": "sha512-pM6WQKcuAtdYoqCsXSvVSu3Ij8K0HY50L8tIheOKHDl0wH1uA4zbP88etY8SIeP16NVCMCTFU+Q2DahSKheGGQ==", + "version": "0.43.1", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.43.1.tgz", + "integrity": "sha512-I238eDtOolvCuvtxrnqtlBaw0BwdQuYqK7eA6XIonicMdOOOb75mqdIzkGDUbS04+1Di007rgm9snFRNeVrOog==", "dev": true, "dependencies": { - "comment-parser": "1.3.1", - "esquery": "^1.4.0", - "jsdoc-type-pratt-parser": "~2.2.5" + "@types/eslint": "^8.56.5", + "@types/estree": "^1.0.5", + "@typescript-eslint/types": "^7.2.0", + "comment-parser": "1.4.1", + "esquery": "^1.5.0", + "jsdoc-type-pratt-parser": "~4.0.0" }, "engines": { - "node": "^12 || ^14 || ^16 || ^17" + "node": ">=16" } }, "node_modules/@eslint/eslintrc": { @@ -2003,6 +2006,7 @@ "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -2020,6 +2024,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -2031,13 +2036,15 @@ "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, + "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -2055,6 +2062,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -2097,6 +2105,7 @@ "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", "dev": true, + "license": "MIT", "dependencies": { "jest-get-type": "^29.6.3" }, @@ -2121,6 +2130,7 @@ "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -2138,6 +2148,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -2153,6 +2164,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2169,6 +2181,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -2180,13 +2193,15 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@jest/types/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2196,6 +2211,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -2323,11 +2339,24 @@ "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, + "license": "MIT", "optional": true, "engines": { "node": ">=14" } }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/@polka/url": { "version": "1.0.0-next.25", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.25.tgz", @@ -2487,6 +2516,7 @@ "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", "dev": true, + "license": "MIT", "optional": true, "peer": true, "engines": { @@ -2614,13 +2644,15 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/istanbul-lib-report": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", "dev": true, + "license": "MIT", "dependencies": { "@types/istanbul-lib-coverage": "*" } @@ -2630,6 +2662,7 @@ "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/istanbul-lib-report": "*" } @@ -2716,7 +2749,8 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/supports-color": { "version": "8.1.3", @@ -2763,6 +2797,7 @@ "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -2772,6 +2807,7 @@ "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", "dev": true, + "license": "MIT", "dependencies": { "@types/yargs-parser": "*" } @@ -2780,7 +2816,8 @@ "version": "21.0.3", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/yauzl": { "version": "2.10.3", @@ -2792,6 +2829,19 @@ "@types/node": "*" } }, + "node_modules/@typescript-eslint/types": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.15.0.tgz", + "integrity": "sha512-aV1+B1+ySXbQH0pLK0rx66I3IkiZNidYobyfn0WFsdGhSXw+P3YOqeTq5GED458SfB24tg+ux3S+9g118hjlTw==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@videojs/http-streaming": { "version": "2.16.3", "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.16.3.tgz", @@ -2917,17 +2967,18 @@ "optional": true }, "node_modules/@wdio/browserstack-service": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/@wdio/browserstack-service/-/browserstack-service-8.38.2.tgz", - "integrity": "sha512-dBvTK97deVbyDskCRdcQ47xuR7QYx3mqNFJUZLWBitwFV/DU5YIpCbGlySLc4gkO4//Zn1A3Gh/TOGWZrigcCQ==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/browserstack-service/-/browserstack-service-8.39.0.tgz", + "integrity": "sha512-EEbmg9hBk0FAf9b2oHEL0w8aIscKPy3ms0/zSaLp+jDMuWHllpVQ83GCW9qHIJbKUzTNUlF031fRdPzq+GQaVg==", "dev": true, + "license": "MIT", "dependencies": { "@percy/appium-app": "^2.0.1", "@percy/selenium-webdriver": "^2.0.3", "@types/gitconfiglocal": "^2.0.1", "@wdio/logger": "8.38.0", - "@wdio/reporter": "8.38.2", - "@wdio/types": "8.38.2", + "@wdio/reporter": "8.39.0", + "@wdio/types": "8.39.0", "browserstack-local": "^1.5.1", "chalk": "^5.3.0", "csv-writer": "^1.6.0", @@ -2936,7 +2987,7 @@ "gitconfiglocal": "^2.1.0", "got": "^12.6.1", "uuid": "^9.0.0", - "webdriverio": "8.38.2", + "webdriverio": "8.39.0", "winston-transport": "^4.5.0", "yauzl": "^3.0.0" }, @@ -2947,98 +2998,67 @@ "@wdio/cli": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@wdio/browserstack-service/node_modules/@puppeteer/browsers": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", - "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", + "node_modules/@wdio/browserstack-service/node_modules/@wdio/reporter": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-8.39.0.tgz", + "integrity": "sha512-XahXhmaA1okdwg4/ThHFSqy/41KywxhbtszPcTzyXB+9INaqFNHA1b1vvWs0mrD5+tTtKbg4caTcEHVJU4iv0w==", "dev": true, + "license": "MIT", "dependencies": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "progress": "2.0.3", - "proxy-agent": "6.3.0", - "tar-fs": "3.0.4", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.1" - }, - "bin": { - "browsers": "lib/cjs/main-cli.js" - }, - "engines": { - "node": ">=16.3.0" - }, - "peerDependencies": { - "typescript": ">= 4.7.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@wdio/browserstack-service/node_modules/@puppeteer/browsers/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" + "@types/node": "^20.1.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.39.0", + "diff": "^5.0.0", + "object-inspect": "^1.12.0" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": "^16.13 || >=18" } }, - "node_modules/@wdio/browserstack-service/node_modules/@puppeteer/browsers/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@wdio/browserstack-service/node_modules/agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "node_modules/@wdio/browserstack-service/node_modules/@wdio/types": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.39.0.tgz", + "integrity": "sha512-86lcYROTapOJuFd9ouomFDfzDnv3Kn+jE0RmqfvN9frZAeLVJ5IKjX9M6HjplsyTZhjGO1uCaehmzx+HJus33Q==", "dev": true, + "license": "MIT", "dependencies": { - "debug": "^4.3.4" + "@types/node": "^20.1.0" }, "engines": { - "node": ">= 14" + "node": "^16.13 || >=18" } }, - "node_modules/@wdio/browserstack-service/node_modules/agent-base/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "node_modules/@wdio/browserstack-service/node_modules/@wdio/utils": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.39.0.tgz", + "integrity": "sha512-jY+n6jlGeK+9Tx8T659PKLwMQTGpLW5H78CSEWgZLbjbVSr2LfGR8Lx0CRktNXxAtqEVZPj16Pi74OtAhvhE6Q==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "@puppeteer/browsers": "^1.6.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.39.0", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.1.0", + "edgedriver": "^5.5.0", + "geckodriver": "^4.3.1", + "get-port": "^7.0.0", + "import-meta-resolve": "^4.0.0", + "locate-app": "^2.1.0", + "safaridriver": "^0.1.0", + "split2": "^4.2.0", + "wait-port": "^1.0.4" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": "^16.13 || >=18" } }, - "node_modules/@wdio/browserstack-service/node_modules/agent-base/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@wdio/browserstack-service/node_modules/archiver": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz", "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==", "dev": true, + "license": "MIT", "dependencies": { "archiver-utils": "^5.0.2", "async": "^3.2.4", @@ -3057,6 +3077,7 @@ "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz", "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==", "dev": true, + "license": "MIT", "dependencies": { "glob": "^10.0.0", "graceful-fs": "^4.2.0", @@ -3074,13 +3095,15 @@ "version": "3.2.5", "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@wdio/browserstack-service/node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } @@ -3104,6 +3127,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" @@ -3114,6 +3138,7 @@ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.0.0" } @@ -3135,6 +3160,7 @@ "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-1.1.2.tgz", "integrity": "sha512-YclTJey34KUm5jB1aEJCq807bSievi7Nb/TU4Gu504fUYi3jw3KCIaH6L7nFWQhdEgH3V+wCh+kKD1P5cXnfxw==", "dev": true, + "license": "Apache-2.0", "optional": true, "peer": true, "dependencies": { @@ -3155,6 +3181,7 @@ "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz", "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==", "dev": true, + "license": "MIT", "dependencies": { "crc-32": "^1.2.0", "crc32-stream": "^6.0.0", @@ -3171,6 +3198,7 @@ "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz", "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==", "dev": true, + "license": "MIT", "dependencies": { "crc-32": "^1.2.0", "readable-stream": "^4.0.0" @@ -3180,12 +3208,15 @@ } }, "node_modules/@wdio/browserstack-service/node_modules/cross-fetch": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", - "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz", + "integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==", "dev": true, + "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "node-fetch": "^2.6.12" + "node-fetch": "^2.6.11" } }, "node_modules/@wdio/browserstack-service/node_modules/debug": { @@ -3193,6 +3224,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "optional": true, "peer": true, "dependencies": { @@ -3200,19 +3232,20 @@ } }, "node_modules/@wdio/browserstack-service/node_modules/devtools": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/devtools/-/devtools-8.38.2.tgz", - "integrity": "sha512-8b+naOPzYqzsiYtZZKYJnUnSqSOIg5orvna2SlWT2kFhkggbAJ1bbMzW7rps6onLfxp93wCNEIvngb9JuxwDsg==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-8.39.0.tgz", + "integrity": "sha512-QNbvNTNQMlU5gZqbmqzF92vfMOP/Eaa8KcvRj87M0jbn3dfwOeBC7WiECPFQ0MAfmynfarK7G7Ec+TfbAAEyNQ==", "dev": true, + "license": "MIT", "optional": true, "peer": true, "dependencies": { "@types/node": "^20.1.0", - "@wdio/config": "8.38.2", + "@wdio/config": "8.39.0", "@wdio/logger": "8.38.0", "@wdio/protocols": "8.38.0", - "@wdio/types": "8.38.2", - "@wdio/utils": "8.38.2", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.39.0", "chrome-launcher": "^1.0.0", "edge-paths": "^3.0.5", "import-meta-resolve": "^4.0.0", @@ -3227,90 +3260,196 @@ } }, "node_modules/@wdio/browserstack-service/node_modules/devtools-protocol": { - "version": "0.0.1302984", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1302984.tgz", - "integrity": "sha512-Rgh2Sk5fUSCtEx4QGH9iwTyECdFPySG2nlz5J8guGh2Wlha6uzSOCq/DCEC8faHlLaMPZJMuZ4ovgcX4LvOkKA==", - "dev": true + "version": "0.0.1120988", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1120988.tgz", + "integrity": "sha512-39fCpE3Z78IaIPChJsP6Lhmkbf4dWXOmzLk/KFTdRkNk/0JymRIfUynDVRndV9HoDz8PyalK1UH21ST/ivwW5Q==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "peer": true }, - "node_modules/@wdio/browserstack-service/node_modules/devtools/node_modules/@puppeteer/browsers": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.3.0.tgz", - "integrity": "sha512-an3QdbNPkuU6qpxpbssxAbjRLJcF+eP4L8UqIY3+6n0sbaVxw5pz7PiCLy9g32XEZuoamUlV5ZQPnA6FxvkIHA==", + "node_modules/@wdio/browserstack-service/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "optional": true, "peer": true, - "dependencies": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "http-proxy-agent": "5.0.0", - "https-proxy-agent": "5.0.1", - "progress": "2.0.3", - "proxy-from-env": "1.1.0", - "tar-fs": "2.1.1", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.1" + "engines": { + "node": ">=10" }, - "bin": { - "browsers": "lib/cjs/main-cli.js" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" }, "engines": { - "node": ">=16.0.0" + "node": ">= 6" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/http-proxy-agent/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "ms": "2.1.2" }, - "peerDependencies": { - "typescript": ">= 4.7.4" + "engines": { + "node": ">=6.0" }, "peerDependenciesMeta": { - "typescript": { + "supports-color": { "optional": true } } }, - "node_modules/@wdio/browserstack-service/node_modules/devtools/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "node_modules/@wdio/browserstack-service/node_modules/http-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/@wdio/browserstack-service/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/lighthouse-logger": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-2.0.1.tgz", + "integrity": "sha512-ioBrW3s2i97noEmnXxmUq7cjIcVRjT5HBpAYy8zE11CxU9HqlWHHeRxfeN1tn8F7OEMVPIC9x1f8t3Z7US9ehQ==", + "dev": true, + "license": "Apache-2.0", "optional": true, "peer": true, "dependencies": { - "debug": "4" + "debug": "^2.6.9", + "marky": "^1.2.2" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">= 6.0.0" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@wdio/browserstack-service/node_modules/devtools/node_modules/chromium-bidi": { - "version": "0.4.9", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.9.tgz", - "integrity": "sha512-u3DC6XwgLCA9QJ5ak1voPslCmacQdulZNCPsI3qNXxSnEcZS7DFIbww+5RM2bznMEje7cc0oydavRLRvOIZtHw==", + "node_modules/@wdio/browserstack-service/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, + "license": "MIT", "optional": true, - "peer": true, + "peer": true + }, + "node_modules/@wdio/browserstack-service/node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", "dependencies": { - "mitt": "3.0.0" + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" }, "peerDependencies": { - "devtools-protocol": "*" + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } } }, - "node_modules/@wdio/browserstack-service/node_modules/devtools/node_modules/cross-fetch": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz", - "integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==", + "node_modules/@wdio/browserstack-service/node_modules/proxy-agent": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.0.tgz", + "integrity": "sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og==", "dev": true, - "optional": true, - "peer": true, + "license": "MIT", "dependencies": { - "node-fetch": "^2.6.11" + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.0.0", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.1" + }, + "engines": { + "node": ">= 14" } }, - "node_modules/@wdio/browserstack-service/node_modules/devtools/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/@wdio/browserstack-service/node_modules/proxy-agent/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", "dev": true, - "optional": true, - "peer": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/proxy-agent/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -3323,58 +3462,47 @@ } } }, - "node_modules/@wdio/browserstack-service/node_modules/devtools/node_modules/devtools-protocol": { - "version": "0.0.1120988", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1120988.tgz", - "integrity": "sha512-39fCpE3Z78IaIPChJsP6Lhmkbf4dWXOmzLk/KFTdRkNk/0JymRIfUynDVRndV9HoDz8PyalK1UH21ST/ivwW5Q==", - "dev": true, - "optional": true, - "peer": true - }, - "node_modules/@wdio/browserstack-service/node_modules/devtools/node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "node_modules/@wdio/browserstack-service/node_modules/proxy-agent/node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "dev": true, - "optional": true, - "peer": true, + "license": "MIT", "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" + "agent-base": "^7.1.0", + "debug": "^4.3.4" }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, - "node_modules/@wdio/browserstack-service/node_modules/devtools/node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "node_modules/@wdio/browserstack-service/node_modules/proxy-agent/node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", "dev": true, - "optional": true, - "peer": true, + "license": "MIT", "dependencies": { - "agent-base": "6", + "agent-base": "^7.0.2", "debug": "4" }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, - "node_modules/@wdio/browserstack-service/node_modules/devtools/node_modules/ms": { + "node_modules/@wdio/browserstack-service/node_modules/proxy-agent/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true, - "optional": true, - "peer": true + "license": "MIT" }, - "node_modules/@wdio/browserstack-service/node_modules/devtools/node_modules/puppeteer-core": { + "node_modules/@wdio/browserstack-service/node_modules/puppeteer-core": { "version": "20.3.0", "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.3.0.tgz", "integrity": "sha512-264pBrIui5bO6NJeOcbJrLa0OCwmA4+WK00JMrLIKTfRiqe2gx8KWTzLsjyw/bizErp3TKS7vt/I0i5fTC+mAw==", "dev": true, + "license": "Apache-2.0", "optional": true, "peer": true, "dependencies": { @@ -3397,237 +3525,30 @@ } } }, - "node_modules/@wdio/browserstack-service/node_modules/devtools/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@wdio/browserstack-service/node_modules/devtools/node_modules/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/@wdio/browserstack-service/node_modules/devtools/node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@wdio/browserstack-service/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@wdio/browserstack-service/node_modules/https-proxy-agent": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", - "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", - "dev": true, - "dependencies": { - "agent-base": "^7.0.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/@wdio/browserstack-service/node_modules/https-proxy-agent/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@wdio/browserstack-service/node_modules/https-proxy-agent/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@wdio/browserstack-service/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@wdio/browserstack-service/node_modules/lighthouse-logger": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-2.0.1.tgz", - "integrity": "sha512-ioBrW3s2i97noEmnXxmUq7cjIcVRjT5HBpAYy8zE11CxU9HqlWHHeRxfeN1tn8F7OEMVPIC9x1f8t3Z7US9ehQ==", + "node_modules/@wdio/browserstack-service/node_modules/puppeteer-core/node_modules/@puppeteer/browsers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.3.0.tgz", + "integrity": "sha512-an3QdbNPkuU6qpxpbssxAbjRLJcF+eP4L8UqIY3+6n0sbaVxw5pz7PiCLy9g32XEZuoamUlV5ZQPnA6FxvkIHA==", "dev": true, + "license": "Apache-2.0", "optional": true, "peer": true, "dependencies": { - "debug": "^2.6.9", - "marky": "^1.2.2" - } - }, - "node_modules/@wdio/browserstack-service/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/@wdio/browserstack-service/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@wdio/browserstack-service/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "optional": true, - "peer": true - }, - "node_modules/@wdio/browserstack-service/node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dev": true, - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/@wdio/browserstack-service/node_modules/proxy-agent": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.0.tgz", - "integrity": "sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og==", - "dev": true, - "dependencies": { - "agent-base": "^7.0.2", - "debug": "^4.3.4", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.0", - "lru-cache": "^7.14.1", - "pac-proxy-agent": "^7.0.0", - "proxy-from-env": "^1.1.0", - "socks-proxy-agent": "^8.0.1" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/@wdio/browserstack-service/node_modules/proxy-agent/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@wdio/browserstack-service/node_modules/proxy-agent/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@wdio/browserstack-service/node_modules/puppeteer-core": { - "version": "20.9.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.9.0.tgz", - "integrity": "sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==", - "dev": true, - "dependencies": { - "@puppeteer/browsers": "1.4.6", - "chromium-bidi": "0.4.16", - "cross-fetch": "4.0.0", "debug": "4.3.4", - "devtools-protocol": "0.0.1147663", - "ws": "8.13.0" + "extract-zip": "2.0.1", + "http-proxy-agent": "5.0.0", + "https-proxy-agent": "5.0.1", + "progress": "2.0.3", + "proxy-from-env": "1.1.0", + "tar-fs": "2.1.1", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" }, "engines": { - "node": ">=16.3.0" + "node": ">=16.0.0" }, "peerDependencies": { "typescript": ">= 4.7.4" @@ -3643,6 +3564,9 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, + "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "ms": "2.1.2" }, @@ -3655,23 +3579,21 @@ } } }, - "node_modules/@wdio/browserstack-service/node_modules/puppeteer-core/node_modules/devtools-protocol": { - "version": "0.0.1147663", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz", - "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==", - "dev": true - }, "node_modules/@wdio/browserstack-service/node_modules/puppeteer-core/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "dev": true, + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/@wdio/browserstack-service/node_modules/readable-stream": { "version": "4.5.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", "dev": true, + "license": "MIT", "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", @@ -3688,6 +3610,7 @@ "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-11.0.3.tgz", "integrity": "sha512-2G2y++21dhj2R7iHAdd0FIzjGwuKZld+7Pl/bTU6YIkrC2ZMbVUjm+luj6A6V34Rv9XfKJDKpTWu9W4Gse1D9g==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^2.12.2" }, @@ -3703,15 +3626,68 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" } }, + "node_modules/@wdio/browserstack-service/node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/tar-fs/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/tar-fs/node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/@wdio/browserstack-service/node_modules/type-fest": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=12.20" }, @@ -3738,6 +3714,7 @@ "url": "https://github.com/sponsors/faisalman" } ], + "license": "MIT", "optional": true, "peer": true, "engines": { @@ -3745,18 +3722,19 @@ } }, "node_modules/@wdio/browserstack-service/node_modules/webdriverio": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.38.2.tgz", - "integrity": "sha512-r09y5UfivyYh5JOzT2SpJJ1zDmQl/R4OTH12opUqkjvp21BibCQm/uu1mrxGy4lzSHljrvqSVrrcGI+6UA1O8w==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.39.0.tgz", + "integrity": "sha512-pDpGu0V+TL1LkXPode67m3s+IPto4TcmcOzMpzFgu2oeLMBornoLN3yQSFR1fjZd1gK4UfnG3lJ4poTGOfbWfw==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "^20.1.0", - "@wdio/config": "8.38.2", + "@wdio/config": "8.39.0", "@wdio/logger": "8.38.0", "@wdio/protocols": "8.38.0", "@wdio/repl": "8.24.12", - "@wdio/types": "8.38.2", - "@wdio/utils": "8.38.2", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.39.0", "archiver": "^7.0.0", "aria-query": "^5.0.0", "css-shorthand-properties": "^1.1.1", @@ -3774,7 +3752,7 @@ "resq": "^1.9.1", "rgb2hex": "0.2.5", "serialize-error": "^11.0.1", - "webdriver": "8.38.2" + "webdriver": "8.39.0" }, "engines": { "node": "^16.13 || >=18" @@ -3788,11 +3766,142 @@ } } }, + "node_modules/@wdio/browserstack-service/node_modules/webdriverio/node_modules/@puppeteer/browsers": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", + "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "progress": "2.0.3", + "proxy-agent": "6.3.0", + "tar-fs": "3.0.4", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=16.3.0" + }, + "peerDependencies": { + "typescript": ">= 4.7.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@wdio/browserstack-service/node_modules/webdriverio/node_modules/chromium-bidi": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.16.tgz", + "integrity": "sha512-7ZbXdWERxRxSwo3txsBjjmc/NLxqb1Bk30mRb0BMS4YIaiV6zvKZqL/UAH+DdqcDYayDWk2n/y8klkBDODrPvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "mitt": "3.0.0" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/webdriverio/node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/webdriverio/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@wdio/browserstack-service/node_modules/webdriverio/node_modules/devtools-protocol": { + "version": "0.0.1302984", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1302984.tgz", + "integrity": "sha512-Rgh2Sk5fUSCtEx4QGH9iwTyECdFPySG2nlz5J8guGh2Wlha6uzSOCq/DCEC8faHlLaMPZJMuZ4ovgcX4LvOkKA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@wdio/browserstack-service/node_modules/webdriverio/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@wdio/browserstack-service/node_modules/webdriverio/node_modules/puppeteer-core": { + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.9.0.tgz", + "integrity": "sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@puppeteer/browsers": "1.4.6", + "chromium-bidi": "0.4.16", + "cross-fetch": "4.0.0", + "debug": "4.3.4", + "devtools-protocol": "0.0.1147663", + "ws": "8.13.0" + }, + "engines": { + "node": ">=16.3.0" + }, + "peerDependencies": { + "typescript": ">= 4.7.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@wdio/browserstack-service/node_modules/webdriverio/node_modules/puppeteer-core/node_modules/devtools-protocol": { + "version": "0.0.1147663", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz", + "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@wdio/browserstack-service/node_modules/webdriverio/node_modules/tar-fs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", + "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + } + }, "node_modules/@wdio/browserstack-service/node_modules/ws": { "version": "8.13.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -3814,6 +3923,7 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", "dev": true, + "license": "MIT", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -3832,6 +3942,7 @@ "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz", "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==", "dev": true, + "license": "MIT", "dependencies": { "archiver-utils": "^5.0.0", "compress-commons": "^6.0.2", @@ -3842,19 +3953,20 @@ } }, "node_modules/@wdio/cli": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-8.38.2.tgz", - "integrity": "sha512-p9y6jxmpmw53OoB9v/uTLwMetmz7Q0K7NewdVONgmeTY/ERpkU15qL3fMw1rXb+E+vrV8dlce4srnXroec6SFA==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-8.39.0.tgz", + "integrity": "sha512-kAd+8TYjJWRN6gZaRGiSu6Yj3k4+ULRt2NWAgNtGhnr0/Rwlr3j9bjAIhXGL574VqrH+rSnrevDdeGuLcZa1xg==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "^20.1.1", "@vitest/snapshot": "^1.2.1", - "@wdio/config": "8.38.2", - "@wdio/globals": "8.38.2", + "@wdio/config": "8.39.0", + "@wdio/globals": "8.39.0", "@wdio/logger": "8.38.0", "@wdio/protocols": "8.38.0", - "@wdio/types": "8.38.2", - "@wdio/utils": "8.38.2", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.39.0", "async-exit-hook": "^2.0.1", "chalk": "^5.2.0", "chokidar": "^3.5.3", @@ -3869,7 +3981,7 @@ "lodash.union": "^4.6.0", "read-pkg-up": "10.0.0", "recursive-readdir": "^2.2.3", - "webdriverio": "8.38.2", + "webdriverio": "8.39.0", "yargs": "^17.7.2" }, "bin": { @@ -3879,116 +3991,50 @@ "node": "^16.13 || >=18" } }, - "node_modules/@wdio/cli/node_modules/@puppeteer/browsers": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", - "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", + "node_modules/@wdio/cli/node_modules/@wdio/types": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.39.0.tgz", + "integrity": "sha512-86lcYROTapOJuFd9ouomFDfzDnv3Kn+jE0RmqfvN9frZAeLVJ5IKjX9M6HjplsyTZhjGO1uCaehmzx+HJus33Q==", "dev": true, + "license": "MIT", "dependencies": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "progress": "2.0.3", - "proxy-agent": "6.3.0", - "tar-fs": "3.0.4", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.1" - }, - "bin": { - "browsers": "lib/cjs/main-cli.js" - }, - "engines": { - "node": ">=16.3.0" - }, - "peerDependencies": { - "typescript": ">= 4.7.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@wdio/cli/node_modules/@puppeteer/browsers/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@wdio/cli/node_modules/@puppeteer/browsers/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@wdio/cli/node_modules/@puppeteer/browsers/node_modules/yargs": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", - "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@wdio/cli/node_modules/agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", - "dev": true, - "dependencies": { - "debug": "^4.3.4" + "@types/node": "^20.1.0" }, "engines": { - "node": ">= 14" + "node": "^16.13 || >=18" } }, - "node_modules/@wdio/cli/node_modules/agent-base/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "node_modules/@wdio/cli/node_modules/@wdio/utils": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.39.0.tgz", + "integrity": "sha512-jY+n6jlGeK+9Tx8T659PKLwMQTGpLW5H78CSEWgZLbjbVSr2LfGR8Lx0CRktNXxAtqEVZPj16Pi74OtAhvhE6Q==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "@puppeteer/browsers": "^1.6.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.39.0", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.1.0", + "edgedriver": "^5.5.0", + "geckodriver": "^4.3.1", + "get-port": "^7.0.0", + "import-meta-resolve": "^4.0.0", + "locate-app": "^2.1.0", + "safaridriver": "^0.1.0", + "split2": "^4.2.0", + "wait-port": "^1.0.4" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": "^16.13 || >=18" } }, - "node_modules/@wdio/cli/node_modules/agent-base/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@wdio/cli/node_modules/archiver": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz", "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==", "dev": true, + "license": "MIT", "dependencies": { "archiver-utils": "^5.0.2", "async": "^3.2.4", @@ -4007,6 +4053,7 @@ "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz", "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==", "dev": true, + "license": "MIT", "dependencies": { "glob": "^10.0.0", "graceful-fs": "^4.2.0", @@ -4025,6 +4072,7 @@ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -4036,13 +4084,15 @@ "version": "3.2.5", "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@wdio/cli/node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } @@ -4066,6 +4116,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" @@ -4076,6 +4127,7 @@ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.0.0" } @@ -4097,6 +4149,7 @@ "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-1.1.2.tgz", "integrity": "sha512-YclTJey34KUm5jB1aEJCq807bSievi7Nb/TU4Gu504fUYi3jw3KCIaH6L7nFWQhdEgH3V+wCh+kKD1P5cXnfxw==", "dev": true, + "license": "Apache-2.0", "optional": true, "peer": true, "dependencies": { @@ -4116,334 +4169,113 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz", "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==", - "dev": true, - "dependencies": { - "crc-32": "^1.2.0", - "crc32-stream": "^6.0.0", - "is-stream": "^2.0.1", - "normalize-path": "^3.0.0", - "readable-stream": "^4.0.0" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/@wdio/cli/node_modules/compress-commons/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@wdio/cli/node_modules/crc32-stream": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz", - "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==", - "dev": true, - "dependencies": { - "crc-32": "^1.2.0", - "readable-stream": "^4.0.0" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/@wdio/cli/node_modules/cross-fetch": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", - "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", - "dev": true, - "dependencies": { - "node-fetch": "^2.6.12" - } - }, - "node_modules/@wdio/cli/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/@wdio/cli/node_modules/devtools": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/devtools/-/devtools-8.38.2.tgz", - "integrity": "sha512-8b+naOPzYqzsiYtZZKYJnUnSqSOIg5orvna2SlWT2kFhkggbAJ1bbMzW7rps6onLfxp93wCNEIvngb9JuxwDsg==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@types/node": "^20.1.0", - "@wdio/config": "8.38.2", - "@wdio/logger": "8.38.0", - "@wdio/protocols": "8.38.0", - "@wdio/types": "8.38.2", - "@wdio/utils": "8.38.2", - "chrome-launcher": "^1.0.0", - "edge-paths": "^3.0.5", - "import-meta-resolve": "^4.0.0", - "puppeteer-core": "20.3.0", - "query-selector-shadow-dom": "^1.0.0", - "ua-parser-js": "^1.0.37", - "uuid": "^9.0.0", - "which": "^4.0.0" - }, - "engines": { - "node": "^16.13 || >=18" - } - }, - "node_modules/@wdio/cli/node_modules/devtools-protocol": { - "version": "0.0.1302984", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1302984.tgz", - "integrity": "sha512-Rgh2Sk5fUSCtEx4QGH9iwTyECdFPySG2nlz5J8guGh2Wlha6uzSOCq/DCEC8faHlLaMPZJMuZ4ovgcX4LvOkKA==", - "dev": true - }, - "node_modules/@wdio/cli/node_modules/devtools/node_modules/@puppeteer/browsers": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.3.0.tgz", - "integrity": "sha512-an3QdbNPkuU6qpxpbssxAbjRLJcF+eP4L8UqIY3+6n0sbaVxw5pz7PiCLy9g32XEZuoamUlV5ZQPnA6FxvkIHA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "http-proxy-agent": "5.0.0", - "https-proxy-agent": "5.0.1", - "progress": "2.0.3", - "proxy-from-env": "1.1.0", - "tar-fs": "2.1.1", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.1" - }, - "bin": { - "browsers": "lib/cjs/main-cli.js" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "typescript": ">= 4.7.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@wdio/cli/node_modules/devtools/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/@wdio/cli/node_modules/devtools/node_modules/chromium-bidi": { - "version": "0.4.9", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.9.tgz", - "integrity": "sha512-u3DC6XwgLCA9QJ5ak1voPslCmacQdulZNCPsI3qNXxSnEcZS7DFIbww+5RM2bznMEje7cc0oydavRLRvOIZtHw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "mitt": "3.0.0" - }, - "peerDependencies": { - "devtools-protocol": "*" - } - }, - "node_modules/@wdio/cli/node_modules/devtools/node_modules/cross-fetch": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz", - "integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "node-fetch": "^2.6.11" - } - }, - "node_modules/@wdio/cli/node_modules/devtools/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@wdio/cli/node_modules/devtools/node_modules/devtools-protocol": { - "version": "0.0.1120988", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1120988.tgz", - "integrity": "sha512-39fCpE3Z78IaIPChJsP6Lhmkbf4dWXOmzLk/KFTdRkNk/0JymRIfUynDVRndV9HoDz8PyalK1UH21ST/ivwW5Q==", - "dev": true, - "optional": true, - "peer": true - }, - "node_modules/@wdio/cli/node_modules/devtools/node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@wdio/cli/node_modules/devtools/node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "optional": true, - "peer": true, + "dev": true, + "license": "MIT", "dependencies": { - "agent-base": "6", - "debug": "4" + "crc-32": "^1.2.0", + "crc32-stream": "^6.0.0", + "is-stream": "^2.0.1", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, - "node_modules/@wdio/cli/node_modules/devtools/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "optional": true, - "peer": true - }, - "node_modules/@wdio/cli/node_modules/devtools/node_modules/puppeteer-core": { - "version": "20.3.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.3.0.tgz", - "integrity": "sha512-264pBrIui5bO6NJeOcbJrLa0OCwmA4+WK00JMrLIKTfRiqe2gx8KWTzLsjyw/bizErp3TKS7vt/I0i5fTC+mAw==", + "node_modules/@wdio/cli/node_modules/compress-commons/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@puppeteer/browsers": "1.3.0", - "chromium-bidi": "0.4.9", - "cross-fetch": "3.1.6", - "debug": "4.3.4", - "devtools-protocol": "0.0.1120988", - "ws": "8.13.0" - }, + "license": "MIT", "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "typescript": ">= 4.7.4" + "node": ">=8" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@wdio/cli/node_modules/devtools/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "node_modules/@wdio/cli/node_modules/crc32-stream": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz", + "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==", "dev": true, - "optional": true, - "peer": true, + "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "crc-32": "^1.2.0", + "readable-stream": "^4.0.0" }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, - "node_modules/@wdio/cli/node_modules/devtools/node_modules/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "node_modules/@wdio/cli/node_modules/cross-fetch": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz", + "integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==", "dev": true, + "license": "MIT", "optional": true, "peer": true, "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" + "node-fetch": "^2.6.11" } }, - "node_modules/@wdio/cli/node_modules/devtools/node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "node_modules/@wdio/cli/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "optional": true, "peer": true, "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" + "ms": "2.0.0" } }, - "node_modules/@wdio/cli/node_modules/devtools/node_modules/yargs": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", - "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "node_modules/@wdio/cli/node_modules/devtools": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-8.39.0.tgz", + "integrity": "sha512-QNbvNTNQMlU5gZqbmqzF92vfMOP/Eaa8KcvRj87M0jbn3dfwOeBC7WiECPFQ0MAfmynfarK7G7Ec+TfbAAEyNQ==", "dev": true, + "license": "MIT", "optional": true, "peer": true, "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" + "@types/node": "^20.1.0", + "@wdio/config": "8.39.0", + "@wdio/logger": "8.38.0", + "@wdio/protocols": "8.38.0", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.39.0", + "chrome-launcher": "^1.0.0", + "edge-paths": "^3.0.5", + "import-meta-resolve": "^4.0.0", + "puppeteer-core": "20.3.0", + "query-selector-shadow-dom": "^1.0.0", + "ua-parser-js": "^1.0.37", + "uuid": "^9.0.0", + "which": "^4.0.0" }, "engines": { - "node": ">=12" + "node": "^16.13 || >=18" } }, + "node_modules/@wdio/cli/node_modules/devtools-protocol": { + "version": "0.0.1120988", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1120988.tgz", + "integrity": "sha512-39fCpE3Z78IaIPChJsP6Lhmkbf4dWXOmzLk/KFTdRkNk/0JymRIfUynDVRndV9HoDz8PyalK1UH21ST/ivwW5Q==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "peer": true + }, "node_modules/@wdio/cli/node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "optional": true, "peer": true, "engines": { @@ -4488,24 +4320,31 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@wdio/cli/node_modules/https-proxy-agent": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", - "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "node_modules/@wdio/cli/node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", "dev": true, + "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "agent-base": "^7.0.2", + "@tootallnate/once": "2", + "agent-base": "6", "debug": "4" }, "engines": { - "node": ">= 14" + "node": ">= 6" } }, - "node_modules/@wdio/cli/node_modules/https-proxy-agent/node_modules/debug": { + "node_modules/@wdio/cli/node_modules/http-proxy-agent/node_modules/debug": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, + "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "ms": "2.1.2" }, @@ -4518,11 +4357,14 @@ } } }, - "node_modules/@wdio/cli/node_modules/https-proxy-agent/node_modules/ms": { + "node_modules/@wdio/cli/node_modules/http-proxy-agent/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "dev": true, + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/@wdio/cli/node_modules/is-stream": { "version": "3.0.0", @@ -4541,6 +4383,7 @@ "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-2.0.1.tgz", "integrity": "sha512-ioBrW3s2i97noEmnXxmUq7cjIcVRjT5HBpAYy8zE11CxU9HqlWHHeRxfeN1tn8F7OEMVPIC9x1f8t3Z7US9ehQ==", "dev": true, + "license": "Apache-2.0", "optional": true, "peer": true, "dependencies": { @@ -4553,6 +4396,7 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true, + "license": "ISC", "engines": { "node": ">=12" } @@ -4570,10 +4414,11 @@ } }, "node_modules/@wdio/cli/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -4589,6 +4434,7 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, + "license": "MIT", "optional": true, "peer": true }, @@ -4597,6 +4443,7 @@ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "dev": true, + "license": "MIT", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -4659,6 +4506,7 @@ "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.0.tgz", "integrity": "sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og==", "dev": true, + "license": "MIT", "dependencies": { "agent-base": "^7.0.2", "debug": "^4.3.4", @@ -4673,11 +4521,25 @@ "node": ">= 14" } }, + "node_modules/@wdio/cli/node_modules/proxy-agent/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/@wdio/cli/node_modules/proxy-agent/node_modules/debug": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -4690,27 +4552,93 @@ } } }, + "node_modules/@wdio/cli/node_modules/proxy-agent/node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@wdio/cli/node_modules/proxy-agent/node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/@wdio/cli/node_modules/proxy-agent/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@wdio/cli/node_modules/puppeteer-core": { - "version": "20.9.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.9.0.tgz", - "integrity": "sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==", + "version": "20.3.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.3.0.tgz", + "integrity": "sha512-264pBrIui5bO6NJeOcbJrLa0OCwmA4+WK00JMrLIKTfRiqe2gx8KWTzLsjyw/bizErp3TKS7vt/I0i5fTC+mAw==", "dev": true, + "license": "Apache-2.0", + "optional": true, + "peer": true, "dependencies": { - "@puppeteer/browsers": "1.4.6", - "chromium-bidi": "0.4.16", - "cross-fetch": "4.0.0", + "@puppeteer/browsers": "1.3.0", + "chromium-bidi": "0.4.9", + "cross-fetch": "3.1.6", "debug": "4.3.4", - "devtools-protocol": "0.0.1147663", + "devtools-protocol": "0.0.1120988", "ws": "8.13.0" }, "engines": { - "node": ">=16.3.0" + "node": ">=16.0.0" + }, + "peerDependencies": { + "typescript": ">= 4.7.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@wdio/cli/node_modules/puppeteer-core/node_modules/@puppeteer/browsers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.3.0.tgz", + "integrity": "sha512-an3QdbNPkuU6qpxpbssxAbjRLJcF+eP4L8UqIY3+6n0sbaVxw5pz7PiCLy9g32XEZuoamUlV5ZQPnA6FxvkIHA==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "peer": true, + "dependencies": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "http-proxy-agent": "5.0.0", + "https-proxy-agent": "5.0.1", + "progress": "2.0.3", + "proxy-from-env": "1.1.0", + "tar-fs": "2.1.1", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=16.0.0" }, "peerDependencies": { "typescript": ">= 4.7.4" @@ -4726,6 +4654,9 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, + "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "ms": "2.1.2" }, @@ -4738,23 +4669,42 @@ } } }, - "node_modules/@wdio/cli/node_modules/puppeteer-core/node_modules/devtools-protocol": { - "version": "0.0.1147663", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz", - "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==", - "dev": true - }, "node_modules/@wdio/cli/node_modules/puppeteer-core/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/@wdio/cli/node_modules/puppeteer-core/node_modules/yargs": { + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } }, "node_modules/@wdio/cli/node_modules/readable-stream": { "version": "4.5.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", "dev": true, + "license": "MIT", "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", @@ -4771,6 +4721,7 @@ "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-11.0.3.tgz", "integrity": "sha512-2G2y++21dhj2R7iHAdd0FIzjGwuKZld+7Pl/bTU6YIkrC2ZMbVUjm+luj6A6V34Rv9XfKJDKpTWu9W4Gse1D9g==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^2.12.2" }, @@ -4798,15 +4749,68 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" } }, + "node_modules/@wdio/cli/node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/@wdio/cli/node_modules/tar-fs/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@wdio/cli/node_modules/tar-fs/node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/@wdio/cli/node_modules/type-fest": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=12.20" }, @@ -4833,6 +4837,7 @@ "url": "https://github.com/sponsors/faisalman" } ], + "license": "MIT", "optional": true, "peer": true, "engines": { @@ -4840,18 +4845,19 @@ } }, "node_modules/@wdio/cli/node_modules/webdriverio": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.38.2.tgz", - "integrity": "sha512-r09y5UfivyYh5JOzT2SpJJ1zDmQl/R4OTH12opUqkjvp21BibCQm/uu1mrxGy4lzSHljrvqSVrrcGI+6UA1O8w==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.39.0.tgz", + "integrity": "sha512-pDpGu0V+TL1LkXPode67m3s+IPto4TcmcOzMpzFgu2oeLMBornoLN3yQSFR1fjZd1gK4UfnG3lJ4poTGOfbWfw==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "^20.1.0", - "@wdio/config": "8.38.2", + "@wdio/config": "8.39.0", "@wdio/logger": "8.38.0", "@wdio/protocols": "8.38.0", "@wdio/repl": "8.24.12", - "@wdio/types": "8.38.2", - "@wdio/utils": "8.38.2", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.39.0", "archiver": "^7.0.0", "aria-query": "^5.0.0", "css-shorthand-properties": "^1.1.1", @@ -4869,7 +4875,7 @@ "resq": "^1.9.1", "rgb2hex": "0.2.5", "serialize-error": "^11.0.1", - "webdriver": "8.38.2" + "webdriver": "8.39.0" }, "engines": { "node": "^16.13 || >=18" @@ -4883,11 +4889,161 @@ } } }, + "node_modules/@wdio/cli/node_modules/webdriverio/node_modules/@puppeteer/browsers": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", + "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "progress": "2.0.3", + "proxy-agent": "6.3.0", + "tar-fs": "3.0.4", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=16.3.0" + }, + "peerDependencies": { + "typescript": ">= 4.7.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@wdio/cli/node_modules/webdriverio/node_modules/chromium-bidi": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.16.tgz", + "integrity": "sha512-7ZbXdWERxRxSwo3txsBjjmc/NLxqb1Bk30mRb0BMS4YIaiV6zvKZqL/UAH+DdqcDYayDWk2n/y8klkBDODrPvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "mitt": "3.0.0" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, + "node_modules/@wdio/cli/node_modules/webdriverio/node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/@wdio/cli/node_modules/webdriverio/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@wdio/cli/node_modules/webdriverio/node_modules/devtools-protocol": { + "version": "0.0.1302984", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1302984.tgz", + "integrity": "sha512-Rgh2Sk5fUSCtEx4QGH9iwTyECdFPySG2nlz5J8guGh2Wlha6uzSOCq/DCEC8faHlLaMPZJMuZ4ovgcX4LvOkKA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@wdio/cli/node_modules/webdriverio/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@wdio/cli/node_modules/webdriverio/node_modules/puppeteer-core": { + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.9.0.tgz", + "integrity": "sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@puppeteer/browsers": "1.4.6", + "chromium-bidi": "0.4.16", + "cross-fetch": "4.0.0", + "debug": "4.3.4", + "devtools-protocol": "0.0.1147663", + "ws": "8.13.0" + }, + "engines": { + "node": ">=16.3.0" + }, + "peerDependencies": { + "typescript": ">= 4.7.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@wdio/cli/node_modules/webdriverio/node_modules/puppeteer-core/node_modules/devtools-protocol": { + "version": "0.0.1147663", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz", + "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@wdio/cli/node_modules/webdriverio/node_modules/tar-fs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", + "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + } + }, + "node_modules/@wdio/cli/node_modules/webdriverio/node_modules/yargs": { + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@wdio/cli/node_modules/ws": { "version": "8.13.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -4927,6 +5083,7 @@ "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz", "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==", "dev": true, + "license": "MIT", "dependencies": { "archiver-utils": "^5.0.0", "compress-commons": "^6.0.2", @@ -4964,14 +5121,15 @@ } }, "node_modules/@wdio/config": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.38.2.tgz", - "integrity": "sha512-xlnapTr1vOA0h5HsHTIqj47729FbG3WjxmgHweDEQvcT4C1g9l+WKf+N3FM7DNNoIsAqxKi6rOHG02rJADQJtw==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.39.0.tgz", + "integrity": "sha512-yNuGPMPibY91s936gnJCHWlStvIyDrwLwGfLC/NCdTin4F7HL4Gp5iJnHWkJFty1/DfFi8jjoIUBNLM8HEez+A==", "dev": true, + "license": "MIT", "dependencies": { "@wdio/logger": "8.38.0", - "@wdio/types": "8.38.2", - "@wdio/utils": "8.38.2", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.39.0", "decamelize": "^6.0.0", "deepmerge-ts": "^5.0.0", "glob": "^10.2.2", @@ -4981,117 +5139,104 @@ "node": "^16.13 || >=18" } }, - "node_modules/@wdio/globals": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-8.38.2.tgz", - "integrity": "sha512-iIrUF1EODfHLh3V/CSNCqbNNxUTe3ND+c86zDjzJcPFjawLX1plvAApsU/eDmtsFShcOS2KHbfSjiydFoqQG1Q==", + "node_modules/@wdio/config/node_modules/@wdio/types": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.39.0.tgz", + "integrity": "sha512-86lcYROTapOJuFd9ouomFDfzDnv3Kn+jE0RmqfvN9frZAeLVJ5IKjX9M6HjplsyTZhjGO1uCaehmzx+HJus33Q==", "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "^20.1.0" + }, "engines": { "node": "^16.13 || >=18" - }, - "optionalDependencies": { - "expect-webdriverio": "^4.11.2", - "webdriverio": "8.38.2" } }, - "node_modules/@wdio/globals/node_modules/@puppeteer/browsers": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", - "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", + "node_modules/@wdio/config/node_modules/@wdio/utils": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.39.0.tgz", + "integrity": "sha512-jY+n6jlGeK+9Tx8T659PKLwMQTGpLW5H78CSEWgZLbjbVSr2LfGR8Lx0CRktNXxAtqEVZPj16Pi74OtAhvhE6Q==", "dev": true, - "optional": true, + "license": "MIT", "dependencies": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "progress": "2.0.3", - "proxy-agent": "6.3.0", - "tar-fs": "3.0.4", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.1" - }, - "bin": { - "browsers": "lib/cjs/main-cli.js" + "@puppeteer/browsers": "^1.6.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.39.0", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.1.0", + "edgedriver": "^5.5.0", + "geckodriver": "^4.3.1", + "get-port": "^7.0.0", + "import-meta-resolve": "^4.0.0", + "locate-app": "^2.1.0", + "safaridriver": "^0.1.0", + "split2": "^4.2.0", + "wait-port": "^1.0.4" }, "engines": { - "node": ">=16.3.0" - }, - "peerDependencies": { - "typescript": ">= 4.7.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "node": "^16.13 || >=18" } }, - "node_modules/@wdio/globals/node_modules/@puppeteer/browsers/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/@wdio/globals": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-8.39.0.tgz", + "integrity": "sha512-qZo6JjRCIOtdvba6fdSqj6b91TnWXD6rmamyud93FTqbcspnhBvr8lmgOs5wnslTKeeTTigCjpsT310b4/AyHA==", "dev": true, - "optional": true, - "dependencies": { - "ms": "2.1.2" - }, + "license": "MIT", "engines": { - "node": ">=6.0" + "node": "^16.13 || >=18" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@wdio/globals/node_modules/@puppeteer/browsers/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "optional": true + "optionalDependencies": { + "expect-webdriverio": "^4.11.2", + "webdriverio": "8.39.0" + } }, - "node_modules/@wdio/globals/node_modules/agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "node_modules/@wdio/globals/node_modules/@wdio/types": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.39.0.tgz", + "integrity": "sha512-86lcYROTapOJuFd9ouomFDfzDnv3Kn+jE0RmqfvN9frZAeLVJ5IKjX9M6HjplsyTZhjGO1uCaehmzx+HJus33Q==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { - "debug": "^4.3.4" + "@types/node": "^20.1.0" }, "engines": { - "node": ">= 14" + "node": "^16.13 || >=18" } }, - "node_modules/@wdio/globals/node_modules/agent-base/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "node_modules/@wdio/globals/node_modules/@wdio/utils": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.39.0.tgz", + "integrity": "sha512-jY+n6jlGeK+9Tx8T659PKLwMQTGpLW5H78CSEWgZLbjbVSr2LfGR8Lx0CRktNXxAtqEVZPj16Pi74OtAhvhE6Q==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { - "ms": "2.1.2" + "@puppeteer/browsers": "^1.6.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.39.0", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.1.0", + "edgedriver": "^5.5.0", + "geckodriver": "^4.3.1", + "get-port": "^7.0.0", + "import-meta-resolve": "^4.0.0", + "locate-app": "^2.1.0", + "safaridriver": "^0.1.0", + "split2": "^4.2.0", + "wait-port": "^1.0.4" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": "^16.13 || >=18" } }, - "node_modules/@wdio/globals/node_modules/agent-base/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "optional": true - }, "node_modules/@wdio/globals/node_modules/archiver": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz", "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "archiver-utils": "^5.0.2", @@ -5111,6 +5256,7 @@ "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz", "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "glob": "^10.0.0", @@ -5130,6 +5276,7 @@ "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/@wdio/globals/node_modules/brace-expansion": { @@ -5137,6 +5284,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "balanced-match": "^1.0.0" @@ -5161,6 +5309,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "optional": true, "dependencies": { "base64-js": "^1.3.1", @@ -5172,6 +5321,7 @@ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", "dev": true, + "license": "MIT", "optional": true, "engines": { "node": ">=8.0.0" @@ -5182,6 +5332,7 @@ "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-1.1.2.tgz", "integrity": "sha512-YclTJey34KUm5jB1aEJCq807bSievi7Nb/TU4Gu504fUYi3jw3KCIaH6L7nFWQhdEgH3V+wCh+kKD1P5cXnfxw==", "dev": true, + "license": "Apache-2.0", "optional": true, "peer": true, "dependencies": { @@ -5202,6 +5353,7 @@ "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz", "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "crc-32": "^1.2.0", @@ -5219,6 +5371,7 @@ "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz", "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "crc-32": "^1.2.0", @@ -5229,13 +5382,15 @@ } }, "node_modules/@wdio/globals/node_modules/cross-fetch": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", - "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz", + "integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==", "dev": true, + "license": "MIT", "optional": true, + "peer": true, "dependencies": { - "node-fetch": "^2.6.12" + "node-fetch": "^2.6.11" } }, "node_modules/@wdio/globals/node_modules/debug": { @@ -5243,6 +5398,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "optional": true, "peer": true, "dependencies": { @@ -5250,19 +5406,20 @@ } }, "node_modules/@wdio/globals/node_modules/devtools": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/devtools/-/devtools-8.38.2.tgz", - "integrity": "sha512-8b+naOPzYqzsiYtZZKYJnUnSqSOIg5orvna2SlWT2kFhkggbAJ1bbMzW7rps6onLfxp93wCNEIvngb9JuxwDsg==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-8.39.0.tgz", + "integrity": "sha512-QNbvNTNQMlU5gZqbmqzF92vfMOP/Eaa8KcvRj87M0jbn3dfwOeBC7WiECPFQ0MAfmynfarK7G7Ec+TfbAAEyNQ==", "dev": true, + "license": "MIT", "optional": true, "peer": true, "dependencies": { "@types/node": "^20.1.0", - "@wdio/config": "8.38.2", + "@wdio/config": "8.39.0", "@wdio/logger": "8.38.0", "@wdio/protocols": "8.38.0", - "@wdio/types": "8.38.2", - "@wdio/utils": "8.38.2", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.39.0", "chrome-launcher": "^1.0.0", "edge-paths": "^3.0.5", "import-meta-resolve": "^4.0.0", @@ -5277,230 +5434,20 @@ } }, "node_modules/@wdio/globals/node_modules/devtools-protocol": { - "version": "0.0.1302984", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1302984.tgz", - "integrity": "sha512-Rgh2Sk5fUSCtEx4QGH9iwTyECdFPySG2nlz5J8guGh2Wlha6uzSOCq/DCEC8faHlLaMPZJMuZ4ovgcX4LvOkKA==", - "dev": true, - "optional": true - }, - "node_modules/@wdio/globals/node_modules/devtools/node_modules/@puppeteer/browsers": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.3.0.tgz", - "integrity": "sha512-an3QdbNPkuU6qpxpbssxAbjRLJcF+eP4L8UqIY3+6n0sbaVxw5pz7PiCLy9g32XEZuoamUlV5ZQPnA6FxvkIHA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "http-proxy-agent": "5.0.0", - "https-proxy-agent": "5.0.1", - "progress": "2.0.3", - "proxy-from-env": "1.1.0", - "tar-fs": "2.1.1", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.1" - }, - "bin": { - "browsers": "lib/cjs/main-cli.js" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "typescript": ">= 4.7.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@wdio/globals/node_modules/devtools/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/@wdio/globals/node_modules/devtools/node_modules/chromium-bidi": { - "version": "0.4.9", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.9.tgz", - "integrity": "sha512-u3DC6XwgLCA9QJ5ak1voPslCmacQdulZNCPsI3qNXxSnEcZS7DFIbww+5RM2bznMEje7cc0oydavRLRvOIZtHw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "mitt": "3.0.0" - }, - "peerDependencies": { - "devtools-protocol": "*" - } - }, - "node_modules/@wdio/globals/node_modules/devtools/node_modules/cross-fetch": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz", - "integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "node-fetch": "^2.6.11" - } - }, - "node_modules/@wdio/globals/node_modules/devtools/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@wdio/globals/node_modules/devtools/node_modules/devtools-protocol": { "version": "0.0.1120988", "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1120988.tgz", "integrity": "sha512-39fCpE3Z78IaIPChJsP6Lhmkbf4dWXOmzLk/KFTdRkNk/0JymRIfUynDVRndV9HoDz8PyalK1UH21ST/ivwW5Q==", "dev": true, + "license": "BSD-3-Clause", "optional": true, "peer": true }, - "node_modules/@wdio/globals/node_modules/devtools/node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@wdio/globals/node_modules/devtools/node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@wdio/globals/node_modules/devtools/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "optional": true, - "peer": true - }, - "node_modules/@wdio/globals/node_modules/devtools/node_modules/puppeteer-core": { - "version": "20.3.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.3.0.tgz", - "integrity": "sha512-264pBrIui5bO6NJeOcbJrLa0OCwmA4+WK00JMrLIKTfRiqe2gx8KWTzLsjyw/bizErp3TKS7vt/I0i5fTC+mAw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@puppeteer/browsers": "1.3.0", - "chromium-bidi": "0.4.9", - "cross-fetch": "3.1.6", - "debug": "4.3.4", - "devtools-protocol": "0.0.1120988", - "ws": "8.13.0" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "typescript": ">= 4.7.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@wdio/globals/node_modules/devtools/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@wdio/globals/node_modules/devtools/node_modules/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/@wdio/globals/node_modules/devtools/node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/@wdio/globals/node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "optional": true, "peer": true, "engines": { @@ -5510,26 +5457,31 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@wdio/globals/node_modules/https-proxy-agent": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", - "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "node_modules/@wdio/globals/node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", "dev": true, + "license": "MIT", "optional": true, + "peer": true, "dependencies": { - "agent-base": "^7.0.2", + "@tootallnate/once": "2", + "agent-base": "6", "debug": "4" }, "engines": { - "node": ">= 14" + "node": ">= 6" } }, - "node_modules/@wdio/globals/node_modules/https-proxy-agent/node_modules/debug": { + "node_modules/@wdio/globals/node_modules/http-proxy-agent/node_modules/debug": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, + "license": "MIT", "optional": true, + "peer": true, "dependencies": { "ms": "2.1.2" }, @@ -5542,18 +5494,21 @@ } } }, - "node_modules/@wdio/globals/node_modules/https-proxy-agent/node_modules/ms": { + "node_modules/@wdio/globals/node_modules/http-proxy-agent/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true, - "optional": true + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/@wdio/globals/node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, + "license": "MIT", "optional": true, "engines": { "node": ">=8" @@ -5567,6 +5522,7 @@ "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-2.0.1.tgz", "integrity": "sha512-ioBrW3s2i97noEmnXxmUq7cjIcVRjT5HBpAYy8zE11CxU9HqlWHHeRxfeN1tn8F7OEMVPIC9x1f8t3Z7US9ehQ==", "dev": true, + "license": "Apache-2.0", "optional": true, "peer": true, "dependencies": { @@ -5579,16 +5535,18 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true, + "license": "ISC", "optional": true, "engines": { "node": ">=12" } }, "node_modules/@wdio/globals/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "license": "ISC", "optional": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -5605,6 +5563,7 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, + "license": "MIT", "optional": true, "peer": true }, @@ -5613,6 +5572,7 @@ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "whatwg-url": "^5.0.0" @@ -5634,6 +5594,7 @@ "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.0.tgz", "integrity": "sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "agent-base": "^7.0.2", @@ -5649,11 +5610,26 @@ "node": ">= 14" } }, + "node_modules/@wdio/globals/node_modules/proxy-agent/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/@wdio/globals/node_modules/proxy-agent/node_modules/debug": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "ms": "2.1.2" @@ -5667,29 +5643,96 @@ } } }, + "node_modules/@wdio/globals/node_modules/proxy-agent/node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@wdio/globals/node_modules/proxy-agent/node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/@wdio/globals/node_modules/proxy-agent/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/@wdio/globals/node_modules/puppeteer-core": { - "version": "20.9.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.9.0.tgz", - "integrity": "sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==", + "version": "20.3.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.3.0.tgz", + "integrity": "sha512-264pBrIui5bO6NJeOcbJrLa0OCwmA4+WK00JMrLIKTfRiqe2gx8KWTzLsjyw/bizErp3TKS7vt/I0i5fTC+mAw==", "dev": true, + "license": "Apache-2.0", "optional": true, + "peer": true, "dependencies": { - "@puppeteer/browsers": "1.4.6", - "chromium-bidi": "0.4.16", - "cross-fetch": "4.0.0", + "@puppeteer/browsers": "1.3.0", + "chromium-bidi": "0.4.9", + "cross-fetch": "3.1.6", "debug": "4.3.4", - "devtools-protocol": "0.0.1147663", + "devtools-protocol": "0.0.1120988", "ws": "8.13.0" }, "engines": { - "node": ">=16.3.0" + "node": ">=16.0.0" + }, + "peerDependencies": { + "typescript": ">= 4.7.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@wdio/globals/node_modules/puppeteer-core/node_modules/@puppeteer/browsers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.3.0.tgz", + "integrity": "sha512-an3QdbNPkuU6qpxpbssxAbjRLJcF+eP4L8UqIY3+6n0sbaVxw5pz7PiCLy9g32XEZuoamUlV5ZQPnA6FxvkIHA==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "peer": true, + "dependencies": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "http-proxy-agent": "5.0.0", + "https-proxy-agent": "5.0.1", + "progress": "2.0.3", + "proxy-from-env": "1.1.0", + "tar-fs": "2.1.1", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=16.0.0" }, "peerDependencies": { "typescript": ">= 4.7.4" @@ -5705,7 +5748,9 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, + "license": "MIT", "optional": true, + "peer": true, "dependencies": { "ms": "2.1.2" }, @@ -5718,25 +5763,21 @@ } } }, - "node_modules/@wdio/globals/node_modules/puppeteer-core/node_modules/devtools-protocol": { - "version": "0.0.1147663", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz", - "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==", - "dev": true, - "optional": true - }, "node_modules/@wdio/globals/node_modules/puppeteer-core/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true, - "optional": true + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/@wdio/globals/node_modules/readable-stream": { "version": "4.5.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "abort-controller": "^3.0.0", @@ -5754,6 +5795,7 @@ "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-11.0.3.tgz", "integrity": "sha512-2G2y++21dhj2R7iHAdd0FIzjGwuKZld+7Pl/bTU6YIkrC2ZMbVUjm+luj6A6V34Rv9XfKJDKpTWu9W4Gse1D9g==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "type-fest": "^2.12.2" @@ -5770,16 +5812,69 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "safe-buffer": "~5.2.0" } }, + "node_modules/@wdio/globals/node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/@wdio/globals/node_modules/tar-fs/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@wdio/globals/node_modules/tar-fs/node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/@wdio/globals/node_modules/type-fest": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", "dev": true, + "license": "(MIT OR CC0-1.0)", "optional": true, "engines": { "node": ">=12.20" @@ -5807,62 +5902,204 @@ "url": "https://github.com/sponsors/faisalman" } ], + "license": "MIT", "optional": true, "peer": true, "engines": { - "node": "*" + "node": "*" + } + }, + "node_modules/@wdio/globals/node_modules/webdriverio": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.39.0.tgz", + "integrity": "sha512-pDpGu0V+TL1LkXPode67m3s+IPto4TcmcOzMpzFgu2oeLMBornoLN3yQSFR1fjZd1gK4UfnG3lJ4poTGOfbWfw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "^20.1.0", + "@wdio/config": "8.39.0", + "@wdio/logger": "8.38.0", + "@wdio/protocols": "8.38.0", + "@wdio/repl": "8.24.12", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.39.0", + "archiver": "^7.0.0", + "aria-query": "^5.0.0", + "css-shorthand-properties": "^1.1.1", + "css-value": "^0.0.1", + "devtools-protocol": "^0.0.1302984", + "grapheme-splitter": "^1.0.2", + "import-meta-resolve": "^4.0.0", + "is-plain-obj": "^4.1.0", + "jszip": "^3.10.1", + "lodash.clonedeep": "^4.5.0", + "lodash.zip": "^4.2.0", + "minimatch": "^9.0.0", + "puppeteer-core": "^20.9.0", + "query-selector-shadow-dom": "^1.0.0", + "resq": "^1.9.1", + "rgb2hex": "0.2.5", + "serialize-error": "^11.0.1", + "webdriver": "8.39.0" + }, + "engines": { + "node": "^16.13 || >=18" + }, + "peerDependencies": { + "devtools": "^8.14.0" + }, + "peerDependenciesMeta": { + "devtools": { + "optional": true + } + } + }, + "node_modules/@wdio/globals/node_modules/webdriverio/node_modules/@puppeteer/browsers": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", + "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "progress": "2.0.3", + "proxy-agent": "6.3.0", + "tar-fs": "3.0.4", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=16.3.0" + }, + "peerDependencies": { + "typescript": ">= 4.7.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@wdio/globals/node_modules/webdriverio/node_modules/chromium-bidi": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.16.tgz", + "integrity": "sha512-7ZbXdWERxRxSwo3txsBjjmc/NLxqb1Bk30mRb0BMS4YIaiV6zvKZqL/UAH+DdqcDYayDWk2n/y8klkBDODrPvA==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "mitt": "3.0.0" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, + "node_modules/@wdio/globals/node_modules/webdriverio/node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/@wdio/globals/node_modules/webdriverio/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/@wdio/globals/node_modules/webdriverio": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.38.2.tgz", - "integrity": "sha512-r09y5UfivyYh5JOzT2SpJJ1zDmQl/R4OTH12opUqkjvp21BibCQm/uu1mrxGy4lzSHljrvqSVrrcGI+6UA1O8w==", + "node_modules/@wdio/globals/node_modules/webdriverio/node_modules/devtools-protocol": { + "version": "0.0.1302984", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1302984.tgz", + "integrity": "sha512-Rgh2Sk5fUSCtEx4QGH9iwTyECdFPySG2nlz5J8guGh2Wlha6uzSOCq/DCEC8faHlLaMPZJMuZ4ovgcX4LvOkKA==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/@wdio/globals/node_modules/webdriverio/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/@wdio/globals/node_modules/webdriverio/node_modules/puppeteer-core": { + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.9.0.tgz", + "integrity": "sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==", "dev": true, + "license": "Apache-2.0", "optional": true, "dependencies": { - "@types/node": "^20.1.0", - "@wdio/config": "8.38.2", - "@wdio/logger": "8.38.0", - "@wdio/protocols": "8.38.0", - "@wdio/repl": "8.24.12", - "@wdio/types": "8.38.2", - "@wdio/utils": "8.38.2", - "archiver": "^7.0.0", - "aria-query": "^5.0.0", - "css-shorthand-properties": "^1.1.1", - "css-value": "^0.0.1", - "devtools-protocol": "^0.0.1302984", - "grapheme-splitter": "^1.0.2", - "import-meta-resolve": "^4.0.0", - "is-plain-obj": "^4.1.0", - "jszip": "^3.10.1", - "lodash.clonedeep": "^4.5.0", - "lodash.zip": "^4.2.0", - "minimatch": "^9.0.0", - "puppeteer-core": "^20.9.0", - "query-selector-shadow-dom": "^1.0.0", - "resq": "^1.9.1", - "rgb2hex": "0.2.5", - "serialize-error": "^11.0.1", - "webdriver": "8.38.2" + "@puppeteer/browsers": "1.4.6", + "chromium-bidi": "0.4.16", + "cross-fetch": "4.0.0", + "debug": "4.3.4", + "devtools-protocol": "0.0.1147663", + "ws": "8.13.0" }, "engines": { - "node": "^16.13 || >=18" + "node": ">=16.3.0" }, "peerDependencies": { - "devtools": "^8.14.0" + "typescript": ">= 4.7.4" }, "peerDependenciesMeta": { - "devtools": { + "typescript": { "optional": true } } }, + "node_modules/@wdio/globals/node_modules/webdriverio/node_modules/puppeteer-core/node_modules/devtools-protocol": { + "version": "0.0.1147663", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz", + "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/@wdio/globals/node_modules/webdriverio/node_modules/tar-fs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", + "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + } + }, "node_modules/@wdio/globals/node_modules/ws": { "version": "8.13.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", "dev": true, + "license": "MIT", "optional": true, "engines": { "node": ">=10.0.0" @@ -5885,6 +6122,7 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "cliui": "^8.0.1", @@ -5904,6 +6142,7 @@ "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz", "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "archiver-utils": "^5.0.0", @@ -5915,16 +6154,17 @@ } }, "node_modules/@wdio/local-runner": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-8.38.2.tgz", - "integrity": "sha512-syW+R5VUHJ3GBkQGFcNYe6MYwWRgklc9W7A83xQDTvKWFNHCetLvc8AtKZ54vs8MItBejjU+Oh94ZNbNX1pBcg==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-8.39.0.tgz", + "integrity": "sha512-TSGJVVWqshH7IO13OKw7G/364q3FczZDEh4h6bYe+GAs91KpZrEhZanyALgjh5F3crWtlffX+GA2HUwpi8X0sA==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "^20.1.0", "@wdio/logger": "8.38.0", "@wdio/repl": "8.24.12", - "@wdio/runner": "8.38.2", - "@wdio/types": "8.38.2", + "@wdio/runner": "8.39.0", + "@wdio/types": "8.39.0", "async-exit-hook": "^2.0.1", "split2": "^4.1.0", "stream-buffers": "^3.0.2" @@ -5933,6 +6173,19 @@ "node": "^16.13 || >=18" } }, + "node_modules/@wdio/local-runner/node_modules/@wdio/types": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.39.0.tgz", + "integrity": "sha512-86lcYROTapOJuFd9ouomFDfzDnv3Kn+jE0RmqfvN9frZAeLVJ5IKjX9M6HjplsyTZhjGO1uCaehmzx+HJus33Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "^20.1.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, "node_modules/@wdio/logger": { "version": "8.38.0", "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-8.38.0.tgz", @@ -5988,6 +6241,7 @@ "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-8.24.12.tgz", "integrity": "sha512-321F3sWafnlw93uRTSjEBVuvWCxTkWNDs7ektQS15drrroL3TMeFOynu4rDrIz0jXD9Vas0HCD2Tq/P0uxFLdw==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "^20.1.0" }, @@ -6012,119 +6266,72 @@ } }, "node_modules/@wdio/runner": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-8.38.2.tgz", - "integrity": "sha512-5lPnKSX2BBLI2AbYW+hoGPiEUAJXj8F8I6NC2LaBVzf1CLN+w2HWZ7lUiqS14XT0b5/hlSUX6+JYwUXlDbpuuw==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-8.39.0.tgz", + "integrity": "sha512-M1ixrrCtuwxHVzwsOKGMWBZCteafV0ztoS9+evMWGQtj0ZEsmhjAhWR3n2nZftt24vWOs+eNLGe2p+IO9Sm9bA==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "^20.11.28", - "@wdio/config": "8.38.2", - "@wdio/globals": "8.38.2", + "@wdio/config": "8.39.0", + "@wdio/globals": "8.39.0", "@wdio/logger": "8.38.0", - "@wdio/types": "8.38.2", - "@wdio/utils": "8.38.2", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.39.0", "deepmerge-ts": "^5.1.0", "expect-webdriverio": "^4.12.0", "gaze": "^1.1.3", - "webdriver": "8.38.2", - "webdriverio": "8.38.2" + "webdriver": "8.39.0", + "webdriverio": "8.39.0" }, "engines": { "node": "^16.13 || >=18" } }, - "node_modules/@wdio/runner/node_modules/@puppeteer/browsers": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", - "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", - "dev": true, - "dependencies": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "progress": "2.0.3", - "proxy-agent": "6.3.0", - "tar-fs": "3.0.4", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.1" - }, - "bin": { - "browsers": "lib/cjs/main-cli.js" - }, - "engines": { - "node": ">=16.3.0" - }, - "peerDependencies": { - "typescript": ">= 4.7.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@wdio/runner/node_modules/@puppeteer/browsers/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@wdio/runner/node_modules/@puppeteer/browsers/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@wdio/runner/node_modules/agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "node_modules/@wdio/runner/node_modules/@wdio/types": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.39.0.tgz", + "integrity": "sha512-86lcYROTapOJuFd9ouomFDfzDnv3Kn+jE0RmqfvN9frZAeLVJ5IKjX9M6HjplsyTZhjGO1uCaehmzx+HJus33Q==", "dev": true, + "license": "MIT", "dependencies": { - "debug": "^4.3.4" + "@types/node": "^20.1.0" }, "engines": { - "node": ">= 14" + "node": "^16.13 || >=18" } }, - "node_modules/@wdio/runner/node_modules/agent-base/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "node_modules/@wdio/runner/node_modules/@wdio/utils": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.39.0.tgz", + "integrity": "sha512-jY+n6jlGeK+9Tx8T659PKLwMQTGpLW5H78CSEWgZLbjbVSr2LfGR8Lx0CRktNXxAtqEVZPj16Pi74OtAhvhE6Q==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "@puppeteer/browsers": "^1.6.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.39.0", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.1.0", + "edgedriver": "^5.5.0", + "geckodriver": "^4.3.1", + "get-port": "^7.0.0", + "import-meta-resolve": "^4.0.0", + "locate-app": "^2.1.0", + "safaridriver": "^0.1.0", + "split2": "^4.2.0", + "wait-port": "^1.0.4" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": "^16.13 || >=18" } }, - "node_modules/@wdio/runner/node_modules/agent-base/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@wdio/runner/node_modules/archiver": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz", "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==", "dev": true, + "license": "MIT", "dependencies": { "archiver-utils": "^5.0.2", "async": "^3.2.4", @@ -6143,6 +6350,7 @@ "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz", "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==", "dev": true, + "license": "MIT", "dependencies": { "glob": "^10.0.0", "graceful-fs": "^4.2.0", @@ -6160,13 +6368,15 @@ "version": "3.2.5", "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@wdio/runner/node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } @@ -6190,6 +6400,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" @@ -6200,6 +6411,7 @@ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.0.0" } @@ -6209,6 +6421,7 @@ "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-1.1.2.tgz", "integrity": "sha512-YclTJey34KUm5jB1aEJCq807bSievi7Nb/TU4Gu504fUYi3jw3KCIaH6L7nFWQhdEgH3V+wCh+kKD1P5cXnfxw==", "dev": true, + "license": "Apache-2.0", "optional": true, "peer": true, "dependencies": { @@ -6229,6 +6442,7 @@ "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz", "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==", "dev": true, + "license": "MIT", "dependencies": { "crc-32": "^1.2.0", "crc32-stream": "^6.0.0", @@ -6245,6 +6459,7 @@ "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz", "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==", "dev": true, + "license": "MIT", "dependencies": { "crc-32": "^1.2.0", "readable-stream": "^4.0.0" @@ -6254,12 +6469,15 @@ } }, "node_modules/@wdio/runner/node_modules/cross-fetch": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", - "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz", + "integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==", "dev": true, + "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "node-fetch": "^2.6.12" + "node-fetch": "^2.6.11" } }, "node_modules/@wdio/runner/node_modules/debug": { @@ -6267,6 +6485,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "optional": true, "peer": true, "dependencies": { @@ -6274,19 +6493,20 @@ } }, "node_modules/@wdio/runner/node_modules/devtools": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/devtools/-/devtools-8.38.2.tgz", - "integrity": "sha512-8b+naOPzYqzsiYtZZKYJnUnSqSOIg5orvna2SlWT2kFhkggbAJ1bbMzW7rps6onLfxp93wCNEIvngb9JuxwDsg==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-8.39.0.tgz", + "integrity": "sha512-QNbvNTNQMlU5gZqbmqzF92vfMOP/Eaa8KcvRj87M0jbn3dfwOeBC7WiECPFQ0MAfmynfarK7G7Ec+TfbAAEyNQ==", "dev": true, + "license": "MIT", "optional": true, "peer": true, "dependencies": { "@types/node": "^20.1.0", - "@wdio/config": "8.38.2", + "@wdio/config": "8.39.0", "@wdio/logger": "8.38.0", "@wdio/protocols": "8.38.0", - "@wdio/types": "8.38.2", - "@wdio/utils": "8.38.2", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.39.0", "chrome-launcher": "^1.0.0", "edge-paths": "^3.0.5", "import-meta-resolve": "^4.0.0", @@ -6301,229 +6521,20 @@ } }, "node_modules/@wdio/runner/node_modules/devtools-protocol": { - "version": "0.0.1302984", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1302984.tgz", - "integrity": "sha512-Rgh2Sk5fUSCtEx4QGH9iwTyECdFPySG2nlz5J8guGh2Wlha6uzSOCq/DCEC8faHlLaMPZJMuZ4ovgcX4LvOkKA==", - "dev": true - }, - "node_modules/@wdio/runner/node_modules/devtools/node_modules/@puppeteer/browsers": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.3.0.tgz", - "integrity": "sha512-an3QdbNPkuU6qpxpbssxAbjRLJcF+eP4L8UqIY3+6n0sbaVxw5pz7PiCLy9g32XEZuoamUlV5ZQPnA6FxvkIHA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "http-proxy-agent": "5.0.0", - "https-proxy-agent": "5.0.1", - "progress": "2.0.3", - "proxy-from-env": "1.1.0", - "tar-fs": "2.1.1", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.1" - }, - "bin": { - "browsers": "lib/cjs/main-cli.js" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "typescript": ">= 4.7.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@wdio/runner/node_modules/devtools/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/@wdio/runner/node_modules/devtools/node_modules/chromium-bidi": { - "version": "0.4.9", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.9.tgz", - "integrity": "sha512-u3DC6XwgLCA9QJ5ak1voPslCmacQdulZNCPsI3qNXxSnEcZS7DFIbww+5RM2bznMEje7cc0oydavRLRvOIZtHw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "mitt": "3.0.0" - }, - "peerDependencies": { - "devtools-protocol": "*" - } - }, - "node_modules/@wdio/runner/node_modules/devtools/node_modules/cross-fetch": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz", - "integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "node-fetch": "^2.6.11" - } - }, - "node_modules/@wdio/runner/node_modules/devtools/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@wdio/runner/node_modules/devtools/node_modules/devtools-protocol": { "version": "0.0.1120988", "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1120988.tgz", "integrity": "sha512-39fCpE3Z78IaIPChJsP6Lhmkbf4dWXOmzLk/KFTdRkNk/0JymRIfUynDVRndV9HoDz8PyalK1UH21ST/ivwW5Q==", "dev": true, + "license": "BSD-3-Clause", "optional": true, "peer": true }, - "node_modules/@wdio/runner/node_modules/devtools/node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@wdio/runner/node_modules/devtools/node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@wdio/runner/node_modules/devtools/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "optional": true, - "peer": true - }, - "node_modules/@wdio/runner/node_modules/devtools/node_modules/puppeteer-core": { - "version": "20.3.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.3.0.tgz", - "integrity": "sha512-264pBrIui5bO6NJeOcbJrLa0OCwmA4+WK00JMrLIKTfRiqe2gx8KWTzLsjyw/bizErp3TKS7vt/I0i5fTC+mAw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@puppeteer/browsers": "1.3.0", - "chromium-bidi": "0.4.9", - "cross-fetch": "3.1.6", - "debug": "4.3.4", - "devtools-protocol": "0.0.1120988", - "ws": "8.13.0" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "typescript": ">= 4.7.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@wdio/runner/node_modules/devtools/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@wdio/runner/node_modules/devtools/node_modules/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/@wdio/runner/node_modules/devtools/node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/@wdio/runner/node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "optional": true, "peer": true, "engines": { @@ -6533,24 +6544,31 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@wdio/runner/node_modules/https-proxy-agent": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", - "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "node_modules/@wdio/runner/node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", "dev": true, + "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "agent-base": "^7.0.2", + "@tootallnate/once": "2", + "agent-base": "6", "debug": "4" }, "engines": { - "node": ">= 14" + "node": ">= 6" } }, - "node_modules/@wdio/runner/node_modules/https-proxy-agent/node_modules/debug": { + "node_modules/@wdio/runner/node_modules/http-proxy-agent/node_modules/debug": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, + "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "ms": "2.1.2" }, @@ -6563,17 +6581,21 @@ } } }, - "node_modules/@wdio/runner/node_modules/https-proxy-agent/node_modules/ms": { + "node_modules/@wdio/runner/node_modules/http-proxy-agent/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "dev": true, + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/@wdio/runner/node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -6586,6 +6608,7 @@ "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-2.0.1.tgz", "integrity": "sha512-ioBrW3s2i97noEmnXxmUq7cjIcVRjT5HBpAYy8zE11CxU9HqlWHHeRxfeN1tn8F7OEMVPIC9x1f8t3Z7US9ehQ==", "dev": true, + "license": "Apache-2.0", "optional": true, "peer": true, "dependencies": { @@ -6598,15 +6621,17 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true, + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/@wdio/runner/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -6622,6 +6647,7 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, + "license": "MIT", "optional": true, "peer": true }, @@ -6630,6 +6656,7 @@ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "dev": true, + "license": "MIT", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -6650,6 +6677,7 @@ "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.0.tgz", "integrity": "sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og==", "dev": true, + "license": "MIT", "dependencies": { "agent-base": "^7.0.2", "debug": "^4.3.4", @@ -6664,11 +6692,25 @@ "node": ">= 14" } }, + "node_modules/@wdio/runner/node_modules/proxy-agent/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/@wdio/runner/node_modules/proxy-agent/node_modules/debug": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -6681,27 +6723,93 @@ } } }, + "node_modules/@wdio/runner/node_modules/proxy-agent/node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@wdio/runner/node_modules/proxy-agent/node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/@wdio/runner/node_modules/proxy-agent/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@wdio/runner/node_modules/puppeteer-core": { - "version": "20.9.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.9.0.tgz", - "integrity": "sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==", + "version": "20.3.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.3.0.tgz", + "integrity": "sha512-264pBrIui5bO6NJeOcbJrLa0OCwmA4+WK00JMrLIKTfRiqe2gx8KWTzLsjyw/bizErp3TKS7vt/I0i5fTC+mAw==", "dev": true, + "license": "Apache-2.0", + "optional": true, + "peer": true, "dependencies": { - "@puppeteer/browsers": "1.4.6", - "chromium-bidi": "0.4.16", - "cross-fetch": "4.0.0", + "@puppeteer/browsers": "1.3.0", + "chromium-bidi": "0.4.9", + "cross-fetch": "3.1.6", "debug": "4.3.4", - "devtools-protocol": "0.0.1147663", + "devtools-protocol": "0.0.1120988", "ws": "8.13.0" }, "engines": { - "node": ">=16.3.0" + "node": ">=16.0.0" + }, + "peerDependencies": { + "typescript": ">= 4.7.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@wdio/runner/node_modules/puppeteer-core/node_modules/@puppeteer/browsers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.3.0.tgz", + "integrity": "sha512-an3QdbNPkuU6qpxpbssxAbjRLJcF+eP4L8UqIY3+6n0sbaVxw5pz7PiCLy9g32XEZuoamUlV5ZQPnA6FxvkIHA==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "peer": true, + "dependencies": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "http-proxy-agent": "5.0.0", + "https-proxy-agent": "5.0.1", + "progress": "2.0.3", + "proxy-from-env": "1.1.0", + "tar-fs": "2.1.1", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=16.0.0" }, "peerDependencies": { "typescript": ">= 4.7.4" @@ -6717,6 +6825,9 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, + "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "ms": "2.1.2" }, @@ -6729,23 +6840,21 @@ } } }, - "node_modules/@wdio/runner/node_modules/puppeteer-core/node_modules/devtools-protocol": { - "version": "0.0.1147663", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz", - "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==", - "dev": true - }, "node_modules/@wdio/runner/node_modules/puppeteer-core/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "dev": true, + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/@wdio/runner/node_modules/readable-stream": { "version": "4.5.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", "dev": true, + "license": "MIT", "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", @@ -6762,6 +6871,7 @@ "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-11.0.3.tgz", "integrity": "sha512-2G2y++21dhj2R7iHAdd0FIzjGwuKZld+7Pl/bTU6YIkrC2ZMbVUjm+luj6A6V34Rv9XfKJDKpTWu9W4Gse1D9g==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^2.12.2" }, @@ -6777,15 +6887,68 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" } }, + "node_modules/@wdio/runner/node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/@wdio/runner/node_modules/tar-fs/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@wdio/runner/node_modules/tar-fs/node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/@wdio/runner/node_modules/type-fest": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=12.20" }, @@ -6812,6 +6975,7 @@ "url": "https://github.com/sponsors/faisalman" } ], + "license": "MIT", "optional": true, "peer": true, "engines": { @@ -6819,18 +6983,19 @@ } }, "node_modules/@wdio/runner/node_modules/webdriverio": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.38.2.tgz", - "integrity": "sha512-r09y5UfivyYh5JOzT2SpJJ1zDmQl/R4OTH12opUqkjvp21BibCQm/uu1mrxGy4lzSHljrvqSVrrcGI+6UA1O8w==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.39.0.tgz", + "integrity": "sha512-pDpGu0V+TL1LkXPode67m3s+IPto4TcmcOzMpzFgu2oeLMBornoLN3yQSFR1fjZd1gK4UfnG3lJ4poTGOfbWfw==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "^20.1.0", - "@wdio/config": "8.38.2", + "@wdio/config": "8.39.0", "@wdio/logger": "8.38.0", "@wdio/protocols": "8.38.0", "@wdio/repl": "8.24.12", - "@wdio/types": "8.38.2", - "@wdio/utils": "8.38.2", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.39.0", "archiver": "^7.0.0", "aria-query": "^5.0.0", "css-shorthand-properties": "^1.1.1", @@ -6848,7 +7013,7 @@ "resq": "^1.9.1", "rgb2hex": "0.2.5", "serialize-error": "^11.0.1", - "webdriver": "8.38.2" + "webdriver": "8.39.0" }, "engines": { "node": "^16.13 || >=18" @@ -6862,11 +7027,142 @@ } } }, + "node_modules/@wdio/runner/node_modules/webdriverio/node_modules/@puppeteer/browsers": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", + "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "progress": "2.0.3", + "proxy-agent": "6.3.0", + "tar-fs": "3.0.4", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=16.3.0" + }, + "peerDependencies": { + "typescript": ">= 4.7.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@wdio/runner/node_modules/webdriverio/node_modules/chromium-bidi": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.16.tgz", + "integrity": "sha512-7ZbXdWERxRxSwo3txsBjjmc/NLxqb1Bk30mRb0BMS4YIaiV6zvKZqL/UAH+DdqcDYayDWk2n/y8klkBDODrPvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "mitt": "3.0.0" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, + "node_modules/@wdio/runner/node_modules/webdriverio/node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/@wdio/runner/node_modules/webdriverio/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@wdio/runner/node_modules/webdriverio/node_modules/devtools-protocol": { + "version": "0.0.1302984", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1302984.tgz", + "integrity": "sha512-Rgh2Sk5fUSCtEx4QGH9iwTyECdFPySG2nlz5J8guGh2Wlha6uzSOCq/DCEC8faHlLaMPZJMuZ4ovgcX4LvOkKA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@wdio/runner/node_modules/webdriverio/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@wdio/runner/node_modules/webdriverio/node_modules/puppeteer-core": { + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.9.0.tgz", + "integrity": "sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@puppeteer/browsers": "1.4.6", + "chromium-bidi": "0.4.16", + "cross-fetch": "4.0.0", + "debug": "4.3.4", + "devtools-protocol": "0.0.1147663", + "ws": "8.13.0" + }, + "engines": { + "node": ">=16.3.0" + }, + "peerDependencies": { + "typescript": ">= 4.7.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@wdio/runner/node_modules/webdriverio/node_modules/puppeteer-core/node_modules/devtools-protocol": { + "version": "0.0.1147663", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz", + "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@wdio/runner/node_modules/webdriverio/node_modules/tar-fs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", + "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + } + }, "node_modules/@wdio/runner/node_modules/ws": { "version": "8.13.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -6888,6 +7184,7 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", "dev": true, + "license": "MIT", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -6906,6 +7203,7 @@ "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz", "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==", "dev": true, + "license": "MIT", "dependencies": { "archiver-utils": "^5.0.0", "compress-commons": "^6.0.2", @@ -7168,6 +7466,7 @@ "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", "dev": true, + "license": "MIT", "dependencies": { "event-target-shim": "^5.0.0" }, @@ -7491,6 +7790,15 @@ "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", "dev": true }, + "node_modules/are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "dev": true, + "engines": { + "node": ">=14" + } + }, "node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -9291,10 +9599,13 @@ } }, "node_modules/chromium-bidi": { - "version": "0.4.16", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.16.tgz", - "integrity": "sha512-7ZbXdWERxRxSwo3txsBjjmc/NLxqb1Bk30mRb0BMS4YIaiV6zvKZqL/UAH+DdqcDYayDWk2n/y8klkBDODrPvA==", + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.9.tgz", + "integrity": "sha512-u3DC6XwgLCA9QJ5ak1voPslCmacQdulZNCPsI3qNXxSnEcZS7DFIbww+5RM2bznMEje7cc0oydavRLRvOIZtHw==", "dev": true, + "license": "Apache-2.0", + "optional": true, + "peer": true, "dependencies": { "mitt": "3.0.0" }, @@ -9313,6 +9624,7 @@ "url": "https://github.com/sponsors/sibiraj-s" } ], + "license": "MIT", "engines": { "node": ">=8" } @@ -9627,9 +9939,9 @@ "dev": true }, "node_modules/comment-parser": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.1.tgz", - "integrity": "sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", + "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", "dev": true, "engines": { "node": ">= 12.0.0" @@ -11235,6 +11547,7 @@ "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", "dev": true, + "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -11943,10 +12256,11 @@ } }, "node_modules/engine.io": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz", - "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==", + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz", + "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==", "dev": true, + "license": "MIT", "dependencies": { "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", @@ -11957,7 +12271,7 @@ "cors": "~2.8.5", "debug": "~4.3.1", "engine.io-parser": "~5.2.1", - "ws": "~8.11.0" + "ws": "~8.17.1" }, "engines": { "node": ">=10.2.0" @@ -12603,25 +12917,27 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "38.1.6", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-38.1.6.tgz", - "integrity": "sha512-n4s95oYlg0L43Bs8C0dkzIldxYf8pLCutC/tCbjIdF7VDiobuzPI+HZn9Q0BvgOvgPNgh5n7CSStql25HUG4Tw==", + "version": "48.5.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.5.0.tgz", + "integrity": "sha512-ukXPNpGby3KjCveCizIS8t1EbuJEHYEu/tBg8GCbn/YbHcXwphyvYCdvRZ/oMRfTscGSSzfsWoZ+ZkAP0/6YMQ==", "dev": true, "dependencies": { - "@es-joy/jsdoccomment": "~0.22.1", - "comment-parser": "1.3.1", + "@es-joy/jsdoccomment": "~0.43.1", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.4.1", "debug": "^4.3.4", "escape-string-regexp": "^4.0.0", - "esquery": "^1.4.0", - "regextras": "^0.8.0", - "semver": "^7.3.5", - "spdx-expression-parse": "^3.0.1" + "esquery": "^1.5.0", + "parse-imports": "^2.1.0", + "semver": "^7.6.2", + "spdx-expression-parse": "^4.0.0", + "synckit": "^0.9.0" }, "engines": { - "node": "^12 || ^14 || ^16 || ^17" + "node": ">=18" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" } }, "node_modules/eslint-plugin-jsdoc/node_modules/escape-string-regexp": { @@ -12648,6 +12964,16 @@ "node": ">=10" } }, + "node_modules/eslint-plugin-jsdoc/node_modules/spdx-expression-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, "node_modules/eslint-plugin-node": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", @@ -13063,6 +13389,7 @@ "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -13269,6 +13596,7 @@ "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/expect-utils": "^29.7.0", "jest-get-type": "^29.6.3", @@ -13281,10 +13609,11 @@ } }, "node_modules/expect-webdriverio": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/expect-webdriverio/-/expect-webdriverio-4.15.0.tgz", - "integrity": "sha512-CIBSLEhDmjZ7kKZq6ItBM7V1jLH/w4JCuKGu3WmR4FscOPvOnp9JN4Zi26SZGeQ73E0dy+YPUL6SIvTNoP/XdQ==", + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/expect-webdriverio/-/expect-webdriverio-4.15.1.tgz", + "integrity": "sha512-xtBSidt7Whs1fsUC+utxVzfmkmaStXWW17b+BcMCiCltx0Yku6l7BTv1Y14DEKX8L6rttaDQobYyRtBKbi4ssg==", "dev": true, + "license": "MIT", "dependencies": { "@vitest/snapshot": "^1.2.2", "expect": "^29.7.0", @@ -13300,104 +13629,52 @@ "webdriverio": "^8.29.3" } }, - "node_modules/expect-webdriverio/node_modules/@puppeteer/browsers": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", - "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", - "dev": true, - "optional": true, - "dependencies": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "progress": "2.0.3", - "proxy-agent": "6.3.0", - "tar-fs": "3.0.4", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.1" - }, - "bin": { - "browsers": "lib/cjs/main-cli.js" - }, - "engines": { - "node": ">=16.3.0" - }, - "peerDependencies": { - "typescript": ">= 4.7.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/expect-webdriverio/node_modules/@puppeteer/browsers/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "optional": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/expect-webdriverio/node_modules/@puppeteer/browsers/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "optional": true - }, - "node_modules/expect-webdriverio/node_modules/agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "node_modules/expect-webdriverio/node_modules/@wdio/types": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.39.0.tgz", + "integrity": "sha512-86lcYROTapOJuFd9ouomFDfzDnv3Kn+jE0RmqfvN9frZAeLVJ5IKjX9M6HjplsyTZhjGO1uCaehmzx+HJus33Q==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { - "debug": "^4.3.4" + "@types/node": "^20.1.0" }, "engines": { - "node": ">= 14" + "node": "^16.13 || >=18" } }, - "node_modules/expect-webdriverio/node_modules/agent-base/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "node_modules/expect-webdriverio/node_modules/@wdio/utils": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.39.0.tgz", + "integrity": "sha512-jY+n6jlGeK+9Tx8T659PKLwMQTGpLW5H78CSEWgZLbjbVSr2LfGR8Lx0CRktNXxAtqEVZPj16Pi74OtAhvhE6Q==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "@puppeteer/browsers": "^1.6.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.39.0", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.1.0", + "edgedriver": "^5.5.0", + "geckodriver": "^4.3.1", + "get-port": "^7.0.0", + "import-meta-resolve": "^4.0.0", + "locate-app": "^2.1.0", + "safaridriver": "^0.1.0", + "split2": "^4.2.0", + "wait-port": "^1.0.4" + }, + "engines": { + "node": "^16.13 || >=18" } }, - "node_modules/expect-webdriverio/node_modules/agent-base/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "optional": true - }, "node_modules/expect-webdriverio/node_modules/archiver": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz", "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "archiver-utils": "^5.0.2", @@ -13417,6 +13694,7 @@ "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz", "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "glob": "^10.0.0", @@ -13436,6 +13714,7 @@ "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/expect-webdriverio/node_modules/brace-expansion": { @@ -13443,6 +13722,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "balanced-match": "^1.0.0" @@ -13467,6 +13747,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "optional": true, "dependencies": { "base64-js": "^1.3.1", @@ -13478,6 +13759,7 @@ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", "dev": true, + "license": "MIT", "optional": true, "engines": { "node": ">=8.0.0" @@ -13488,6 +13770,7 @@ "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-1.1.2.tgz", "integrity": "sha512-YclTJey34KUm5jB1aEJCq807bSievi7Nb/TU4Gu504fUYi3jw3KCIaH6L7nFWQhdEgH3V+wCh+kKD1P5cXnfxw==", "dev": true, + "license": "Apache-2.0", "optional": true, "peer": true, "dependencies": { @@ -13508,6 +13791,7 @@ "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz", "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "crc-32": "^1.2.0", @@ -13525,6 +13809,7 @@ "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz", "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "crc-32": "^1.2.0", @@ -13535,13 +13820,15 @@ } }, "node_modules/expect-webdriverio/node_modules/cross-fetch": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", - "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz", + "integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==", "dev": true, + "license": "MIT", "optional": true, + "peer": true, "dependencies": { - "node-fetch": "^2.6.12" + "node-fetch": "^2.6.11" } }, "node_modules/expect-webdriverio/node_modules/debug": { @@ -13549,6 +13836,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "optional": true, "peer": true, "dependencies": { @@ -13556,19 +13844,20 @@ } }, "node_modules/expect-webdriverio/node_modules/devtools": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/devtools/-/devtools-8.38.2.tgz", - "integrity": "sha512-8b+naOPzYqzsiYtZZKYJnUnSqSOIg5orvna2SlWT2kFhkggbAJ1bbMzW7rps6onLfxp93wCNEIvngb9JuxwDsg==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-8.39.0.tgz", + "integrity": "sha512-QNbvNTNQMlU5gZqbmqzF92vfMOP/Eaa8KcvRj87M0jbn3dfwOeBC7WiECPFQ0MAfmynfarK7G7Ec+TfbAAEyNQ==", "dev": true, + "license": "MIT", "optional": true, "peer": true, "dependencies": { "@types/node": "^20.1.0", - "@wdio/config": "8.38.2", + "@wdio/config": "8.39.0", "@wdio/logger": "8.38.0", "@wdio/protocols": "8.38.0", - "@wdio/types": "8.38.2", - "@wdio/utils": "8.38.2", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.39.0", "chrome-launcher": "^1.0.0", "edge-paths": "^3.0.5", "import-meta-resolve": "^4.0.0", @@ -13583,230 +13872,20 @@ } }, "node_modules/expect-webdriverio/node_modules/devtools-protocol": { - "version": "0.0.1302984", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1302984.tgz", - "integrity": "sha512-Rgh2Sk5fUSCtEx4QGH9iwTyECdFPySG2nlz5J8guGh2Wlha6uzSOCq/DCEC8faHlLaMPZJMuZ4ovgcX4LvOkKA==", - "dev": true, - "optional": true - }, - "node_modules/expect-webdriverio/node_modules/devtools/node_modules/@puppeteer/browsers": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.3.0.tgz", - "integrity": "sha512-an3QdbNPkuU6qpxpbssxAbjRLJcF+eP4L8UqIY3+6n0sbaVxw5pz7PiCLy9g32XEZuoamUlV5ZQPnA6FxvkIHA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "http-proxy-agent": "5.0.0", - "https-proxy-agent": "5.0.1", - "progress": "2.0.3", - "proxy-from-env": "1.1.0", - "tar-fs": "2.1.1", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.1" - }, - "bin": { - "browsers": "lib/cjs/main-cli.js" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "typescript": ">= 4.7.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/expect-webdriverio/node_modules/devtools/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/expect-webdriverio/node_modules/devtools/node_modules/chromium-bidi": { - "version": "0.4.9", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.9.tgz", - "integrity": "sha512-u3DC6XwgLCA9QJ5ak1voPslCmacQdulZNCPsI3qNXxSnEcZS7DFIbww+5RM2bznMEje7cc0oydavRLRvOIZtHw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "mitt": "3.0.0" - }, - "peerDependencies": { - "devtools-protocol": "*" - } - }, - "node_modules/expect-webdriverio/node_modules/devtools/node_modules/cross-fetch": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz", - "integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "node-fetch": "^2.6.11" - } - }, - "node_modules/expect-webdriverio/node_modules/devtools/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/expect-webdriverio/node_modules/devtools/node_modules/devtools-protocol": { "version": "0.0.1120988", "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1120988.tgz", "integrity": "sha512-39fCpE3Z78IaIPChJsP6Lhmkbf4dWXOmzLk/KFTdRkNk/0JymRIfUynDVRndV9HoDz8PyalK1UH21ST/ivwW5Q==", "dev": true, + "license": "BSD-3-Clause", "optional": true, "peer": true }, - "node_modules/expect-webdriverio/node_modules/devtools/node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/expect-webdriverio/node_modules/devtools/node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/expect-webdriverio/node_modules/devtools/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "optional": true, - "peer": true - }, - "node_modules/expect-webdriverio/node_modules/devtools/node_modules/puppeteer-core": { - "version": "20.3.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.3.0.tgz", - "integrity": "sha512-264pBrIui5bO6NJeOcbJrLa0OCwmA4+WK00JMrLIKTfRiqe2gx8KWTzLsjyw/bizErp3TKS7vt/I0i5fTC+mAw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@puppeteer/browsers": "1.3.0", - "chromium-bidi": "0.4.9", - "cross-fetch": "3.1.6", - "debug": "4.3.4", - "devtools-protocol": "0.0.1120988", - "ws": "8.13.0" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "typescript": ">= 4.7.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/expect-webdriverio/node_modules/devtools/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/expect-webdriverio/node_modules/devtools/node_modules/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/expect-webdriverio/node_modules/devtools/node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/expect-webdriverio/node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "optional": true, "peer": true, "engines": { @@ -13816,26 +13895,31 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/expect-webdriverio/node_modules/https-proxy-agent": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", - "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "node_modules/expect-webdriverio/node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", "dev": true, + "license": "MIT", "optional": true, + "peer": true, "dependencies": { - "agent-base": "^7.0.2", + "@tootallnate/once": "2", + "agent-base": "6", "debug": "4" }, "engines": { - "node": ">= 14" + "node": ">= 6" } }, - "node_modules/expect-webdriverio/node_modules/https-proxy-agent/node_modules/debug": { + "node_modules/expect-webdriverio/node_modules/http-proxy-agent/node_modules/debug": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, + "license": "MIT", "optional": true, + "peer": true, "dependencies": { "ms": "2.1.2" }, @@ -13848,18 +13932,21 @@ } } }, - "node_modules/expect-webdriverio/node_modules/https-proxy-agent/node_modules/ms": { + "node_modules/expect-webdriverio/node_modules/http-proxy-agent/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true, - "optional": true + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/expect-webdriverio/node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, + "license": "MIT", "optional": true, "engines": { "node": ">=8" @@ -13873,6 +13960,7 @@ "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-2.0.1.tgz", "integrity": "sha512-ioBrW3s2i97noEmnXxmUq7cjIcVRjT5HBpAYy8zE11CxU9HqlWHHeRxfeN1tn8F7OEMVPIC9x1f8t3Z7US9ehQ==", "dev": true, + "license": "Apache-2.0", "optional": true, "peer": true, "dependencies": { @@ -13885,16 +13973,18 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true, + "license": "ISC", "optional": true, "engines": { "node": ">=12" } }, "node_modules/expect-webdriverio/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "license": "ISC", "optional": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -13911,6 +14001,7 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, + "license": "MIT", "optional": true, "peer": true }, @@ -13919,6 +14010,7 @@ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "whatwg-url": "^5.0.0" @@ -13940,6 +14032,7 @@ "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.0.tgz", "integrity": "sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "agent-base": "^7.0.2", @@ -13955,11 +14048,26 @@ "node": ">= 14" } }, + "node_modules/expect-webdriverio/node_modules/proxy-agent/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/expect-webdriverio/node_modules/proxy-agent/node_modules/debug": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "ms": "2.1.2" @@ -13973,29 +14081,96 @@ } } }, + "node_modules/expect-webdriverio/node_modules/proxy-agent/node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/expect-webdriverio/node_modules/proxy-agent/node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/expect-webdriverio/node_modules/proxy-agent/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/expect-webdriverio/node_modules/puppeteer-core": { - "version": "20.9.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.9.0.tgz", - "integrity": "sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==", + "version": "20.3.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.3.0.tgz", + "integrity": "sha512-264pBrIui5bO6NJeOcbJrLa0OCwmA4+WK00JMrLIKTfRiqe2gx8KWTzLsjyw/bizErp3TKS7vt/I0i5fTC+mAw==", "dev": true, + "license": "Apache-2.0", "optional": true, + "peer": true, "dependencies": { - "@puppeteer/browsers": "1.4.6", - "chromium-bidi": "0.4.16", - "cross-fetch": "4.0.0", + "@puppeteer/browsers": "1.3.0", + "chromium-bidi": "0.4.9", + "cross-fetch": "3.1.6", "debug": "4.3.4", - "devtools-protocol": "0.0.1147663", + "devtools-protocol": "0.0.1120988", "ws": "8.13.0" }, "engines": { - "node": ">=16.3.0" + "node": ">=16.0.0" + }, + "peerDependencies": { + "typescript": ">= 4.7.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/expect-webdriverio/node_modules/puppeteer-core/node_modules/@puppeteer/browsers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.3.0.tgz", + "integrity": "sha512-an3QdbNPkuU6qpxpbssxAbjRLJcF+eP4L8UqIY3+6n0sbaVxw5pz7PiCLy9g32XEZuoamUlV5ZQPnA6FxvkIHA==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "peer": true, + "dependencies": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "http-proxy-agent": "5.0.0", + "https-proxy-agent": "5.0.1", + "progress": "2.0.3", + "proxy-from-env": "1.1.0", + "tar-fs": "2.1.1", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=16.0.0" }, "peerDependencies": { "typescript": ">= 4.7.4" @@ -14011,7 +14186,9 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, + "license": "MIT", "optional": true, + "peer": true, "dependencies": { "ms": "2.1.2" }, @@ -14024,25 +14201,21 @@ } } }, - "node_modules/expect-webdriverio/node_modules/puppeteer-core/node_modules/devtools-protocol": { - "version": "0.0.1147663", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz", - "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==", - "dev": true, - "optional": true - }, "node_modules/expect-webdriverio/node_modules/puppeteer-core/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true, - "optional": true + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/expect-webdriverio/node_modules/readable-stream": { "version": "4.5.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "abort-controller": "^3.0.0", @@ -14060,6 +14233,7 @@ "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-11.0.3.tgz", "integrity": "sha512-2G2y++21dhj2R7iHAdd0FIzjGwuKZld+7Pl/bTU6YIkrC2ZMbVUjm+luj6A6V34Rv9XfKJDKpTWu9W4Gse1D9g==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "type-fest": "^2.12.2" @@ -14076,16 +14250,69 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "safe-buffer": "~5.2.0" } }, + "node_modules/expect-webdriverio/node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/expect-webdriverio/node_modules/tar-fs/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/expect-webdriverio/node_modules/tar-fs/node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/expect-webdriverio/node_modules/type-fest": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", "dev": true, + "license": "(MIT OR CC0-1.0)", "optional": true, "engines": { "node": ">=12.20" @@ -14113,6 +14340,7 @@ "url": "https://github.com/sponsors/faisalman" } ], + "license": "MIT", "optional": true, "peer": true, "engines": { @@ -14120,19 +14348,20 @@ } }, "node_modules/expect-webdriverio/node_modules/webdriverio": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.38.2.tgz", - "integrity": "sha512-r09y5UfivyYh5JOzT2SpJJ1zDmQl/R4OTH12opUqkjvp21BibCQm/uu1mrxGy4lzSHljrvqSVrrcGI+6UA1O8w==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.39.0.tgz", + "integrity": "sha512-pDpGu0V+TL1LkXPode67m3s+IPto4TcmcOzMpzFgu2oeLMBornoLN3yQSFR1fjZd1gK4UfnG3lJ4poTGOfbWfw==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "@types/node": "^20.1.0", - "@wdio/config": "8.38.2", + "@wdio/config": "8.39.0", "@wdio/logger": "8.38.0", "@wdio/protocols": "8.38.0", "@wdio/repl": "8.24.12", - "@wdio/types": "8.38.2", - "@wdio/utils": "8.38.2", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.39.0", "archiver": "^7.0.0", "aria-query": "^5.0.0", "css-shorthand-properties": "^1.1.1", @@ -14150,7 +14379,7 @@ "resq": "^1.9.1", "rgb2hex": "0.2.5", "serialize-error": "^11.0.1", - "webdriver": "8.38.2" + "webdriver": "8.39.0" }, "engines": { "node": "^16.13 || >=18" @@ -14164,11 +14393,151 @@ } } }, + "node_modules/expect-webdriverio/node_modules/webdriverio/node_modules/@puppeteer/browsers": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", + "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "progress": "2.0.3", + "proxy-agent": "6.3.0", + "tar-fs": "3.0.4", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=16.3.0" + }, + "peerDependencies": { + "typescript": ">= 4.7.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/expect-webdriverio/node_modules/webdriverio/node_modules/chromium-bidi": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.16.tgz", + "integrity": "sha512-7ZbXdWERxRxSwo3txsBjjmc/NLxqb1Bk30mRb0BMS4YIaiV6zvKZqL/UAH+DdqcDYayDWk2n/y8klkBDODrPvA==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "mitt": "3.0.0" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, + "node_modules/expect-webdriverio/node_modules/webdriverio/node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/expect-webdriverio/node_modules/webdriverio/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/expect-webdriverio/node_modules/webdriverio/node_modules/devtools-protocol": { + "version": "0.0.1302984", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1302984.tgz", + "integrity": "sha512-Rgh2Sk5fUSCtEx4QGH9iwTyECdFPySG2nlz5J8guGh2Wlha6uzSOCq/DCEC8faHlLaMPZJMuZ4ovgcX4LvOkKA==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/expect-webdriverio/node_modules/webdriverio/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/expect-webdriverio/node_modules/webdriverio/node_modules/puppeteer-core": { + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.9.0.tgz", + "integrity": "sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@puppeteer/browsers": "1.4.6", + "chromium-bidi": "0.4.16", + "cross-fetch": "4.0.0", + "debug": "4.3.4", + "devtools-protocol": "0.0.1147663", + "ws": "8.13.0" + }, + "engines": { + "node": ">=16.3.0" + }, + "peerDependencies": { + "typescript": ">= 4.7.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/expect-webdriverio/node_modules/webdriverio/node_modules/puppeteer-core/node_modules/devtools-protocol": { + "version": "0.0.1147663", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz", + "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/expect-webdriverio/node_modules/webdriverio/node_modules/tar-fs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", + "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + } + }, "node_modules/expect-webdriverio/node_modules/ws": { "version": "8.13.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", "dev": true, + "license": "MIT", "optional": true, "engines": { "node": ">=10.0.0" @@ -14191,6 +14560,7 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "cliui": "^8.0.1", @@ -14210,6 +14580,7 @@ "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz", "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "archiver-utils": "^5.0.0", @@ -14710,182 +15081,6 @@ "node": ">= 0.10" } }, - "node_modules/findup-sync/node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/braces/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/braces/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/fill-range/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/fill-range/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "node_modules/findup-sync/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/fined": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", @@ -15019,10 +15214,11 @@ "dev": true }, "node_modules/foreground-child": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.0.tgz", - "integrity": "sha512-CrWQNaEl1/6WeZoarcM9LHupTo3RpZO2Pdk1vktwzPiQTsJnAKJmm3TACKeG5UZbWDfaH2AbvYxzP96y0MT7fA==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", + "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", "dev": true, + "license": "ISC", "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -15039,6 +15235,7 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, + "license": "ISC", "engines": { "node": ">=14" }, @@ -15353,6 +15550,7 @@ "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", "dev": true, + "license": "MIT", "dependencies": { "globule": "^1.0.0" }, @@ -15634,15 +15832,17 @@ "dev": true }, "node_modules/glob": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", - "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "version": "10.4.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.2.tgz", + "integrity": "sha512-GwMlUF6PkPo3Gk21UxkCohOv0PLcIXVtKyLlpEI28R/cO/4eNOdmLk3CMW1wROV/WR/EsZOWAfBbBOqYvs88/w==", "dev": true, + "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { @@ -15777,15 +15977,6 @@ "node": ">=0.10.0" } }, - "node_modules/glob-watcher/node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/glob-watcher/node_modules/binary-extensions": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", @@ -15946,18 +16137,6 @@ "node": ">=0.10.0" } }, - "node_modules/glob-watcher/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/glob-watcher/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -15970,64 +16149,6 @@ "node": ">=0.10.0" } }, - "node_modules/glob-watcher/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/glob-watcher/node_modules/micromatch/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/glob-watcher/node_modules/micromatch/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/glob-watcher/node_modules/micromatch/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/glob-watcher/node_modules/readdirp": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", @@ -16060,15 +16181,17 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/glob/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -16178,6 +16301,7 @@ "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.4.tgz", "integrity": "sha512-OPTIfhMBh7JbBYDpa5b+Q5ptmMWKwcNcFSR/0c6t8V4f3ZAVBEsKNY37QdVqmLRYSMhOUGYrY0QhSoEpzGr/Eg==", "dev": true, + "license": "MIT", "dependencies": { "glob": "~7.1.1", "lodash": "^4.17.21", @@ -16193,6 +16317,7 @@ "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -16213,6 +16338,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -16296,6 +16422,7 @@ "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", "dev": true, + "license": "MIT", "dependencies": { "glob-watcher": "^5.0.3", "gulp-cli": "^2.2.0", @@ -18699,7 +18826,8 @@ "version": "3.0.6", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/import-fresh": { "version": "3.3.0", @@ -19818,6 +19946,7 @@ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.0.tgz", "integrity": "sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -19930,6 +20059,7 @@ "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.0.0", "diff-sequences": "^29.6.3", @@ -19945,6 +20075,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -19960,6 +20091,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -19976,6 +20108,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -19987,13 +20120,15 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-diff/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -20003,6 +20138,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -20015,6 +20151,7 @@ "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", "dev": true, + "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -20024,6 +20161,7 @@ "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.0.0", "jest-diff": "^29.7.0", @@ -20039,6 +20177,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -20054,6 +20193,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -20070,6 +20210,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -20081,13 +20222,15 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-matcher-utils/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -20097,6 +20240,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -20109,6 +20253,7 @@ "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.12.13", "@jest/types": "^29.6.3", @@ -20129,6 +20274,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -20144,6 +20290,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -20160,6 +20307,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -20171,22 +20319,39 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-message-util/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, + "node_modules/jest-message-util/node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/jest-message-util/node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -20196,6 +20361,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -20208,6 +20374,7 @@ "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", @@ -20225,6 +20392,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -20240,6 +20408,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -20256,6 +20425,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -20267,13 +20437,15 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-util/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -20283,6 +20455,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -20364,9 +20537,9 @@ "dev": true }, "node_modules/jsdoc-type-pratt-parser": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-2.2.5.tgz", - "integrity": "sha512-2a6eRxSxp1BW040hFvaJxhsCMI9lT8QB8t14t+NY5tC5rckIR0U9cr2tjOeaFirmEOy6MHvmJnY7zTBHq431Lw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", + "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", "dev": true, "engines": { "node": ">=12.0.0" @@ -20459,6 +20632,7 @@ "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", "dev": true, + "license": "(MIT OR GPL-3.0-or-later)", "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", @@ -21128,6 +21302,7 @@ "resolved": "https://registry.npmjs.org/ky/-/ky-0.33.3.tgz", "integrity": "sha512-CasD9OCEQSFIam2U8efFK81Yeg8vNMTBUqtMOHlrcWQHqUX3HeCl9Dr31u4toV7emlH8Mymk5+9p0lL6mKb/Xw==", "dev": true, + "license": "MIT", "engines": { "node": ">=14.16" }, @@ -21211,6 +21386,7 @@ "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", "dev": true, + "license": "MIT", "dependencies": { "immediate": "~3.0.5" } @@ -21560,7 +21736,8 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.isobject": { "version": "3.0.2", @@ -21908,106 +22085,6 @@ "node": ">= 0.10.0" } }, - "node_modules/matchdep/node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/braces/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/braces/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/fill-range/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/fill-range/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/matchdep/node_modules/findup-sync": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", @@ -22023,12 +22100,6 @@ "node": ">= 0.10" } }, - "node_modules/matchdep/node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, "node_modules/matchdep/node_modules/is-glob": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", @@ -22041,76 +22112,6 @@ "node": ">=0.10.0" } }, - "node_modules/matchdep/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/mdast-util-definitions": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz", @@ -23032,16 +23033,193 @@ ] }, "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" }, "engines": { - "node": ">=8.6" + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/braces/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/fill-range/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true, + "license": "MIT" + }, + "node_modules/micromatch/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" } }, "node_modules/mime": { @@ -23131,6 +23309,7 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, + "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } @@ -23139,7 +23318,8 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz", "integrity": "sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/mixin-deep": { "version": "1.3.2", @@ -24740,11 +24920,19 @@ "node": ">= 14" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true + "dev": true, + "license": "(MIT AND Zlib)" }, "node_modules/parent-module": { "version": "1.0.1", @@ -24772,6 +24960,19 @@ "node": ">=0.8" } }, + "node_modules/parse-imports": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/parse-imports/-/parse-imports-2.1.0.tgz", + "integrity": "sha512-JQWgmK2o4w8leUkZeZPatWdAny6vXGU/3siIUvMF6J2rDCud9aTt8h/px9oZJ6U3EcfhngBJ635uPFI0q0VAeA==", + "dev": true, + "dependencies": { + "es-module-lexer": "^1.5.3", + "slashes": "^3.0.12" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/parse-json": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-7.1.1.tgz", @@ -24935,6 +25136,7 @@ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -24947,10 +25149,11 @@ } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", - "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.3.0.tgz", + "integrity": "sha512-CQl19J/g+Hbjbv4Y3mFNNXFEL/5t/KCg8POCuUqd4rMKjGG+j1ybER83hxV58zL+dFI1PTkt3GNFSHRt+d8qEQ==", "dev": true, + "license": "ISC", "engines": { "node": "14 || >=16.14" } @@ -25968,15 +26171,6 @@ "node": ">=4" } }, - "node_modules/regextras": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/regextras/-/regextras-0.8.0.tgz", - "integrity": "sha512-k519uI04Z3SaY0fLX843MRXnDeG2+vHOFsyhiPZvNLe7r8rD2YNRjq4BQLZZ0oAr2NrtvZlICsXysGNFPGa3CQ==", - "dev": true, - "engines": { - "node": ">=0.1.14" - } - }, "node_modules/regjsparser": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", @@ -26985,6 +27179,7 @@ "deprecated": "16.1.1", "dev": true, "hasInstallScript": true, + "license": "BSD-3-Clause", "dependencies": { "@sinonjs/formatio": "^2.0.0", "diff": "^3.1.0", @@ -27027,6 +27222,12 @@ "node": ">=0.10.0" } }, + "node_modules/slashes": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/slashes/-/slashes-3.0.12.tgz", + "integrity": "sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==", + "dev": true + }, "node_modules/slice-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", @@ -27256,13 +27457,14 @@ } }, "node_modules/socket.io-adapter": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.4.tgz", - "integrity": "sha512-wDNHGXGewWAjQPt3pyeYBtpWSq9cLE5UW1ZUPL/2eGK9jtse/FpXib7epSTsz0Q0m+6sg6Y4KtcFTlah1bdOVg==", + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", + "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", "dev": true, + "license": "MIT", "dependencies": { "debug": "~4.3.4", - "ws": "~8.11.0" + "ws": "~8.17.1" } }, "node_modules/socket.io-parser": { @@ -27533,6 +27735,7 @@ "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", "dev": true, + "license": "MIT", "dependencies": { "escape-string-regexp": "^2.0.0" }, @@ -27545,6 +27748,7 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -27742,6 +27946,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -27756,6 +27961,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -27859,6 +28065,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -27961,6 +28168,28 @@ "es6-symbol": "^3.1.1" } }, + "node_modules/synckit": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.0.tgz", + "integrity": "sha512-7RnqIMq572L8PeEzKeBINYEJDDxpcH8JEgLwUqBd3TkofhFRbkq4QLR0u+36avGAhCRbk2nnmjcW9SE531hPDg==", + "dev": true, + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/synckit/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, "node_modules/table": { "version": "6.8.2", "resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz", @@ -29955,18 +30184,19 @@ } }, "node_modules/webdriver": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.38.2.tgz", - "integrity": "sha512-NGfjW0BDYwFgOIzeojOcWGn3tYloQdvHr+Y2xKKYVqa9Rs0x1mzlTjU1kWtC4DaV8DltskwaPa7o+s8hTNpuyA==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.39.0.tgz", + "integrity": "sha512-Kc3+SfiH4ufyrIht683VT2vnJocx0pfH8rYdyPvEh1b2OYewtFTHK36k9rBDHZiBmk6jcSXs4M2xeFgOuon9Lg==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "^20.1.0", "@types/ws": "^8.5.3", - "@wdio/config": "8.38.2", + "@wdio/config": "8.39.0", "@wdio/logger": "8.38.0", "@wdio/protocols": "8.38.0", - "@wdio/types": "8.38.2", - "@wdio/utils": "8.38.2", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.39.0", "deepmerge-ts": "^5.1.0", "got": "^12.6.1", "ky": "^0.33.0", @@ -29976,6 +30206,44 @@ "node": "^16.13 || >=18" } }, + "node_modules/webdriver/node_modules/@wdio/types": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.39.0.tgz", + "integrity": "sha512-86lcYROTapOJuFd9ouomFDfzDnv3Kn+jE0RmqfvN9frZAeLVJ5IKjX9M6HjplsyTZhjGO1uCaehmzx+HJus33Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "^20.1.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/webdriver/node_modules/@wdio/utils": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.39.0.tgz", + "integrity": "sha512-jY+n6jlGeK+9Tx8T659PKLwMQTGpLW5H78CSEWgZLbjbVSr2LfGR8Lx0CRktNXxAtqEVZPj16Pi74OtAhvhE6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@puppeteer/browsers": "^1.6.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.39.0", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.1.0", + "edgedriver": "^5.5.0", + "geckodriver": "^4.3.1", + "get-port": "^7.0.0", + "import-meta-resolve": "^4.0.0", + "locate-app": "^2.1.0", + "safaridriver": "^0.1.0", + "split2": "^4.2.0", + "wait-port": "^1.0.4" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, "node_modules/webdriverio": { "version": "7.36.0", "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.36.0.tgz", @@ -30566,10 +30834,11 @@ } }, "node_modules/webpack-bundle-analyzer/node_modules/ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.3.0" }, @@ -30983,6 +31252,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -31000,6 +31270,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -31015,6 +31286,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -31026,13 +31298,15 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -31104,16 +31378,17 @@ } }, "node_modules/ws": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -32418,14 +32693,17 @@ "dev": true }, "@es-joy/jsdoccomment": { - "version": "0.22.2", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.22.2.tgz", - "integrity": "sha512-pM6WQKcuAtdYoqCsXSvVSu3Ij8K0HY50L8tIheOKHDl0wH1uA4zbP88etY8SIeP16NVCMCTFU+Q2DahSKheGGQ==", + "version": "0.43.1", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.43.1.tgz", + "integrity": "sha512-I238eDtOolvCuvtxrnqtlBaw0BwdQuYqK7eA6XIonicMdOOOb75mqdIzkGDUbS04+1Di007rgm9snFRNeVrOog==", "dev": true, "requires": { - "comment-parser": "1.3.1", - "esquery": "^1.4.0", - "jsdoc-type-pratt-parser": "~2.2.5" + "@types/eslint": "^8.56.5", + "@types/estree": "^1.0.5", + "@typescript-eslint/types": "^7.2.0", + "comment-parser": "1.4.1", + "esquery": "^1.5.0", + "jsdoc-type-pratt-parser": "~4.0.0" } }, "@eslint/eslintrc": { @@ -32858,6 +33136,12 @@ "dev": true, "optional": true }, + "@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true + }, "@polka/url": { "version": "1.0.0-next.25", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.25.tgz", @@ -33285,6 +33569,12 @@ "@types/node": "*" } }, + "@typescript-eslint/types": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.15.0.tgz", + "integrity": "sha512-aV1+B1+ySXbQH0pLK0rx66I3IkiZNidYobyfn0WFsdGhSXw+P3YOqeTq5GED458SfB24tg+ux3S+9g118hjlTw==", + "dev": true + }, "@videojs/http-streaming": { "version": "2.16.3", "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.16.3.tgz", @@ -33396,17 +33686,17 @@ "optional": true }, "@wdio/browserstack-service": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/@wdio/browserstack-service/-/browserstack-service-8.38.2.tgz", - "integrity": "sha512-dBvTK97deVbyDskCRdcQ47xuR7QYx3mqNFJUZLWBitwFV/DU5YIpCbGlySLc4gkO4//Zn1A3Gh/TOGWZrigcCQ==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/browserstack-service/-/browserstack-service-8.39.0.tgz", + "integrity": "sha512-EEbmg9hBk0FAf9b2oHEL0w8aIscKPy3ms0/zSaLp+jDMuWHllpVQ83GCW9qHIJbKUzTNUlF031fRdPzq+GQaVg==", "dev": true, "requires": { "@percy/appium-app": "^2.0.1", "@percy/selenium-webdriver": "^2.0.3", "@types/gitconfiglocal": "^2.0.1", "@wdio/logger": "8.38.0", - "@wdio/reporter": "8.38.2", - "@wdio/types": "8.38.2", + "@wdio/reporter": "8.39.0", + "@wdio/types": "8.39.0", "browserstack-local": "^1.5.1", "chalk": "^5.3.0", "csv-writer": "^1.6.0", @@ -33415,67 +33705,52 @@ "gitconfiglocal": "^2.1.0", "got": "^12.6.1", "uuid": "^9.0.0", - "webdriverio": "8.38.2", + "webdriverio": "8.39.0", "winston-transport": "^4.5.0", "yauzl": "^3.0.0" }, "dependencies": { - "@puppeteer/browsers": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", - "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", + "@wdio/reporter": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-8.39.0.tgz", + "integrity": "sha512-XahXhmaA1okdwg4/ThHFSqy/41KywxhbtszPcTzyXB+9INaqFNHA1b1vvWs0mrD5+tTtKbg4caTcEHVJU4iv0w==", "dev": true, "requires": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "progress": "2.0.3", - "proxy-agent": "6.3.0", - "tar-fs": "3.0.4", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.1" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } + "@types/node": "^20.1.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.39.0", + "diff": "^5.0.0", + "object-inspect": "^1.12.0" } }, - "agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "@wdio/types": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.39.0.tgz", + "integrity": "sha512-86lcYROTapOJuFd9ouomFDfzDnv3Kn+jE0RmqfvN9frZAeLVJ5IKjX9M6HjplsyTZhjGO1uCaehmzx+HJus33Q==", "dev": true, "requires": { - "debug": "^4.3.4" - }, - "dependencies": { - "debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } + "@types/node": "^20.1.0" + } + }, + "@wdio/utils": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.39.0.tgz", + "integrity": "sha512-jY+n6jlGeK+9Tx8T659PKLwMQTGpLW5H78CSEWgZLbjbVSr2LfGR8Lx0CRktNXxAtqEVZPj16Pi74OtAhvhE6Q==", + "dev": true, + "requires": { + "@puppeteer/browsers": "^1.6.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.39.0", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.1.0", + "edgedriver": "^5.5.0", + "geckodriver": "^4.3.1", + "get-port": "^7.0.0", + "import-meta-resolve": "^4.0.0", + "locate-app": "^2.1.0", + "safaridriver": "^0.1.0", + "split2": "^4.2.0", + "wait-port": "^1.0.4" } }, "archiver": { @@ -33583,12 +33858,14 @@ } }, "cross-fetch": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", - "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz", + "integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==", "dev": true, + "optional": true, + "peer": true, "requires": { - "node-fetch": "^2.6.12" + "node-fetch": "^2.6.11" } }, "debug": { @@ -33603,19 +33880,19 @@ } }, "devtools": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/devtools/-/devtools-8.38.2.tgz", - "integrity": "sha512-8b+naOPzYqzsiYtZZKYJnUnSqSOIg5orvna2SlWT2kFhkggbAJ1bbMzW7rps6onLfxp93wCNEIvngb9JuxwDsg==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-8.39.0.tgz", + "integrity": "sha512-QNbvNTNQMlU5gZqbmqzF92vfMOP/Eaa8KcvRj87M0jbn3dfwOeBC7WiECPFQ0MAfmynfarK7G7Ec+TfbAAEyNQ==", "dev": true, "optional": true, "peer": true, "requires": { "@types/node": "^20.1.0", - "@wdio/config": "8.38.2", + "@wdio/config": "8.39.0", "@wdio/logger": "8.38.0", "@wdio/protocols": "8.38.0", - "@wdio/types": "8.38.2", - "@wdio/utils": "8.38.2", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.39.0", "chrome-launcher": "^1.0.0", "edge-paths": "^3.0.5", "import-meta-resolve": "^4.0.0", @@ -33624,177 +33901,15 @@ "ua-parser-js": "^1.0.37", "uuid": "^9.0.0", "which": "^4.0.0" - }, - "dependencies": { - "@puppeteer/browsers": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.3.0.tgz", - "integrity": "sha512-an3QdbNPkuU6qpxpbssxAbjRLJcF+eP4L8UqIY3+6n0sbaVxw5pz7PiCLy9g32XEZuoamUlV5ZQPnA6FxvkIHA==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "http-proxy-agent": "5.0.0", - "https-proxy-agent": "5.0.1", - "progress": "2.0.3", - "proxy-from-env": "1.1.0", - "tar-fs": "2.1.1", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.1" - } - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "debug": "4" - } - }, - "chromium-bidi": { - "version": "0.4.9", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.9.tgz", - "integrity": "sha512-u3DC6XwgLCA9QJ5ak1voPslCmacQdulZNCPsI3qNXxSnEcZS7DFIbww+5RM2bznMEje7cc0oydavRLRvOIZtHw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "mitt": "3.0.0" - } - }, - "cross-fetch": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz", - "integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "node-fetch": "^2.6.11" - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "ms": "2.1.2" - } - }, - "devtools-protocol": { - "version": "0.0.1120988", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1120988.tgz", - "integrity": "sha512-39fCpE3Z78IaIPChJsP6Lhmkbf4dWXOmzLk/KFTdRkNk/0JymRIfUynDVRndV9HoDz8PyalK1UH21ST/ivwW5Q==", - "dev": true, - "optional": true, - "peer": true - }, - "http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - } - }, - "https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "optional": true, - "peer": true - }, - "puppeteer-core": { - "version": "20.3.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.3.0.tgz", - "integrity": "sha512-264pBrIui5bO6NJeOcbJrLa0OCwmA4+WK00JMrLIKTfRiqe2gx8KWTzLsjyw/bizErp3TKS7vt/I0i5fTC+mAw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "@puppeteer/browsers": "1.3.0", - "chromium-bidi": "0.4.9", - "cross-fetch": "3.1.6", - "debug": "4.3.4", - "devtools-protocol": "0.0.1120988", - "ws": "8.13.0" - } - }, - "readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - } - } } }, "devtools-protocol": { - "version": "0.0.1302984", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1302984.tgz", - "integrity": "sha512-Rgh2Sk5fUSCtEx4QGH9iwTyECdFPySG2nlz5J8guGh2Wlha6uzSOCq/DCEC8faHlLaMPZJMuZ4ovgcX4LvOkKA==", - "dev": true + "version": "0.0.1120988", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1120988.tgz", + "integrity": "sha512-39fCpE3Z78IaIPChJsP6Lhmkbf4dWXOmzLk/KFTdRkNk/0JymRIfUynDVRndV9HoDz8PyalK1UH21ST/ivwW5Q==", + "dev": true, + "optional": true, + "peer": true }, "escape-string-regexp": { "version": "4.0.0", @@ -33804,13 +33919,16 @@ "optional": true, "peer": true }, - "https-proxy-agent": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", - "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", "dev": true, + "optional": true, + "peer": true, "requires": { - "agent-base": "^7.0.2", + "@tootallnate/once": "2", + "agent-base": "6", "debug": "4" }, "dependencies": { @@ -33819,6 +33937,8 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, + "optional": true, + "peer": true, "requires": { "ms": "2.1.2" } @@ -33827,7 +33947,9 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "dev": true, + "optional": true, + "peer": true } } }, @@ -33856,9 +33978,9 @@ "dev": true }, "minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -33897,6 +34019,15 @@ "socks-proxy-agent": "^8.0.1" }, "dependencies": { + "agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "requires": { + "debug": "^4.3.4" + } + }, "debug": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", @@ -33906,6 +34037,26 @@ "ms": "2.1.2" } }, + "http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "requires": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + } + }, + "https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dev": true, + "requires": { + "agent-base": "^7.0.2", + "debug": "4" + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -33915,39 +34066,58 @@ } }, "puppeteer-core": { - "version": "20.9.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.9.0.tgz", - "integrity": "sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==", + "version": "20.3.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.3.0.tgz", + "integrity": "sha512-264pBrIui5bO6NJeOcbJrLa0OCwmA4+WK00JMrLIKTfRiqe2gx8KWTzLsjyw/bizErp3TKS7vt/I0i5fTC+mAw==", "dev": true, + "optional": true, + "peer": true, "requires": { - "@puppeteer/browsers": "1.4.6", - "chromium-bidi": "0.4.16", - "cross-fetch": "4.0.0", + "@puppeteer/browsers": "1.3.0", + "chromium-bidi": "0.4.9", + "cross-fetch": "3.1.6", "debug": "4.3.4", - "devtools-protocol": "0.0.1147663", + "devtools-protocol": "0.0.1120988", "ws": "8.13.0" }, "dependencies": { + "@puppeteer/browsers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.3.0.tgz", + "integrity": "sha512-an3QdbNPkuU6qpxpbssxAbjRLJcF+eP4L8UqIY3+6n0sbaVxw5pz7PiCLy9g32XEZuoamUlV5ZQPnA6FxvkIHA==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "http-proxy-agent": "5.0.0", + "https-proxy-agent": "5.0.1", + "progress": "2.0.3", + "proxy-from-env": "1.1.0", + "tar-fs": "2.1.1", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + } + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, + "optional": true, + "peer": true, "requires": { "ms": "2.1.2" } }, - "devtools-protocol": { - "version": "0.0.1147663", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz", - "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==", - "dev": true - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "dev": true, + "optional": true, + "peer": true } } }, @@ -33982,6 +34152,50 @@ "safe-buffer": "~5.2.0" } }, + "tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + } + } + }, "type-fest": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", @@ -33997,18 +34211,18 @@ "peer": true }, "webdriverio": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.38.2.tgz", - "integrity": "sha512-r09y5UfivyYh5JOzT2SpJJ1zDmQl/R4OTH12opUqkjvp21BibCQm/uu1mrxGy4lzSHljrvqSVrrcGI+6UA1O8w==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.39.0.tgz", + "integrity": "sha512-pDpGu0V+TL1LkXPode67m3s+IPto4TcmcOzMpzFgu2oeLMBornoLN3yQSFR1fjZd1gK4UfnG3lJ4poTGOfbWfw==", "dev": true, "requires": { "@types/node": "^20.1.0", - "@wdio/config": "8.38.2", + "@wdio/config": "8.39.0", "@wdio/logger": "8.38.0", "@wdio/protocols": "8.38.0", "@wdio/repl": "8.24.12", - "@wdio/types": "8.38.2", - "@wdio/utils": "8.38.2", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.39.0", "archiver": "^7.0.0", "aria-query": "^5.0.0", "css-shorthand-properties": "^1.1.1", @@ -34026,7 +34240,96 @@ "resq": "^1.9.1", "rgb2hex": "0.2.5", "serialize-error": "^11.0.1", - "webdriver": "8.38.2" + "webdriver": "8.39.0" + }, + "dependencies": { + "@puppeteer/browsers": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", + "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", + "dev": true, + "requires": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "progress": "2.0.3", + "proxy-agent": "6.3.0", + "tar-fs": "3.0.4", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + } + }, + "chromium-bidi": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.16.tgz", + "integrity": "sha512-7ZbXdWERxRxSwo3txsBjjmc/NLxqb1Bk30mRb0BMS4YIaiV6zvKZqL/UAH+DdqcDYayDWk2n/y8klkBDODrPvA==", + "dev": true, + "requires": { + "mitt": "3.0.0" + } + }, + "cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dev": true, + "requires": { + "node-fetch": "^2.6.12" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "devtools-protocol": { + "version": "0.0.1302984", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1302984.tgz", + "integrity": "sha512-Rgh2Sk5fUSCtEx4QGH9iwTyECdFPySG2nlz5J8guGh2Wlha6uzSOCq/DCEC8faHlLaMPZJMuZ4ovgcX4LvOkKA==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "puppeteer-core": { + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.9.0.tgz", + "integrity": "sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==", + "dev": true, + "requires": { + "@puppeteer/browsers": "1.4.6", + "chromium-bidi": "0.4.16", + "cross-fetch": "4.0.0", + "debug": "4.3.4", + "devtools-protocol": "0.0.1147663", + "ws": "8.13.0" + }, + "dependencies": { + "devtools-protocol": { + "version": "0.0.1147663", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz", + "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==", + "dev": true + } + } + }, + "tar-fs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", + "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", + "dev": true, + "requires": { + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + } + } } }, "ws": { @@ -34065,19 +34368,19 @@ } }, "@wdio/cli": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-8.38.2.tgz", - "integrity": "sha512-p9y6jxmpmw53OoB9v/uTLwMetmz7Q0K7NewdVONgmeTY/ERpkU15qL3fMw1rXb+E+vrV8dlce4srnXroec6SFA==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-8.39.0.tgz", + "integrity": "sha512-kAd+8TYjJWRN6gZaRGiSu6Yj3k4+ULRt2NWAgNtGhnr0/Rwlr3j9bjAIhXGL574VqrH+rSnrevDdeGuLcZa1xg==", "dev": true, "requires": { "@types/node": "^20.1.1", "@vitest/snapshot": "^1.2.1", - "@wdio/config": "8.38.2", - "@wdio/globals": "8.38.2", + "@wdio/config": "8.39.0", + "@wdio/globals": "8.39.0", "@wdio/logger": "8.38.0", "@wdio/protocols": "8.38.0", - "@wdio/types": "8.38.2", - "@wdio/utils": "8.38.2", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.39.0", "async-exit-hook": "^2.0.1", "chalk": "^5.2.0", "chokidar": "^3.5.3", @@ -34092,81 +34395,38 @@ "lodash.union": "^4.6.0", "read-pkg-up": "10.0.0", "recursive-readdir": "^2.2.3", - "webdriverio": "8.38.2", + "webdriverio": "8.39.0", "yargs": "^17.7.2" }, "dependencies": { - "@puppeteer/browsers": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", - "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", + "@wdio/types": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.39.0.tgz", + "integrity": "sha512-86lcYROTapOJuFd9ouomFDfzDnv3Kn+jE0RmqfvN9frZAeLVJ5IKjX9M6HjplsyTZhjGO1uCaehmzx+HJus33Q==", "dev": true, "requires": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "progress": "2.0.3", - "proxy-agent": "6.3.0", - "tar-fs": "3.0.4", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.1" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "yargs": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", - "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", - "dev": true, - "requires": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - } - } + "@types/node": "^20.1.0" } }, - "agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "@wdio/utils": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.39.0.tgz", + "integrity": "sha512-jY+n6jlGeK+9Tx8T659PKLwMQTGpLW5H78CSEWgZLbjbVSr2LfGR8Lx0CRktNXxAtqEVZPj16Pi74OtAhvhE6Q==", "dev": true, "requires": { - "debug": "^4.3.4" - }, - "dependencies": { - "debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } + "@puppeteer/browsers": "^1.6.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.39.0", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.1.0", + "edgedriver": "^5.5.0", + "geckodriver": "^4.3.1", + "get-port": "^7.0.0", + "import-meta-resolve": "^4.0.0", + "locate-app": "^2.1.0", + "safaridriver": "^0.1.0", + "split2": "^4.2.0", + "wait-port": "^1.0.4" } }, "archiver": { @@ -34290,12 +34550,14 @@ } }, "cross-fetch": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", - "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz", + "integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==", "dev": true, + "optional": true, + "peer": true, "requires": { - "node-fetch": "^2.6.12" + "node-fetch": "^2.6.11" } }, "debug": { @@ -34310,19 +34572,19 @@ } }, "devtools": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/devtools/-/devtools-8.38.2.tgz", - "integrity": "sha512-8b+naOPzYqzsiYtZZKYJnUnSqSOIg5orvna2SlWT2kFhkggbAJ1bbMzW7rps6onLfxp93wCNEIvngb9JuxwDsg==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-8.39.0.tgz", + "integrity": "sha512-QNbvNTNQMlU5gZqbmqzF92vfMOP/Eaa8KcvRj87M0jbn3dfwOeBC7WiECPFQ0MAfmynfarK7G7Ec+TfbAAEyNQ==", "dev": true, "optional": true, "peer": true, "requires": { "@types/node": "^20.1.0", - "@wdio/config": "8.38.2", + "@wdio/config": "8.39.0", "@wdio/logger": "8.38.0", "@wdio/protocols": "8.38.0", - "@wdio/types": "8.38.2", - "@wdio/utils": "8.38.2", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.39.0", "chrome-launcher": "^1.0.0", "edge-paths": "^3.0.5", "import-meta-resolve": "^4.0.0", @@ -34331,194 +34593,15 @@ "ua-parser-js": "^1.0.37", "uuid": "^9.0.0", "which": "^4.0.0" - }, - "dependencies": { - "@puppeteer/browsers": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.3.0.tgz", - "integrity": "sha512-an3QdbNPkuU6qpxpbssxAbjRLJcF+eP4L8UqIY3+6n0sbaVxw5pz7PiCLy9g32XEZuoamUlV5ZQPnA6FxvkIHA==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "http-proxy-agent": "5.0.0", - "https-proxy-agent": "5.0.1", - "progress": "2.0.3", - "proxy-from-env": "1.1.0", - "tar-fs": "2.1.1", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.1" - } - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "debug": "4" - } - }, - "chromium-bidi": { - "version": "0.4.9", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.9.tgz", - "integrity": "sha512-u3DC6XwgLCA9QJ5ak1voPslCmacQdulZNCPsI3qNXxSnEcZS7DFIbww+5RM2bznMEje7cc0oydavRLRvOIZtHw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "mitt": "3.0.0" - } - }, - "cross-fetch": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz", - "integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "node-fetch": "^2.6.11" - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "ms": "2.1.2" - } - }, - "devtools-protocol": { - "version": "0.0.1120988", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1120988.tgz", - "integrity": "sha512-39fCpE3Z78IaIPChJsP6Lhmkbf4dWXOmzLk/KFTdRkNk/0JymRIfUynDVRndV9HoDz8PyalK1UH21ST/ivwW5Q==", - "dev": true, - "optional": true, - "peer": true - }, - "http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - } - }, - "https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "optional": true, - "peer": true - }, - "puppeteer-core": { - "version": "20.3.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.3.0.tgz", - "integrity": "sha512-264pBrIui5bO6NJeOcbJrLa0OCwmA4+WK00JMrLIKTfRiqe2gx8KWTzLsjyw/bizErp3TKS7vt/I0i5fTC+mAw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "@puppeteer/browsers": "1.3.0", - "chromium-bidi": "0.4.9", - "cross-fetch": "3.1.6", - "debug": "4.3.4", - "devtools-protocol": "0.0.1120988", - "ws": "8.13.0" - } - }, - "readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - } - }, - "yargs": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", - "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - } - } } }, "devtools-protocol": { - "version": "0.0.1302984", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1302984.tgz", - "integrity": "sha512-Rgh2Sk5fUSCtEx4QGH9iwTyECdFPySG2nlz5J8guGh2Wlha6uzSOCq/DCEC8faHlLaMPZJMuZ4ovgcX4LvOkKA==", - "dev": true + "version": "0.0.1120988", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1120988.tgz", + "integrity": "sha512-39fCpE3Z78IaIPChJsP6Lhmkbf4dWXOmzLk/KFTdRkNk/0JymRIfUynDVRndV9HoDz8PyalK1UH21ST/ivwW5Q==", + "dev": true, + "optional": true, + "peer": true }, "escape-string-regexp": { "version": "4.0.0", @@ -34551,13 +34634,16 @@ "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", "dev": true }, - "https-proxy-agent": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", - "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", "dev": true, + "optional": true, + "peer": true, "requires": { - "agent-base": "^7.0.2", + "@tootallnate/once": "2", + "agent-base": "6", "debug": "4" }, "dependencies": { @@ -34566,6 +34652,8 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, + "optional": true, + "peer": true, "requires": { "ms": "2.1.2" } @@ -34574,7 +34662,9 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "dev": true, + "optional": true, + "peer": true } } }, @@ -34609,9 +34699,9 @@ "dev": true }, "minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -34674,6 +34764,15 @@ "socks-proxy-agent": "^8.0.1" }, "dependencies": { + "agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "requires": { + "debug": "^4.3.4" + } + }, "debug": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", @@ -34683,6 +34782,26 @@ "ms": "2.1.2" } }, + "http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "requires": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + } + }, + "https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dev": true, + "requires": { + "agent-base": "^7.0.2", + "debug": "4" + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -34692,39 +34811,75 @@ } }, "puppeteer-core": { - "version": "20.9.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.9.0.tgz", - "integrity": "sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==", + "version": "20.3.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.3.0.tgz", + "integrity": "sha512-264pBrIui5bO6NJeOcbJrLa0OCwmA4+WK00JMrLIKTfRiqe2gx8KWTzLsjyw/bizErp3TKS7vt/I0i5fTC+mAw==", "dev": true, + "optional": true, + "peer": true, "requires": { - "@puppeteer/browsers": "1.4.6", - "chromium-bidi": "0.4.16", - "cross-fetch": "4.0.0", + "@puppeteer/browsers": "1.3.0", + "chromium-bidi": "0.4.9", + "cross-fetch": "3.1.6", "debug": "4.3.4", - "devtools-protocol": "0.0.1147663", + "devtools-protocol": "0.0.1120988", "ws": "8.13.0" }, "dependencies": { + "@puppeteer/browsers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.3.0.tgz", + "integrity": "sha512-an3QdbNPkuU6qpxpbssxAbjRLJcF+eP4L8UqIY3+6n0sbaVxw5pz7PiCLy9g32XEZuoamUlV5ZQPnA6FxvkIHA==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "http-proxy-agent": "5.0.0", + "https-proxy-agent": "5.0.1", + "progress": "2.0.3", + "proxy-from-env": "1.1.0", + "tar-fs": "2.1.1", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + } + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, + "optional": true, + "peer": true, "requires": { "ms": "2.1.2" } }, - "devtools-protocol": { - "version": "0.0.1147663", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz", - "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==", - "dev": true - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "dev": true, + "optional": true, + "peer": true + }, + "yargs": { + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + } } } }, @@ -34765,6 +34920,50 @@ "safe-buffer": "~5.2.0" } }, + "tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + } + } + }, "type-fest": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", @@ -34780,18 +34979,18 @@ "peer": true }, "webdriverio": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.38.2.tgz", - "integrity": "sha512-r09y5UfivyYh5JOzT2SpJJ1zDmQl/R4OTH12opUqkjvp21BibCQm/uu1mrxGy4lzSHljrvqSVrrcGI+6UA1O8w==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.39.0.tgz", + "integrity": "sha512-pDpGu0V+TL1LkXPode67m3s+IPto4TcmcOzMpzFgu2oeLMBornoLN3yQSFR1fjZd1gK4UfnG3lJ4poTGOfbWfw==", "dev": true, "requires": { "@types/node": "^20.1.0", - "@wdio/config": "8.38.2", + "@wdio/config": "8.39.0", "@wdio/logger": "8.38.0", "@wdio/protocols": "8.38.0", "@wdio/repl": "8.24.12", - "@wdio/types": "8.38.2", - "@wdio/utils": "8.38.2", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.39.0", "archiver": "^7.0.0", "aria-query": "^5.0.0", "css-shorthand-properties": "^1.1.1", @@ -34809,7 +35008,111 @@ "resq": "^1.9.1", "rgb2hex": "0.2.5", "serialize-error": "^11.0.1", - "webdriver": "8.38.2" + "webdriver": "8.39.0" + }, + "dependencies": { + "@puppeteer/browsers": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", + "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", + "dev": true, + "requires": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "progress": "2.0.3", + "proxy-agent": "6.3.0", + "tar-fs": "3.0.4", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + } + }, + "chromium-bidi": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.16.tgz", + "integrity": "sha512-7ZbXdWERxRxSwo3txsBjjmc/NLxqb1Bk30mRb0BMS4YIaiV6zvKZqL/UAH+DdqcDYayDWk2n/y8klkBDODrPvA==", + "dev": true, + "requires": { + "mitt": "3.0.0" + } + }, + "cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dev": true, + "requires": { + "node-fetch": "^2.6.12" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "devtools-protocol": { + "version": "0.0.1302984", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1302984.tgz", + "integrity": "sha512-Rgh2Sk5fUSCtEx4QGH9iwTyECdFPySG2nlz5J8guGh2Wlha6uzSOCq/DCEC8faHlLaMPZJMuZ4ovgcX4LvOkKA==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "puppeteer-core": { + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.9.0.tgz", + "integrity": "sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==", + "dev": true, + "requires": { + "@puppeteer/browsers": "1.4.6", + "chromium-bidi": "0.4.16", + "cross-fetch": "4.0.0", + "debug": "4.3.4", + "devtools-protocol": "0.0.1147663", + "ws": "8.13.0" + }, + "dependencies": { + "devtools-protocol": { + "version": "0.0.1147663", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz", + "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==", + "dev": true + } + } + }, + "tar-fs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", + "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", + "dev": true, + "requires": { + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + } + }, + "yargs": { + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "dev": true, + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + } + } } }, "ws": { @@ -34868,92 +35171,92 @@ } }, "@wdio/config": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.38.2.tgz", - "integrity": "sha512-xlnapTr1vOA0h5HsHTIqj47729FbG3WjxmgHweDEQvcT4C1g9l+WKf+N3FM7DNNoIsAqxKi6rOHG02rJADQJtw==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.39.0.tgz", + "integrity": "sha512-yNuGPMPibY91s936gnJCHWlStvIyDrwLwGfLC/NCdTin4F7HL4Gp5iJnHWkJFty1/DfFi8jjoIUBNLM8HEez+A==", "dev": true, "requires": { "@wdio/logger": "8.38.0", - "@wdio/types": "8.38.2", - "@wdio/utils": "8.38.2", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.39.0", "decamelize": "^6.0.0", "deepmerge-ts": "^5.0.0", "glob": "^10.2.2", "import-meta-resolve": "^4.0.0" + }, + "dependencies": { + "@wdio/types": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.39.0.tgz", + "integrity": "sha512-86lcYROTapOJuFd9ouomFDfzDnv3Kn+jE0RmqfvN9frZAeLVJ5IKjX9M6HjplsyTZhjGO1uCaehmzx+HJus33Q==", + "dev": true, + "requires": { + "@types/node": "^20.1.0" + } + }, + "@wdio/utils": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.39.0.tgz", + "integrity": "sha512-jY+n6jlGeK+9Tx8T659PKLwMQTGpLW5H78CSEWgZLbjbVSr2LfGR8Lx0CRktNXxAtqEVZPj16Pi74OtAhvhE6Q==", + "dev": true, + "requires": { + "@puppeteer/browsers": "^1.6.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.39.0", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.1.0", + "edgedriver": "^5.5.0", + "geckodriver": "^4.3.1", + "get-port": "^7.0.0", + "import-meta-resolve": "^4.0.0", + "locate-app": "^2.1.0", + "safaridriver": "^0.1.0", + "split2": "^4.2.0", + "wait-port": "^1.0.4" + } + } } }, "@wdio/globals": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-8.38.2.tgz", - "integrity": "sha512-iIrUF1EODfHLh3V/CSNCqbNNxUTe3ND+c86zDjzJcPFjawLX1plvAApsU/eDmtsFShcOS2KHbfSjiydFoqQG1Q==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-8.39.0.tgz", + "integrity": "sha512-qZo6JjRCIOtdvba6fdSqj6b91TnWXD6rmamyud93FTqbcspnhBvr8lmgOs5wnslTKeeTTigCjpsT310b4/AyHA==", "dev": true, "requires": { "expect-webdriverio": "^4.11.2", - "webdriverio": "8.38.2" + "webdriverio": "8.39.0" }, "dependencies": { - "@puppeteer/browsers": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", - "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", + "@wdio/types": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.39.0.tgz", + "integrity": "sha512-86lcYROTapOJuFd9ouomFDfzDnv3Kn+jE0RmqfvN9frZAeLVJ5IKjX9M6HjplsyTZhjGO1uCaehmzx+HJus33Q==", "dev": true, "optional": true, "requires": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "progress": "2.0.3", - "proxy-agent": "6.3.0", - "tar-fs": "3.0.4", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.1" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "optional": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "optional": true - } + "@types/node": "^20.1.0" } }, - "agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "@wdio/utils": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.39.0.tgz", + "integrity": "sha512-jY+n6jlGeK+9Tx8T659PKLwMQTGpLW5H78CSEWgZLbjbVSr2LfGR8Lx0CRktNXxAtqEVZPj16Pi74OtAhvhE6Q==", "dev": true, "optional": true, "requires": { - "debug": "^4.3.4" - }, - "dependencies": { - "debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "optional": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "optional": true - } + "@puppeteer/browsers": "^1.6.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.39.0", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.1.0", + "edgedriver": "^5.5.0", + "geckodriver": "^4.3.1", + "get-port": "^7.0.0", + "import-meta-resolve": "^4.0.0", + "locate-app": "^2.1.0", + "safaridriver": "^0.1.0", + "split2": "^4.2.0", + "wait-port": "^1.0.4" } }, "archiver": { @@ -35063,13 +35366,14 @@ } }, "cross-fetch": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", - "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz", + "integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==", "dev": true, "optional": true, + "peer": true, "requires": { - "node-fetch": "^2.6.12" + "node-fetch": "^2.6.11" } }, "debug": { @@ -35084,19 +35388,19 @@ } }, "devtools": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/devtools/-/devtools-8.38.2.tgz", - "integrity": "sha512-8b+naOPzYqzsiYtZZKYJnUnSqSOIg5orvna2SlWT2kFhkggbAJ1bbMzW7rps6onLfxp93wCNEIvngb9JuxwDsg==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-8.39.0.tgz", + "integrity": "sha512-QNbvNTNQMlU5gZqbmqzF92vfMOP/Eaa8KcvRj87M0jbn3dfwOeBC7WiECPFQ0MAfmynfarK7G7Ec+TfbAAEyNQ==", "dev": true, "optional": true, "peer": true, "requires": { "@types/node": "^20.1.0", - "@wdio/config": "8.38.2", + "@wdio/config": "8.39.0", "@wdio/logger": "8.38.0", "@wdio/protocols": "8.38.0", - "@wdio/types": "8.38.2", - "@wdio/utils": "8.38.2", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.39.0", "chrome-launcher": "^1.0.0", "edge-paths": "^3.0.5", "import-meta-resolve": "^4.0.0", @@ -35105,178 +35409,15 @@ "ua-parser-js": "^1.0.37", "uuid": "^9.0.0", "which": "^4.0.0" - }, - "dependencies": { - "@puppeteer/browsers": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.3.0.tgz", - "integrity": "sha512-an3QdbNPkuU6qpxpbssxAbjRLJcF+eP4L8UqIY3+6n0sbaVxw5pz7PiCLy9g32XEZuoamUlV5ZQPnA6FxvkIHA==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "http-proxy-agent": "5.0.0", - "https-proxy-agent": "5.0.1", - "progress": "2.0.3", - "proxy-from-env": "1.1.0", - "tar-fs": "2.1.1", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.1" - } - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "debug": "4" - } - }, - "chromium-bidi": { - "version": "0.4.9", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.9.tgz", - "integrity": "sha512-u3DC6XwgLCA9QJ5ak1voPslCmacQdulZNCPsI3qNXxSnEcZS7DFIbww+5RM2bznMEje7cc0oydavRLRvOIZtHw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "mitt": "3.0.0" - } - }, - "cross-fetch": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz", - "integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "node-fetch": "^2.6.11" - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "ms": "2.1.2" - } - }, - "devtools-protocol": { - "version": "0.0.1120988", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1120988.tgz", - "integrity": "sha512-39fCpE3Z78IaIPChJsP6Lhmkbf4dWXOmzLk/KFTdRkNk/0JymRIfUynDVRndV9HoDz8PyalK1UH21ST/ivwW5Q==", - "dev": true, - "optional": true, - "peer": true - }, - "http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - } - }, - "https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "optional": true, - "peer": true - }, - "puppeteer-core": { - "version": "20.3.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.3.0.tgz", - "integrity": "sha512-264pBrIui5bO6NJeOcbJrLa0OCwmA4+WK00JMrLIKTfRiqe2gx8KWTzLsjyw/bizErp3TKS7vt/I0i5fTC+mAw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "@puppeteer/browsers": "1.3.0", - "chromium-bidi": "0.4.9", - "cross-fetch": "3.1.6", - "debug": "4.3.4", - "devtools-protocol": "0.0.1120988", - "ws": "8.13.0" - } - }, - "readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - } - } } }, "devtools-protocol": { - "version": "0.0.1302984", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1302984.tgz", - "integrity": "sha512-Rgh2Sk5fUSCtEx4QGH9iwTyECdFPySG2nlz5J8guGh2Wlha6uzSOCq/DCEC8faHlLaMPZJMuZ4ovgcX4LvOkKA==", + "version": "0.0.1120988", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1120988.tgz", + "integrity": "sha512-39fCpE3Z78IaIPChJsP6Lhmkbf4dWXOmzLk/KFTdRkNk/0JymRIfUynDVRndV9HoDz8PyalK1UH21ST/ivwW5Q==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "escape-string-regexp": { "version": "4.0.0", @@ -35286,14 +35427,16 @@ "optional": true, "peer": true }, - "https-proxy-agent": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", - "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", "dev": true, "optional": true, + "peer": true, "requires": { - "agent-base": "^7.0.2", + "@tootallnate/once": "2", + "agent-base": "6", "debug": "4" }, "dependencies": { @@ -35303,6 +35446,7 @@ "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, "optional": true, + "peer": true, "requires": { "ms": "2.1.2" } @@ -35312,7 +35456,8 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true, - "optional": true + "optional": true, + "peer": true } } }, @@ -35343,9 +35488,9 @@ "optional": true }, "minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "optional": true, "requires": { @@ -35387,6 +35532,16 @@ "socks-proxy-agent": "^8.0.1" }, "dependencies": { + "agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "optional": true, + "requires": { + "debug": "^4.3.4" + } + }, "debug": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", @@ -35397,6 +35552,28 @@ "ms": "2.1.2" } }, + "http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "optional": true, + "requires": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + } + }, + "https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dev": true, + "optional": true, + "requires": { + "agent-base": "^7.0.2", + "debug": "4" + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -35407,43 +35584,58 @@ } }, "puppeteer-core": { - "version": "20.9.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.9.0.tgz", - "integrity": "sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==", + "version": "20.3.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.3.0.tgz", + "integrity": "sha512-264pBrIui5bO6NJeOcbJrLa0OCwmA4+WK00JMrLIKTfRiqe2gx8KWTzLsjyw/bizErp3TKS7vt/I0i5fTC+mAw==", "dev": true, "optional": true, + "peer": true, "requires": { - "@puppeteer/browsers": "1.4.6", - "chromium-bidi": "0.4.16", - "cross-fetch": "4.0.0", + "@puppeteer/browsers": "1.3.0", + "chromium-bidi": "0.4.9", + "cross-fetch": "3.1.6", "debug": "4.3.4", - "devtools-protocol": "0.0.1147663", + "devtools-protocol": "0.0.1120988", "ws": "8.13.0" }, "dependencies": { + "@puppeteer/browsers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.3.0.tgz", + "integrity": "sha512-an3QdbNPkuU6qpxpbssxAbjRLJcF+eP4L8UqIY3+6n0sbaVxw5pz7PiCLy9g32XEZuoamUlV5ZQPnA6FxvkIHA==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "http-proxy-agent": "5.0.0", + "https-proxy-agent": "5.0.1", + "progress": "2.0.3", + "proxy-from-env": "1.1.0", + "tar-fs": "2.1.1", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + } + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "optional": true, + "peer": true, "requires": { "ms": "2.1.2" } }, - "devtools-protocol": { - "version": "0.0.1147663", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz", - "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==", - "dev": true, - "optional": true - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true, - "optional": true + "optional": true, + "peer": true } } }, @@ -35481,6 +35673,50 @@ "safe-buffer": "~5.2.0" } }, + "tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + } + } + }, "type-fest": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", @@ -35497,19 +35733,19 @@ "peer": true }, "webdriverio": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.38.2.tgz", - "integrity": "sha512-r09y5UfivyYh5JOzT2SpJJ1zDmQl/R4OTH12opUqkjvp21BibCQm/uu1mrxGy4lzSHljrvqSVrrcGI+6UA1O8w==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.39.0.tgz", + "integrity": "sha512-pDpGu0V+TL1LkXPode67m3s+IPto4TcmcOzMpzFgu2oeLMBornoLN3yQSFR1fjZd1gK4UfnG3lJ4poTGOfbWfw==", "dev": true, "optional": true, "requires": { "@types/node": "^20.1.0", - "@wdio/config": "8.38.2", + "@wdio/config": "8.39.0", "@wdio/logger": "8.38.0", "@wdio/protocols": "8.38.0", "@wdio/repl": "8.24.12", - "@wdio/types": "8.38.2", - "@wdio/utils": "8.38.2", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.39.0", "archiver": "^7.0.0", "aria-query": "^5.0.0", "css-shorthand-properties": "^1.1.1", @@ -35527,7 +35763,105 @@ "resq": "^1.9.1", "rgb2hex": "0.2.5", "serialize-error": "^11.0.1", - "webdriver": "8.38.2" + "webdriver": "8.39.0" + }, + "dependencies": { + "@puppeteer/browsers": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", + "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", + "dev": true, + "optional": true, + "requires": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "progress": "2.0.3", + "proxy-agent": "6.3.0", + "tar-fs": "3.0.4", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + } + }, + "chromium-bidi": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.16.tgz", + "integrity": "sha512-7ZbXdWERxRxSwo3txsBjjmc/NLxqb1Bk30mRb0BMS4YIaiV6zvKZqL/UAH+DdqcDYayDWk2n/y8klkBDODrPvA==", + "dev": true, + "optional": true, + "requires": { + "mitt": "3.0.0" + } + }, + "cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dev": true, + "optional": true, + "requires": { + "node-fetch": "^2.6.12" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "optional": true, + "requires": { + "ms": "2.1.2" + } + }, + "devtools-protocol": { + "version": "0.0.1302984", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1302984.tgz", + "integrity": "sha512-Rgh2Sk5fUSCtEx4QGH9iwTyECdFPySG2nlz5J8guGh2Wlha6uzSOCq/DCEC8faHlLaMPZJMuZ4ovgcX4LvOkKA==", + "dev": true, + "optional": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "optional": true + }, + "puppeteer-core": { + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.9.0.tgz", + "integrity": "sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==", + "dev": true, + "optional": true, + "requires": { + "@puppeteer/browsers": "1.4.6", + "chromium-bidi": "0.4.16", + "cross-fetch": "4.0.0", + "debug": "4.3.4", + "devtools-protocol": "0.0.1147663", + "ws": "8.13.0" + }, + "dependencies": { + "devtools-protocol": { + "version": "0.0.1147663", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz", + "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==", + "dev": true, + "optional": true + } + } + }, + "tar-fs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", + "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", + "dev": true, + "optional": true, + "requires": { + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + } + } } }, "ws": { @@ -35569,19 +35903,30 @@ } }, "@wdio/local-runner": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-8.38.2.tgz", - "integrity": "sha512-syW+R5VUHJ3GBkQGFcNYe6MYwWRgklc9W7A83xQDTvKWFNHCetLvc8AtKZ54vs8MItBejjU+Oh94ZNbNX1pBcg==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-8.39.0.tgz", + "integrity": "sha512-TSGJVVWqshH7IO13OKw7G/364q3FczZDEh4h6bYe+GAs91KpZrEhZanyALgjh5F3crWtlffX+GA2HUwpi8X0sA==", "dev": true, "requires": { "@types/node": "^20.1.0", "@wdio/logger": "8.38.0", "@wdio/repl": "8.24.12", - "@wdio/runner": "8.38.2", - "@wdio/types": "8.38.2", + "@wdio/runner": "8.39.0", + "@wdio/types": "8.39.0", "async-exit-hook": "^2.0.1", "split2": "^4.1.0", "stream-buffers": "^3.0.2" + }, + "dependencies": { + "@wdio/types": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.39.0.tgz", + "integrity": "sha512-86lcYROTapOJuFd9ouomFDfzDnv3Kn+jE0RmqfvN9frZAeLVJ5IKjX9M6HjplsyTZhjGO1uCaehmzx+HJus33Q==", + "dev": true, + "requires": { + "@types/node": "^20.1.0" + } + } } }, "@wdio/logger": { @@ -35647,80 +35992,52 @@ } }, "@wdio/runner": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-8.38.2.tgz", - "integrity": "sha512-5lPnKSX2BBLI2AbYW+hoGPiEUAJXj8F8I6NC2LaBVzf1CLN+w2HWZ7lUiqS14XT0b5/hlSUX6+JYwUXlDbpuuw==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-8.39.0.tgz", + "integrity": "sha512-M1ixrrCtuwxHVzwsOKGMWBZCteafV0ztoS9+evMWGQtj0ZEsmhjAhWR3n2nZftt24vWOs+eNLGe2p+IO9Sm9bA==", "dev": true, "requires": { "@types/node": "^20.11.28", - "@wdio/config": "8.38.2", - "@wdio/globals": "8.38.2", + "@wdio/config": "8.39.0", + "@wdio/globals": "8.39.0", "@wdio/logger": "8.38.0", - "@wdio/types": "8.38.2", - "@wdio/utils": "8.38.2", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.39.0", "deepmerge-ts": "^5.1.0", "expect-webdriverio": "^4.12.0", "gaze": "^1.1.3", - "webdriver": "8.38.2", - "webdriverio": "8.38.2" + "webdriver": "8.39.0", + "webdriverio": "8.39.0" }, "dependencies": { - "@puppeteer/browsers": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", - "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", + "@wdio/types": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.39.0.tgz", + "integrity": "sha512-86lcYROTapOJuFd9ouomFDfzDnv3Kn+jE0RmqfvN9frZAeLVJ5IKjX9M6HjplsyTZhjGO1uCaehmzx+HJus33Q==", "dev": true, "requires": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "progress": "2.0.3", - "proxy-agent": "6.3.0", - "tar-fs": "3.0.4", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.1" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } + "@types/node": "^20.1.0" } }, - "agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "@wdio/utils": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.39.0.tgz", + "integrity": "sha512-jY+n6jlGeK+9Tx8T659PKLwMQTGpLW5H78CSEWgZLbjbVSr2LfGR8Lx0CRktNXxAtqEVZPj16Pi74OtAhvhE6Q==", "dev": true, "requires": { - "debug": "^4.3.4" - }, - "dependencies": { - "debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } + "@puppeteer/browsers": "^1.6.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.39.0", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.1.0", + "edgedriver": "^5.5.0", + "geckodriver": "^4.3.1", + "get-port": "^7.0.0", + "import-meta-resolve": "^4.0.0", + "locate-app": "^2.1.0", + "safaridriver": "^0.1.0", + "split2": "^4.2.0", + "wait-port": "^1.0.4" } }, "archiver": { @@ -35822,12 +36139,14 @@ } }, "cross-fetch": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", - "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz", + "integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==", "dev": true, + "optional": true, + "peer": true, "requires": { - "node-fetch": "^2.6.12" + "node-fetch": "^2.6.11" } }, "debug": { @@ -35842,19 +36161,19 @@ } }, "devtools": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/devtools/-/devtools-8.38.2.tgz", - "integrity": "sha512-8b+naOPzYqzsiYtZZKYJnUnSqSOIg5orvna2SlWT2kFhkggbAJ1bbMzW7rps6onLfxp93wCNEIvngb9JuxwDsg==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-8.39.0.tgz", + "integrity": "sha512-QNbvNTNQMlU5gZqbmqzF92vfMOP/Eaa8KcvRj87M0jbn3dfwOeBC7WiECPFQ0MAfmynfarK7G7Ec+TfbAAEyNQ==", "dev": true, "optional": true, "peer": true, "requires": { "@types/node": "^20.1.0", - "@wdio/config": "8.38.2", + "@wdio/config": "8.39.0", "@wdio/logger": "8.38.0", "@wdio/protocols": "8.38.0", - "@wdio/types": "8.38.2", - "@wdio/utils": "8.38.2", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.39.0", "chrome-launcher": "^1.0.0", "edge-paths": "^3.0.5", "import-meta-resolve": "^4.0.0", @@ -35863,177 +36182,15 @@ "ua-parser-js": "^1.0.37", "uuid": "^9.0.0", "which": "^4.0.0" - }, - "dependencies": { - "@puppeteer/browsers": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.3.0.tgz", - "integrity": "sha512-an3QdbNPkuU6qpxpbssxAbjRLJcF+eP4L8UqIY3+6n0sbaVxw5pz7PiCLy9g32XEZuoamUlV5ZQPnA6FxvkIHA==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "http-proxy-agent": "5.0.0", - "https-proxy-agent": "5.0.1", - "progress": "2.0.3", - "proxy-from-env": "1.1.0", - "tar-fs": "2.1.1", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.1" - } - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "debug": "4" - } - }, - "chromium-bidi": { - "version": "0.4.9", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.9.tgz", - "integrity": "sha512-u3DC6XwgLCA9QJ5ak1voPslCmacQdulZNCPsI3qNXxSnEcZS7DFIbww+5RM2bznMEje7cc0oydavRLRvOIZtHw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "mitt": "3.0.0" - } - }, - "cross-fetch": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz", - "integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "node-fetch": "^2.6.11" - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "ms": "2.1.2" - } - }, - "devtools-protocol": { - "version": "0.0.1120988", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1120988.tgz", - "integrity": "sha512-39fCpE3Z78IaIPChJsP6Lhmkbf4dWXOmzLk/KFTdRkNk/0JymRIfUynDVRndV9HoDz8PyalK1UH21ST/ivwW5Q==", - "dev": true, - "optional": true, - "peer": true - }, - "http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - } - }, - "https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "optional": true, - "peer": true - }, - "puppeteer-core": { - "version": "20.3.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.3.0.tgz", - "integrity": "sha512-264pBrIui5bO6NJeOcbJrLa0OCwmA4+WK00JMrLIKTfRiqe2gx8KWTzLsjyw/bizErp3TKS7vt/I0i5fTC+mAw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "@puppeteer/browsers": "1.3.0", - "chromium-bidi": "0.4.9", - "cross-fetch": "3.1.6", - "debug": "4.3.4", - "devtools-protocol": "0.0.1120988", - "ws": "8.13.0" - } - }, - "readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - } - } } }, "devtools-protocol": { - "version": "0.0.1302984", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1302984.tgz", - "integrity": "sha512-Rgh2Sk5fUSCtEx4QGH9iwTyECdFPySG2nlz5J8guGh2Wlha6uzSOCq/DCEC8faHlLaMPZJMuZ4ovgcX4LvOkKA==", - "dev": true + "version": "0.0.1120988", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1120988.tgz", + "integrity": "sha512-39fCpE3Z78IaIPChJsP6Lhmkbf4dWXOmzLk/KFTdRkNk/0JymRIfUynDVRndV9HoDz8PyalK1UH21ST/ivwW5Q==", + "dev": true, + "optional": true, + "peer": true }, "escape-string-regexp": { "version": "4.0.0", @@ -36043,13 +36200,16 @@ "optional": true, "peer": true }, - "https-proxy-agent": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", - "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", "dev": true, + "optional": true, + "peer": true, "requires": { - "agent-base": "^7.0.2", + "@tootallnate/once": "2", + "agent-base": "6", "debug": "4" }, "dependencies": { @@ -36058,6 +36218,8 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, + "optional": true, + "peer": true, "requires": { "ms": "2.1.2" } @@ -36066,7 +36228,9 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "dev": true, + "optional": true, + "peer": true } } }, @@ -36095,9 +36259,9 @@ "dev": true }, "minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -36136,6 +36300,15 @@ "socks-proxy-agent": "^8.0.1" }, "dependencies": { + "agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "requires": { + "debug": "^4.3.4" + } + }, "debug": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", @@ -36145,6 +36318,26 @@ "ms": "2.1.2" } }, + "http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "requires": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + } + }, + "https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dev": true, + "requires": { + "agent-base": "^7.0.2", + "debug": "4" + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -36154,39 +36347,58 @@ } }, "puppeteer-core": { - "version": "20.9.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.9.0.tgz", - "integrity": "sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==", + "version": "20.3.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.3.0.tgz", + "integrity": "sha512-264pBrIui5bO6NJeOcbJrLa0OCwmA4+WK00JMrLIKTfRiqe2gx8KWTzLsjyw/bizErp3TKS7vt/I0i5fTC+mAw==", "dev": true, + "optional": true, + "peer": true, "requires": { - "@puppeteer/browsers": "1.4.6", - "chromium-bidi": "0.4.16", - "cross-fetch": "4.0.0", + "@puppeteer/browsers": "1.3.0", + "chromium-bidi": "0.4.9", + "cross-fetch": "3.1.6", "debug": "4.3.4", - "devtools-protocol": "0.0.1147663", + "devtools-protocol": "0.0.1120988", "ws": "8.13.0" }, "dependencies": { + "@puppeteer/browsers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.3.0.tgz", + "integrity": "sha512-an3QdbNPkuU6qpxpbssxAbjRLJcF+eP4L8UqIY3+6n0sbaVxw5pz7PiCLy9g32XEZuoamUlV5ZQPnA6FxvkIHA==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "http-proxy-agent": "5.0.0", + "https-proxy-agent": "5.0.1", + "progress": "2.0.3", + "proxy-from-env": "1.1.0", + "tar-fs": "2.1.1", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + } + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, + "optional": true, + "peer": true, "requires": { "ms": "2.1.2" } }, - "devtools-protocol": { - "version": "0.0.1147663", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz", - "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==", - "dev": true - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "dev": true, + "optional": true, + "peer": true } } }, @@ -36221,6 +36433,50 @@ "safe-buffer": "~5.2.0" } }, + "tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + } + } + }, "type-fest": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", @@ -36236,18 +36492,18 @@ "peer": true }, "webdriverio": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.38.2.tgz", - "integrity": "sha512-r09y5UfivyYh5JOzT2SpJJ1zDmQl/R4OTH12opUqkjvp21BibCQm/uu1mrxGy4lzSHljrvqSVrrcGI+6UA1O8w==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.39.0.tgz", + "integrity": "sha512-pDpGu0V+TL1LkXPode67m3s+IPto4TcmcOzMpzFgu2oeLMBornoLN3yQSFR1fjZd1gK4UfnG3lJ4poTGOfbWfw==", "dev": true, "requires": { "@types/node": "^20.1.0", - "@wdio/config": "8.38.2", + "@wdio/config": "8.39.0", "@wdio/logger": "8.38.0", "@wdio/protocols": "8.38.0", "@wdio/repl": "8.24.12", - "@wdio/types": "8.38.2", - "@wdio/utils": "8.38.2", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.39.0", "archiver": "^7.0.0", "aria-query": "^5.0.0", "css-shorthand-properties": "^1.1.1", @@ -36265,7 +36521,96 @@ "resq": "^1.9.1", "rgb2hex": "0.2.5", "serialize-error": "^11.0.1", - "webdriver": "8.38.2" + "webdriver": "8.39.0" + }, + "dependencies": { + "@puppeteer/browsers": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", + "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", + "dev": true, + "requires": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "progress": "2.0.3", + "proxy-agent": "6.3.0", + "tar-fs": "3.0.4", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + } + }, + "chromium-bidi": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.16.tgz", + "integrity": "sha512-7ZbXdWERxRxSwo3txsBjjmc/NLxqb1Bk30mRb0BMS4YIaiV6zvKZqL/UAH+DdqcDYayDWk2n/y8klkBDODrPvA==", + "dev": true, + "requires": { + "mitt": "3.0.0" + } + }, + "cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dev": true, + "requires": { + "node-fetch": "^2.6.12" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "devtools-protocol": { + "version": "0.0.1302984", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1302984.tgz", + "integrity": "sha512-Rgh2Sk5fUSCtEx4QGH9iwTyECdFPySG2nlz5J8guGh2Wlha6uzSOCq/DCEC8faHlLaMPZJMuZ4ovgcX4LvOkKA==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "puppeteer-core": { + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.9.0.tgz", + "integrity": "sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==", + "dev": true, + "requires": { + "@puppeteer/browsers": "1.4.6", + "chromium-bidi": "0.4.16", + "cross-fetch": "4.0.0", + "debug": "4.3.4", + "devtools-protocol": "0.0.1147663", + "ws": "8.13.0" + }, + "dependencies": { + "devtools-protocol": { + "version": "0.0.1147663", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz", + "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==", + "dev": true + } + } + }, + "tar-fs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", + "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", + "dev": true, + "requires": { + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + } + } } }, "ws": { @@ -36781,6 +37126,12 @@ "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", "dev": true }, + "are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "dev": true + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -38206,10 +38557,12 @@ "dev": true }, "chromium-bidi": { - "version": "0.4.16", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.16.tgz", - "integrity": "sha512-7ZbXdWERxRxSwo3txsBjjmc/NLxqb1Bk30mRb0BMS4YIaiV6zvKZqL/UAH+DdqcDYayDWk2n/y8klkBDODrPvA==", + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.9.tgz", + "integrity": "sha512-u3DC6XwgLCA9QJ5ak1voPslCmacQdulZNCPsI3qNXxSnEcZS7DFIbww+5RM2bznMEje7cc0oydavRLRvOIZtHw==", "dev": true, + "optional": true, + "peer": true, "requires": { "mitt": "3.0.0" } @@ -38457,9 +38810,9 @@ "dev": true }, "comment-parser": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.1.tgz", - "integrity": "sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", + "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", "dev": true }, "commondir": { @@ -40191,9 +40544,9 @@ } }, "engine.io": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz", - "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==", + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz", + "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==", "dev": true, "requires": { "@types/cookie": "^0.4.1", @@ -40205,7 +40558,7 @@ "cors": "~2.8.5", "debug": "~4.3.1", "engine.io-parser": "~5.2.1", - "ws": "~8.11.0" + "ws": "~8.17.1" }, "dependencies": { "cookie": { @@ -40827,19 +41180,21 @@ } }, "eslint-plugin-jsdoc": { - "version": "38.1.6", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-38.1.6.tgz", - "integrity": "sha512-n4s95oYlg0L43Bs8C0dkzIldxYf8pLCutC/tCbjIdF7VDiobuzPI+HZn9Q0BvgOvgPNgh5n7CSStql25HUG4Tw==", + "version": "48.5.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.5.0.tgz", + "integrity": "sha512-ukXPNpGby3KjCveCizIS8t1EbuJEHYEu/tBg8GCbn/YbHcXwphyvYCdvRZ/oMRfTscGSSzfsWoZ+ZkAP0/6YMQ==", "dev": true, "requires": { - "@es-joy/jsdoccomment": "~0.22.1", - "comment-parser": "1.3.1", + "@es-joy/jsdoccomment": "~0.43.1", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.4.1", "debug": "^4.3.4", "escape-string-regexp": "^4.0.0", - "esquery": "^1.4.0", - "regextras": "^0.8.0", - "semver": "^7.3.5", - "spdx-expression-parse": "^3.0.1" + "esquery": "^1.5.0", + "parse-imports": "^2.1.0", + "semver": "^7.6.2", + "spdx-expression-parse": "^4.0.0", + "synckit": "^0.9.0" }, "dependencies": { "escape-string-regexp": { @@ -40853,6 +41208,16 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true + }, + "spdx-expression-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } } } }, @@ -41234,9 +41599,9 @@ } }, "expect-webdriverio": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/expect-webdriverio/-/expect-webdriverio-4.15.0.tgz", - "integrity": "sha512-CIBSLEhDmjZ7kKZq6ItBM7V1jLH/w4JCuKGu3WmR4FscOPvOnp9JN4Zi26SZGeQ73E0dy+YPUL6SIvTNoP/XdQ==", + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/expect-webdriverio/-/expect-webdriverio-4.15.1.tgz", + "integrity": "sha512-xtBSidt7Whs1fsUC+utxVzfmkmaStXWW17b+BcMCiCltx0Yku6l7BTv1Y14DEKX8L6rttaDQobYyRtBKbi4ssg==", "dev": true, "requires": { "@vitest/snapshot": "^1.2.2", @@ -41248,68 +41613,36 @@ "webdriverio": "^8.29.3" }, "dependencies": { - "@puppeteer/browsers": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", - "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", + "@wdio/types": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.39.0.tgz", + "integrity": "sha512-86lcYROTapOJuFd9ouomFDfzDnv3Kn+jE0RmqfvN9frZAeLVJ5IKjX9M6HjplsyTZhjGO1uCaehmzx+HJus33Q==", "dev": true, "optional": true, "requires": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "progress": "2.0.3", - "proxy-agent": "6.3.0", - "tar-fs": "3.0.4", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.1" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "optional": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "optional": true - } + "@types/node": "^20.1.0" } }, - "agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "@wdio/utils": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.39.0.tgz", + "integrity": "sha512-jY+n6jlGeK+9Tx8T659PKLwMQTGpLW5H78CSEWgZLbjbVSr2LfGR8Lx0CRktNXxAtqEVZPj16Pi74OtAhvhE6Q==", "dev": true, "optional": true, "requires": { - "debug": "^4.3.4" - }, - "dependencies": { - "debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "optional": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "optional": true - } + "@puppeteer/browsers": "^1.6.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.39.0", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.1.0", + "edgedriver": "^5.5.0", + "geckodriver": "^4.3.1", + "get-port": "^7.0.0", + "import-meta-resolve": "^4.0.0", + "locate-app": "^2.1.0", + "safaridriver": "^0.1.0", + "split2": "^4.2.0", + "wait-port": "^1.0.4" } }, "archiver": { @@ -41419,13 +41752,14 @@ } }, "cross-fetch": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", - "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz", + "integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==", "dev": true, "optional": true, + "peer": true, "requires": { - "node-fetch": "^2.6.12" + "node-fetch": "^2.6.11" } }, "debug": { @@ -41440,19 +41774,19 @@ } }, "devtools": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/devtools/-/devtools-8.38.2.tgz", - "integrity": "sha512-8b+naOPzYqzsiYtZZKYJnUnSqSOIg5orvna2SlWT2kFhkggbAJ1bbMzW7rps6onLfxp93wCNEIvngb9JuxwDsg==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-8.39.0.tgz", + "integrity": "sha512-QNbvNTNQMlU5gZqbmqzF92vfMOP/Eaa8KcvRj87M0jbn3dfwOeBC7WiECPFQ0MAfmynfarK7G7Ec+TfbAAEyNQ==", "dev": true, "optional": true, "peer": true, "requires": { "@types/node": "^20.1.0", - "@wdio/config": "8.38.2", + "@wdio/config": "8.39.0", "@wdio/logger": "8.38.0", "@wdio/protocols": "8.38.0", - "@wdio/types": "8.38.2", - "@wdio/utils": "8.38.2", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.39.0", "chrome-launcher": "^1.0.0", "edge-paths": "^3.0.5", "import-meta-resolve": "^4.0.0", @@ -41461,178 +41795,15 @@ "ua-parser-js": "^1.0.37", "uuid": "^9.0.0", "which": "^4.0.0" - }, - "dependencies": { - "@puppeteer/browsers": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.3.0.tgz", - "integrity": "sha512-an3QdbNPkuU6qpxpbssxAbjRLJcF+eP4L8UqIY3+6n0sbaVxw5pz7PiCLy9g32XEZuoamUlV5ZQPnA6FxvkIHA==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "http-proxy-agent": "5.0.0", - "https-proxy-agent": "5.0.1", - "progress": "2.0.3", - "proxy-from-env": "1.1.0", - "tar-fs": "2.1.1", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.1" - } - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "debug": "4" - } - }, - "chromium-bidi": { - "version": "0.4.9", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.9.tgz", - "integrity": "sha512-u3DC6XwgLCA9QJ5ak1voPslCmacQdulZNCPsI3qNXxSnEcZS7DFIbww+5RM2bznMEje7cc0oydavRLRvOIZtHw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "mitt": "3.0.0" - } - }, - "cross-fetch": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz", - "integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "node-fetch": "^2.6.11" - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "ms": "2.1.2" - } - }, - "devtools-protocol": { - "version": "0.0.1120988", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1120988.tgz", - "integrity": "sha512-39fCpE3Z78IaIPChJsP6Lhmkbf4dWXOmzLk/KFTdRkNk/0JymRIfUynDVRndV9HoDz8PyalK1UH21ST/ivwW5Q==", - "dev": true, - "optional": true, - "peer": true - }, - "http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - } - }, - "https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "optional": true, - "peer": true - }, - "puppeteer-core": { - "version": "20.3.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.3.0.tgz", - "integrity": "sha512-264pBrIui5bO6NJeOcbJrLa0OCwmA4+WK00JMrLIKTfRiqe2gx8KWTzLsjyw/bizErp3TKS7vt/I0i5fTC+mAw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "@puppeteer/browsers": "1.3.0", - "chromium-bidi": "0.4.9", - "cross-fetch": "3.1.6", - "debug": "4.3.4", - "devtools-protocol": "0.0.1120988", - "ws": "8.13.0" - } - }, - "readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - } - } } }, "devtools-protocol": { - "version": "0.0.1302984", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1302984.tgz", - "integrity": "sha512-Rgh2Sk5fUSCtEx4QGH9iwTyECdFPySG2nlz5J8guGh2Wlha6uzSOCq/DCEC8faHlLaMPZJMuZ4ovgcX4LvOkKA==", + "version": "0.0.1120988", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1120988.tgz", + "integrity": "sha512-39fCpE3Z78IaIPChJsP6Lhmkbf4dWXOmzLk/KFTdRkNk/0JymRIfUynDVRndV9HoDz8PyalK1UH21ST/ivwW5Q==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "escape-string-regexp": { "version": "4.0.0", @@ -41642,14 +41813,16 @@ "optional": true, "peer": true }, - "https-proxy-agent": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", - "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", "dev": true, "optional": true, + "peer": true, "requires": { - "agent-base": "^7.0.2", + "@tootallnate/once": "2", + "agent-base": "6", "debug": "4" }, "dependencies": { @@ -41659,6 +41832,7 @@ "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, "optional": true, + "peer": true, "requires": { "ms": "2.1.2" } @@ -41668,7 +41842,8 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true, - "optional": true + "optional": true, + "peer": true } } }, @@ -41699,9 +41874,9 @@ "optional": true }, "minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "optional": true, "requires": { @@ -41743,6 +41918,16 @@ "socks-proxy-agent": "^8.0.1" }, "dependencies": { + "agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "optional": true, + "requires": { + "debug": "^4.3.4" + } + }, "debug": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", @@ -41753,6 +41938,28 @@ "ms": "2.1.2" } }, + "http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "optional": true, + "requires": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + } + }, + "https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dev": true, + "optional": true, + "requires": { + "agent-base": "^7.0.2", + "debug": "4" + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -41763,43 +41970,58 @@ } }, "puppeteer-core": { - "version": "20.9.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.9.0.tgz", - "integrity": "sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==", + "version": "20.3.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.3.0.tgz", + "integrity": "sha512-264pBrIui5bO6NJeOcbJrLa0OCwmA4+WK00JMrLIKTfRiqe2gx8KWTzLsjyw/bizErp3TKS7vt/I0i5fTC+mAw==", "dev": true, "optional": true, + "peer": true, "requires": { - "@puppeteer/browsers": "1.4.6", - "chromium-bidi": "0.4.16", - "cross-fetch": "4.0.0", + "@puppeteer/browsers": "1.3.0", + "chromium-bidi": "0.4.9", + "cross-fetch": "3.1.6", "debug": "4.3.4", - "devtools-protocol": "0.0.1147663", + "devtools-protocol": "0.0.1120988", "ws": "8.13.0" }, "dependencies": { + "@puppeteer/browsers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.3.0.tgz", + "integrity": "sha512-an3QdbNPkuU6qpxpbssxAbjRLJcF+eP4L8UqIY3+6n0sbaVxw5pz7PiCLy9g32XEZuoamUlV5ZQPnA6FxvkIHA==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "http-proxy-agent": "5.0.0", + "https-proxy-agent": "5.0.1", + "progress": "2.0.3", + "proxy-from-env": "1.1.0", + "tar-fs": "2.1.1", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + } + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "optional": true, + "peer": true, "requires": { "ms": "2.1.2" } }, - "devtools-protocol": { - "version": "0.0.1147663", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz", - "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==", - "dev": true, - "optional": true - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true, - "optional": true + "optional": true, + "peer": true } } }, @@ -41837,6 +42059,50 @@ "safe-buffer": "~5.2.0" } }, + "tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + } + } + }, "type-fest": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", @@ -41853,19 +42119,19 @@ "peer": true }, "webdriverio": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.38.2.tgz", - "integrity": "sha512-r09y5UfivyYh5JOzT2SpJJ1zDmQl/R4OTH12opUqkjvp21BibCQm/uu1mrxGy4lzSHljrvqSVrrcGI+6UA1O8w==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.39.0.tgz", + "integrity": "sha512-pDpGu0V+TL1LkXPode67m3s+IPto4TcmcOzMpzFgu2oeLMBornoLN3yQSFR1fjZd1gK4UfnG3lJ4poTGOfbWfw==", "dev": true, "optional": true, "requires": { "@types/node": "^20.1.0", - "@wdio/config": "8.38.2", + "@wdio/config": "8.39.0", "@wdio/logger": "8.38.0", "@wdio/protocols": "8.38.0", "@wdio/repl": "8.24.12", - "@wdio/types": "8.38.2", - "@wdio/utils": "8.38.2", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.39.0", "archiver": "^7.0.0", "aria-query": "^5.0.0", "css-shorthand-properties": "^1.1.1", @@ -41883,7 +42149,105 @@ "resq": "^1.9.1", "rgb2hex": "0.2.5", "serialize-error": "^11.0.1", - "webdriver": "8.38.2" + "webdriver": "8.39.0" + }, + "dependencies": { + "@puppeteer/browsers": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", + "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", + "dev": true, + "optional": true, + "requires": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "progress": "2.0.3", + "proxy-agent": "6.3.0", + "tar-fs": "3.0.4", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + } + }, + "chromium-bidi": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.16.tgz", + "integrity": "sha512-7ZbXdWERxRxSwo3txsBjjmc/NLxqb1Bk30mRb0BMS4YIaiV6zvKZqL/UAH+DdqcDYayDWk2n/y8klkBDODrPvA==", + "dev": true, + "optional": true, + "requires": { + "mitt": "3.0.0" + } + }, + "cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dev": true, + "optional": true, + "requires": { + "node-fetch": "^2.6.12" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "optional": true, + "requires": { + "ms": "2.1.2" + } + }, + "devtools-protocol": { + "version": "0.0.1302984", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1302984.tgz", + "integrity": "sha512-Rgh2Sk5fUSCtEx4QGH9iwTyECdFPySG2nlz5J8guGh2Wlha6uzSOCq/DCEC8faHlLaMPZJMuZ4ovgcX4LvOkKA==", + "dev": true, + "optional": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "optional": true + }, + "puppeteer-core": { + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.9.0.tgz", + "integrity": "sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==", + "dev": true, + "optional": true, + "requires": { + "@puppeteer/browsers": "1.4.6", + "chromium-bidi": "0.4.16", + "cross-fetch": "4.0.0", + "debug": "4.3.4", + "devtools-protocol": "0.0.1147663", + "ws": "8.13.0" + }, + "dependencies": { + "devtools-protocol": { + "version": "0.0.1147663", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz", + "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==", + "dev": true, + "optional": true + } + } + }, + "tar-fs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", + "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", + "dev": true, + "optional": true, + "requires": { + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + } + } } }, "ws": { @@ -42328,151 +42692,6 @@ "is-glob": "^4.0.0", "micromatch": "^3.0.4", "resolve-dir": "^1.0.1" - }, - "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "dev": true - } - } - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "dev": true - } - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - } } }, "fined": { @@ -42575,9 +42794,9 @@ "dev": true }, "foreground-child": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.0.tgz", - "integrity": "sha512-CrWQNaEl1/6WeZoarcM9LHupTo3RpZO2Pdk1vktwzPiQTsJnAKJmm3TACKeG5UZbWDfaH2AbvYxzP96y0MT7fA==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", + "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", "dev": true, "requires": { "cross-spawn": "^7.0.0", @@ -43056,15 +43275,16 @@ "dev": true }, "glob": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", - "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "version": "10.4.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.2.tgz", + "integrity": "sha512-GwMlUF6PkPo3Gk21UxkCohOv0PLcIXVtKyLlpEI28R/cO/4eNOdmLk3CMW1wROV/WR/EsZOWAfBbBOqYvs88/w==", "dev": true, "requires": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "dependencies": { @@ -43078,9 +43298,9 @@ } }, "minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -43192,12 +43412,6 @@ } } }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", - "dev": true - }, "binary-extensions": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", @@ -43325,15 +43539,6 @@ "kind-of": "^3.0.2" } }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -43343,54 +43548,6 @@ "is-buffer": "^1.1.5" } }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - } - } - }, "readdirp": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", @@ -46528,6 +46685,16 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dev": true, + "requires": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + } + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -46666,9 +46833,9 @@ "dev": true }, "jsdoc-type-pratt-parser": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-2.2.5.tgz", - "integrity": "sha512-2a6eRxSxp1BW040hFvaJxhsCMI9lT8QB8t14t+NY5tC5rckIR0U9cr2tjOeaFirmEOy6MHvmJnY7zTBHq431Lw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", + "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", "dev": true }, "jsesc": { @@ -47930,86 +48097,6 @@ "stack-trace": "0.0.10" }, "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "dev": true - } - } - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "dev": true - } - } - }, "findup-sync": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", @@ -48022,12 +48109,6 @@ "resolve-dir": "^1.0.1" } }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, "is-glob": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", @@ -48036,63 +48117,6 @@ "requires": { "is-extglob": "^2.1.0" } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } } } }, @@ -48701,13 +48725,148 @@ "dev": true }, "micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, "requires": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true + } + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true + } + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } } }, "mime": { @@ -49956,6 +50115,12 @@ "netmask": "^2.0.2" } }, + "package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "dev": true + }, "pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", @@ -49982,6 +50147,16 @@ "path-root": "^0.1.1" } }, + "parse-imports": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/parse-imports/-/parse-imports-2.1.0.tgz", + "integrity": "sha512-JQWgmK2o4w8leUkZeZPatWdAny6vXGU/3siIUvMF6J2rDCud9aTt8h/px9oZJ6U3EcfhngBJ635uPFI0q0VAeA==", + "dev": true, + "requires": { + "es-module-lexer": "^1.5.3", + "slashes": "^3.0.12" + } + }, "parse-json": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-7.1.1.tgz", @@ -50111,9 +50286,9 @@ }, "dependencies": { "lru-cache": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", - "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.3.0.tgz", + "integrity": "sha512-CQl19J/g+Hbjbv4Y3mFNNXFEL/5t/KCg8POCuUqd4rMKjGG+j1ybER83hxV58zL+dFI1PTkt3GNFSHRt+d8qEQ==", "dev": true } } @@ -50877,12 +51052,6 @@ "unicode-match-property-value-ecmascript": "^2.1.0" } }, - "regextras": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/regextras/-/regextras-0.8.0.tgz", - "integrity": "sha512-k519uI04Z3SaY0fLX843MRXnDeG2+vHOFsyhiPZvNLe7r8rD2YNRjq4BQLZZ0oAr2NrtvZlICsXysGNFPGa3CQ==", - "dev": true - }, "regjsparser": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", @@ -51717,6 +51886,12 @@ "integrity": "sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg==", "dev": true }, + "slashes": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/slashes/-/slashes-3.0.12.tgz", + "integrity": "sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==", + "dev": true + }, "slice-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", @@ -51904,13 +52079,13 @@ } }, "socket.io-adapter": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.4.tgz", - "integrity": "sha512-wDNHGXGewWAjQPt3pyeYBtpWSq9cLE5UW1ZUPL/2eGK9jtse/FpXib7epSTsz0Q0m+6sg6Y4KtcFTlah1bdOVg==", + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", + "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", "dev": true, "requires": { "debug": "~4.3.4", - "ws": "~8.11.0" + "ws": "~8.17.1" } }, "socket.io-parser": { @@ -52455,6 +52630,24 @@ "es6-symbol": "^3.1.1" } }, + "synckit": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.0.tgz", + "integrity": "sha512-7RnqIMq572L8PeEzKeBINYEJDDxpcH8JEgLwUqBd3TkofhFRbkq4QLR0u+36avGAhCRbk2nnmjcW9SE531hPDg==", + "dev": true, + "requires": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + } + } + }, "table": { "version": "6.8.2", "resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz", @@ -54029,22 +54222,54 @@ "dev": true }, "webdriver": { - "version": "8.38.2", - "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.38.2.tgz", - "integrity": "sha512-NGfjW0BDYwFgOIzeojOcWGn3tYloQdvHr+Y2xKKYVqa9Rs0x1mzlTjU1kWtC4DaV8DltskwaPa7o+s8hTNpuyA==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.39.0.tgz", + "integrity": "sha512-Kc3+SfiH4ufyrIht683VT2vnJocx0pfH8rYdyPvEh1b2OYewtFTHK36k9rBDHZiBmk6jcSXs4M2xeFgOuon9Lg==", "dev": true, "requires": { "@types/node": "^20.1.0", "@types/ws": "^8.5.3", - "@wdio/config": "8.38.2", + "@wdio/config": "8.39.0", "@wdio/logger": "8.38.0", "@wdio/protocols": "8.38.0", - "@wdio/types": "8.38.2", - "@wdio/utils": "8.38.2", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.39.0", "deepmerge-ts": "^5.1.0", "got": "^12.6.1", "ky": "^0.33.0", "ws": "^8.8.0" + }, + "dependencies": { + "@wdio/types": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.39.0.tgz", + "integrity": "sha512-86lcYROTapOJuFd9ouomFDfzDnv3Kn+jE0RmqfvN9frZAeLVJ5IKjX9M6HjplsyTZhjGO1uCaehmzx+HJus33Q==", + "dev": true, + "requires": { + "@types/node": "^20.1.0" + } + }, + "@wdio/utils": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.39.0.tgz", + "integrity": "sha512-jY+n6jlGeK+9Tx8T659PKLwMQTGpLW5H78CSEWgZLbjbVSr2LfGR8Lx0CRktNXxAtqEVZPj16Pi74OtAhvhE6Q==", + "dev": true, + "requires": { + "@puppeteer/browsers": "^1.6.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.39.0", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.1.0", + "edgedriver": "^5.5.0", + "geckodriver": "^4.3.1", + "get-port": "^7.0.0", + "import-meta-resolve": "^4.0.0", + "locate-app": "^2.1.0", + "safaridriver": "^0.1.0", + "split2": "^4.2.0", + "wait-port": "^1.0.4" + } + } } }, "webdriverio": { @@ -54521,9 +54746,9 @@ "dev": true }, "ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", "dev": true, "requires": {} } @@ -54878,9 +55103,9 @@ } }, "ws": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "dev": true, "requires": {} }, diff --git a/package.json b/package.json index c0bbb1674c7..de8afe546ef 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "9.4.0-pre", + "version": "9.7.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.public.js", "exports": { @@ -66,7 +66,7 @@ "eslint": "^7.27.0", "eslint-config-standard": "^10.2.1", "eslint-plugin-import": "^2.20.2", - "eslint-plugin-jsdoc": "^38.1.6", + "eslint-plugin-jsdoc": "^48.5.0", "eslint-plugin-node": "^11.1.0", "eslint-plugin-prebid": "file:./plugins/eslint", "eslint-plugin-promise": "^5.1.0", @@ -74,7 +74,7 @@ "execa": "^1.0.0", "faker": "^5.5.3", "fs.extra": "^1.3.2", - "gulp": "^4.0.0", + "gulp": "^4.0.2", "gulp-clean": "^0.4.0", "gulp-concat": "^2.6.0", "gulp-connect": "^5.7.0", @@ -115,7 +115,7 @@ "opn": "^5.4.0", "querystring": "^0.2.1", "resolve-from": "^5.0.0", - "sinon": "^4.1.3", + "sinon": "^4.5.0", "through2": "^4.0.2", "url": "^0.11.0", "url-parse": "^1.0.5", diff --git a/plugins/eslint/index.js b/plugins/eslint/index.js index 5041675f6ad..f8acf54683b 100644 --- a/plugins/eslint/index.js +++ b/plugins/eslint/index.js @@ -1,52 +1,13 @@ const _ = require('lodash'); const { flagErrors } = require('./validateImports.js'); +const noGlobal = require('eslint/lib/rules/no-restricted-globals.js'); + +function getName(node) { + return node.type === 'Literal' ? node.value : node.name; +} module.exports = { rules: { - 'no-outerText': { - meta: { - docs: { - description: '.outerText property on DOM elements should not be used due to performance issues' - }, - messages: { - noInnerText: 'Use of `.outerText` is not allowed. Use `.textContent` instead.', - } - }, - create: function(context) { - return { - MemberExpression(node) { - if (node.property && node.property.name === 'outerText') { - context.report({ - node: node.property, - messageId: 'noOuterText', - }); - } - } - } - } - }, - 'no-innerText': { - meta: { - docs: { - description: '.innerText property on DOM elements should not be used due to performance issues' - }, - messages: { - noInnerText: 'Use of `.innerText` is not allowed. Use `.textContent` instead.', - } - }, - create: function(context) { - return { - MemberExpression(node) { - if (node.property && node.property.name === 'innerText') { - context.report({ - node: node.property, - messageId: 'noInnerText', - }); - } - } - } - } - }, 'validate-imports': { meta: { docs: { @@ -69,8 +30,75 @@ module.exports = { let importPath = node.source.value.trim(); flagErrors(context, node, importPath); } + }; + } + }, + 'no-member': { + meta: { + schema: { + type: 'array', + items: { + type: 'object', + properties: { + target: { type: 'string' }, + name: { type: 'string' }, + message: { type: 'string' } + }, + required: ['name', 'message'], + additionalProperties: false + }, + uniqueItems: true, + minItems: 1 + }, + + messages: { + noMember: "Unexpected use of '{{target}}.{{name}}'. {{message}}", } + }, + + create(context) { + return { + MemberExpression(node) { + context.options.forEach(({name, target, message}) => { + if (target === node.object.name && getName(node.property) === name) { + context.report({ + node, + messageId: 'noMember', + data: { + name, + target: target || '', + message + } + }); + } + }); + } + } + } + }, + 'no-global': Object.assign({}, noGlobal, { + // no-restricted-global that also looks for `window.GLOBAL` + create(context) { + const globals = Object.fromEntries( + context.options.map(option => typeof option === 'string' ? [option, null] : [option.name, option.message]) + ) + return Object.assign(noGlobal.create(context), { + MemberExpression(node) { + const name = getName(node.property); + if (node.object.name === 'window' && globals.hasOwnProperty(name)) { + const customMessage = globals[name]; + context.report({ + node, + messageId: customMessage == null ? 'defaultMessage' : 'customMessage', + data: { + name, + customMessage + } + }) + } + } + }) } - } + }), } }; diff --git a/src/adRendering.js b/src/adRendering.js index 33f7fe9252c..9eb894ec190 100644 --- a/src/adRendering.js +++ b/src/adRendering.js @@ -1,6 +1,15 @@ -import {createIframe, deepAccess, inIframe, insertElement, logError, logWarn, replaceMacros} from './utils.js'; +import { + createIframe, + createInvisibleIframe, + deepAccess, + inIframe, + insertElement, + logError, + logWarn, + replaceMacros +} from './utils.js'; import * as events from './events.js'; -import { AD_RENDER_FAILED_REASON, BID_STATUS, EVENTS, MESSAGES } from './constants.js'; +import {AD_RENDER_FAILED_REASON, BID_STATUS, EVENTS, MESSAGES, PB_LOCATOR} from './constants.js'; import {config} from './config.js'; import {executeRenderer, isRendererRequired} from './Renderer.js'; import {VIDEO} from './mediaTypes.js'; @@ -235,3 +244,21 @@ export function renderAdDirect(doc, adId, options) { fail(EXCEPTION, e.message); } } + +/** + * Insert an invisible, named iframe that can be used by creatives to locate the window Prebid is running in + * (by looking for one that has `.frames[PB_LOCATOR]` defined). + * This is necessary because in some situations creatives may be rendered inside nested iframes - Prebid is not necessarily + * in the immediate parent window. + */ +export function insertLocatorFrame() { + if (!window.frames[PB_LOCATOR]) { + if (!document.body) { + window.requestAnimationFrame(insertLocatorFrame); + } else { + const frame = createInvisibleIframe(); + frame.name = PB_LOCATOR; + document.body.appendChild(frame); + } + } +} diff --git a/src/adloader.js b/src/adloader.js index 12b552373a0..79ea6e017bb 100644 --- a/src/adloader.js +++ b/src/adloader.js @@ -31,6 +31,7 @@ const _approvedLoadExternalJSList = [ 'qortex', 'dynamicAdBoost', '51Degrees', + 'symitridap', // UserId Submodules 'justtag', 'tncId', diff --git a/src/ajax.js b/src/ajax.js index 1ef100e7fd3..7f9857ad18d 100644 --- a/src/ajax.js +++ b/src/ajax.js @@ -104,6 +104,7 @@ function toXHR({status, statusText = '', headers, url}, responseText) { return xml; } return { + // eslint-disable-next-line prebid/no-global readyState: XMLHttpRequest.DONE, status, statusText, @@ -147,5 +148,19 @@ export function ajaxBuilder(timeout = 3000, {request, done} = {}) { }; } +/** + * simple wrapper around sendBeacon such that invocations of navigator.sendBeacon can be centrally maintained. + * verifies that the navigator and sendBeacon are defined for maximum compatibility + * @param {string} url The URL that will receive the data. Can be relative or absolute. + * @param {*} data An ArrayBuffer, a TypedArray, a DataView, a Blob, a string literal or object, a FormData or a URLSearchParams object containing the data to send. + * @returns {boolean} true if the user agent successfully queued the data for transfer. Otherwise, it returns false. + */ +export function sendBeacon(url, data) { + if (!window.navigator || !window.navigator.sendBeacon) { + return false; + } + return window.navigator.sendBeacon(url, data); +} + export const ajax = ajaxBuilder(); export const fetch = fetcherFactory(); diff --git a/src/config.js b/src/config.js index 1fc9b4ea895..e9c37a8d329 100644 --- a/src/config.js +++ b/src/config.js @@ -38,8 +38,6 @@ const DEFAULT_DEVICE_ACCESS = true; const DEFAULT_MAX_NESTED_IFRAMES = 10; const DEFAULT_MAXBID_VALUE = 5000 -const DEFAULT_TIMEOUTBUFFER = 400; - const DEFAULT_IFRAMES_CONFIG = {}; export const RANDOM = 'random'; @@ -157,8 +155,6 @@ export function newConfig() { */ deviceAccess: DEFAULT_DEVICE_ACCESS, - // timeout buffer to adjust for bidder CDN latency - timeoutBuffer: DEFAULT_TIMEOUTBUFFER, disableAjaxTimeout: DEFAULT_DISABLE_AJAX_TIMEOUT, // default max nested iframes for referer detection diff --git a/src/constants.js b/src/constants.js index 4ca5f6a1b12..bb20f1b66b9 100644 --- a/src/constants.js +++ b/src/constants.js @@ -193,3 +193,5 @@ export const MESSAGES = { NATIVE: 'Prebid Native', EVENT: 'Prebid Event' }; + +export const PB_LOCATOR = '__pb_locator__'; diff --git a/src/debugging.js b/src/debugging.js index f5d13d1a134..045855ccb28 100644 --- a/src/debugging.js +++ b/src/debugging.js @@ -73,6 +73,7 @@ export const reset = ctl.reset; export function loadSession() { let storage = null; try { + // eslint-disable-next-line prebid/no-global storage = window.sessionStorage; } catch (e) {} diff --git a/src/prebid.js b/src/prebid.js index 4c09966482e..e91af3e4d04 100644 --- a/src/prebid.js +++ b/src/prebid.js @@ -39,7 +39,7 @@ import {newMetrics, useMetrics} from './utils/perfMetrics.js'; import {defer, GreedyPromise} from './utils/promise.js'; import {enrichFPD} from './fpd/enrichment.js'; import {allConsent} from './consentHandler.js'; -import {renderAdDirect} from './adRendering.js'; +import {insertLocatorFrame, renderAdDirect} from './adRendering.js'; import {getHighestCpm} from './utils/reducers.js'; import {fillVideoDefaults} from './video.js'; @@ -869,6 +869,10 @@ pbjsInstance.getHighestCpmBids = function (adUnitCode) { return targeting.getWinningBids(adUnitCode); }; +pbjsInstance.clearAllAuctions = function () { + auctionManager.clearAllAuctions(); +}; + if (FEATURES.VIDEO) { /** * Mark the winning bid as used, should only be used in conjunction with video @@ -976,6 +980,7 @@ function processQueue(queue) { * @alias module:pbjs.processQueue */ pbjsInstance.processQueue = function () { + insertLocatorFrame(); hook.ready(); processQueue(pbjsInstance.que); processQueue(pbjsInstance.cmd); diff --git a/src/secureCreatives.js b/src/secureCreatives.js index a33f742b738..9fa01c990c2 100644 --- a/src/secureCreatives.js +++ b/src/secureCreatives.js @@ -144,7 +144,7 @@ export function resizeRemoteCreative({adId, adUnitCode, width, height}) { elementStyle.width = getDimension(width) elementStyle.height = getDimension(height); } else { - logWarn(`Unable to locate matching page element for adUnitCode ${adUnitCode}. Can't resize it to ad's dimensions. Please review setup.`); + logError(`Unable to locate matching page element for adUnitCode ${adUnitCode}. Can't resize it to ad's dimensions. Please review setup.`); } }); diff --git a/src/storageManager.js b/src/storageManager.js index 87d714f77b8..493c44f056e 100644 --- a/src/storageManager.js +++ b/src/storageManager.js @@ -18,6 +18,8 @@ export const STORAGE_TYPE_COOKIES = 'cookie'; export let storageCallbacks = []; +/* eslint-disable prebid/no-global */ + /* * Storage manager constructor. Consumers should prefer one of `getStorageManager` or `getCoreStorageManager`. */ @@ -64,6 +66,7 @@ export function newStorageManager({moduleName, moduleType} = {}, {isAllowed = is const expiresPortion = (expires && expires !== '') ? ` ;expires=${expires}` : ''; const isNone = (sameSite != null && sameSite.toLowerCase() == 'none') const secure = (isNone) ? '; Secure' : ''; + // eslint-disable-next-line prebid/no-member document.cookie = `${key}=${encodeURIComponent(value)}${expiresPortion}; path=/${domainPortion}${sameSite ? `; SameSite=${sameSite}` : ''}${secure}`; } } @@ -85,27 +88,6 @@ export function newStorageManager({moduleName, moduleType} = {}, {isAllowed = is return schedule(cb, STORAGE_TYPE_COOKIES, done); }; - /** - * @returns {boolean} - */ - const localStorageIsEnabled = function (done) { - let cb = function (result) { - if (result && result.valid) { - try { - localStorage.setItem('prebid.cookieTest', '1'); - return localStorage.getItem('prebid.cookieTest') === '1'; - } catch (error) { - } finally { - try { - localStorage.removeItem('prebid.cookieTest'); - } catch (error) {} - } - } - return false; - } - return schedule(cb, STORAGE_TYPE_LOCALSTORAGE, done); - } - /** * @returns {boolean} */ @@ -119,60 +101,69 @@ export function newStorageManager({moduleName, moduleType} = {}, {isAllowed = is return schedule(cb, STORAGE_TYPE_COOKIES, done); } - /** - * @param {string} key - * @param {string} value - */ - const setDataInLocalStorage = function (key, value, done) { - let cb = function (result) { - if (result && result.valid && hasLocalStorage()) { - window.localStorage.setItem(key, value); - } - } - return schedule(cb, STORAGE_TYPE_LOCALSTORAGE, done); - } + function storageMethods(name) { + const capName = name.charAt(0).toUpperCase() + name.substring(1); + const backend = () => window[name]; - /** - * @param {string} key - * @returns {(string|null)} - */ - const getDataFromLocalStorage = function (key, done) { - let cb = function (result) { - if (result && result.valid && hasLocalStorage()) { - return window.localStorage.getItem(key); - } - return null; - } - return schedule(cb, STORAGE_TYPE_LOCALSTORAGE, done); - } - - /** - * @param {string} key - */ - const removeDataFromLocalStorage = function (key, done) { - let cb = function (result) { - if (result && result.valid && hasLocalStorage()) { - window.localStorage.removeItem(key); + const hasStorage = function (done) { + let cb = function (result) { + if (result && result.valid) { + try { + return !!backend(); + } catch (e) { + logError(`${name} api disabled`); + } + } + return false; } + return schedule(cb, STORAGE_TYPE_LOCALSTORAGE, done); } - return schedule(cb, STORAGE_TYPE_LOCALSTORAGE, done); - } - /** - * @returns {boolean} - */ - const hasLocalStorage = function (done) { - let cb = function (result) { - if (result && result.valid) { - try { - return !!window.localStorage; - } catch (e) { - logError('Local storage api disabled'); + return { + [`has${capName}`]: hasStorage, + [`${name}IsEnabled`](done) { + let cb = function (result) { + if (result && result.valid) { + try { + backend().setItem('prebid.cookieTest', '1'); + return backend().getItem('prebid.cookieTest') === '1'; + } catch (error) { + } finally { + try { + backend().removeItem('prebid.cookieTest'); + } catch (error) {} + } + } + return false; } + return schedule(cb, STORAGE_TYPE_LOCALSTORAGE, done); + }, + [`setDataIn${capName}`](key, value, done) { + let cb = function (result) { + if (result && result.valid && hasStorage()) { + backend().setItem(key, value); + } + } + return schedule(cb, STORAGE_TYPE_LOCALSTORAGE, done); + }, + [`getDataFrom${capName}`](key, done) { + let cb = function (result) { + if (result && result.valid && hasStorage()) { + return backend().getItem(key); + } + return null; + } + return schedule(cb, STORAGE_TYPE_LOCALSTORAGE, done); + }, + [`removeDataFrom${capName}`](key, done) { + let cb = function (result) { + if (result && result.valid && hasStorage()) { + backend().removeItem(key); + } + } + return schedule(cb, STORAGE_TYPE_LOCALSTORAGE, done); } - return false; } - return schedule(cb, STORAGE_TYPE_LOCALSTORAGE, done); } /** @@ -186,6 +177,7 @@ export function newStorageManager({moduleName, moduleType} = {}, {isAllowed = is if (result && result.valid) { const all = []; if (hasDeviceAccess()) { + // eslint-disable-next-line prebid/no-member const cookies = document.cookie.split(';'); while (cookies.length) { const cookie = cookies.pop(); @@ -207,12 +199,9 @@ export function newStorageManager({moduleName, moduleType} = {}, {isAllowed = is return { setCookie, getCookie, - localStorageIsEnabled, cookiesAreEnabled, - setDataInLocalStorage, - getDataFromLocalStorage, - removeDataFromLocalStorage, - hasLocalStorage, + ...storageMethods('localStorage'), + ...storageMethods('sessionStorage'), findSimilarCookies } } diff --git a/src/targeting.js b/src/targeting.js index 0c4874fc50b..9a2ea5d66fa 100644 --- a/src/targeting.js +++ b/src/targeting.js @@ -1,3 +1,21 @@ +import { auctionManager } from './auctionManager.js'; +import { getTTL } from './bidTTL.js'; +import { bidderSettings } from './bidderSettings.js'; +import { config } from './config.js'; +import { + BID_STATUS, + DEFAULT_TARGETING_KEYS, + EVENTS, + JSON_MAPPING, + NATIVE_KEYS, + STATUS, + TARGETING_KEYS +} from './constants.js'; +import * as events from './events.js'; +import { hook } from './hook.js'; +import { ADPOD } from './mediaTypes.js'; +import { NATIVE_TARGETING_KEYS } from './native.js'; +import { find, includes } from './polyfill.js'; import { deepAccess, deepClone, @@ -14,25 +32,7 @@ import { timestamp, uniques, } from './utils.js'; -import {config} from './config.js'; -import {NATIVE_TARGETING_KEYS} from './native.js'; -import {auctionManager} from './auctionManager.js'; -import {ADPOD} from './mediaTypes.js'; -import {hook} from './hook.js'; -import {bidderSettings} from './bidderSettings.js'; -import {find, includes} from './polyfill.js'; -import { - BID_STATUS, - DEFAULT_TARGETING_KEYS, - EVENTS, - JSON_MAPPING, - NATIVE_KEYS, - STATUS, - TARGETING_KEYS -} from './constants.js'; -import {getHighestCpm, getOldestHighestCpmBid} from './utils/reducers.js'; -import {getTTL} from './bidTTL.js'; -import * as events from './events.js'; +import { getHighestCpm, getOldestHighestCpmBid } from './utils/reducers.js'; var pbTargetingKeys = []; @@ -139,7 +139,7 @@ export function sortByDealAndPriceBucketOrCpm(useCpm = false) { * @param {Array} adUnitCodes * @param customSlotMatching * @param getSlots - * @return {{[p: string]: any}} + * @return {Object.} */ export function getGPTSlotsForAdUnits(adUnitCodes, customSlotMatching, getSlots = () => window.googletag.pubads().getSlots()) { return getSlots().reduce((auToSlots, slot) => { @@ -461,10 +461,16 @@ export function newTargeting(auctionManager) { }); }); + targeting.targetingDone(targetingSet); + // emit event events.emit(EVENTS.SET_TARGETING, targetingSet); }, 'setTargetingForGPT'); + targeting.targetingDone = hook('sync', function (targetingSet) { + return targetingSet; + }, 'targetingDone'); + /** * normlizes input to a `adUnit.code` array * @param {(string|string[])} adUnitCode [description] diff --git a/src/utils.js b/src/utils.js index 35596cb6442..ec227c6d74b 100644 --- a/src/utils.js +++ b/src/utils.js @@ -4,8 +4,9 @@ import {includes} from './polyfill.js'; import { EVENTS, S2S } from './constants.js'; import {GreedyPromise} from './utils/promise.js'; import {getGlobal} from './prebidGlobal.js'; +import { default as deepAccess } from 'dlv/index.js'; -export { default as deepAccess } from 'dlv/index.js'; +export { deepAccess }; export { dset as deepSetValue } from 'dset'; var tStr = 'String'; @@ -747,6 +748,7 @@ export function hasDeviceAccess() { * @returns {(boolean|undefined)} */ export function checkCookieSupport() { + // eslint-disable-next-line prebid/no-member if (window.navigator.cookieEnabled || !!document.cookie.length) { return true; } @@ -1108,6 +1110,14 @@ export function safeJSONParse(data) { } catch (e) {} } +export function safeJSONEncode(data) { + try { + return JSON.stringify(data); + } catch (e) { + return ''; + } +} + /** * Returns a memoized version of `fn`. * @@ -1231,3 +1241,20 @@ export function hasNonSerializableProperty(obj, checkedObjects = new Set()) { } return false; } + +/** + * Returns the value of a nested property in an array of objects. + * + * @param {Array} collection - Array of objects. + * @param {String} key - Key of nested property. + * @returns {any, undefined} - Value of nested property. + */ +export function setOnAny(collection, key) { + for (let i = 0, result; i < collection.length; i++) { + result = deepAccess(collection[i], key); + if (result) { + return result; + } + } + return undefined; +} diff --git a/src/utils/gpdr.js b/src/utils/gdpr.js similarity index 100% rename from src/utils/gpdr.js rename to src/utils/gdpr.js diff --git a/test/pages/banner_sync.html b/test/pages/banner_sync.html new file mode 100644 index 00000000000..71403ba5570 --- /dev/null +++ b/test/pages/banner_sync.html @@ -0,0 +1,97 @@ + + + + + + + Prebid.js Banner Example + + + + + + + + + + + + + + + +

Prebid.js Banner Ad Unit Test

+
+ +
+
+ + + diff --git a/test/pages/consent_mgt_gdpr.html b/test/pages/consent_mgt_gdpr.html index c55a2b9236f..6ff24938bf3 100644 --- a/test/pages/consent_mgt_gdpr.html +++ b/test/pages/consent_mgt_gdpr.html @@ -1,6 +1,6 @@ - + ' @@ -1832,38 +1867,6 @@ describe('AppNexusAdapter', function () { expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0])); }); - it('should parse non-default currency', function () { - let eurCpmResponse = deepClone(response); - eurCpmResponse.tags[0].ads[0].publisher_currency_codename = 'EUR'; - - let bidderRequest = { - bidderCode: 'appnexus', - bids: [{ - bidId: '3db3773286ee59', - adUnitCode: 'code' - }] - }; - - let result = spec.interpretResponse({ body: eurCpmResponse }, { bidderRequest }); - expect(result[0].currency).to.equal('EUR'); - }); - - it('should parse default currency', function () { - let defaultCpmResponse = deepClone(response); - delete defaultCpmResponse.tags[0].ads[0].publisher_currency_codename; - - let bidderRequest = { - bidderCode: 'appnexus', - bids: [{ - bidId: '3db3773286ee59', - adUnitCode: 'code' - }] - }; - - let result = spec.interpretResponse({ body: defaultCpmResponse }, { bidderRequest }); - expect(result[0].currency).to.equal('USD'); - }); - it('should reject 0 cpm bids', function () { let zeroCpmResponse = deepClone(response); zeroCpmResponse.tags[0].ads[0].cpm = 0; diff --git a/test/spec/modules/azerionedgeRtdProvider_spec.js b/test/spec/modules/azerionedgeRtdProvider_spec.js index f08aaebdf55..0eef82a2512 100644 --- a/test/spec/modules/azerionedgeRtdProvider_spec.js +++ b/test/spec/modules/azerionedgeRtdProvider_spec.js @@ -8,11 +8,17 @@ describe('Azerion Edge RTD submodule', function () { { id: '1', visits: 123 }, { id: '2', visits: 456 }, ]; - + const IMPROVEDIGITAL_GVLID = '253'; const key = 'publisher123'; const bidders = ['appnexus', 'improvedigital']; const process = { key: 'value' }; const dataProvider = { name: 'azerionedge', waitForIt: true }; + const userConsent = {gdpr: {gdprApplies: 'gdpr-applies', consentString: 'consent-string'}, usp: 'usp'}; + + const resetAll = () => { + window.azerionPublisherAudiences.resetHistory(); + loadExternalScript.resetHistory(); + } let reqBidsConfigObj; let storageStub; @@ -33,7 +39,11 @@ describe('Azerion Edge RTD submodule', function () { let returned; beforeEach(function () { - returned = azerionedgeRTD.azerionedgeSubmodule.init(dataProvider); + returned = azerionedgeRTD.azerionedgeSubmodule.init(dataProvider, userConsent); + }); + + it('should have the correct gvlid', () => { + expect(azerionedgeRTD.azerionedgeSubmodule.gvlid).to.equal(IMPROVEDIGITAL_GVLID); }); it('should return true', function () { @@ -49,18 +59,21 @@ describe('Azerion Edge RTD submodule', function () { expect(loadExternalScript.args[0][0]).to.deep.equal(expected); }); - it('should call azerionPublisherAudiencesStub with empty configuration', function () { - expect(window.azerionPublisherAudiences.args[0][0]).to.deep.equal({}); + [ + ['gdprApplies', userConsent.gdpr.gdprApplies], + ['gdprConsent', userConsent.gdpr.consentString], + ['uspConsent', userConsent.usp], + ].forEach(([key, value]) => { + it(`should call azerionPublisherAudiencesStub with ${key}:${value}`, function () { + expect(window.azerionPublisherAudiences.args[0][0]).to.include({[key]: value}); + }); }); describe('with key', function () { beforeEach(function () { - window.azerionPublisherAudiences.resetHistory(); - loadExternalScript.resetHistory(); - returned = azerionedgeRTD.azerionedgeSubmodule.init({ - ...dataProvider, - params: { key }, - }); + resetAll(); + const config = { ...dataProvider, params: { key } }; + returned = azerionedgeRTD.azerionedgeSubmodule.init(config, userConsent); }); it('should return true', function () { @@ -75,22 +88,24 @@ describe('Azerion Edge RTD submodule', function () { describe('with process configuration', function () { beforeEach(function () { - window.azerionPublisherAudiences.resetHistory(); - loadExternalScript.resetHistory(); - returned = azerionedgeRTD.azerionedgeSubmodule.init({ - ...dataProvider, - params: { process }, - }); + resetAll(); + const config = { ...dataProvider, params: { process } }; + returned = azerionedgeRTD.azerionedgeSubmodule.init(config, userConsent); }); it('should return true', function () { expect(returned).to.equal(true); }); - it('should call azerionPublisherAudiencesStub with process configuration', function () { - expect(window.azerionPublisherAudiences.args[0][0]).to.deep.equal( - process - ); + [ + ['gdprApplies', userConsent.gdpr.gdprApplies], + ['gdprConsent', userConsent.gdpr.consentString], + ['uspConsent', userConsent.usp], + ...Object.entries(process), + ].forEach(([key, value]) => { + it(`should call azerionPublisherAudiencesStub with ${key}:${value}`, function () { + expect(window.azerionPublisherAudiences.args[0][0]).to.include({[key]: value}); + }); }); }); }); @@ -111,7 +126,7 @@ describe('Azerion Edge RTD submodule', function () { ); }); - it('does not run apply audiences to bidders', function () { + it('does not apply audiences to bidders', function () { expect(reqBidsConfigObj.ortb2Fragments.bidder).to.deep.equal({}); }); diff --git a/test/spec/modules/cleanmedianetBidAdapter_spec.js b/test/spec/modules/cleanmedianetBidAdapter_spec.js index d1ec37c4999..58270438772 100644 --- a/test/spec/modules/cleanmedianetBidAdapter_spec.js +++ b/test/spec/modules/cleanmedianetBidAdapter_spec.js @@ -395,7 +395,7 @@ describe('CleanmedianetAdapter', () => { expect(response.data.imp[0].video.mimes).to.equal(bidRequestWithVideo.mediaTypes.video.mimes); expect(response.data.imp[0].video.skip).to.not.exist; - expect(response.data.imp[0].video.placement).to.equal(1); + expect(response.data.imp[0].video.plcmt).to.equal(1); expect(response.data.imp[0].video.minduration).to.equal(1); expect(response.data.imp[0].video.playbackmethod).to.equal(1); expect(response.data.imp[0].video.startdelay).to.equal(1); diff --git a/test/spec/modules/connatixBidAdapter_spec.js b/test/spec/modules/connatixBidAdapter_spec.js index 4d816c4e816..1bf04ed9db8 100644 --- a/test/spec/modules/connatixBidAdapter_spec.js +++ b/test/spec/modules/connatixBidAdapter_spec.js @@ -3,7 +3,7 @@ import { spec, getBidFloor as connatixGetBidFloor } from '../../../modules/connatixBidAdapter.js'; -import { BANNER } from '../../../src/mediaTypes.js'; +import { ADPOD, BANNER, VIDEO } from '../../../src/mediaTypes.js'; describe('connatixBidAdapter', function () { let bid; @@ -24,6 +24,26 @@ describe('connatixBidAdapter', function () { }; }; + function addVideoToBidMock(bid) { + const mediaTypes = { + video: { + context: 'instream', + w: 1280, + h: 720, + playerSize: [1280, 720], + placement: 1, + plcmt: 1, + api: [1, 2], + mimes: ['video/mp4', 'application/javascript'], + minduration: 30, + maxduration: 60, + startdelay: 0, + } + } + + bid.mediaTypes = mediaTypes; + } + describe('isBidRequestValid', function () { this.beforeEach(function () { bid = mockBidRequest(); @@ -52,7 +72,7 @@ describe('connatixBidAdapter', function () { delete bid.mediaTypes; expect(spec.isBidRequestValid(bid)).to.be.false; }); - it('Should return false if banner is missing from mediaTypes ', function () { + it('Should return false if both banner and video are missing from mediaTypes', function () { delete bid.mediaTypes.banner; expect(spec.isBidRequestValid(bid)).to.be.false; }); @@ -68,6 +88,15 @@ describe('connatixBidAdapter', function () { bid.mediaTypes.banner.sizes = []; expect(spec.isBidRequestValid(bid)).to.be.false; }); + it('Should return true if video is set correctly', function () { + addVideoToBidMock(bid); + expect(spec.isBidRequestValid(bid)).to.be.true; + }); + it('Should return false if context is set to adpod on video media type', function() { + addVideoToBidMock(bid); + bid.mediaTypes.video.context = ADPOD; + expect(spec.isBidRequestValid(bid)).to.be.false; + }); it('Should return true if add an extra field was added to the bidRequest', function () { bid.params.test = 1; expect(spec.isBidRequestValid(bid)).to.be.true; @@ -197,6 +226,30 @@ describe('connatixBidAdapter', function () { expect(bidResponses[0].cpm).to.equal(firstBidCpm); expect(bidResponses[1].cpm).to.equal(secondBidCpm); }); + + it('Should contain specific values for banner bids', function () { + const adHtml = 'ad html' + serverResponse.body.Bids = [ { ...Bid, Ad: adHtml } ]; + + const bidResponses = spec.interpretResponse(serverResponse); + const [ bidResponse ] = bidResponses; + + expect(bidResponse.vastXml).to.be.undefined; + expect(bidResponse.ad).to.equal(adHtml); + expect(bidResponse.mediaType).to.equal(BANNER); + }); + + it('Should contain specific values for video bids', function () { + const adVastXml = 'ad vast xml' + serverResponse.body.Bids = [ { ...Bid, VastXml: adVastXml } ]; + + const bidResponses = spec.interpretResponse(serverResponse); + const [ bidResponse ] = bidResponses; + + expect(bidResponse.ad).to.be.undefined; + expect(bidResponse.vastXml).to.equal(adVastXml); + expect(bidResponse.mediaType).to.equal(VIDEO); + }); }); describe('getUserSyncs', function() { diff --git a/test/spec/modules/connectIdSystem_spec.js b/test/spec/modules/connectIdSystem_spec.js index 686c3d63a63..3009ecef769 100644 --- a/test/spec/modules/connectIdSystem_spec.js +++ b/test/spec/modules/connectIdSystem_spec.js @@ -549,24 +549,28 @@ describe('Yahoo ConnectID Submodule', () => { expect(result.callback).to.be.a('function'); }); + function mockOptout(value) { + getLocalStorageStub.callsFake((key) => { + if (key === 'connectIdOptOut') return value; + }) + } + it('returns an undefined if the Yahoo specific opt-out key is present in local storage', () => { - localStorage.setItem('connectIdOptOut', '1'); + mockOptout('1'); expect(invokeGetIdAPI({ he: HASHED_EMAIL, pixelId: PIXEL_ID }, consentData)).to.be.undefined; - localStorage.removeItem('connectIdOptOut'); }); it('returns an object with the callback function if the correct params are passed and Yahoo opt-out value is not "1"', () => { - localStorage.setItem('connectIdOptOut', 'true'); + mockOptout('true'); let result = invokeGetIdAPI({ he: HASHED_EMAIL, pixelId: PIXEL_ID }, consentData); expect(result).to.be.an('object').that.has.all.keys('callback'); expect(result.callback).to.be.a('function'); - localStorage.removeItem('connectIdOptOut'); }); it('Makes an ajax GET request to the production API endpoint with pixelId and he query params', () => { @@ -804,6 +808,25 @@ describe('Yahoo ConnectID Submodule', () => { }); }); }); + describe('userHasOptedOut()', () => { + it('should return a function', () => { + expect(connectIdSubmodule.userHasOptedOut).to.be.a('function'); + }); + + it('should return false when local storage key has not been set function', () => { + expect(connectIdSubmodule.userHasOptedOut()).to.be.false; + }); + + it('should return true when local storage key has been set to "1"', () => { + getLocalStorageStub.returns('1'); + expect(connectIdSubmodule.userHasOptedOut()).to.be.true; + }); + + it('should return false when local storage key has not been set to "1"', () => { + getLocalStorageStub.returns('hello'); + expect(connectIdSubmodule.userHasOptedOut()).to.be.false; + }); + }); }); describe('decode()', () => { @@ -884,28 +907,4 @@ describe('Yahoo ConnectID Submodule', () => { })).to.be.true; }); }); - - describe('userHasOptedOut()', () => { - afterEach(() => { - localStorage.removeItem('connectIdOptOut'); - }); - - it('should return a function', () => { - expect(connectIdSubmodule.userHasOptedOut).to.be.a('function'); - }); - - it('should return false when local storage key has not been set function', () => { - expect(connectIdSubmodule.userHasOptedOut()).to.be.false; - }); - - it('should return true when local storage key has been set to "1"', () => { - localStorage.setItem('connectIdOptOut', '1'); - expect(connectIdSubmodule.userHasOptedOut()).to.be.true; - }); - - it('should return false when local storage key has not been set to "1"', () => { - localStorage.setItem('connectIdOptOut', 'hello'); - expect(connectIdSubmodule.userHasOptedOut()).to.be.false; - }); - }); }); diff --git a/test/spec/modules/consentManagement_spec.js b/test/spec/modules/consentManagement_spec.js index 73db5600ba6..9131e6748e8 100644 --- a/test/spec/modules/consentManagement_spec.js +++ b/test/spec/modules/consentManagement_spec.js @@ -284,7 +284,7 @@ describe('consentManagement', function () { expect(consent).to.be.null; }); - it('should call gpdrDataHandler.setConsentData() when unknown CMP api is used', () => { + it('should call gdprDataHandler.setConsentData() when unknown CMP api is used', () => { setConsentConfig({gdpr: {cmpApi: 'invalid'}}); let hookRan = false; requestBidsHook(() => { hookRan = true; }, {}); diff --git a/test/spec/modules/contxtfulRtdProvider_spec.js b/test/spec/modules/contxtfulRtdProvider_spec.js index 01e7a242d19..5dda23caafc 100644 --- a/test/spec/modules/contxtfulRtdProvider_spec.js +++ b/test/spec/modules/contxtfulRtdProvider_spec.js @@ -322,6 +322,8 @@ describe('contxtfulRtdProvider', function () { ]; theories.forEach(([adUnits, expected, _description]) => { + // TODO: commented out because of rule violations + /* it('uses non-expired info from session storage and adds receptivity to the ad units using session storage', function (done) { let config = buildInitConfig(VERSION, CUSTOMER); // Simulate that there was a write to sessionStorage in the past. @@ -335,6 +337,7 @@ describe('contxtfulRtdProvider', function () { done(); }, TIMEOUT); }); + */ }); }); @@ -453,6 +456,8 @@ describe('contxtfulRtdProvider', function () { }); describe('getBidRequestData', function () { + // TODO: commented out because of rule violations + /* it('uses non-expired info from session storage and adds receptivity to the reqBidsConfigObj', function (done) { let config = buildInitConfig(VERSION, CUSTOMER); // Simulate that there was a write to sessionStorage in the past. @@ -493,6 +498,7 @@ describe('contxtfulRtdProvider', function () { done(); }, TIMEOUT); }); + */ }); describe('getBidRequestData', function () { diff --git a/test/spec/modules/cpmstarBidAdapter_spec.js b/test/spec/modules/cpmstarBidAdapter_spec.js index 285fca9690a..f9b1ba59cde 100755 --- a/test/spec/modules/cpmstarBidAdapter_spec.js +++ b/test/spec/modules/cpmstarBidAdapter_spec.js @@ -149,7 +149,7 @@ describe('Cpmstar Bid Adapter', function () { }; var requests = spec.buildRequests(reqs, bidderRequest); expect(requests[0]).to.have.property('url'); - expect(requests[0].url).to.include('&schain=1.0,1!exchange1.com,1234,1,,,!exchange2.com,abcd,1,,,'); + expect(requests[0].url).to.include('&schain=1.0%2C1%21exchange1.com%2C1234%2C1%2C%2C%2C%21exchange2.com%2Cabcd%2C1%2C%2C%2C'); }); describe('interpretResponse', function () { diff --git a/test/spec/modules/dailymotionBidAdapter_spec.js b/test/spec/modules/dailymotionBidAdapter_spec.js index 4f8862982ad..dd8f3fa5630 100644 --- a/test/spec/modules/dailymotionBidAdapter_spec.js +++ b/test/spec/modules/dailymotionBidAdapter_spec.js @@ -165,6 +165,7 @@ describe('dailymotionBidAdapterTests', () => { const { data: reqData } = request; + expect(request.options.withCredentials).to.eql(false); expect(request.url).to.equal('https://pb.dmxleo.com'); expect(reqData.pbv).to.eql('$prebid.version$'); @@ -178,7 +179,6 @@ describe('dailymotionBidAdapterTests', () => { expect(reqData.coppa).to.be.true; expect(reqData.request.auctionId).to.eql(bidRequestData[0].auctionId); expect(reqData.request.bidId).to.eql(bidRequestData[0].bidId); - expect(reqData.request.mediaTypes.video).to.eql(bidRequestData[0].mediaTypes.video); expect(reqData.video_metadata).to.eql({ description: bidRequestData[0].params.video.description, @@ -204,6 +204,499 @@ describe('dailymotionBidAdapterTests', () => { }); }); + it('validates buildRequests with global consent', () => { + const bidRequestData = [{ + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: 123456, + adUnitCode: 'preroll', + mediaTypes: { + video: { + api: [2, 7], + mimes: ['video/mp4'], + minduration: 5, + maxduration: 30, + playbackmethod: [3], + plcmt: 1, + protocols: [1, 2, 3, 4, 5, 6, 7, 8], + skip: 1, + skipafter: 5, + skipmin: 10, + startdelay: 0, + w: 1280, + h: 720, + }, + }, + sizes: [[1920, 1080]], + params: { + apiKey: 'test_api_key', + video: { + description: 'this is a test video', + duration: 556, + iabcat1: ['IAB-1'], + iabcat2: ['6', '17'], + id: '54321', + lang: 'FR', + private: false, + tags: 'tag_1,tag_2,tag_3', + title: 'test video', + url: 'https://test.com/test', + topics: 'topic_1, topic_2', + xid: 'x123456', + livestream: 1, + isCreatedForKids: true, + videoViewsInSession: 2, + autoplay: true, + playerVolume: 8, + }, + }, + }]; + + const bidderRequestData = { + refererInfo: { + page: 'https://publisher.com', + }, + uspConsent: '1YN-', + gdprConsent: { + apiVersion: 2, + consentString: 'xxx', + gdprApplies: true, + vendorData: { + hasGlobalConsent: true + } + }, + gppConsent: { + gppString: 'xxx', + applicableSections: [5], + }, + ortb2: { + regs: { + coppa: 1, + }, + site: { + content: { + data: [ + { + name: 'dataprovider.com', + ext: { segtax: 5 }, + segment: [{ id: '200' }], + }, + ], + }, + }, + }, + }; + + const [request] = config.runWithBidder( + 'dailymotion', + () => spec.buildRequests(bidRequestData, bidderRequestData), + ); + + expect(request.options.withCredentials).to.eql(true); + }); + + it('validates buildRequests without gdpr applying', () => { + const bidRequestData = [{ + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: 123456, + adUnitCode: 'preroll', + mediaTypes: { + video: { + api: [2, 7], + mimes: ['video/mp4'], + minduration: 5, + maxduration: 30, + playbackmethod: [3], + plcmt: 1, + protocols: [1, 2, 3, 4, 5, 6, 7, 8], + skip: 1, + skipafter: 5, + skipmin: 10, + startdelay: 0, + w: 1280, + h: 720, + }, + }, + sizes: [[1920, 1080]], + params: { + apiKey: 'test_api_key', + video: { + description: 'this is a test video', + duration: 556, + iabcat1: ['IAB-1'], + iabcat2: ['6', '17'], + id: '54321', + lang: 'FR', + private: false, + tags: 'tag_1,tag_2,tag_3', + title: 'test video', + url: 'https://test.com/test', + topics: 'topic_1, topic_2', + xid: 'x123456', + livestream: 1, + isCreatedForKids: true, + videoViewsInSession: 2, + autoplay: true, + playerVolume: 8, + }, + }, + }]; + + const bidderRequestData = { + refererInfo: { + page: 'https://publisher.com', + }, + uspConsent: '1YN-', + gdprConsent: { + apiVersion: 2, + consentString: 'xxx', + gdprApplies: false, + }, + gppConsent: { + gppString: 'xxx', + applicableSections: [5], + }, + ortb2: { + regs: { + coppa: 1, + }, + site: { + content: { + data: [ + { + name: 'dataprovider.com', + ext: { segtax: 5 }, + segment: [{ id: '200' }], + }, + ], + }, + }, + }, + }; + + const [request] = config.runWithBidder( + 'dailymotion', + () => spec.buildRequests(bidRequestData, bidderRequestData), + ); + + expect(request.options.withCredentials).to.eql(true); + }); + + it('validates buildRequests with detailed consent, no legitimate interest', () => { + const bidRequestData = [{ + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: 123456, + adUnitCode: 'preroll', + mediaTypes: { + video: { + api: [2, 7], + mimes: ['video/mp4'], + minduration: 5, + maxduration: 30, + playbackmethod: [3], + plcmt: 1, + protocols: [1, 2, 3, 4, 5, 6, 7, 8], + skip: 1, + skipafter: 5, + skipmin: 10, + startdelay: 0, + w: 1280, + h: 720, + }, + }, + sizes: [[1920, 1080]], + params: { + apiKey: 'test_api_key', + video: { + description: 'this is a test video', + duration: 556, + iabcat1: ['IAB-1'], + iabcat2: ['6', '17'], + id: '54321', + lang: 'FR', + private: false, + tags: 'tag_1,tag_2,tag_3', + title: 'test video', + url: 'https://test.com/test', + topics: 'topic_1, topic_2', + xid: 'x123456', + livestream: 1, + isCreatedForKids: true, + videoViewsInSession: 2, + autoplay: true, + playerVolume: 8, + }, + }, + }]; + + const bidderRequestData = { + refererInfo: { + page: 'https://publisher.com', + }, + uspConsent: '1YN-', + gdprConsent: { + apiVersion: 2, + consentString: 'xxx', + gdprApplies: true, + vendorData: { + hasGlobalConsent: false, + purpose: { + consents: { + 1: true, + 2: true, + 3: true, + 4: true, + 7: true, + 9: true, + 10: true, + }, + }, + vendor: { + consents: { + 573: true + } + }, + }, + }, + gppConsent: { + gppString: 'xxx', + applicableSections: [5], + }, + ortb2: { + regs: { + coppa: 1, + }, + site: { + content: { + data: [ + { + name: 'dataprovider.com', + ext: { segtax: 5 }, + segment: [{ id: '200' }], + }, + ], + }, + }, + }, + }; + + const [request] = config.runWithBidder( + 'dailymotion', + () => spec.buildRequests(bidRequestData, bidderRequestData), + ); + + expect(request.options.withCredentials).to.eql(true); + }); + + it('validates buildRequests with detailed consent, with legitimate interest', () => { + const bidRequestData = [{ + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: 123456, + adUnitCode: 'preroll', + mediaTypes: { + video: { + api: [2, 7], + mimes: ['video/mp4'], + minduration: 5, + maxduration: 30, + playbackmethod: [3], + plcmt: 1, + protocols: [1, 2, 3, 4, 5, 6, 7, 8], + skip: 1, + skipafter: 5, + skipmin: 10, + startdelay: 0, + w: 1280, + h: 720, + }, + }, + sizes: [[1920, 1080]], + params: { + apiKey: 'test_api_key', + video: { + description: 'this is a test video', + duration: 556, + iabcat1: ['IAB-1'], + iabcat2: ['6', '17'], + id: '54321', + lang: 'FR', + private: false, + tags: 'tag_1,tag_2,tag_3', + title: 'test video', + url: 'https://test.com/test', + topics: 'topic_1, topic_2', + xid: 'x123456', + livestream: 1, + isCreatedForKids: true, + videoViewsInSession: 2, + autoplay: true, + playerVolume: 8, + }, + }, + }]; + + const bidderRequestData = { + refererInfo: { + page: 'https://publisher.com', + }, + uspConsent: '1YN-', + gdprConsent: { + apiVersion: 2, + consentString: 'xxx', + gdprApplies: true, + vendorData: { + hasGlobalConsent: false, + purpose: { + consents: { + 1: true, + 3: true, + 4: true, + }, + legitimateInterests: { + 2: true, + 7: true, + 9: true, + 10: true, + }, + }, + vendor: { + consents: { + 573: true + } + }, + }, + }, + gppConsent: { + gppString: 'xxx', + applicableSections: [5], + }, + ortb2: { + regs: { + coppa: 1, + }, + site: { + content: { + data: [ + { + name: 'dataprovider.com', + ext: { segtax: 5 }, + segment: [{ id: '200' }], + }, + ], + }, + }, + }, + }; + + const [request] = config.runWithBidder( + 'dailymotion', + () => spec.buildRequests(bidRequestData, bidderRequestData), + ); + + expect(request.options.withCredentials).to.eql(true); + }); + + it('validates buildRequests with insufficient consent', () => { + const bidRequestData = [{ + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: 123456, + adUnitCode: 'preroll', + mediaTypes: { + video: { + api: [2, 7], + mimes: ['video/mp4'], + minduration: 5, + maxduration: 30, + playbackmethod: [3], + plcmt: 1, + protocols: [1, 2, 3, 4, 5, 6, 7, 8], + skip: 1, + skipafter: 5, + skipmin: 10, + startdelay: 0, + w: 1280, + h: 720, + }, + }, + sizes: [[1920, 1080]], + params: { + apiKey: 'test_api_key', + video: { + description: 'this is a test video', + duration: 556, + iabcat1: ['IAB-1'], + iabcat2: ['6', '17'], + id: '54321', + lang: 'FR', + private: false, + tags: 'tag_1,tag_2,tag_3', + title: 'test video', + url: 'https://test.com/test', + topics: 'topic_1, topic_2', + xid: 'x123456', + livestream: 1, + isCreatedForKids: true, + videoViewsInSession: 2, + autoplay: true, + playerVolume: 8, + }, + }, + }]; + + const bidderRequestData = { + refererInfo: { + page: 'https://publisher.com', + }, + uspConsent: '1YN-', + gdprConsent: { + apiVersion: 2, + consentString: 'xxx', + gdprApplies: true, + vendorData: { + hasGlobalConsent: false, + purpose: { + consents: { + 1: true, + 3: true, + 4: true, + }, + }, + vendor: { + consents: { + 573: true + } + }, + }, + }, + gppConsent: { + gppString: 'xxx', + applicableSections: [5], + }, + ortb2: { + regs: { + coppa: 1, + }, + site: { + content: { + data: [ + { + name: 'dataprovider.com', + ext: { segtax: 5 }, + segment: [{ id: '200' }], + }, + ], + }, + }, + }, + }; + + const [request] = config.runWithBidder( + 'dailymotion', + () => spec.buildRequests(bidRequestData, bidderRequestData), + ); + + expect(request.options.withCredentials).to.eql(false); + }); + it('validates buildRequests with content values from App', () => { const bidRequestData = [{ auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', @@ -479,7 +972,7 @@ describe('dailymotionBidAdapterTests', () => { minduration: 0, maxduration: 0, playbackmethod: [], - plcmt: 1, + plcmt: undefined, protocols: [], skip: 0, skipafter: 0, @@ -559,12 +1052,12 @@ describe('dailymotionBidAdapterTests', () => { minduration: 0, maxduration: 0, playbackmethod: [], - plcmt: 1, + plcmt: undefined, protocols: [], skip: 0, skipafter: 0, skipmin: 0, - startdelay: 0, + startdelay: undefined, w: 0, h: 0, }, @@ -647,7 +1140,7 @@ describe('dailymotionBidAdapterTests', () => { // No permissions { - const responses = [{ user_syncs: [{ url: 'https://usersyncurl.com', type: 'image' }] }]; + const responses = [{ body: { userSyncs: [{ url: 'https://usersyncurl.com', type: 'image' }] } }]; const syncOptions = { iframeEnabled: false, pixelEnabled: false }; expect(config.runWithBidder( @@ -656,7 +1149,7 @@ describe('dailymotionBidAdapterTests', () => { )).to.eql([]); } - // Has permissions but no user_syncs urls + // Has permissions but no userSyncs urls { const responses = [{}]; const syncOptions = { iframeEnabled: false, pixelEnabled: true }; @@ -667,14 +1160,16 @@ describe('dailymotionBidAdapterTests', () => { )).to.eql([]); } - // Return user_syncs urls for pixels + // Return userSyncs urls for pixels { const responses = [{ - user_syncs: [ - { url: 'https://usersyncurl.com', type: 'image' }, - { url: 'https://usersyncurl2.com', type: 'image' }, - { url: 'https://usersyncurl3.com', type: 'iframe' } - ], + body: { + userSyncs: [ + { url: 'https://usersyncurl.com', type: 'image' }, + { url: 'https://usersyncurl2.com', type: 'image' }, + { url: 'https://usersyncurl3.com', type: 'iframe' } + ], + } }]; const syncOptions = { iframeEnabled: false, pixelEnabled: true }; @@ -688,14 +1183,16 @@ describe('dailymotionBidAdapterTests', () => { ]); } - // Return user_syncs urls for iframes + // Return userSyncs urls for iframes { const responses = [{ - user_syncs: [ - { url: 'https://usersyncurl.com', type: 'image' }, - { url: 'https://usersyncurl2.com', type: 'image' }, - { url: 'https://usersyncurl3.com', type: 'iframe' } - ], + body: { + userSyncs: [ + { url: 'https://usersyncurl.com', type: 'image' }, + { url: 'https://usersyncurl2.com', type: 'image' }, + { url: 'https://usersyncurl3.com', type: 'iframe' } + ], + } }]; const syncOptions = { iframeEnabled: true, pixelEnabled: true }; diff --git a/test/spec/modules/discoveryBidAdapter_spec.js b/test/spec/modules/discoveryBidAdapter_spec.js index a3a252880c1..ffb733a2cb2 100644 --- a/test/spec/modules/discoveryBidAdapter_spec.js +++ b/test/spec/modules/discoveryBidAdapter_spec.js @@ -3,15 +3,12 @@ import { spec, getPmgUID, storage, - getPageTitle, - getPageDescription, - getPageKeywords, - getConnectionDownLink, THIRD_PARTY_COOKIE_ORIGIN, COOKIE_KEY_MGUID, - getCurrentTimeToUTCString, + getCookieTimeToUTCString, buildUTMTagData, } from 'modules/discoveryBidAdapter.js'; +import { getPageTitle, getPageDescription, getPageKeywords, getConnectionDownLink } from '../../../libraries/fpdUtils/pageInfo.js'; import * as utils from 'src/utils.js'; import { getHLen, getHC, getDM } from '../../../src/fpd/navigator.js'; @@ -22,6 +19,7 @@ describe('discovery:BidAdapterTests', function () { sandbox = sinon.sandbox.create(); sandbox.stub(storage, 'getCookie'); sandbox.stub(storage, 'setCookie'); + sandbox.stub(storage, 'getDataFromLocalStorage'); sandbox.stub(utils, 'generateUUID').returns('new-uuid'); sandbox.stub(utils, 'parseUrl').returns({ search: { @@ -258,6 +256,11 @@ describe('discovery:BidAdapterTests', function () { getPmgUID(); expect(storage.setCookie.calledOnce).to.be.false; }); + it('should return other ID from storage and cookie', () => { + spec.buildRequests(bidRequestData.bids, bidRequestData); + expect(storage.getCookie.called).to.be.true; + expect(storage.getDataFromLocalStorage.called).to.be.true; + }); }) describe('buildUTMTagData function', function() { it('should set UTM cookie', () => { @@ -591,7 +594,7 @@ describe('discovery Bid Adapter Tests', function () { const response = event.data; if (!response.optout && response.mguid) { - storage.setCookie(COOKIE_KEY_MGUID, response.mguid, getCurrentTimeToUTCString()); + storage.setCookie(COOKIE_KEY_MGUID, response.mguid, getCookieTimeToUTCString()); } } diff --git a/test/spec/modules/docereeAdManagerBidAdapter_spec.js b/test/spec/modules/docereeAdManagerBidAdapter_spec.js index 26b054f4e29..e367aab9678 100644 --- a/test/spec/modules/docereeAdManagerBidAdapter_spec.js +++ b/test/spec/modules/docereeAdManagerBidAdapter_spec.js @@ -25,6 +25,7 @@ describe('docereeadmanager', function () { userid: '', zipcode: '', userconsent: '', + platformUid: '' }, }, }, diff --git a/test/spec/modules/dspxBidAdapter_spec.js b/test/spec/modules/dspxBidAdapter_spec.js index 2d9e05cca25..8f02e51f131 100644 --- a/test/spec/modules/dspxBidAdapter_spec.js +++ b/test/spec/modules/dspxBidAdapter_spec.js @@ -1,7 +1,9 @@ import { expect } from 'chai'; +import { config } from 'src/config.js'; import { spec } from 'modules/dspxBidAdapter.js'; import { newBidder } from 'src/adapters/bidderFactory.js'; import { deepClone } from '../../../src/utils'; +import {BANNER} from '../../../src/mediaTypes'; const ENDPOINT_URL = 'https://buyer.dspx.tv/request/'; const ENDPOINT_URL_DEV = 'https://dcbuyer.dspx.tv/request/'; @@ -33,11 +35,18 @@ describe('dspxAdapter', function () { }); it('should return false when required params are not passed', function () { - let invalidBid = Object.assign({}, bid); - delete invalidBid.params; - invalidBid.params = { - 'someIncorrectParam': 0 - }; + const invalidBid = { + bidId: '30b31c1838de1e', + bidder: 'dspx', + mediaTypes: { + [BANNER]: { + sizes: [[300, 250]] + } + }, + params: { + someIncorrectParam: 0 + } + } expect(spec.isBidRequestValid(invalidBid)).to.equal(false); }); }); @@ -77,7 +86,26 @@ describe('dspxAdapter', function () { 'sharedid': { 'id': '01EXPPGZ9C8NKG1MTXVHV98505', 'third': '01EXPPGZ9C8NKG1MTXVHV98505' - } + }, + 'pubProvidedId': [{ + 'source': 'puburl2.com', + 'uids': [{ + 'id': 'pubid2' + }, { + 'id': 'pubid2-123' + }] + }, { + 'source': 'puburl.com', + 'uids': [{ + 'id': 'pubid1', + 'atype': 1, + 'ext': { + 'stype': 'ppuid' + } + }] + }], + 'euid': {}, + 'tdid': 'tdid_ID', }, 'crumbs': { 'pubcid': 'e09ab6a3-ae74-4f01-b2e8-81b141d6dc61' @@ -228,12 +256,54 @@ describe('dspxAdapter', function () { } }; + // With ortb2 + var bidderRequestWithORTB = { + refererInfo: { + referer: 'some_referrer.net' + }, + gdprConsent: { + consentString: 'BOJ/P2HOJ/P2HABABMAAAAAZ+A==', + vendorData: {someData: 'value'}, + gdprApplies: true + }, + ortb2: { + source: {}, + site: { + domain: 'buyer', + publisher: { + domain: 'buyer' + }, + page: 'http://buyer/schain.php?ver=8.5.0-pre:latest-dev-build&pbjs_debug=true', + ref: 'http://buyer/pbjsv/', + content: { + id: 'contentID', + episode: 1, + title: 'contentTitle', + series: 'contentSeries', + season: 'contentSeason 3', + artist: 'contentArtist', + genre: 'rock', + isrc: 'contentIsrc', + url: 'https://content-url.com/', + context: 1, + keywords: 'kw1,kw2,keqword 3', + livestream: 0, + cat: [ + 'IAB1-1', + 'IAB1-2', + 'IAB2-10' + ] + } + }, + } + }; + var request1 = spec.buildRequests([bidRequests[0]], bidderRequest)[0]; it('sends bid request to our endpoint via GET', function () { expect(request1.method).to.equal('GET'); expect(request1.url).to.equal(ENDPOINT_URL); let data = request1.data.replace(/rnd=\d+\&/g, '').replace(/ref=.*\&bid/g, 'bid').replace(/pbver=.*?&/g, 'pbver=test&'); - expect(data).to.equal('_f=auto&alternative=prebid_js&inventory_item_id=6682&srw=300&srh=250&idt=100&bid_id=30b31c1838de1e1&pbver=test&pfilter%5Bfloorprice%5D=1000000&pfilter%5Bprivate_auction%5D=0&pfilter%5Bgeo%5D%5Bcountry%5D=DE&pfilter%5Bgdpr_consent%5D=BOJ%2FP2HOJ%2FP2HABABMAAAAAZ%2BA%3D%3D&pfilter%5Bgdpr%5D=true&bcat=IAB2%2CIAB4&dvt=desktop&did_netid=123&did_id5=ID5-ZHMOcvSShIBZiIth_yYh9odjNFxVEmMQ_i5TArPfWw!ID5*dtrjfV5mPLasyya5TW2IE9oVzQZwx7xRPGyAYS4hcWkAAOoxoFef4bIoREpQys8x&did_id5_linktype=2&did_uid2=456&did_sharedid=01EXPPGZ9C8NKG1MTXVHV98505&did_pubcid=e09ab6a3-ae74-4f01-b2e8-81b141d6dc61&did_cpubcid=e09ab6a3-ae74-4f01-b2e8-81b141d6dc61&schain%5Bver%5D=1.0&schain%5Bcomplete%5D=1&schain%5Bnodes%5D%5B0%5D%5Basi%5D=example.com&schain%5Bnodes%5D%5B0%5D%5Bsid%5D=0&schain%5Bnodes%5D%5B0%5D%5Bhp%5D=1&schain%5Bnodes%5D%5B0%5D%5Brid%5D=bidrequestid&schain%5Bnodes%5D%5B0%5D%5Bdomain%5D=example.com&auctionId=1d1a030790a475&pbcode=testDiv1&media_types%5Bbanner%5D=300x250'); + expect(data).to.equal('_f=auto&alternative=prebid_js&inventory_item_id=6682&srw=300&srh=250&idt=100&bid_id=30b31c1838de1e1&pbver=test&pfilter%5Bfloorprice%5D=1000000&pfilter%5Bprivate_auction%5D=0&pfilter%5Bgeo%5D%5Bcountry%5D=DE&pfilter%5Bgdpr_consent%5D=BOJ%2FP2HOJ%2FP2HABABMAAAAAZ%2BA%3D%3D&pfilter%5Bgdpr%5D=true&bcat=IAB2%2CIAB4&dvt=desktop&auctionId=1d1a030790a475&pbcode=testDiv1&media_types%5Bbanner%5D=300x250&schain%5Bver%5D=1.0&schain%5Bcomplete%5D=1&schain%5Bnodes%5D%5B0%5D%5Basi%5D=example.com&schain%5Bnodes%5D%5B0%5D%5Bsid%5D=0&schain%5Bnodes%5D%5B0%5D%5Bhp%5D=1&schain%5Bnodes%5D%5B0%5D%5Brid%5D=bidrequestid&schain%5Bnodes%5D%5B0%5D%5Bdomain%5D=example.com&did_netid=123&did_id5=ID5-ZHMOcvSShIBZiIth_yYh9odjNFxVEmMQ_i5TArPfWw!ID5*dtrjfV5mPLasyya5TW2IE9oVzQZwx7xRPGyAYS4hcWkAAOoxoFef4bIoREpQys8x&did_id5_linktype=2&did_uid2=456&did_sharedid=01EXPPGZ9C8NKG1MTXVHV98505&did_pubcid=e09ab6a3-ae74-4f01-b2e8-81b141d6dc61&did_tdid=tdid_ID&did_ppuid=1%3Apuburl.com%3Apubid1&did_cpubcid=e09ab6a3-ae74-4f01-b2e8-81b141d6dc61'); }); var request2 = spec.buildRequests([bidRequests[1]], bidderRequest)[0]; @@ -281,6 +351,14 @@ describe('dspxAdapter', function () { expect(data).to.equal('_f=auto&alternative=prebid_js&inventory_item_id=107&srw=300&srh=250&idt=100&bid_id=30b31c1838de1e4&pbver=test&pfilter%5Btest%5D=1&prebidDevMode=1&auctionId=1d1a030790a478&pbcode=testDiv3&media_types%5Bvideo%5D=640x480&media_types%5Bbanner%5D=300x250&vctx=instream&vpl%5Bmimes%5D%5B0%5D=video%2Fmp4&vpl%5Bprotocols%5D%5B0%5D=1&vpl%5Bprotocols%5D%5B1%5D=2&vpl%5Bplaybackmethod%5D%5B0%5D=2&vpl%5Bskip%5D=1'); }); + var request7 = spec.buildRequests([bidRequests[5]], bidderRequestWithORTB)[0]; + it('ortb2 iab_content test', function () { + expect(request7.method).to.equal('GET'); + expect(request7.url).to.equal('http://localhost'); + let data = request7.data.replace(/rnd=\d+\&/g, '').replace(/ref=.*\&bid/g, 'bid').replace(/pbver=.*?&/g, 'pbver=test&'); + expect(data).to.equal('_f=auto&alternative=prebid_js&inventory_item_id=107&srw=300&srh=250&idt=100&bid_id=30b31c1838de1e4&pbver=test&pfilter%5Btest%5D=1&pfilter%5Bgdpr_consent%5D=BOJ%2FP2HOJ%2FP2HABABMAAAAAZ%2BA%3D%3D&pfilter%5Bgdpr%5D=true&pfilter%5Biab_content%5D=cat%3AIAB1-1%7CIAB1-2%7CIAB2-10%2Cepisode%3A1%2Ccontext%3A1%2Cid%3AcontentID%2Ctitle%3AcontentTitle%2Cseries%3AcontentSeries%2Cseason%3AcontentSeason%25203%2Cartist%3AcontentArtist%2Cgenre%3Arock%2Cisrc%3AcontentIsrc%2Curl%3Ahttps%253A%252F%252Fcontent-url.com%252F%2Ckeywords%3Akw1%252Ckw2%252Ckeqword%25203&prebidDevMode=1&auctionId=1d1a030790a478&pbcode=testDiv3&media_types%5Bvideo%5D=640x480&media_types%5Bbanner%5D=300x250&vctx=instream&vpl%5Bmimes%5D%5B0%5D=video%2Fmp4&vpl%5Bprotocols%5D%5B0%5D=1&vpl%5Bprotocols%5D%5B1%5D=2&vpl%5Bplaybackmethod%5D%5B0%5D=2&vpl%5Bskip%5D=1'); + }); + // bidfloor tests const getFloorResponse = {currency: 'EUR', floor: 5}; let testBidRequest = deepClone(bidRequests[1]); @@ -321,6 +399,109 @@ describe('dspxAdapter', function () { }); }); + describe('google topics handling', () => { + afterEach(() => { + config.resetConfig(); + }); + + const REQPARAMS = { + refererInfo: { + referer: 'some_referrer.net' + }, + gdprConsent: { + consentString: 'BOJ/P2HOJ/P2HABABMAAAAAZ+A==', + vendorData: {someData: 'value'}, + gdprApplies: true + } + }; + + const defaultRequest = { + 'bidder': 'dspx', + 'params': { + 'placement': '6682', + 'pfilter': { + 'floorprice': 1000000, + 'private_auction': 0, + 'geo': { + 'country': 'DE' + } + }, + 'bcat': 'IAB2,IAB4', + 'dvt': 'desktop' + }, + 'sizes': [ + [300, 250] + ], + 'bidId': '30b31c1838de1e1', + 'bidderRequestId': '22edbae2733bf61', + 'auctionId': '1d1a030790a475', + 'adUnitCode': 'testDiv1', + }; + + it('does pass segtax, segclass, segments for google topics data', () => { + const GOOGLE_TOPICS_DATA = { + ortb2: { + user: { + data: [ + { + ext: { + segtax: 600, + segclass: 'v1', + }, + segment: [ + {id: '717'}, {id: '808'}, + ] + } + ] + }, + }, + } + config.setConfig(GOOGLE_TOPICS_DATA); + const request = spec.buildRequests([defaultRequest], { ...REQPARAMS, ...GOOGLE_TOPICS_DATA })[0]; + expect(request.data).to.contain('segtx=600&segcl=v1&segs=717%2C808'); + }); + + it('does not pass topics params for invalid topics data', () => { + const INVALID_TOPICS_DATA = { + ortb2: { + user: { + data: [ + { + segment: [] + }, + { + segment: [{id: ''}] + }, + { + segment: [{id: null}] + }, + { + segment: [{id: 'dummy'}, {id: '123'}] + }, + { + ext: { + segtax: 600, + segclass: 'v1', + }, + segment: [ + { + name: 'dummy' + } + ] + }, + ] + } + } + }; + + config.setConfig(INVALID_TOPICS_DATA); + let request = spec.buildRequests([defaultRequest], { ...REQPARAMS, ...INVALID_TOPICS_DATA })[0]; + expect(request.data).to.not.contain('segtax'); + expect(request.data).to.not.contain('segclass'); + expect(request.data).to.not.contain('segments'); + }); + }); + describe('interpretResponse', function () { let serverResponse = { 'body': { diff --git a/test/spec/modules/eightPodAnalyticsAdapter_spec.js b/test/spec/modules/eightPodAnalyticsAdapter_spec.js index 930b15bda31..55a09db03b4 100644 --- a/test/spec/modules/eightPodAnalyticsAdapter_spec.js +++ b/test/spec/modules/eightPodAnalyticsAdapter_spec.js @@ -1,4 +1,4 @@ -import analyticsAdapter, { storage, queue, context, trackEvent } from 'modules/eightPodAnalyticsAdapter.js'; +import analyticsAdapter, { storage, queue, trackEvent } from 'modules/eightPodAnalyticsAdapter.js'; import { expect } from 'chai'; import adapterManager from 'src/adapterManager.js'; import eightPodAnalytics from 'modules/eightPodAnalyticsAdapter.js'; @@ -45,11 +45,12 @@ describe('eightPodAnalyticAdapter', function() { it('should subscribe on messageEvents', function() { getDataFromLocalStorageStub.returns(JSON.stringify([])); sandbox.spy(eightPodAnalytics, 'eventSubscribe'); + sandbox.spy(eightPodAnalytics, 'getEventFromLocalStorage'); analyticsAdapter.setupPage(); - sandbox.assert.callCount(analyticsAdapter.eventSubscribe, 1); - sandbox.assert.callCount(addEventListenerSpy, 1); + sandbox.assert.callCount(analyticsAdapter.eventSubscribe, 0); + sandbox.assert.callCount(analyticsAdapter.getEventFromLocalStorage, 1); }); it('should receive saved events list', function() { @@ -67,6 +68,7 @@ describe('eightPodAnalyticAdapter', function() { beforeEach(function() { setupPageStub = sandbox.stub(eightPodAnalytics, 'setupPage'); + eightPodAnalytics.resetContext(); }); afterEach(function() { @@ -79,16 +81,18 @@ describe('eightPodAnalyticAdapter', function() { }) sandbox.assert.callCount(setupPageStub, 0); - expect(context).to.deep.equal(undefined) + expect(analyticsAdapter.getContext()).to.deep.equal({}) }); it('should call setup page and get context', function() { eightPodAnalytics.track({ eventType: BID_WON, args: { + adUnitCode: 'adUnitCode', bidder: 'eightPod', creativeId: 'creativeId', seatBidId: 'seatBidId', + cid: 'campaignId', params: [ { publisherId: 'publisherId', @@ -99,23 +103,27 @@ describe('eightPodAnalyticAdapter', function() { }) sandbox.assert.callCount(setupPageStub, 1); - expect(context).to.deep.equal({ - bidId: 'seatBidId', - campaignId: 'campaignId', - placementId: 'placementId', - publisherId: 'publisherId', - variantId: 'creativeId' + expect(analyticsAdapter.getContext()).to.deep.equal({ + adUnitCode: { + bidId: 'seatBidId', + campaignId: 'campaignId', + placementId: 'placementId', + publisherId: 'publisherId', + variantId: 'creativeId' + } }) }); }); describe('trackEvent', function() { let getContextStub, getTimeStub; + const adUnitCode = 'adUnitCode'; beforeEach(function() { getContextStub = sandbox.stub(eightPodAnalytics, 'getContext'); getTimeStub = sandbox.stub(Date.prototype, 'getTime').returns(1234); eightPodAnalytics.resetQueue(); + eightPodAnalytics.resetContext(); }); afterEach(function() { @@ -124,7 +132,7 @@ describe('eightPodAnalyticAdapter', function() { }); it('should add event to the queue', function() { - getContextStub.returns({}); + getContextStub.returns({adUnitCode: {}}); const event1 = { detail: { @@ -169,9 +177,10 @@ describe('eightPodAnalyticAdapter', function() { value: 2 } } - trackEvent(event1) + + trackEvent(event1, adUnitCode) expect(queue).to.deep.equal([result1]); - trackEvent(event2); + trackEvent(event2, adUnitCode); expect(queue).to.deep.equal([result1, result2]); }); }); diff --git a/test/spec/modules/gamoshiBidAdapter_spec.js b/test/spec/modules/gamoshiBidAdapter_spec.js index f41750cfe71..8f9818ed901 100644 --- a/test/spec/modules/gamoshiBidAdapter_spec.js +++ b/test/spec/modules/gamoshiBidAdapter_spec.js @@ -398,7 +398,7 @@ describe('GamoshiAdapter', () => { expect(response.data.imp[0].video.mimes).to.equal(bidRequestWithVideo.mediaTypes.video.mimes); expect(response.data.imp[0].video.skip).to.not.exist; - expect(response.data.imp[0].video.placement).to.equal(1); + expect(response.data.imp[0].video.plcmt).to.equal(1); expect(response.data.imp[0].video.minduration).to.equal(1); expect(response.data.imp[0].video.playbackmethod).to.equal(1); expect(response.data.imp[0].video.startdelay).to.equal(1); diff --git a/test/spec/modules/gptPreAuction_spec.js b/test/spec/modules/gptPreAuction_spec.js index 5caa95404dc..88062f2b785 100644 --- a/test/spec/modules/gptPreAuction_spec.js +++ b/test/spec/modules/gptPreAuction_spec.js @@ -2,10 +2,16 @@ import { appendGptSlots, appendPbAdSlot, _currentConfig, - makeBidRequestsHook + makeBidRequestsHook, + getAuctionsIdsFromTargeting, + getSegments, + getSignals, + getSignalsArrayByAuctionsIds, + getSignalsIntersection } from 'modules/gptPreAuction.js'; import { config } from 'src/config.js'; import { makeSlot } from '../integration/faker/googletag.js'; +import { taxonomies } from '../../../libraries/gptUtils/gptUtils.js'; describe('GPT pre-auction module', () => { let sandbox; @@ -25,6 +31,87 @@ describe('GPT pre-auction module', () => { makeSlot({ code: 'slotCode4', divId: 'div5' }) ]; + const mockTargeting = {'/123456/header-bid-tag-0': {'hb_deal_rubicon': '1234', 'hb_deal': '1234', 'hb_pb': '0.53', 'hb_adid': '148018fe5e', 'hb_bidder': 'rubicon', 'foobar': '300x250', 'hb_pb_rubicon': '0.53', 'hb_adid_rubicon': '148018fe5e', 'hb_bidder_rubicon': 'rubicon', 'hb_deal_appnexus': '4321', 'hb_pb_appnexus': '0.1', 'hb_adid_appnexus': '567891011', 'hb_bidder_appnexus': 'appnexus'}} + + const mockAuctionManager = { + findBidByAdId(adId) { + const bidsMap = { + '148018fe5e': { + auctionId: mocksAuctions[0].auctionId + }, + '567891011': { + auctionId: mocksAuctions[1].auctionId + }, + }; + return bidsMap[adId]; + }, + index: { + getAuction({ auctionId }) { + return mocksAuctions.find(auction => auction.auctionId === auctionId); + } + } + } + + const mocksAuctions = [ + { + auctionId: '1111', + getFPD: () => ({ + global: { + user: { + data: [{ + name: 'dataprovider.com', + ext: { + segtax: 4 + }, + segment: [{ + id: '1' + }, { + id: '2' + }] + }], + } + } + }) + }, + { + auctionId: '234234', + getFPD: () => ({ + global: { + user: { + data: [{ + name: 'dataprovider.com', + ext: { + segtax: 4 + }, + segment: [{ + id: '2' + }] + }] + } + } + }), + }, { + auctionId: '234324234', + getFPD: () => ({ + global: { + user: { + data: [{ + name: 'dataprovider.com', + ext: { + segtax: 4 + }, + segment: [{ + id: '2' + }, { + id: '3' + }] + }] + } + } + }) + }, + ] + describe('appendPbAdSlot', () => { // sets up our document body to test the pbAdSlot dom actions against document.body.innerHTML = '
test1
' + @@ -454,4 +541,59 @@ describe('GPT pre-auction module', () => { expect(returnedAdUnits).to.deep.equal(expectedAdUnits); }); }); + + describe('pps gpt config', () => { + it('should parse segments from fpd', () => { + const twoSegments = getSegments(mocksAuctions[0].getFPD().global, ['user.data'], 4); + expect(JSON.stringify(twoSegments)).to.equal(JSON.stringify(['1', '2'])); + const zeroSegments = getSegments(mocksAuctions[0].getFPD().global, ['user.data'], 6); + expect(zeroSegments).to.length(0); + }); + + it('should return signals from fpd', () => { + const signals = getSignals(mocksAuctions[0].getFPD().global); + const expectedSignals = [{ taxonomy: taxonomies[0], values: ['1', '2'] }]; + expect(signals).to.eql(expectedSignals); + }); + + it('should properly get auctions ids from targeting', () => { + const auctionsIds = getAuctionsIdsFromTargeting(mockTargeting, mockAuctionManager); + expect(auctionsIds).to.eql([mocksAuctions[0].auctionId, mocksAuctions[1].auctionId]) + }); + + it('should filter out adIds that do not map to any auction', () => { + const auctionsIds = getAuctionsIdsFromTargeting({ + ...mockTargeting, + 'au': {'hb_adid': 'missing'}, + }, mockAuctionManager); + expect(auctionsIds).to.eql([mocksAuctions[0].auctionId, mocksAuctions[1].auctionId]); + }) + + it('should properly return empty array of auction ids for invalid targeting', () => { + let auctionsIds = getAuctionsIdsFromTargeting({}, mockAuctionManager); + expect(Array.isArray(auctionsIds)).to.equal(true); + expect(auctionsIds).to.length(0); + auctionsIds = getAuctionsIdsFromTargeting({'/123456/header-bid-tag-0/bg': {'invalidContent': '123'}}, mockAuctionManager); + expect(Array.isArray(auctionsIds)).to.equal(true); + expect(auctionsIds).to.length(0); + }); + + it('should properly get signals from auctions', () => { + const signals = getSignalsArrayByAuctionsIds(['1111', '234234', '234324234'], mockAuctionManager.index); + const intersection = getSignalsIntersection(signals); + const expectedResult = { IAB_AUDIENCE_1_1: { values: ['2'] }, IAB_CONTENT_2_2: { values: [] } }; + expect(JSON.stringify(intersection)).to.be.equal(JSON.stringify(expectedResult)); + }); + + it('should return empty signals array for empty auctions ids array', () => { + const signals = getSignalsArrayByAuctionsIds([], mockAuctionManager.index); + expect(Array.isArray(signals)).to.equal(true); + expect(signals).to.length(0); + }); + + it('should return properly formatted object for getSignalsIntersection invoked with empty array', () => { + const signals = getSignalsIntersection([]); + expect(Object.keys(signals)).to.contain.members(taxonomies); + }); + }); }); diff --git a/test/spec/modules/gumgumBidAdapter_spec.js b/test/spec/modules/gumgumBidAdapter_spec.js index 3424d172775..e6fa6d468ca 100644 --- a/test/spec/modules/gumgumBidAdapter_spec.js +++ b/test/spec/modules/gumgumBidAdapter_spec.js @@ -321,6 +321,23 @@ describe('gumgumAdapter', function () { expect(bidRequest.data).to.have.property('gpid'); expect(bidRequest.data.gpid).to.equal('/17037559/jeusol/jeusol_D_1'); }); + it('should set ae value to 1 for PAAPI', function () { + const req = { ...bidRequests[0], + ortb2Imp: { + ext: { + ae: 1, + data: { + adserver: { + name: 'test', + adslot: 123456 + } + } + } + } } + const bidRequest = spec.buildRequests([req])[0]; + expect(bidRequest.data).to.have.property('ae'); + expect(bidRequest.data.ae).to.equal(true); + }); it('should set the global placement id (gpid) if in pbadslot property', function () { const pbadslot = 'abc123' diff --git a/test/spec/modules/idImportLibrary_spec.js b/test/spec/modules/idImportLibrary_spec.js index d5b3e32546d..6045eb0bda0 100644 --- a/test/spec/modules/idImportLibrary_spec.js +++ b/test/spec/modules/idImportLibrary_spec.js @@ -4,6 +4,10 @@ import * as idImportlibrary from 'modules/idImportLibrary.js'; import {getGlobal} from '../../../src/prebidGlobal.js'; import {config} from 'src/config.js'; import {hook} from '../../../src/hook.js'; +import * as activities from '../../../src/activities/rules.js'; +import { ACTIVITY_ENRICH_UFPD } from '../../../src/activities/activities.js'; +import { CONF_DEFAULT_FULL_BODY_SCAN, CONF_DEFAULT_INPUT_SCAN } from '../../../modules/idImportLibrary.js'; + var expect = require('chai').expect; const mockMutationObserver = { @@ -86,6 +90,16 @@ describe('IdImportLibrary Tests', function () { idImportlibrary.setConfig(config); expect(config.inputscan).to.be.equal(true); }); + it('results when activity is not allowed', function () { + sandbox.stub(activities, 'isActivityAllowed').callsFake((activity) => { + return !(activity === ACTIVITY_ENRICH_UFPD); + }); + let config = { 'url': 'URL', 'debounce': 0 }; + idImportlibrary.setConfig(config); + sinon.assert.called(utils.logError); + expect(config.inputscan).to.be.not.equal(CONF_DEFAULT_INPUT_SCAN); + expect(config.fullscan).to.be.not.equal(CONF_DEFAULT_FULL_BODY_SCAN); + }); }); describe('Test with email is found', function () { let mutationObserverStub; diff --git a/test/spec/modules/illuminBidAdapter_spec.js b/test/spec/modules/illuminBidAdapter_spec.js index c689307416f..3e809862b95 100644 --- a/test/spec/modules/illuminBidAdapter_spec.js +++ b/test/spec/modules/illuminBidAdapter_spec.js @@ -2,6 +2,14 @@ import {expect} from 'chai'; import { spec as adapter, createDomain, + storage +} from 'modules/illuminBidAdapter.js'; +import * as utils from 'src/utils.js'; +import {version} from 'package.json'; +import {useFakeTimers} from 'sinon'; +import {BANNER, VIDEO} from '../../../src/mediaTypes'; +import {config} from '../../../src/config'; +import { hashCode, extractPID, extractCID, @@ -10,12 +18,7 @@ import { setStorageItem, tryParseJSON, getUniqueDealId, -} from 'modules/illuminBidAdapter.js'; -import * as utils from 'src/utils.js'; -import {version} from 'package.json'; -import {useFakeTimers} from 'sinon'; -import {BANNER, VIDEO} from '../../../src/mediaTypes'; -import {config} from '../../../src/config'; +} from '../../../libraries/vidazooUtils/bidderUtils.js'; export const TEST_ID_SYSTEMS = ['criteoId', 'id5id', 'idl_env', 'lipb', 'netId', 'pubcid', 'tdid', 'pubProvidedId']; @@ -325,7 +328,12 @@ describe('IlluminBidAdapter', function () { startdelay: 0 } }, - gpid: '0123456789' + gpid: '0123456789', + cat: [], + contentData: [], + isStorageAllowed: true, + pagecat: [], + userData: [] } }); }); @@ -387,6 +395,11 @@ describe('IlluminBidAdapter', function () { uqs: getTopWindowQueryParams(), 'ext.param1': 'loremipsum', 'ext.param2': 'dolorsitamet', + cat: [], + contentData: [], + isStorageAllowed: true, + pagecat: [], + userData: [] } }); }); @@ -562,13 +575,13 @@ describe('IlluminBidAdapter', function () { const key = 'myKey'; let uniqueDealId; beforeEach(() => { - uniqueDealId = getUniqueDealId(key, 0); + uniqueDealId = getUniqueDealId(storage, key, 0); }) it('should get current unique deal id', function (done) { // waiting some time so `now` will become past setTimeout(() => { - const current = getUniqueDealId(key); + const current = getUniqueDealId(storage, key); expect(current).to.be.equal(uniqueDealId); done(); }, 200); @@ -576,7 +589,7 @@ describe('IlluminBidAdapter', function () { it('should get new unique deal id on expiration', function (done) { setTimeout(() => { - const current = getUniqueDealId(key, 100); + const current = getUniqueDealId(storage, key, 100); expect(current).to.not.be.equal(uniqueDealId); done(); }, 200) @@ -600,8 +613,8 @@ describe('IlluminBidAdapter', function () { shouldAdvanceTime: true, now }); - setStorageItem('myKey', 2020); - const {value, created} = getStorageItem('myKey'); + setStorageItem(storage, 'myKey', 2020); + const {value, created} = getStorageItem(storage, 'myKey'); expect(created).to.be.equal(now); expect(value).to.be.equal(2020); expect(typeof value).to.be.equal('number'); @@ -612,7 +625,7 @@ describe('IlluminBidAdapter', function () { it('should get external stored value', function () { const value = 'superman' window.localStorage.setItem('myExternalKey', value); - const item = getStorageItem('myExternalKey'); + const item = getStorageItem(storage, 'myExternalKey'); expect(item).to.be.equal(value); }); diff --git a/test/spec/modules/insticatorBidAdapter_spec.js b/test/spec/modules/insticatorBidAdapter_spec.js index 64033c5a7d4..158fdebeb76 100644 --- a/test/spec/modules/insticatorBidAdapter_spec.js +++ b/test/spec/modules/insticatorBidAdapter_spec.js @@ -389,7 +389,7 @@ describe('InsticatorBidAdapter', function () { expect(data.device).to.be.an('object'); expect(data.device.w).to.equal(window.innerWidth); expect(data.device.h).to.equal(window.innerHeight); - expect(data.device.js).to.equal(true); + expect(data.device.js).to.equal(1); expect(data.device.ext).to.be.an('object'); expect(data.device.ext.localStorage).to.equal(true); expect(data.device.ext.cookies).to.equal(false); @@ -439,6 +439,13 @@ describe('InsticatorBidAdapter', function () { insticator: { adUnitId: bidRequest.params.adUnitId, }, + prebid: { + bidder: { + insticator: { + adUnitId: bidRequest.params.adUnitId, + } + } + } } }]); expect(data.ext).to.be.an('object'); diff --git a/test/spec/modules/intentIqAnalyticsAdapter_spec.js b/test/spec/modules/intentIqAnalyticsAdapter_spec.js new file mode 100644 index 00000000000..9a204dde31b --- /dev/null +++ b/test/spec/modules/intentIqAnalyticsAdapter_spec.js @@ -0,0 +1,172 @@ +import { expect } from 'chai'; +import iiqAnalyticsAnalyticsAdapter from 'modules/intentIqAnalyticsAdapter.js'; +import * as utils from 'src/utils.js'; +import { server } from 'test/mocks/xhr.js'; +import { config } from 'src/config.js'; +import { EVENTS } from 'src/constants.js'; +import * as events from 'src/events.js'; +import { getStorageManager } from 'src/storageManager.js'; +import sinon from 'sinon'; +import { FIRST_PARTY_KEY } from '../../../modules/intentIqIdSystem'; +import { REPORTER_ID, getReferrer, preparePayload } from '../../../modules/intentIqAnalyticsAdapter'; + +const partner = 10; +const defaultData = '{"pcid":"f961ffb1-a0e1-4696-a9d2-a21d815bd344", "group": "A"}'; + +const storage = getStorageManager({ moduleType: 'analytics', moduleName: 'iiqAnalytics' }); + +const USERID_CONFIG = [ + { + 'name': 'intentIqId', + 'params': { + 'partner': partner, + 'unpack': null, + }, + 'storage': { + 'type': 'html5', + 'name': 'intentIqId', + 'expires': 60, + 'refreshInSeconds': 14400 + } + } +]; + +let wonRequest = { + 'bidderCode': 'pubmatic', + 'width': 728, + 'height': 90, + 'statusMessage': 'Bid available', + 'adId': '23caeb34c55da51', + 'requestId': '87615b45ca4973', + 'transactionId': '5e69fd76-8c86-496a-85ce-41ae55787a50', + 'auctionId': '0cbd3a43-ff45-47b8-b002-16d3946b23bf', + 'mediaType': 'banner', + 'source': 'client', + 'cpm': 5, + 'currency': 'USD', + 'ttl': 300, + 'referrer': '', + 'adapterCode': 'pubmatic', + 'originalCpm': 5, + 'originalCurrency': 'USD', + 'responseTimestamp': 1669644710345, + 'requestTimestamp': 1669644710109, + 'bidder': 'testbidder', + 'adUnitCode': 'addUnitCode', + 'timeToRespond': 236, + 'pbLg': '5.00', + 'pbMg': '5.00', + 'pbHg': '5.00', + 'pbAg': '5.00', + 'pbDg': '5.00', + 'pbCg': '', + 'size': '728x90', + 'status': 'rendered' +}; + +describe('IntentIQ tests all', function () { + let logErrorStub; + + beforeEach(function () { + logErrorStub = sinon.stub(utils, 'logError'); + sinon.stub(config, 'getConfig').withArgs('userSync.userIds').returns(USERID_CONFIG); + sinon.stub(events, 'getEvents').returns([]); + iiqAnalyticsAnalyticsAdapter.enableAnalytics({ + provider: 'iiqAnalytics', + }); + iiqAnalyticsAnalyticsAdapter.initOptions = { + lsValueInitialized: false, + partner: null, + fpid: null, + userGroup: null, + currentGroup: null, + dataInLs: null, + eidl: null, + lsIdsInitialized: false, + manualReport: false + }; + if (iiqAnalyticsAnalyticsAdapter.track.restore) { + iiqAnalyticsAnalyticsAdapter.track.restore(); + } + sinon.spy(iiqAnalyticsAnalyticsAdapter, 'track'); + }); + + afterEach(function () { + logErrorStub.restore(); + config.getConfig.restore(); + events.getEvents.restore(); + iiqAnalyticsAnalyticsAdapter.disableAnalytics(); + if (iiqAnalyticsAnalyticsAdapter.track.restore) { + iiqAnalyticsAnalyticsAdapter.track.restore(); + } + localStorage.clear(); + server.reset(); + }); + + it('IIQ Analytical Adapter bid win report', function () { + localStorage.setItem(FIRST_PARTY_KEY, defaultData); + + events.emit(EVENTS.BID_WON, wonRequest); + + expect(server.requests.length).to.be.above(0); + const request = server.requests[0]; + expect(request.url).to.contain('https://reports.intentiq.com/report?pid=' + partner + '&mct=1'); + expect(request.url).to.contain('&jsver=0.1&vrref=http://localhost:9876/'); + expect(request.url).to.contain('&payload='); + expect(request.url).to.contain('iiqid=f961ffb1-a0e1-4696-a9d2-a21d815bd344'); + }); + + it('should initialize with default configurations', function () { + expect(iiqAnalyticsAnalyticsAdapter.initOptions.lsValueInitialized).to.be.false; + }); + + it('should handle BID_WON event with group configuration from local storage', function () { + localStorage.setItem(FIRST_PARTY_KEY, '{"pcid":"testpcid", "group": "B"}'); + + events.emit(EVENTS.BID_WON, wonRequest); + + expect(server.requests.length).to.be.above(0); + const request = server.requests[0]; + expect(request.url).to.contain('https://reports.intentiq.com/report?pid=' + partner + '&mct=1'); + expect(request.url).to.contain('&jsver=0.1&vrref=http://localhost:9876/'); + expect(request.url).to.contain('iiqid=testpcid'); + }); + + it('should handle BID_WON event with default group configuration', function () { + localStorage.setItem(FIRST_PARTY_KEY, defaultData); + + events.emit(EVENTS.BID_WON, wonRequest); + + expect(server.requests.length).to.be.above(0); + const request = server.requests[0]; + const data = preparePayload(wonRequest); + const base64String = btoa(JSON.stringify(data)); + const payload = `[%22${base64String}%22]`; + expect(request.url).to.equal( + `https://reports.intentiq.com/report?pid=${partner}&mct=1&iiqid=f961ffb1-a0e1-4696-a9d2-a21d815bd344&agid=${REPORTER_ID}&jsver=0.1&vrref=${getReferrer()}&source=pbjs&payload=${payload}` + ); + }); + + it('should not send request if manualReport is true', function () { + iiqAnalyticsAnalyticsAdapter.initOptions.manualReport = true; + events.emit(EVENTS.BID_WON, wonRequest); + expect(server.requests.length).to.equal(0); + }); + + it('should read data from local storage', function () { + localStorage.setItem(FIRST_PARTY_KEY, '{"group": "A"}'); + localStorage.setItem(FIRST_PARTY_KEY + '_' + partner, '{"data":"testpcid", "eidl": 10}'); + events.emit(EVENTS.BID_WON, wonRequest); + expect(iiqAnalyticsAnalyticsAdapter.initOptions.dataInLs).to.equal('testpcid'); + expect(iiqAnalyticsAnalyticsAdapter.initOptions.eidl).to.equal(10); + expect(iiqAnalyticsAnalyticsAdapter.initOptions.currentGroup).to.equal('A'); + }); + + it('should handle initialization values from local storage', function () { + localStorage.setItem(FIRST_PARTY_KEY, '{"pcid":"testpcid", "group": "B"}'); + localStorage.setItem(FIRST_PARTY_KEY + '_' + partner, '{"data":"testpcid"}'); + events.emit(EVENTS.BID_WON, wonRequest); + expect(iiqAnalyticsAnalyticsAdapter.initOptions.currentGroup).to.equal('B'); + expect(iiqAnalyticsAnalyticsAdapter.initOptions.fpid).to.be.not.null; + }); +}); diff --git a/test/spec/modules/jwplayerRtdProvider_spec.js b/test/spec/modules/jwplayerRtdProvider_spec.js index 36794ceeae3..58cfc751a4f 100644 --- a/test/spec/modules/jwplayerRtdProvider_spec.js +++ b/test/spec/modules/jwplayerRtdProvider_spec.js @@ -12,6 +12,7 @@ import { getVatFromCache, getVatFromPlayer, setOverrides, + getPlayer, jwplayerSubmodule } from 'modules/jwplayerRtdProvider.js'; import {server} from 'test/mocks/xhr.js'; @@ -1603,6 +1604,66 @@ describe('jwplayerRtdProvider', function() { }); }); + describe('Player detection', function () { + const playerInstanceMock = { + getPlaylist: () => [], + getPlaylistItem: () => ({}) + }; + + beforeEach(function () { + window.jwplayer = sinon.stub(); + }); + + afterEach(function () { + delete window.jwplayer; + }); + + it('should fail if jwplayer global does not exist', function () { + delete window.jwplayer; + expect(getPlayer('divId')).to.be.undefined; + }); + + it('should return the player instance for the specified div id', function () { + window.jwplayer.returns(playerInstanceMock); + const player = getPlayer('divId'); + expect(player).to.deep.equal(playerInstanceMock); + }); + + it('should request a player when the div id does not match a player on the page and only 1 player is in the DOM', function () { + const playerDomElement = document.createElement('div'); + playerDomElement.className = 'jwplayer'; + document.body.appendChild(playerDomElement); + + window.jwplayer.withArgs('invalidDivId').returns(undefined); + window.jwplayer.returns(playerInstanceMock); + + const playerInstance = getPlayer('invalidDivId'); + + expect(playerInstance).to.deep.equal(playerInstanceMock); + + document.body.removeChild(playerDomElement); + }); + + it('should fail when the div id does not match a player on the page, and multiple players are instantiated', function () { + const firstPlayerDomElement = document.createElement('div'); + const secondPlayerDomElement = document.createElement('div'); + firstPlayerDomElement.className = 'jwplayer'; + secondPlayerDomElement.className = 'jwplayer'; + document.body.appendChild(firstPlayerDomElement); + document.body.appendChild(secondPlayerDomElement); + + window.jwplayer.withArgs('invalidDivId').returns(undefined); + window.jwplayer.returns(playerInstanceMock); + + const playerInstance = getPlayer('invalidDivId'); + + expect(playerInstance).to.be.undefined; + + document.body.removeChild(firstPlayerDomElement); + document.body.removeChild(secondPlayerDomElement); + }); + }); + describe('jwplayerSubmodule', function () { it('successfully instantiates', function () { expect(jwplayerSubmodule.init()).to.equal(true); diff --git a/test/spec/modules/kargoBidAdapter_spec.js b/test/spec/modules/kargoBidAdapter_spec.js index 590d98969c3..e24c34dd1ab 100644 --- a/test/spec/modules/kargoBidAdapter_spec.js +++ b/test/spec/modules/kargoBidAdapter_spec.js @@ -1885,16 +1885,15 @@ describe('kargo adapter tests', function() { describe('getUserSyncs', function() { let crb = {}; const clientId = 'random-client-id-string'; - const baseUrl = 'https://crb.kargo.com/api/v1/initsyncrnd/random-client-id-string?seed=3205e885-8d37-4139-b47e-f82cff268000&idx=0&gdpr=0&gdpr_consent=&us_privacy=&gpp=&gpp_sid='; + const baseUrl = 'https://crb.kargo.com/api/v1/initsyncrnd/random-client-id-string?seed=3205e885-8d37-4139-b47e-f82cff268000&gdpr=0&gdpr_consent=&us_privacy=&gpp=&gpp_sid='; - function buildSyncUrls(baseUrl = 'https://crb.kargo.com/api/v1/initsyncrnd/random-client-id-string?seed=3205e885-8d37-4139-b47e-f82cff268000&idx=0&gdpr=0&gdpr_consent=&us_privacy=&gpp=&gpp_sid=') { + function buildSyncUrls(baseUrl = 'https://crb.kargo.com/api/v1/initsyncrnd/random-client-id-string?seed=3205e885-8d37-4139-b47e-f82cff268000&gdpr=0&gdpr_consent=&us_privacy=&gpp=&gpp_sid=') { let syncs = []; - for (let i = 0; i < 5; i++) { - syncs.push({ - type: 'iframe', - url: baseUrl.replace(/idx=\d+&/, `idx=${i}&`), - }); - } + + syncs.push({ + type: 'iframe', + url: baseUrl + }); return syncs; } diff --git a/test/spec/modules/kimberliteBidAdapter_spec.js b/test/spec/modules/kimberliteBidAdapter_spec.js index 1480f1cc768..c0394a2090b 100644 --- a/test/spec/modules/kimberliteBidAdapter_spec.js +++ b/test/spec/modules/kimberliteBidAdapter_spec.js @@ -1,6 +1,6 @@ -import { spec } from 'modules/kimberliteBidAdapter.js'; +import { spec, ENDPOINT_URL } from 'modules/kimberliteBidAdapter.js'; import { assert } from 'chai'; -import { BANNER } from '../../../src/mediaTypes.js'; +import { BANNER, VIDEO } from '../../../src/mediaTypes.js'; const BIDDER_CODE = 'kimberlite'; @@ -8,74 +8,104 @@ describe('kimberliteBidAdapter', function () { const sizes = [[640, 480]]; describe('isBidRequestValid', function () { - let bidRequest; + let bidRequests; beforeEach(function () { - bidRequest = { - mediaTypes: { - [BANNER]: { - sizes: [[320, 240]] + bidRequests = [ + { + mediaTypes: { + [BANNER]: { + sizes: [[320, 240]] + } + }, + params: { + placementId: 'test-placement' } }, - params: { - placementId: 'test-placement' + { + mediaTypes: { + [VIDEO]: { + mimes: ['video/mp4'] + } + }, + params: { + placementId: 'test-placement' + } } - }; + ]; }); - it('pass on valid bidRequest', function () { - assert.isTrue(spec.isBidRequestValid(bidRequest)); + it('pass on valid banner bidRequest', function () { + assert.isTrue(spec.isBidRequestValid(bidRequests[0])); }); it('fails on missed placementId', function () { - delete bidRequest.params.placementId; - assert.isFalse(spec.isBidRequestValid(bidRequest)); + delete bidRequests[0].params.placementId; + assert.isFalse(spec.isBidRequestValid(bidRequests[0])); }); it('fails on empty banner', function () { - delete bidRequest.mediaTypes.banner; - assert.isFalse(spec.isBidRequestValid(bidRequest)); + delete bidRequests[0].mediaTypes.banner; + assert.isFalse(spec.isBidRequestValid(bidRequests[0])); }); it('fails on empty banner.sizes', function () { - delete bidRequest.mediaTypes.banner.sizes; - assert.isFalse(spec.isBidRequestValid(bidRequest)); + delete bidRequests[0].mediaTypes.banner.sizes; + assert.isFalse(spec.isBidRequestValid(bidRequests[0])); }); it('fails on empty request', function () { assert.isFalse(spec.isBidRequestValid()); }); + + it('pass on valid video bidRequest', function () { + assert.isTrue(spec.isBidRequestValid(bidRequests[1])); + }); + + it('fails on missed video.mimes', function () { + delete bidRequests[1].mediaTypes.video.mimes; + assert.isFalse(spec.isBidRequestValid(bidRequests[1])); + }); }); describe('buildRequests', function () { let bidRequests, bidderRequest; beforeEach(function () { - bidRequests = [{ - mediaTypes: { - [BANNER]: {sizes: sizes} + bidRequests = [ + { + mediaTypes: { + [BANNER]: {sizes: sizes} + }, + params: { + placementId: 'test-placement' + } }, - params: { - placementId: 'test-placement' + { + mediaTypes: { + [VIDEO]: { + mimes: ['video/mp4'], + } + }, + params: { + placementId: 'test-placement' + } } - }]; + ]; bidderRequest = { refererInfo: { domain: 'example.com', page: 'https://www.example.com/test.html', - }, - bids: [{ - mediaTypes: { - [BANNER]: {sizes: sizes} - } - }] + } }; }); it('valid bid request', function () { const bidRequest = spec.buildRequests(bidRequests, bidderRequest); + assert.equal(bidRequest.method, 'POST'); + assert.equal(bidRequest.url, ENDPOINT_URL); assert.ok(bidRequest.data); const requestData = bidRequest.data; @@ -87,10 +117,10 @@ describe('kimberliteBidAdapter', function () { expect(requestData.ext).to.be.an('Object').and.have.all.keys('prebid'); expect(requestData.ext.prebid).to.be.an('Object').and.have.all.keys('ver', 'adapterVer'); - const impData = requestData.imp[0]; - expect(impData.banner).is.to.be.an('Object').and.have.all.keys(['format', 'topframe']); + const impBannerData = requestData.imp[0]; + expect(impBannerData.banner).is.to.be.an('Object').and.have.all.keys(['format', 'topframe']); - const bannerData = impData.banner; + const bannerData = impBannerData.banner; expect(bannerData.format).to.be.an('array').and.is.not.empty; const formatData = bannerData.format[0]; @@ -98,30 +128,44 @@ describe('kimberliteBidAdapter', function () { assert.equal(formatData.w, sizes[0][0]); assert.equal(formatData.h, sizes[0][1]); + + if (FEATURES.VIDEO) { + const impVideoData = requestData.imp[1]; + expect(impVideoData.video).is.to.be.an('Object').and.have.all.keys(['mimes']); + + const videoData = impVideoData.video; + expect(videoData.mimes).to.be.an('array').and.is.not.empty; + expect(videoData.mimes[0]).to.be.a('string').that.equals('video/mp4'); + } }); }); describe('interpretResponse', function () { - let bidderResponse, bidderRequest, bidRequest, expectedBid; + let bidderResponse, bidderRequest, bidRequest, expectedBids; const requestId = '07fba8b0-8812-4dc6-b91e-4a525d81729c'; - const bidId = '222209853178'; - const impId = 'imp-id'; - const crId = 'creative-id'; - const adm = 'landing'; + const bannerAdm = 'landing'; + const videoAdm = 'test vast'; beforeEach(function () { bidderResponse = { body: { id: requestId, seatbid: [{ - bid: [{ - crid: crId, - id: bidId, - impid: impId, - price: 1, - adm: adm - }] + bid: [ + { + crid: 1, + impid: 1, + price: 1, + adm: bannerAdm + }, + { + crid: 2, + impid: 2, + price: 1, + adm: videoAdm + } + ] }] } }; @@ -131,36 +175,64 @@ describe('kimberliteBidAdapter', function () { domain: 'example.com', page: 'https://www.example.com/test.html', }, - bids: [{ - bidId: impId, - mediaTypes: { - [BANNER]: {sizes: sizes} + bids: [ + { + bidId: 1, + mediaTypes: { + banner: {sizes: sizes} + }, + params: { + placementId: 'test-placement' + } }, - params: { - placementId: 'test-placement' + { + bidId: 2, + mediaTypes: { + video: { + mimes: ['video/mp4'] + } + }, + params: { + placementId: 'test-placement' + } } - }] + ] }; - expectedBid = { - mediaType: 'banner', - requestId: 'imp-id', - seatBidId: '222209853178', - cpm: 1, - creative_id: 'creative-id', - creativeId: 'creative-id', - ttl: 300, - netRevenue: true, - ad: adm, - meta: {} - }; + expectedBids = [ + { + mediaType: 'banner', + requestId: 1, + cpm: 1, + creative_id: 1, + creativeId: 1, + ttl: 300, + netRevenue: true, + ad: bannerAdm, + meta: {} + }, + { + mediaType: 'video', + requestId: 2, + cpm: 1, + creative_id: 2, + creativeId: 2, + ttl: 300, + netRevenue: true, + vastXml: videoAdm, + meta: {} + }, + ]; bidRequest = spec.buildRequests(bidderRequest.bids, bidderRequest); }); it('pass on valid request', function () { const bids = spec.interpretResponse(bidderResponse, bidRequest); - assert.deepEqual(bids[0], expectedBid); + assert.deepEqual(bids[0], expectedBids[0]); + if (FEATURES.VIDEO) { + assert.deepEqual(bids[1], expectedBids[1]); + } }); it('fails on empty response', function () { diff --git a/test/spec/modules/kueezRtbBidAdapter_spec.js b/test/spec/modules/kueezRtbBidAdapter_spec.js index ebd11885af4..dd3ea4bfb2b 100644 --- a/test/spec/modules/kueezRtbBidAdapter_spec.js +++ b/test/spec/modules/kueezRtbBidAdapter_spec.js @@ -2,6 +2,14 @@ import {expect} from 'chai'; import { spec as adapter, createDomain, + storage +} from 'modules/kueezRtbBidAdapter.js'; +import * as utils from 'src/utils.js'; +import {version} from 'package.json'; +import {useFakeTimers} from 'sinon'; +import {BANNER, VIDEO} from '../../../src/mediaTypes'; +import {config} from '../../../src/config'; +import { hashCode, extractPID, extractCID, @@ -10,12 +18,7 @@ import { setStorageItem, tryParseJSON, getUniqueDealId, -} from 'modules/kueezRtbBidAdapter.js'; -import * as utils from 'src/utils.js'; -import {version} from 'package.json'; -import {useFakeTimers} from 'sinon'; -import {BANNER, VIDEO} from '../../../src/mediaTypes'; -import {config} from '../../../src/config'; +} from '../../../libraries/vidazooUtils/bidderUtils.js'; export const TEST_ID_SYSTEMS = ['britepoolid', 'criteoId', 'id5id', 'idl_env', 'lipb', 'netId', 'parrableId', 'pubcid', 'tdid', 'pubProvidedId']; @@ -322,7 +325,12 @@ describe('KueezRtbBidAdapter', function () { startdelay: 0 } }, - gpid: '' + gpid: '', + cat: [], + contentData: [], + isStorageAllowed: true, + pagecat: [], + userData: [] } }); }); @@ -384,6 +392,11 @@ describe('KueezRtbBidAdapter', function () { uqs: getTopWindowQueryParams(), 'ext.param1': 'loremipsum', 'ext.param2': 'dolorsitamet', + cat: [], + contentData: [], + isStorageAllowed: true, + pagecat: [], + userData: [] } }); }); @@ -526,8 +539,6 @@ describe('KueezRtbBidAdapter', function () { switch (idSystemProvider) { case 'lipb': return {lipbid: id}; - case 'parrableId': - return {eid: id}; case 'id5id': return {uid: id}; default: @@ -580,13 +591,13 @@ describe('KueezRtbBidAdapter', function () { const key = 'myKey'; let uniqueDealId; beforeEach(() => { - uniqueDealId = getUniqueDealId(key, 0); + uniqueDealId = getUniqueDealId(storage, key, 0); }) it('should get current unique deal id', function (done) { // waiting some time so `now` will become past setTimeout(() => { - const current = getUniqueDealId(key); + const current = getUniqueDealId(storage, key); expect(current).to.be.equal(uniqueDealId); done(); }, 200); @@ -594,7 +605,7 @@ describe('KueezRtbBidAdapter', function () { it('should get new unique deal id on expiration', function (done) { setTimeout(() => { - const current = getUniqueDealId(key, 100); + const current = getUniqueDealId(storage, key, 100); expect(current).to.not.be.equal(uniqueDealId); done(); }, 200) @@ -618,8 +629,8 @@ describe('KueezRtbBidAdapter', function () { shouldAdvanceTime: true, now }); - setStorageItem('myKey', 2020); - const {value, created} = getStorageItem('myKey'); + setStorageItem(storage, 'myKey', 2020); + const {value, created} = getStorageItem(storage, 'myKey'); expect(created).to.be.equal(now); expect(value).to.be.equal(2020); expect(typeof value).to.be.equal('number'); @@ -630,7 +641,7 @@ describe('KueezRtbBidAdapter', function () { it('should get external stored value', function () { const value = 'superman' window.localStorage.setItem('myExternalKey', value); - const item = getStorageItem('myExternalKey'); + const item = getStorageItem(storage, 'myExternalKey'); expect(item).to.be.equal(value); }); diff --git a/test/spec/modules/mediagoBidAdapter_spec.js b/test/spec/modules/mediagoBidAdapter_spec.js index 6e58217b3d3..5a1545ae028 100644 --- a/test/spec/modules/mediagoBidAdapter_spec.js +++ b/test/spec/modules/mediagoBidAdapter_spec.js @@ -3,14 +3,11 @@ import { spec, getPmgUID, storage, - getPageTitle, - getPageDescription, - getPageKeywords, - getConnectionDownLink, THIRD_PARTY_COOKIE_ORIGIN, COOKIE_KEY_MGUID, getCurrentTimeToUTCString } from 'modules/mediagoBidAdapter.js'; +import { getPageTitle, getPageDescription, getPageKeywords, getConnectionDownLink } from '../../../libraries/fpdUtils/pageInfo.js'; import * as utils from 'src/utils.js'; describe('mediago:BidAdapterTests', function () { @@ -260,43 +257,43 @@ describe('mediago:BidAdapterTests', function () { expect(bid.height).to.equal(250); expect(bid.currency).to.equal('USD'); }); +}); - describe('mediago: getUserSyncs', function() { - const COOKY_SYNC_IFRAME_URL = 'https://cdn.mediago.io/js/cookieSync.html'; - const IFRAME_ENABLED = { - iframeEnabled: true, - pixelEnabled: false, - }; - const IFRAME_DISABLED = { - iframeEnabled: false, - pixelEnabled: false, - }; - const GDPR_CONSENT = { - consentString: 'gdprConsentString', - gdprApplies: true - }; - const USP_CONSENT = { - consentString: 'uspConsentString' +describe('mediago: getUserSyncs', function() { + const COOKY_SYNC_IFRAME_URL = 'https://cdn.mediago.io/js/cookieSync.html'; + const IFRAME_ENABLED = { + iframeEnabled: true, + pixelEnabled: false, + }; + const IFRAME_DISABLED = { + iframeEnabled: false, + pixelEnabled: false, + }; + const GDPR_CONSENT = { + consentString: 'gdprConsentString', + gdprApplies: true + }; + const USP_CONSENT = { + consentString: 'uspConsentString' + } + + let syncParamUrl = `dm=${encodeURIComponent(location.origin || `https://${location.host}`)}`; + syncParamUrl += '&gdpr=1&gdpr_consent=gdprConsentString&ccpa_consent=uspConsentString'; + const expectedIframeSyncs = [ + { + type: 'iframe', + url: `${COOKY_SYNC_IFRAME_URL}?${syncParamUrl}` } + ]; - let syncParamUrl = `dm=${encodeURIComponent(location.origin || `https://${location.host}`)}`; - syncParamUrl += '&gdpr=1&gdpr_consent=gdprConsentString&ccpa_consent=uspConsentString'; - const expectedIframeSyncs = [ - { - type: 'iframe', - url: `${COOKY_SYNC_IFRAME_URL}?${syncParamUrl}` - } - ]; - - it('should return nothing if iframe is disabled', () => { - const userSyncs = spec.getUserSyncs(IFRAME_DISABLED, undefined, GDPR_CONSENT, USP_CONSENT, undefined); - expect(userSyncs).to.be.undefined; - }); + it('should return nothing if iframe is disabled', () => { + const userSyncs = spec.getUserSyncs(IFRAME_DISABLED, undefined, GDPR_CONSENT, USP_CONSENT, undefined); + expect(userSyncs).to.be.undefined; + }); - it('should do userSyncs if iframe is enabled', () => { - const userSyncs = spec.getUserSyncs(IFRAME_ENABLED, undefined, GDPR_CONSENT, USP_CONSENT, undefined); - expect(userSyncs).to.deep.equal(expectedIframeSyncs); - }); + it('should do userSyncs if iframe is enabled', () => { + const userSyncs = spec.getUserSyncs(IFRAME_ENABLED, undefined, GDPR_CONSENT, USP_CONSENT, undefined); + expect(userSyncs).to.deep.equal(expectedIframeSyncs); }); }); diff --git a/test/spec/modules/medianetBidAdapter_spec.js b/test/spec/modules/medianetBidAdapter_spec.js index bdfc86e7148..d3eab769f4a 100644 --- a/test/spec/modules/medianetBidAdapter_spec.js +++ b/test/spec/modules/medianetBidAdapter_spec.js @@ -1,7 +1,8 @@ import {expect, assert} from 'chai'; -import {spec} from 'modules/medianetBidAdapter.js'; +import {spec, EVENT_PIXEL_URL, EVENTS} from 'modules/medianetBidAdapter.js'; import { makeSlot } from '../integration/faker/googletag.js'; import { config } from 'src/config.js'; +import {server} from '../../mocks/xhr.js'; $$PREBID_GLOBAL$$.version = $$PREBID_GLOBAL$$.version || 'version'; let VALID_BID_REQUEST = [{ @@ -264,6 +265,72 @@ let VALID_BID_REQUEST = [{ 'auctionId': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', 'bidRequestsCount': 1 }], + VALID_BID_REQUEST_WITH_USERIDASEIDS = [{ + 'bidder': 'medianet', + 'params': { + 'crid': 'crid', + 'cid': 'customer_id', + 'site': { + 'page': 'http://media.net/prebidtest', + 'domain': 'media.net', + 'ref': 'http://media.net/prebidtest', + 'isTop': true + } + }, + userIdAsEids: [{ + 'source': 'criteo.com', + 'uids': [ + { + 'id': 'VZME3l9ycFFORncwaGJRVUNtUzB1UVhpWVd5TElrR3A5SHVSWXAwSFVPJTJCWiUyRnV2UTBPWjZOZ1ZrWnN4SldxcWUlMkJhUnFmUVNzUVg4N1NsdW84SGpUU1BsUllQSnN5bERMdFdPM2pWVXAlMkZVSSUyQkZsJTJGcktlenpZaHp0YXlvU25INWRQQ2tXciUyRk9PQmdac3RHeG9adDNKVzlRWE51ZyUzRCUzRA', + 'atype': 1 + } + ] + } + ], + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + ortb2Imp: { + ext: { + tid: '277b631f-92f5-4844-8b19-ea13c095d3f1', + } + }, + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250]], + } + }, + 'bidId': '28f8f8130a583e', + 'bidderRequestId': '1e9b1f07797c1c', + 'auctionId': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', + 'bidRequestsCount': 1 + }, { + 'bidder': 'medianet', + 'params': { + 'crid': 'crid', + 'cid': 'customer_id', + 'site': { + 'page': 'http://media.net/prebidtest', + 'domain': 'media.net', + 'ref': 'http://media.net/prebidtest', + 'isTop': true + } + }, + 'adUnitCode': 'div-gpt-ad-1460505748561-123', + ortb2Imp: { + ext: { + tid: 'c52a5c62-3c2b-4b90-9ff8-ec1487754822', + } + }, + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 251]], + } + }, + 'sizes': [[300, 251]], + 'bidId': '3f97ca71b1e5c2', + 'bidderRequestId': '1e9b1f07797c1c', + 'auctionId': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', + 'bidRequestsCount': 1 + }], VALID_BID_REQUEST_INVALID_BIDFLOOR = [{ 'bidder': 'medianet', @@ -457,7 +524,7 @@ let VALID_BID_REQUEST = [{ }, 'ext': { 'customer_id': 'customer_id', - 'prebid_version': $$PREBID_GLOBAL$$.version, + 'prebid_version': 'v' + '$prebid.version$', 'gdpr_applies': false, 'usp_applies': false, 'coppa_applies': false, @@ -535,6 +602,7 @@ let VALID_BID_REQUEST = [{ } } }], + 'ortb2': {}, 'tmax': config.getConfig('bidderTimeout') }, VALID_PAYLOAD_NATIVE = { @@ -547,7 +615,7 @@ let VALID_BID_REQUEST = [{ }, 'ext': { 'customer_id': 'customer_id', - 'prebid_version': $$PREBID_GLOBAL$$.version, + 'prebid_version': 'v' + '$prebid.version$', 'gdpr_applies': false, 'usp_applies': false, 'coppa_applies': false, @@ -626,6 +694,7 @@ let VALID_BID_REQUEST = [{ } } }], + 'ortb2': {}, 'tmax': config.getConfig('bidderTimeout') }, VALID_PAYLOAD = { @@ -638,7 +707,7 @@ let VALID_BID_REQUEST = [{ }, 'ext': { 'customer_id': 'customer_id', - 'prebid_version': $$PREBID_GLOBAL$$.version, + 'prebid_version': 'v' + '$prebid.version$', 'gdpr_applies': false, 'usp_applies': false, 'coppa_applies': false, @@ -715,6 +784,7 @@ let VALID_BID_REQUEST = [{ } } }], + 'ortb2': {}, 'tmax': config.getConfig('bidderTimeout') }, VALID_PAYLOAD_WITH_USERID = { @@ -727,7 +797,7 @@ let VALID_BID_REQUEST = [{ }, 'ext': { 'customer_id': 'customer_id', - 'prebid_version': $$PREBID_GLOBAL$$.version, + 'prebid_version': 'v' + '$prebid.version$', 'gdpr_applies': false, 'user_id': { britepoolid: '82efd5e1-816b-4f87-97f8-044f407e2911' @@ -811,6 +881,114 @@ let VALID_BID_REQUEST = [{ } } }], + 'ortb2': {}, + 'tmax': config.getConfig('bidderTimeout') + }, + VALID_PAYLOAD_WITH_USERIDASEIDS = { + 'site': { + 'page': 'http://media.net/prebidtest', + 'domain': 'media.net', + 'ref': 'http://media.net/prebidtest', + 'topMostLocation': 'http://media.net/topmost', + 'isTop': true + }, + 'ext': { + 'customer_id': 'customer_id', + 'prebid_version': 'v' + '$prebid.version$', + 'gdpr_applies': false, + 'usp_applies': false, + 'coppa_applies': false, + 'screen': { + 'w': 1000, + 'h': 1000 + } + }, + 'id': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', + 'imp': [{ + 'id': '28f8f8130a583e', + ortb2Imp: VALID_BID_REQUEST_WITH_USERID[0].ortb2Imp, + 'transactionId': '277b631f-92f5-4844-8b19-ea13c095d3f1', + 'tagid': 'crid', + 'ext': { + 'dfp_id': 'div-gpt-ad-1460505748561-0', + 'visibility': 1, + 'viewability': 1, + 'coordinates': { + 'top_left': { + x: 50, + y: 50 + }, + 'bottom_right': { + x: 100, + y: 100 + } + }, + 'display_count': 1 + }, + 'banner': [{ + 'w': 300, + 'h': 250 + }], + 'all': { + 'cid': 'customer_id', + 'crid': 'crid', + 'site': { + 'page': 'http://media.net/prebidtest', + 'domain': 'media.net', + 'ref': 'http://media.net/prebidtest', + 'isTop': true + } + } + }, { + 'id': '3f97ca71b1e5c2', + ortb2Imp: VALID_BID_REQUEST_WITH_USERID[1].ortb2Imp, + 'transactionId': 'c52a5c62-3c2b-4b90-9ff8-ec1487754822', + 'tagid': 'crid', + 'ext': { + 'dfp_id': 'div-gpt-ad-1460505748561-123', + 'visibility': 1, + 'viewability': 1, + 'coordinates': { + 'top_left': { + x: 50, + y: 50 + }, + 'bottom_right': { + x: 100, + y: 100 + } + }, + 'display_count': 1 + }, + 'banner': [{ + 'w': 300, + 'h': 251 + }], + 'all': { + 'cid': 'customer_id', + 'crid': 'crid', + 'site': { + 'page': 'http://media.net/prebidtest', + 'domain': 'media.net', + 'ref': 'http://media.net/prebidtest', + 'isTop': true + } + } + }], + 'ortb2': { + 'user': { + 'ext': { + 'eids': [{ + 'source': 'criteo.com', + 'uids': [{ + 'id': 'VZME3l9ycFFORncwaGJRVUNtUzB1UVhpWVd5TElrR3A5SHVSWXAwSFVPJTJCWiUyRnV2UTBPWjZOZ1ZrWnN4SldxcWUlMkJhUnFmUVNzUVg4N1NsdW84SGpUU1BsUllQSnN5bERMdFdPM2pWVXAlMkZVSSUyQkZsJTJGcktlenpZaHp0YXlvU25INWRQQ2tXciUyRk9PQmdac3RHeG9adDNKVzlRWE51ZyUzRCUzRA', + 'atype': 1 + } + ] + }] + } + }, + }, 'tmax': config.getConfig('bidderTimeout') }, VALID_PAYLOAD_WITH_CRID = { @@ -823,7 +1001,7 @@ let VALID_BID_REQUEST = [{ }, 'ext': { 'customer_id': 'customer_id', - 'prebid_version': $$PREBID_GLOBAL$$.version, + 'prebid_version': 'v' + '$prebid.version$', 'gdpr_applies': false, 'usp_applies': false, 'coppa_applies': true, @@ -904,6 +1082,7 @@ let VALID_BID_REQUEST = [{ } } }], + 'ortb2': {}, 'tmax': config.getConfig('bidderTimeout') }, // Protected Audience API Valid Payload @@ -917,7 +1096,7 @@ let VALID_BID_REQUEST = [{ }, 'ext': { 'customer_id': 'customer_id', - 'prebid_version': $$PREBID_GLOBAL$$.version, + 'prebid_version': 'v' + '$prebid.version$', 'gdpr_applies': false, 'usp_applies': false, 'coppa_applies': false, @@ -973,6 +1152,7 @@ let VALID_BID_REQUEST = [{ 'tagid': 'crid' } ], + 'ortb2': {}, 'tmax': 3000 }, @@ -1451,7 +1631,7 @@ let VALID_BID_REQUEST = [{ }, 'ext': { 'customer_id': 'customer_id', - 'prebid_version': $$PREBID_GLOBAL$$.version, + 'prebid_version': 'v' + '$prebid.version$', 'gdpr_consent_string': 'consentString', 'gdpr_applies': true, 'usp_applies': true, @@ -1530,6 +1710,7 @@ let VALID_BID_REQUEST = [{ } } }], + 'ortb2': {}, 'tmax': 3000, }, VALID_BIDDER_REQUEST_WITH_GPP_IN_ORTB2 = { @@ -1559,7 +1740,7 @@ let VALID_BID_REQUEST = [{ }, 'ext': { 'customer_id': 'customer_id', - 'prebid_version': $$PREBID_GLOBAL$$.version, + 'prebid_version': 'v' + '$prebid.version$', 'gdpr_applies': false, 'usp_applies': false, 'coppa_applies': false, @@ -1767,6 +1948,11 @@ describe('Media.net bid adapter', function () { expect(JSON.parse(bidReq.data)).to.deep.equal(VALID_PAYLOAD_WITH_USERID); }); + it('should have userIdAsEids in bid request', function () { + let bidReq = spec.buildRequests(VALID_BID_REQUEST_WITH_USERIDASEIDS, VALID_AUCTIONDATA); + expect(JSON.parse(bidReq.data)).to.deep.equal(VALID_PAYLOAD_WITH_USERIDASEIDS); + }); + it('should have valid payload when PAAPI is enabled', function () { let bidReq = spec.buildRequests(VALID_BID_REQUEST_WITH_AE_IN_ORTB2IMP, {...VALID_AUCTIONDATA, paapi: {enabled: true}}); expect(JSON.parse(bidReq.data)).to.deep.equal(VALID_PAYLOAD_PAAPI); @@ -1782,7 +1968,7 @@ describe('Media.net bid adapter', function () { describe('build requests: when page meta-data is available', () => { beforeEach(() => { - spec.clearMnData(); + spec.clearPageMeta(); }); it('should pass canonical, twitter and fb paramters if available', () => { let documentStub = sandbox.stub(window.top.document, 'querySelector'); @@ -1983,16 +2169,111 @@ describe('Media.net bid adapter', function () { }); describe('onTimeout', function () { - it('should have valid timeout data', function() { - let response = spec.onTimeout({}); - expect(response).to.deep.equal(undefined); + it('onTimeout exist as a function', () => { + assert.typeOf(spec.onTimeout, 'function'); + }); + it('should send timeout data correctly', function () { + const timeoutData = [{ + bidder: 'medianet', + bidId: 'mnet-4644-442a-b5e0-93f268cf8d19', + adUnitCode: 'adUnit-code', + timeout: 3000, + auctionId: '12a34b56c' + }]; + sandbox.stub(window.navigator, 'sendBeacon').returns(false); + + spec.onTimeout(timeoutData); + const reqBody = new URLSearchParams(server.requests[0].requestBody); + + assert.equal(server.requests[0].method, 'POST'); + assert.equal(server.requests[0].url, EVENT_PIXEL_URL); + assert.equal(reqBody.get('event'), EVENTS.TIMEOUT_EVENT_NAME); + assert.equal(reqBody.get('rd'), timeoutData[0].timeout.toString()); + assert.equal(reqBody.get('acid[]'), timeoutData[0].auctionId); }); }); describe('onBidWon', function () { - it('should have valid bid data', function() { - let response = spec.onBidWon(undefined); - expect(response).to.deep.equal(undefined); + it('onBidWon exist as a function', () => { + assert.typeOf(spec.onBidWon, 'function'); + }); + it('should send winning bid data correctly', function () { + const bid = { + bidder: 'medianet', + bidId: 'mnet-4644-442a-b5e0-93f268cf8d19', + adUnitCode: 'adUnit-code', + timeout: 3000, + auctionId: '12a34b56c', + cpm: 12.24 + }; + sandbox.stub(window.navigator, 'sendBeacon').returns(false); + + spec.onBidWon(bid); + const reqBody = new URLSearchParams(server.requests[0].requestBody); + + assert.equal(server.requests[0].method, 'POST'); + assert.equal(server.requests[0].url, EVENT_PIXEL_URL); + assert.equal(reqBody.get('event'), EVENTS.BID_WON_EVENT_NAME); + assert.equal(reqBody.get('value'), bid.cpm.toString()); + assert.equal(reqBody.get('acid[]'), bid.auctionId); + }); + }); + + describe('onSetTargeting', function () { + it('onSetTargeting exist as a function', () => { + assert.typeOf(spec.onSetTargeting, 'function'); + }); + it('should send targeting data correctly', function () { + const bid = { + bidder: 'medianet', + bidId: 'mnet-4644-442a-b5e0-93f268cf8d19', + adUnitCode: 'adUnit-code', + timeout: 3000, + auctionId: '12a34b56c', + cpm: 12.24 + }; + sandbox.stub(window.navigator, 'sendBeacon').returns(false); + sandbox.stub(config, 'getConfig').withArgs('enableSendAllBids').returns(false); + + spec.onSetTargeting(bid); + const reqBody = new URLSearchParams(server.requests[0].requestBody); + + assert.equal(server.requests[0].method, 'POST'); + assert.equal(server.requests[0].url, EVENT_PIXEL_URL); + assert.equal(reqBody.get('event'), EVENTS.SET_TARGETING); + assert.equal(reqBody.get('value'), bid.cpm.toString()); + assert.equal(reqBody.get('acid[]'), bid.auctionId); + }); + }); + + describe('onBidderError', function () { + it('onBidderError exist as a function', () => { + assert.typeOf(spec.onBidderError, 'function'); + }); + it('should send bidderError data correctly', function () { + const error = { + reason: {message: 'Failed to fetch', status: 500}, + timedOut: true, + status: 0 + } + const bids = [{ + bidder: 'medianet', + bidId: 'mnet-4644-442a-b5e0-93f268cf8d19', + adUnitCode: 'adUnit-code', + timeout: 3000, + auctionId: '12a34b56c', + cpm: 12.24 + }]; + sandbox.stub(window.navigator, 'sendBeacon').returns(false); + + spec.onBidderError({error, bidderRequest: {bids}}); + const reqBody = new URLSearchParams(server.requests[0].requestBody); + + assert.equal(server.requests[0].method, 'POST'); + assert.equal(server.requests[0].url, EVENT_PIXEL_URL); + assert.equal(reqBody.get('event'), EVENTS.BIDDER_ERROR); + assert.equal(reqBody.get('rd'), `timedOut:${error.timedOut}|status:${error.status}|message:${error.reason.message}`); + assert.equal(reqBody.get('acid[]'), bids[0].auctionId); }); }); diff --git a/test/spec/modules/mgidBidAdapter_spec.js b/test/spec/modules/mgidBidAdapter_spec.js index f9bb1fb91e1..180b0dc723e 100644 --- a/test/spec/modules/mgidBidAdapter_spec.js +++ b/test/spec/modules/mgidBidAdapter_spec.js @@ -320,6 +320,14 @@ describe('Mgid bid adapter', function () { let abid = { adUnitCode: 'div', bidder: 'mgid', + ortb2Imp: { + ext: { + gpid: '/1111/gpid', + data: { + pbadslot: '/1111/gpid', + } + } + }, params: { accountId: '1', placementId: '2', @@ -447,12 +455,13 @@ describe('Mgid bid adapter', function () { expect(data.device.w).equal(screenWidth); expect(data.device.language).to.deep.equal(lang); expect(data.imp[0].tagid).to.deep.equal('2/div'); + expect(data.imp[0].ext.gpid).to.deep.equal('/1111/gpid'); expect(data.imp[0].banner).to.deep.equal({w: 300, h: 250}); expect(data.imp[0].secure).to.deep.equal(secure); expect(request).to.deep.equal({ 'method': 'POST', 'url': 'https://prebid.mgid.com/prebid/1', - 'data': `{"site":{"domain":"${domain}","page":"${page}"},"cur":["USD"],"geo":{"utcoffset":${utcOffset}},"device":{"ua":"${ua}","js":1,"dnt":${dnt},"h":${screenHeight},"w":${screenWidth},"language":"${lang}"},"ext":{"mgid_ver":"${mgid_ver}","prebid_ver":"${version}"},"imp":[{"tagid":"2/div","secure":${secure},"banner":{"w":300,"h":250}}],"tmax":3000}`, + 'data': `{"site":{"domain":"${domain}","page":"${page}"},"cur":["USD"],"geo":{"utcoffset":${utcOffset}},"device":{"ua":"${ua}","js":1,"dnt":${dnt},"h":${screenHeight},"w":${screenWidth},"language":"${lang}"},"ext":{"mgid_ver":"${mgid_ver}","prebid_ver":"${version}"},"imp":[{"tagid":"2/div","secure":${secure},"ext":{"gpid":"/1111/gpid"},"banner":{"w":300,"h":250}}],"tmax":3000}`, }); }); it('should not return native imp if minimum asset list not requested', function () { @@ -496,12 +505,13 @@ describe('Mgid bid adapter', function () { expect(data.device.w).equal(screenWidth); expect(data.device.language).to.deep.equal(lang); expect(data.imp[0].tagid).to.deep.equal('2/div'); + expect(data.imp[0].ext.gpid).to.deep.equal('/1111/gpid'); expect(data.imp[0].native).is.a('object').and.to.deep.equal({'request': {'assets': [{'id': 1, 'required': 1, 'title': {'len': 80}}, {'id': 2, 'img': {'h': 80, 'type': 3, 'w': 80}, 'required': 0}, {'data': {'type': 1}, 'id': 11, 'required': 0}], 'plcmtcnt': 1}}); expect(data.imp[0].secure).to.deep.equal(secure); expect(request).to.deep.equal({ 'method': 'POST', 'url': 'https://prebid.mgid.com/prebid/1', - 'data': `{"site":{"domain":"${domain}","page":"${page}"},"cur":["USD"],"geo":{"utcoffset":${utcOffset}},"device":{"ua":"${ua}","js":1,"dnt":${dnt},"h":${screenHeight},"w":${screenWidth},"language":"${lang}"},"ext":{"mgid_ver":"${mgid_ver}","prebid_ver":"${version}"},"imp":[{"tagid":"2/div","secure":${secure},"native":{"request":{"plcmtcnt":1,"assets":[{"id":1,"required":1,"title":{"len":80}},{"id":2,"required":0,"img":{"type":3,"w":80,"h":80}},{"id":11,"required":0,"data":{"type":1}}]}}}],"tmax":3000}`, + 'data': `{"site":{"domain":"${domain}","page":"${page}"},"cur":["USD"],"geo":{"utcoffset":${utcOffset}},"device":{"ua":"${ua}","js":1,"dnt":${dnt},"h":${screenHeight},"w":${screenWidth},"language":"${lang}"},"ext":{"mgid_ver":"${mgid_ver}","prebid_ver":"${version}"},"imp":[{"tagid":"2/div","secure":${secure},"ext":{"gpid":"/1111/gpid"},"native":{"request":{"plcmtcnt":1,"assets":[{"id":1,"required":1,"title":{"len":80}},{"id":2,"required":0,"img":{"type":3,"w":80,"h":80}},{"id":11,"required":0,"data":{"type":1}}]}}}],"tmax":3000}`, }); }); it('should return proper native imp with image altered', function () { @@ -538,7 +548,7 @@ describe('Mgid bid adapter', function () { expect(request).to.deep.equal({ 'method': 'POST', 'url': 'https://prebid.mgid.com/prebid/1', - 'data': `{"site":{"domain":"${domain}","page":"${page}"},"cur":["USD"],"geo":{"utcoffset":${utcOffset}},"device":{"ua":"${ua}","js":1,"dnt":${dnt},"h":${screenHeight},"w":${screenWidth},"language":"${lang}"},"ext":{"mgid_ver":"${mgid_ver}","prebid_ver":"${version}"},"imp":[{"tagid":"2/div","secure":${secure},"native":{"request":{"plcmtcnt":1,"assets":[{"id":1,"required":1,"title":{"len":80}},{"id":2,"required":1,"img":{"type":3,"w":492,"h":328,"wmin":50,"hmin":50}},{"id":3,"required":0,"img":{"type":1,"w":50,"h":50}},{"id":11,"required":0,"data":{"type":1}}]}}}],"tmax":3000}`, + 'data': `{"site":{"domain":"${domain}","page":"${page}"},"cur":["USD"],"geo":{"utcoffset":${utcOffset}},"device":{"ua":"${ua}","js":1,"dnt":${dnt},"h":${screenHeight},"w":${screenWidth},"language":"${lang}"},"ext":{"mgid_ver":"${mgid_ver}","prebid_ver":"${version}"},"imp":[{"tagid":"2/div","secure":${secure},"ext":{"gpid":"/1111/gpid"},"native":{"request":{"plcmtcnt":1,"assets":[{"id":1,"required":1,"title":{"len":80}},{"id":2,"required":1,"img":{"type":3,"w":492,"h":328,"wmin":50,"hmin":50}},{"id":3,"required":0,"img":{"type":1,"w":50,"h":50}},{"id":11,"required":0,"data":{"type":1}}]}}}],"tmax":3000}`, }); }); it('should return proper native imp with sponsoredBy', function () { @@ -574,7 +584,7 @@ describe('Mgid bid adapter', function () { expect(request).to.deep.equal({ 'method': 'POST', 'url': 'https://prebid.mgid.com/prebid/1', - 'data': `{"site":{"domain":"${domain}","page":"${page}"},"cur":["USD"],"geo":{"utcoffset":${utcOffset}},"device":{"ua":"${ua}","js":1,"dnt":${dnt},"h":${screenHeight},"w":${screenWidth},"language":"${lang}"},"ext":{"mgid_ver":"${mgid_ver}","prebid_ver":"${version}"},"imp":[{"tagid":"2/div","secure":${secure},"native":{"request":{"plcmtcnt":1,"assets":[{"id":1,"required":1,"title":{"len":80}},{"id":2,"required":0,"img":{"type":3,"w":80,"h":80}},{"id":4,"required":0,"data":{"type":1}}]}}}],"tmax":3000}`, + 'data': `{"site":{"domain":"${domain}","page":"${page}"},"cur":["USD"],"geo":{"utcoffset":${utcOffset}},"device":{"ua":"${ua}","js":1,"dnt":${dnt},"h":${screenHeight},"w":${screenWidth},"language":"${lang}"},"ext":{"mgid_ver":"${mgid_ver}","prebid_ver":"${version}"},"imp":[{"tagid":"2/div","secure":${secure},"ext":{"gpid":"/1111/gpid"},"native":{"request":{"plcmtcnt":1,"assets":[{"id":1,"required":1,"title":{"len":80}},{"id":2,"required":0,"img":{"type":3,"w":80,"h":80}},{"id":4,"required":0,"data":{"type":1}}]}}}],"tmax":3000}`, }); }); it('should return proper banner request', function () { @@ -608,7 +618,7 @@ describe('Mgid bid adapter', function () { expect(request).to.deep.equal({ 'method': 'POST', 'url': 'https://prebid.mgid.com/prebid/1', - 'data': `{"site":{"domain":"${domain}","page":"${page}"},"cur":["USD"],"geo":{"utcoffset":${utcOffset}},"device":{"ua":"${ua}","js":1,"dnt":${dnt},"h":${screenHeight},"w":${screenWidth},"language":"${lang}"},"ext":{"mgid_ver":"${mgid_ver}","prebid_ver":"${version}"},"imp":[{"tagid":"2/div","secure":${secure},"banner":{"w":300,"h":600,"format":[{"w":300,"h":600},{"w":300,"h":250}],"pos":1}}],"tmax":3000}`, + 'data': `{"site":{"domain":"${domain}","page":"${page}"},"cur":["USD"],"geo":{"utcoffset":${utcOffset}},"device":{"ua":"${ua}","js":1,"dnt":${dnt},"h":${screenHeight},"w":${screenWidth},"language":"${lang}"},"ext":{"mgid_ver":"${mgid_ver}","prebid_ver":"${version}"},"imp":[{"tagid":"2/div","secure":${secure},"ext":{"gpid":"/1111/gpid"},"banner":{"w":300,"h":600,"format":[{"w":300,"h":600},{"w":300,"h":250}],"pos":1}}],"tmax":3000}`, }); }); it('should proper handle ortb2 data', function () { diff --git a/test/spec/modules/mobianRtdProvider_spec.js b/test/spec/modules/mobianRtdProvider_spec.js index 0b09f4fd0cd..6f7da8888fc 100644 --- a/test/spec/modules/mobianRtdProvider_spec.js +++ b/test/spec/modules/mobianRtdProvider_spec.js @@ -12,9 +12,7 @@ describe('Mobian RTD Submodule', function () { ortb2Fragments: { global: { site: { - ext: { - data: {} - } + ext: {} } } } @@ -27,81 +25,132 @@ describe('Mobian RTD Submodule', function () { it('should return no_risk when server responds with garm_no_risk', function () { ajaxStub = sinon.stub(ajax, 'ajaxBuilder').returns(function(url, callbacks) { - callbacks.success({ + callbacks.success(JSON.stringify({ garm_no_risk: true, garm_low_risk: false, garm_medium_risk: false, garm_high_risk: false - }); + })); }); return mobianBrandSafetySubmodule.getBidRequestData(bidReqConfig, {}, {}).then((risk) => { expect(risk).to.have.property('mobianGarmRisk'); - expect(risk['mobianGarmRisk']).to.equal('no_risk'); + expect(risk['mobianGarmRisk']).to.equal('none'); expect(bidReqConfig.ortb2Fragments.global.site.ext.data.mobian).to.deep.equal(risk); }); }); - it('should return low_risk when server responds with garm_no_risk', function () { + it('should return low_risk when server responds with garm_low_risk', function () { ajaxStub = sinon.stub(ajax, 'ajaxBuilder').returns(function(url, callbacks) { - callbacks.success({ + callbacks.success(JSON.stringify({ garm_no_risk: false, garm_low_risk: true, garm_medium_risk: false, garm_high_risk: false - }); + })); }); return mobianBrandSafetySubmodule.getBidRequestData(bidReqConfig, {}, {}).then((risk) => { expect(risk).to.have.property('mobianGarmRisk'); - expect(risk['mobianGarmRisk']).to.equal('low_risk'); + expect(risk['mobianGarmRisk']).to.equal('low'); expect(bidReqConfig.ortb2Fragments.global.site.ext.data.mobian).to.deep.equal(risk); }); }); it('should return medium_risk when server responds with garm_medium_risk', function () { ajaxStub = sinon.stub(ajax, 'ajaxBuilder').returns(function(url, callbacks) { - callbacks.success({ + callbacks.success(JSON.stringify({ garm_no_risk: false, garm_low_risk: false, garm_medium_risk: true, garm_high_risk: false - }); + })); }); return mobianBrandSafetySubmodule.getBidRequestData(bidReqConfig, {}, {}).then((risk) => { expect(risk).to.have.property('mobianGarmRisk'); - expect(risk['mobianGarmRisk']).to.equal('medium_risk'); + expect(risk['mobianGarmRisk']).to.equal('medium'); expect(bidReqConfig.ortb2Fragments.global.site.ext.data.mobian).to.deep.equal(risk); }); }); it('should return high_risk when server responds with garm_high_risk', function () { ajaxStub = sinon.stub(ajax, 'ajaxBuilder').returns(function(url, callbacks) { - callbacks.success({ + callbacks.success(JSON.stringify({ garm_no_risk: false, garm_low_risk: false, garm_medium_risk: false, garm_high_risk: true - }); + })); }); return mobianBrandSafetySubmodule.getBidRequestData(bidReqConfig, {}, {}).then((risk) => { expect(risk).to.have.property('mobianGarmRisk'); - expect(risk['mobianGarmRisk']).to.equal('high_risk'); + expect(risk['mobianGarmRisk']).to.equal('high'); expect(bidReqConfig.ortb2Fragments.global.site.ext.data.mobian).to.deep.equal(risk); }); }); - it('should return unknown when server response is not of the expected shape', function () { + it('should return empty object when server response is not valid JSON', function () { ajaxStub = sinon.stub(ajax, 'ajaxBuilder').returns(function(url, callbacks) { callbacks.success('unexpected output not even of the right type'); }); + const originalConfig = JSON.parse(JSON.stringify(bidReqConfig)); + return mobianBrandSafetySubmodule.getBidRequestData(bidReqConfig, {}, {}).then((risk) => { + expect(risk).to.deep.equal({}); + // Check that bidReqConfig hasn't been modified + expect(bidReqConfig).to.deep.equal(originalConfig); + }); + }); + + it('should handle response with direct garm_risk field', function () { + ajaxStub = sinon.stub(ajax, 'ajaxBuilder').returns(function(url, callbacks) { + callbacks.success(JSON.stringify({ + garm_risk: 'low', + sentiment_positive: true, + emotion_joy: true + })); + }); return mobianBrandSafetySubmodule.getBidRequestData(bidReqConfig, {}, {}).then((risk) => { - expect(risk).to.have.property('mobianGarmRisk'); - expect(risk['mobianGarmRisk']).to.equal('unknown'); - expect(bidReqConfig.ortb2Fragments.global.site.ext.data.mobian).to.deep.equal(risk); + expect(risk).to.deep.equal({ + mobianGarmRisk: 'low', + garmContentCategories: [], + sentiment: 'positive', + emotions: ['joy'] + }); + }); + }); + + it('should handle response with GARM content categories, sentiment, and emotions', function () { + ajaxStub = sinon.stub(ajax, 'ajaxBuilder').returns(function(url, callbacks) { + callbacks.success(JSON.stringify({ + garm_risk: 'medium', + garm_content_category_arms: true, + garm_content_category_crime: true, + sentiment_negative: true, + emotion_anger: true, + emotion_fear: true + })); + }); + + return mobianBrandSafetySubmodule.getBidRequestData(bidReqConfig, {}, {}).then((risk) => { + expect(risk).to.deep.equal({ + mobianGarmRisk: 'medium', + garmContentCategories: ['arms', 'crime'], + sentiment: 'negative', + emotions: ['anger', 'fear'] + }); + }); + }); + + it('should handle error response', function () { + ajaxStub = sinon.stub(ajax, 'ajaxBuilder').returns(function(url, callbacks) { + callbacks.error(); + }); + + return mobianBrandSafetySubmodule.getBidRequestData(bidReqConfig, {}, {}).then((risk) => { + expect(risk).to.deep.equal({}); }); }); }); diff --git a/test/spec/modules/nexx360BidAdapter_spec.js b/test/spec/modules/nexx360BidAdapter_spec.js index 06cbec347ff..48fa0e2a021 100644 --- a/test/spec/modules/nexx360BidAdapter_spec.js +++ b/test/spec/modules/nexx360BidAdapter_spec.js @@ -405,7 +405,7 @@ describe('Nexx360 bid adapter tests', function () { expect(requestContent.imp[1].tagid).to.be.eql('div-2-abcd'); expect(requestContent.imp[1].ext.adUnitCode).to.be.eql('div-2-abcd'); expect(requestContent.imp[1].ext.divId).to.be.eql('div-2-abcd'); - expect(requestContent.ext.bidderVersion).to.be.eql('4.1'); + expect(requestContent.ext.bidderVersion).to.be.eql('4.2'); expect(requestContent.ext.source).to.be.eql('prebid.js'); }); diff --git a/test/spec/modules/outbrainBidAdapter_spec.js b/test/spec/modules/outbrainBidAdapter_spec.js index 9825eb3ee79..5e9d76b59b9 100644 --- a/test/spec/modules/outbrainBidAdapter_spec.js +++ b/test/spec/modules/outbrainBidAdapter_spec.js @@ -65,6 +65,23 @@ describe('Outbrain Adapter', function () { } } + const ortb2WithDeviceData = { + ortb2: { + device: { + w: 980, + h: 1720, + dnt: 0, + ua: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/125.0.6422.80 Mobile/15E148 Safari/604.1', + language: 'en', + devicetype: 1, + make: 'Apple', + model: 'iPhone 12 Pro Max', + os: 'iOS', + osv: '17.4' + } + } + }; + describe('isBidRequestValid', function () { before(() => { config.setConfig({ @@ -390,7 +407,8 @@ describe('Outbrain Adapter', function () { minduration: 3, maxduration: 10, startdelay: 2, - placement: 4, + placement: 5, + plcmt: 4, linearity: 1 } } @@ -620,6 +638,19 @@ describe('Outbrain Adapter', function () { const resData = JSON.parse(res.data) expect(resData.imp[0].native.request).to.equal(JSON.stringify(expectedNativeAssets)); }); + + it('should pass ortb2 device data', function () { + const bidRequest = { + ...commonBidRequest, + ...nativeBidRequestParams, + }; + + const res = spec.buildRequests( + [bidRequest], + {...commonBidderRequest, ...ortb2WithDeviceData}, + ); + expect(JSON.parse(res.data).device).to.deep.equal(ortb2WithDeviceData.ortb2.device); + }); }) describe('interpretResponse', function () { diff --git a/test/spec/modules/ownadxBidAdapter_spec.js b/test/spec/modules/ownadxBidAdapter_spec.js new file mode 100644 index 00000000000..13d69b3a261 --- /dev/null +++ b/test/spec/modules/ownadxBidAdapter_spec.js @@ -0,0 +1,103 @@ +import { expect } from 'chai'; +import { spec } from 'modules/ownadxBidAdapter.js'; + +describe('ownadx', function () { + const METHOD = 'POST'; + const URL = 'https://pbs-js.prebid-ownadx.com/publisher/prebid/9/1231?token=3f2941af4f7e446f9a19ca6045f8cff4'; + + const bidRequest = { + bidder: 'ownadx', + params: { + tokenId: '3f2941af4f7e446f9a19ca6045f8cff4', + sspId: '1231', + seatId: '9' + }, + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]] + } + }, + sizes: [ + [300, 250], + [300, 600] + ], + bidId: 'bid-id-123456', + adUnitCode: 'ad-unit-code-1', + bidderRequestId: 'bidder-request-id-123456', + auctionId: 'auction-id-123456', + transactionId: 'transaction-id-123456' + }; + + describe('isBidRequestValid', function () { + it('should return true where required params found', function () { + expect(spec.isBidRequestValid(bidRequest)).to.equal(true); + }); + }); + + describe('buildRequests', function () { + let bidderRequest = { + refererInfo: { + page: 'https://www.test.com', + reachedTop: true, + isAmp: false, + numIframes: 0, + stack: [ + 'https://www.test.com' + ], + canonicalUrl: null + } + }; + + it('should build correct POST request for banner bid', function () { + const request = spec.buildRequests([bidRequest], bidderRequest)[0]; + expect(request).to.be.an('object'); + expect(request.method).to.equal('POST'); + expect(request.url).to.equal('https://pbs-js.prebid-ownadx.com/publisher/prebid/9/1231?token=3f2941af4f7e446f9a19ca6045f8cff4'); + const payload = request.data; + expect(payload).to.be.an('object'); + expect(payload.sizes).to.be.an('array'); + expect(payload.slotBidId).to.be.a('string'); + expect(payload.PageUrl).to.be.a('string'); + expect(payload.mediaChannel).to.be.a('number'); + }); + }); + + describe('interpretResponse', function () { + let serverResponse = { + body: { + tokenId: '3f2941af4f7e446f9a19ca6045f8cff4', + bid: 'BID-XXXX-XXXX', + width: '300', + height: '250', + cpm: '0.7', + adm: '

Ad from OwnAdX

', + slotBidId: 'bid-id-123456', + adType: '1', + statusText: 'Success' + } + }; + + let expectedResponse = [{ + token: '3f2941af4f7e446f9a19ca6045f8cff4', + requestId: 'bid-id-123456', + cpm: '0.7', + currency: 'USD', + aType: '1', + netRevenue: false, + width: '300', + height: '250', + creativeId: 0, + ttl: 300, + ad: '

Ad from OwnAdX

', + meta: { + mediaType: 'banner', + advertiserDomains: [] + } + }]; + + it('should correctly interpret valid banner response', function () { + let result = spec.interpretResponse(serverResponse); + expect(result).to.deep.equal(expectedResponse); + }); + }); +}); diff --git a/test/spec/modules/paapi_spec.js b/test/spec/modules/paapi_spec.js index 77c8a6d7dda..cc839307c8e 100644 --- a/test/spec/modules/paapi_spec.js +++ b/test/spec/modules/paapi_spec.js @@ -7,7 +7,7 @@ import {hook} from '../../../src/hook.js'; import 'modules/appnexusBidAdapter.js'; import 'modules/rubiconBidAdapter.js'; import { - addPaapiConfigHook, + addPaapiConfigHook, addPaapiData, buyersToAuctionConfigs, getPAAPIConfig, getPAAPISize, @@ -652,110 +652,171 @@ describe('paapi module', () => { config.resetConfig(); }); - function mark() { - return Object.fromEntries( - adapterManager.makeBidRequests( - adUnits, - Date.now(), - utils.getUniqueIdentifierStr(), - function callback() { - }, - [] - ).map(b => [b.bidderCode, b]) - ); - } - - function expectFledgeFlags(...enableFlags) { - const bidRequests = mark(); - expect(bidRequests.appnexus.paapi?.enabled).to.eql(enableFlags[0].enabled); - bidRequests.appnexus.bids.forEach(bid => expect(bid.ortb2Imp.ext.ae).to.eql(enableFlags[0].ae)); + describe('makeBidRequests', () => { + function mark() { + return Object.fromEntries( + adapterManager.makeBidRequests( + adUnits, + Date.now(), + utils.getUniqueIdentifierStr(), + function callback() { + }, + [] + ).map(b => [b.bidderCode, b]) + ); + } - expect(bidRequests.rubicon.paapi?.enabled).to.eql(enableFlags[1].enabled); - bidRequests.rubicon.bids.forEach(bid => expect(bid.ortb2Imp?.ext?.ae).to.eql(enableFlags[1].ae)); + function expectFledgeFlags(...enableFlags) { + const bidRequests = mark(); + expect(bidRequests.appnexus.paapi?.enabled).to.eql(enableFlags[0].enabled); + bidRequests.appnexus.bids.forEach(bid => expect(bid.ortb2Imp.ext.ae).to.eql(enableFlags[0].ae)); - Object.values(bidRequests).flatMap(req => req.bids).forEach(bid => { - if (bid.ortb2Imp?.ext?.ae) { - sinon.assert.match(bid.ortb2Imp.ext.igs, { - ae: bid.ortb2Imp.ext.ae, - biddable: 1 - }); - } - }); - } + expect(bidRequests.rubicon.paapi?.enabled).to.eql(enableFlags[1].enabled); + bidRequests.rubicon.bids.forEach(bid => expect(bid.ortb2Imp?.ext?.ae).to.eql(enableFlags[1].ae)); - describe('with setConfig()', () => { - it('should set paapi.enabled correctly per bidder', function () { - config.setConfig({ - bidderSequence: 'fixed', - paapi: { - enabled: true, - bidders: ['appnexus'], - defaultForSlots: 1, + Object.values(bidRequests).flatMap(req => req.bids).forEach(bid => { + if (bid.ortb2Imp?.ext?.ae) { + sinon.assert.match(bid.ortb2Imp.ext.igs, { + ae: bid.ortb2Imp.ext.ae, + biddable: 1 + }); } }); - expectFledgeFlags({enabled: true, ae: 1}, {enabled: false, ae: undefined}); - }); + } - it('should set paapi.enabled correctly for all bidders', function () { - config.setConfig({ - bidderSequence: 'fixed', - paapi: { - enabled: true, - defaultForSlots: 1, - } + describe('with setConfig()', () => { + it('should set paapi.enabled correctly per bidder', function () { + config.setConfig({ + bidderSequence: 'fixed', + paapi: { + enabled: true, + bidders: ['appnexus'], + defaultForSlots: 1, + } + }); + expectFledgeFlags({enabled: true, ae: 1}, {enabled: false, ae: 0}); }); - expectFledgeFlags({enabled: true, ae: 1}, {enabled: true, ae: 1}); - }); - Object.entries({ - 'not set': { - cfg: {}, - componentSeller: false - }, - 'set': { - cfg: { - componentSeller: { - auctionConfig: { - decisionLogicURL: 'publisher.example' - } - } - }, - componentSeller: true - } - }).forEach(([t, {cfg, componentSeller}]) => { - it(`should set request paapi.componentSeller = ${componentSeller} when config componentSeller is ${t}`, () => { + it('should set paapi.enabled correctly for all bidders', function () { config.setConfig({ + bidderSequence: 'fixed', paapi: { enabled: true, defaultForSlots: 1, - ...cfg } }); - Object.values(mark()).forEach(br => expect(br.paapi?.componentSeller).to.eql(componentSeller)); + expectFledgeFlags({enabled: true, ae: 1}, {enabled: true, ae: 1}); + }); + + Object.entries({ + 'not set': { + cfg: {}, + componentSeller: false + }, + 'set': { + cfg: { + componentSeller: { + auctionConfig: { + decisionLogicURL: 'publisher.example' + } + } + }, + componentSeller: true + } + }).forEach(([t, {cfg, componentSeller}]) => { + it(`should set request paapi.componentSeller = ${componentSeller} when config componentSeller is ${t}`, () => { + config.setConfig({ + paapi: { + enabled: true, + defaultForSlots: 1, + ...cfg + } + }); + Object.values(mark()).forEach(br => expect(br.paapi?.componentSeller).to.eql(componentSeller)); + }); }); }); + }); + describe('addPaapiData', () => { + function getEnrichedAdUnits() { + const next = sinon.stub(); + addPaapiData(next, adUnits); + sinon.assert.calledWith(next, adUnits); + return adUnits; + } + + function getImpExt() { + const next = sinon.stub(); + addPaapiData(next, adUnits); + sinon.assert.calledWith(next, adUnits); + return { + global: adUnits[0].ortb2Imp?.ext, + ...Object.fromEntries(adUnits[0].bids.map(bid => [bid.bidder, bid.ortb2Imp?.ext])) + } + } it('should not override pub-defined ext.ae', () => { config.setConfig({ - bidderSequence: 'fixed', paapi: { enabled: true, defaultForSlots: 1, } }); Object.assign(adUnits[0], {ortb2Imp: {ext: {ae: 0}}}); - expectFledgeFlags({enabled: true, ae: 0}, {enabled: true, ae: 0}); + sinon.assert.match(getImpExt(), { + global: { + ae: 0, + }, + rubicon: undefined, + appnexus: undefined + }); }); + it('should override per-bidder when excluded via paapi.bidders', () => { + config.setConfig({ + paapi: { + enabled: true, + defaultForSlots: 1, + bidders: ['rubicon'] + } + }) + sinon.assert.match(getImpExt(), { + global: { + ae: 1, + igs: { + ae: 1, + biddable: 1 + } + }, + rubicon: undefined, + appnexus: { + ae: 0, + igs: { + ae: 0, + biddable: 0 + } + } + }) + }) + it('should populate ext.igs when request has ext.ae', () => { config.setConfig({ - bidderSequence: 'fixed', paapi: { enabled: true } }); Object.assign(adUnits[0], {ortb2Imp: {ext: {ae: 3}}}); - expectFledgeFlags({enabled: true, ae: 3}, {enabled: true, ae: 3}); + sinon.assert.match(getImpExt(), { + global: { + ae: 3, + igs: { + ae: 3, + biddable: 1 + } + }, + rubicon: undefined, + appnexus: undefined, + }); }); it('should not override pub-defined ext.igs', () => { @@ -765,16 +826,17 @@ describe('paapi module', () => { } }); Object.assign(adUnits[0], {ortb2Imp: {ext: {ae: 1, igs: {biddable: 0}}}}); - const bidReqs = mark(); - Object.values(bidReqs).flatMap(req => req.bids).forEach(bid => { - sinon.assert.match(bid.ortb2Imp.ext, { + sinon.assert.match(getImpExt(), { + global: { ae: 1, igs: { ae: 1, biddable: 0 } - }); - }); + }, + rubicon: undefined, + appnexus: undefined + }) }); it('should fill ext.ae from ext.igs, if defined', () => { @@ -784,60 +846,64 @@ describe('paapi module', () => { } }); Object.assign(adUnits[0], {ortb2Imp: {ext: {igs: {}}}}); - expectFledgeFlags({enabled: true, ae: 1}, {enabled: true, ae: 1}); + sinon.assert.match(getImpExt(), { + global: { + ae: 1, + igs: { + ae: 1, + biddable: 1 + } + }, + appnexus: undefined, + rubicon: undefined + }) }); - }); - describe('ortb2Imp.ext.paapi.requestedSize', () => { - beforeEach(() => { - config.setConfig({ - paapi: { - enabled: true, - defaultForSlots: 1, - } + describe('ortb2Imp.ext.paapi.requestedSize', () => { + beforeEach(() => { + config.setConfig({ + paapi: { + enabled: true, + defaultForSlots: 1, + } + }); }); - }); - it('should default to value returned by getPAAPISize', () => { - getPAAPISizeStub.returns([123, 321]); - Object.values(mark()).flatMap(b => b.bids).forEach(bidRequest => { - sinon.assert.match(bidRequest.ortb2Imp.ext.paapi, { + it('should default to value returned by getPAAPISize', () => { + getPAAPISizeStub.returns([123, 321]); + expect(getImpExt().global.paapi).to.eql({ requestedSize: { width: 123, height: 321 } }); }); - }); - it('should not be overridden, if provided by the pub', () => { - adUnits[0].ortb2Imp = { - ext: { - paapi: { - requestedSize: { - width: '123px', - height: '321px' + it('should not be overridden, if provided by the pub', () => { + adUnits[0].ortb2Imp = { + ext: { + paapi: { + requestedSize: { + width: '123px', + height: '321px' + } } } - } - }; - Object.values(mark()).flatMap(b => b.bids).forEach(bidRequest => { - sinon.assert.match(bidRequest.ortb2Imp.ext.paapi, { + }; + expect(getImpExt().global.paapi).to.eql({ requestedSize: { width: '123px', height: '321px' } - }); + }) + sinon.assert.notCalled(getPAAPISizeStub); }); - sinon.assert.notCalled(getPAAPISizeStub); - }); - it('should not be set if adUnit has no banner sizes', () => { - adUnits[0].mediaTypes = { - video: {} - }; - Object.values(mark()).flatMap(b => b.bids).forEach(bidRequest => { - expect(bidRequest.ortb2Imp?.ext?.paapi?.requestedSize).to.not.exist; + it('should not be set if adUnit has no banner sizes', () => { + adUnits[0].mediaTypes = { + video: {} + }; + expect(getImpExt().global?.paapi?.requestedSize).to.not.exist; }); }); }); diff --git a/test/spec/modules/permutiveRtdProvider_spec.js b/test/spec/modules/permutiveRtdProvider_spec.js index 73218fee7b9..51fbba7e936 100644 --- a/test/spec/modules/permutiveRtdProvider_spec.js +++ b/test/spec/modules/permutiveRtdProvider_spec.js @@ -484,7 +484,9 @@ describe('permutiveRtdProvider', function () { _psegs: [], _ppam: [], _pcrprs: [], - _pssps: { ssps: [], cohorts: [] } + _pindexs: [], + _pssps: { ssps: [], cohorts: [] }, + _ppsts: {}, }) setBidderRtb(bidderConfig, moduleConfig, segmentsData) @@ -568,6 +570,7 @@ describe('permutiveRtdProvider', function () { const data = transformedTargeting() expect(getSegments(250)).to.deep.equal(data) }) + it('should enforce max segments', function () { const max = 1 const segments = getSegments(max) @@ -584,6 +587,26 @@ describe('permutiveRtdProvider', function () { } } }) + + it('should coerce numbers to strings', function () { + setLocalStorage({ _prubicons: [1, 2, 3], _pssps: { ssps: ['foo', 'bar'], cohorts: [4, 5, 6] } }) + + const segments = getSegments(200) + + expect(segments.rubicon).to.deep.equal(['1', '2', '3']) + expect(segments.ssp.ssps).to.deep.equal(['foo', 'bar']) + expect(segments.ssp.cohorts).to.deep.equal(['4', '5', '6']) + }) + + it('should return empty values on unexpected format', function () { + setLocalStorage({ _prubicons: 'a string instead?', _pssps: 123 }) + + const segments = getSegments(200) + + expect(segments.rubicon).to.deep.equal([]) + expect(segments.ssp.ssps).to.deep.equal([]) + expect(segments.ssp.cohorts).to.deep.equal([]) + }) }) describe('Existing key-value targeting', function () { @@ -703,14 +726,25 @@ function getConfig () { } function transformedTargeting (data = getTargetingData()) { + const topics = (() => { + const topics = {} + for (const topic in data._ppsts) { + topics[topic] = data._ppsts[topic].map(String) + } + return topics + })() + return { - ac: [...data._pcrprs, ...data._ppam, ...data._psegs.filter(seg => seg >= 1000000)], - appnexus: data._papns, - ix: data._pindexs, - rubicon: data._prubicons, - gam: data._pdfps, - ssp: data._pssps, - topics: data._ppsts, + ac: [...data._pcrprs, ...data._ppam, ...data._psegs.filter(seg => seg >= 1000000)].map(String), + appnexus: data._papns.map(String), + ix: data._pindexs.map(String), + rubicon: data._prubicons.map(String), + gam: data._pdfps.map(String), + ssp: { + ssps: data._pssps.ssps.map(String), + cohorts: data._pssps.cohorts.map(String) + }, + topics, } } diff --git a/test/spec/modules/prebidServerBidAdapter_spec.js b/test/spec/modules/prebidServerBidAdapter_spec.js index d44a67d2acc..a6d91a6309b 100644 --- a/test/spec/modules/prebidServerBidAdapter_spec.js +++ b/test/spec/modules/prebidServerBidAdapter_spec.js @@ -825,7 +825,7 @@ describe('S2S Adapter', function () { }) }) }) - + it('should set customHeaders correctly when publisher has provided it', () => { let configWithCustomHeaders = utils.deepClone(CONFIG); configWithCustomHeaders.customHeaders = { customHeader1: 'customHeader1Value' }; @@ -3578,18 +3578,32 @@ describe('S2S Adapter', function () { sinon.assert.calledWith(fledgeStub, sinon.match({auctionId, adUnitCode: AU, ortb2: undefined, ortb2Imp: undefined}), sinon.match({config: {id: 2}})) } - it('calls addComponentAuction alongside addBidResponse', function () { + it('calls addPaapiConfig alongside addBidResponse', function () { adapter.callBids(request, bidderRequests, addBidResponse, done, ajax); server.requests[0].respond(200, {}, JSON.stringify(mergeDeep({}, RESPONSE_OPENRTB, FLEDGE_RESP))); expect(addBidResponse.called).to.be.true; expectFledgeCalls(); }); - it('calls addComponentAuction when there is no bid in the response', () => { + it('calls addPaapiConfig when there is no bid in the response', () => { adapter.callBids(request, bidderRequests, addBidResponse, done, ajax); server.requests[0].respond(200, {}, JSON.stringify(FLEDGE_RESP)); expect(addBidResponse.called).to.be.false; expectFledgeCalls(); + }); + + it('wraps call in runWithBidder', () => { + let fail = false; + fledgeStub.callsFake(({bidder}) => { + try { + expect(bidder).to.exist.and.to.eql(config.getCurrentBidder()); + } catch (e) { + fail = true; + } + }); + adapter.callBids(request, bidderRequests, addBidResponse, done, ajax); + server.requests[0].respond(200, {}, JSON.stringify(FLEDGE_RESP)); + expect(fail).to.be.false; }) }); }); diff --git a/test/spec/modules/proxistoreBidAdapter_spec.js b/test/spec/modules/proxistoreBidAdapter_spec.js index bcddb9e8b04..92e68f60b85 100644 --- a/test/spec/modules/proxistoreBidAdapter_spec.js +++ b/test/spec/modules/proxistoreBidAdapter_spec.js @@ -81,7 +81,7 @@ describe('ProxistoreBidAdapter', function () { it('should contain a valid url', function () { // has gdpr consent expect(request.url).equal(url.cookieBase); - // doens't have gpdr consent + // doens't have gdpr consent bidderRequest.gdprConsent.vendorData = null; request = spec.buildRequests([bid], bidderRequest); diff --git a/test/spec/modules/pubmaticBidAdapter_spec.js b/test/spec/modules/pubmaticBidAdapter_spec.js index 7d42f407448..82715ac518a 100644 --- a/test/spec/modules/pubmaticBidAdapter_spec.js +++ b/test/spec/modules/pubmaticBidAdapter_spec.js @@ -4084,6 +4084,46 @@ describe('PubMatic adapter', function () { }) }); } + + describe('Banner Request param battr checking', function() { + it('should add battr params to bannerObj if present in ortb2Imp.banner', function() { + let originalBidRequests = utils.deepClone(bidRequests); + let bannerObj = utils.deepClone(originalBidRequests[0].ortb2Imp.banner); + originalBidRequests[0].ortb2Imp.banner = Object.assign(bannerObj, { + battr: [1, 2] + }); + + const req = spec.buildRequests(originalBidRequests, { + auctionId: 'new-auction-id' + }); + let data = JSON.parse(req.data); + expect(data.imp[0]['banner']['battr']).to.exist.and.to.be.an('array'); + expect(data.imp[0]['banner']['battr'][0]).to.equal(originalBidRequests[0].ortb2Imp.banner['battr'][0]); + expect(data.imp[0]['banner']['battr'][1]).to.equal(originalBidRequests[0].ortb2Imp.banner['battr'][1]); + }); + + it('should not add battr params to bannerObj if not present in ortb2Imp.banner', function() { + const req = spec.buildRequests(bidRequests, { + auctionId: 'new-auction-id' + }); + let data = JSON.parse(req.data); + expect(data.imp[0]['banner']['battr']).to.equal(undefined); + }); + + it('should not add battr params if _checkParamDataType returns undefined (Mismatch data type)', function() { + let originalBidRequests = utils.deepClone(bidRequests); + let bannerObj = utils.deepClone(originalBidRequests[0].ortb2Imp.banner); + originalBidRequests[0].ortb2Imp.banner = Object.assign(bannerObj, { + battr: 1 + }); + + const req = spec.buildRequests(originalBidRequests, { + auctionId: 'new-auction-id' + }); + let data = JSON.parse(req.data); + expect(data.imp[0]['banner']['battr']).to.equal(undefined); + }); + }); }); if (FEATURES.VIDEO) { diff --git a/test/spec/modules/pubxaiAnalyticsAdapter_spec.js b/test/spec/modules/pubxaiAnalyticsAdapter_spec.js index 9af1ef185e1..237a2d32d54 100644 --- a/test/spec/modules/pubxaiAnalyticsAdapter_spec.js +++ b/test/spec/modules/pubxaiAnalyticsAdapter_spec.js @@ -1,675 +1,731 @@ -import pubxaiAnalyticsAdapter, {getBrowser, getDeviceType, getOS} from 'modules/pubxaiAnalyticsAdapter.js'; -import {expect} from 'chai'; -import adapterManager from 'src/adapterManager.js'; -import * as utils from 'src/utils.js'; -import {server} from 'test/mocks/xhr.js'; -import {getGptSlotInfoForAdUnitCode} from '../../../libraries/gptUtils/gptUtils.js'; +/* globals describe, beforeEach, afterEach, sinon */ +import { expect } from 'chai'; +import { getGptSlotInfoForAdUnitCode } from 'libraries/gptUtils/gptUtils.js'; +import { getDeviceType, getBrowser, getOS } from 'libraries/userAgentUtils'; +import pubxaiAnalyticsAdapter, { + auctionCache, +} from 'modules/pubxaiAnalyticsAdapter.js'; import { EVENTS } from 'src/constants.js'; +import adapterManager from 'src/adapterManager.js'; +import { getWindowLocation } from 'src/utils.js'; +import { getGlobal } from 'src/prebidGlobal.js'; +import * as events from 'src/events.js' -let events = require('src/events'); +const readBlobSafariCompat = (blob) => { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => resolve(reader.result) + reader.onerror = reject + reader.readAsText(blob) + }) +} -describe('pubxai analytics adapter', function() { - beforeEach(function() { +describe('pubxai analytics adapter', () => { + beforeEach(() => { + getGlobal().refreshUserIds() sinon.stub(events, 'getEvents').returns([]); }); - afterEach(function() { + afterEach(() => { events.getEvents.restore(); }); - describe('track', function() { + describe('track', () => { let initOptions = { samplingRate: '1', - pubxId: '6c415fc0-8b0e-4cf5-be73-01526a4db625' + pubxId: '6c415fc0-8b0e-4cf5-be73-01526a4db625', }; - let location = utils.getWindowLocation(); - let storage = window.top['sessionStorage']; + let originalVS; + + let location = getWindowLocation(); + + const replaceProperty = (obj, params) => { + let strObj = JSON.stringify(obj); + params.forEach(({ field, updated, replaced }) => { + strObj = strObj.replace( + new RegExp('"' + field + '":' + replaced, 'g'), + '"' + field + '":' + updated + ); + }); + return JSON.parse(strObj); + }; let prebidEvent = { - 'auctionInit': { - 'auctionId': 'bc3806e4-873e-453c-8ae5-204f35e923b4', - 'timestamp': 1603865707180, - 'auctionStatus': 'inProgress', - 'adUnits': [{ - 'code': '/19968336/header-bid-tag-1', - 'mediaTypes': { - 'banner': { - 'sizes': [ - [ - 300, - 250 - ] - ] - } - }, - 'bids': [{ - 'bidder': 'appnexus', - 'params': { - 'placementId': 13144370 + auctionInit: { + auctionId: 'bc3806e4-873e-453c-8ae5-204f35e923b4', + timestamp: 1603865707180, + auctionStatus: 'inProgress', + adUnits: [ + { + code: '/19968336/header-bid-tag-1', + mediaTypes: { + banner: { + sizes: [[300, 250]], + }, }, - 'auctionId': 'bc3806e4-873e-453c-8ae5-204f35e923b4', - 'floorData': { - 'skipped': false, - 'skipRate': 0, - 'modelVersion': 'test model 1.0', - 'location': 'fetch', - 'floorProvider': 'PubXFloorProvider', - 'fetchStatus': 'success' - } - }], - 'sizes': [ - [ - 300, - 250 - ] - ], - 'transactionId': '41ec8eaf-3e7c-4a8b-8344-ab796ff6e294' - }], - 'adUnitCodes': [ - '/19968336/header-bid-tag-1' + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 13144370, + }, + auctionId: 'bc3806e4-873e-453c-8ae5-204f35e923b4', + floorData: { + skipped: false, + skipRate: 0, + modelVersion: 'test model 1.0', + location: 'fetch', + floorProvider: 'PubXFloorProvider', + fetchStatus: 'success', + }, + }, + ], + sizes: [[300, 250]], + transactionId: '41ec8eaf-3e7c-4a8b-8344-ab796ff6e294', + }, ], - 'bidderRequests': [{ - 'bidderCode': 'appnexus', - 'auctionId': 'bc3806e4-873e-453c-8ae5-204f35e923b4', - 'bidderRequestId': '184cbc05bb90ba', - 'bids': [{ - 'bidder': 'appnexus', - 'params': { - 'placementId': 13144370 - }, - 'auctionId': 'bc3806e4-873e-453c-8ae5-204f35e923b4', - 'floorData': { - 'skipped': false, - 'skipRate': 0, - 'modelVersion': 'test model 1.0', - 'location': 'fetch', - 'floorProvider': 'PubXFloorProvider', - 'fetchStatus': 'success' + adUnitCodes: ['/19968336/header-bid-tag-1'], + bidderRequests: [ + { + bidderCode: 'appnexus', + auctionId: 'bc3806e4-873e-453c-8ae5-204f35e923b4', + bidderRequestId: '184cbc05bb90ba', + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 13144370, + }, + auctionId: 'bc3806e4-873e-453c-8ae5-204f35e923b4', + floorData: { + skipped: false, + skipRate: 0, + modelVersion: 'test model 1.0', + location: 'fetch', + floorProvider: 'PubXFloorProvider', + fetchStatus: 'success', + }, + mediaTypes: { + banner: { + sizes: [[300, 250]], + }, + }, + adUnitCode: '/19968336/header-bid-tag-1', + transactionId: '41ec8eaf-3e7c-4a8b-8344-ab796ff6e294', + sizes: [[300, 250]], + bidId: '248f9a4489835e', + bidderRequestId: '184cbc05bb90ba', + src: 'client', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, + }, + ], + ortb2: { + device: { + ext: { + cdep: true, + }, + }, }, - 'mediaTypes': { - 'banner': { - 'sizes': [ - [ - 300, - 250 - ] - ] - } + auctionStart: 1603865707180, + timeout: 1000, + refererInfo: { + referer: 'http://local-pnh.net:8080/stream/', + reachedTop: true, + isAmp: false, + numIframes: 0, + stack: ['http://local-pnh.net:8080/stream/'], + canonicalUrl: null, }, - 'adUnitCode': '/19968336/header-bid-tag-1', - 'transactionId': '41ec8eaf-3e7c-4a8b-8344-ab796ff6e294', - 'sizes': [ - [ - 300, - 250 - ] - ], - 'bidId': '248f9a4489835e', - 'bidderRequestId': '184cbc05bb90ba', - 'src': 'client', - 'bidRequestsCount': 1, - 'bidderRequestsCount': 1, - 'bidderWinsCount': 0 - }], - 'auctionStart': 1603865707180, - 'timeout': 1000, - 'refererInfo': { - 'referer': 'http://local-pnh.net:8080/stream/', - 'reachedTop': true, - 'isAmp': false, - 'numIframes': 0, - 'stack': [ - 'http://local-pnh.net:8080/stream/' - ], - 'canonicalUrl': null + start: 1603865707182, }, - 'start': 1603865707182 - }], - 'noBids': [], - 'bidsReceived': [], - 'winningBids': [], - 'timeout': 1000, - 'config': { - 'samplingRate': '1', - 'pubxId': '6c415fc0-8b0e-4cf5-be73-01526a4db625' - } + ], + noBids: [], + bidsReceived: [], + winningBids: [], + timeout: 1000, + config: { + samplingRate: '1', + pubxId: '6c415fc0-8b0e-4cf5-be73-01526a4db625', + }, }, - 'bidRequested': { - 'bidderCode': 'appnexus', - 'auctionId': 'bc3806e4-873e-453c-8ae5-204f35e923b4', - 'bidderRequestId': '184cbc05bb90ba', - 'bids': [{ - 'bidder': 'appnexus', - 'params': { - 'placementId': 13144370 - }, - 'auctionId': 'bc3806e4-873e-453c-8ae5-204f35e923b4', - 'floorData': { - 'skipped': false, - 'skipRate': 0, - 'modelVersion': 'test model 1.0', - 'location': 'fetch', - 'floorProvider': 'PubXFloorProvider', - 'fetchStatus': 'success' + bidRequested: { + bidderCode: 'appnexus', + auctionId: 'bc3806e4-873e-453c-8ae5-204f35e923b4', + bidderRequestId: '184cbc05bb90ba', + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 13144370, + }, + auctionId: 'bc3806e4-873e-453c-8ae5-204f35e923b4', + floorData: { + skipped: false, + skipRate: 0, + modelVersion: 'test model 1.0', + location: 'fetch', + floorProvider: 'PubXFloorProvider', + fetchStatus: 'success', + }, + mediaTypes: { + banner: { + sizes: [[300, 250]], + }, + }, + adUnitCode: '/19968336/header-bid-tag-1', + transactionId: '41ec8eaf-3e7c-4a8b-8344-ab796ff6e294', + sizes: [[300, 250]], + bidId: '248f9a4489835e', + bidderRequestId: '184cbc05bb90ba', + src: 'client', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, }, - 'mediaTypes': { - 'banner': { - 'sizes': [ - [ - 300, - 250 - ] - ] - } + ], + ortb2: { + device: { + ext: { + cdep: true, + }, }, - 'adUnitCode': '/19968336/header-bid-tag-1', - 'transactionId': '41ec8eaf-3e7c-4a8b-8344-ab796ff6e294', - 'sizes': [ - [ - 300, - 250 - ] - ], - 'bidId': '248f9a4489835e', - 'bidderRequestId': '184cbc05bb90ba', - 'src': 'client', - 'bidRequestsCount': 1, - 'bidderRequestsCount': 1, - 'bidderWinsCount': 0 - }], - 'auctionStart': 1603865707180, - 'timeout': 1000, - 'refererInfo': { - 'referer': 'http://local-pnh.net:8080/stream/', - 'reachedTop': true, - 'isAmp': false, - 'numIframes': 0, - 'stack': [ - 'http://local-pnh.net:8080/stream/' - ], - 'canonicalUrl': null }, - 'start': 1603865707182 + auctionStart: 1603865707180, + timeout: 1000, + refererInfo: { + referer: 'http://local-pnh.net:8080/stream/', + reachedTop: true, + isAmp: false, + numIframes: 0, + stack: ['http://local-pnh.net:8080/stream/'], + canonicalUrl: null, + }, + start: 1603865707182, }, - 'bidTimeout': [], - 'bidResponse': { - 'bidderCode': 'appnexus', - 'width': 300, - 'height': 250, - 'statusMessage': 'Bid available', - 'adId': '32780c4bc382cb', - 'requestId': '248f9a4489835e', - 'mediaType': 'banner', - 'source': 'client', - 'cpm': 0.5, - 'creativeId': 96846035, - 'currency': 'USD', - 'netRevenue': true, - 'ttl': 300, - 'adUnitCode': '/19968336/header-bid-tag-1', - 'appnexus': { - 'buyerMemberId': 9325 + bidTimeout: [], + bidResponse: { + bidderCode: 'appnexus', + width: 300, + height: 250, + statusMessage: 'Bid available', + adId: '32780c4bc382cb', + requestId: '248f9a4489835e', + mediaType: 'banner', + source: 'client', + cpm: 0.5, + creativeId: 96846035, + currency: 'USD', + netRevenue: true, + ttl: 300, + adUnitCode: '/19968336/header-bid-tag-1', + appnexus: { + buyerMemberId: 9325, }, - 'meta': { - 'advertiserId': 2529885 + meta: { + advertiserId: 2529885, }, - 'ad': '', - 'originalCpm': 0.5, - 'originalCurrency': 'USD', - 'floorData': { - 'fetchStatus': 'success', - 'floorProvider': 'PubXFloorProvider', - 'location': 'fetch', - 'modelVersion': 'test model 1.0', - 'skipRate': 0, - 'skipped': false, - 'floorValue': 0.4, - 'floorRule': '/19968336/header-bid-tag-1|banner', - 'floorCurrency': 'USD', - 'cpmAfterAdjustments': 0.5, - 'enforcements': { - 'enforceJS': true, - 'enforcePBS': false, - 'floorDeals': true, - 'bidAdjustment': true + ad: '', + originalCpm: 0.5, + originalCurrency: 'USD', + floorData: { + fetchStatus: 'success', + floorProvider: 'PubXFloorProvider', + location: 'fetch', + modelVersion: 'test model 1.0', + skipRate: 0, + skipped: false, + floorValue: 0.4, + floorRule: '/19968336/header-bid-tag-1|banner', + floorCurrency: 'USD', + cpmAfterAdjustments: 0.5, + enforcements: { + enforceJS: true, + enforcePBS: false, + floorDeals: true, + bidAdjustment: true, + }, + matchedFields: { + gptSlot: '/19968336/header-bid-tag-1', + mediaType: 'banner', }, - 'matchedFields': { - 'gptSlot': '/19968336/header-bid-tag-1', - 'mediaType': 'banner' - } }, - 'auctionId': 'bc3806e4-873e-453c-8ae5-204f35e923b4', - 'responseTimestamp': 1616654313071, - 'requestTimestamp': 1616654312804, - 'bidder': 'appnexus', - 'timeToRespond': 267, - 'pbLg': '0.50', - 'pbMg': '0.50', - 'pbHg': '0.50', - 'pbAg': '0.50', - 'pbDg': '0.50', - 'pbCg': '0.50', - 'size': '300x250', - 'adserverTargeting': { - 'hb_bidder': 'appnexus', - 'hb_adid': '32780c4bc382cb', - 'hb_pb': '0.50', - 'hb_size': '300x250', - 'hb_source': 'client', - 'hb_format': 'banner' + auctionId: 'bc3806e4-873e-453c-8ae5-204f35e923b4', + responseTimestamp: 1616654313071, + requestTimestamp: 1616654312804, + bidder: 'appnexus', + timeToRespond: 267, + pbLg: '0.50', + pbMg: '0.50', + pbHg: '0.50', + pbAg: '0.50', + pbDg: '0.50', + pbCg: '0.50', + size: '300x250', + adserverTargeting: { + hb_bidder: 'appnexus', + hb_adid: '32780c4bc382cb', + hb_pb: '0.50', + hb_size: '300x250', + hb_source: 'client', + hb_format: 'banner', }, }, - 'auctionEnd': { - 'auctionId': 'bc3806e4-873e-453c-8ae5-204f35e923b4', - 'timestamp': 1616654312804, - 'auctionEnd': 1616654313090, - 'auctionStatus': 'completed', - 'adUnits': [{ - 'code': '/19968336/header-bid-tag-1', - 'mediaTypes': { - 'banner': { - 'sizes': [ - [ - 300, - 250 - ] - ] - } + auctionEnd: { + auctionId: 'bc3806e4-873e-453c-8ae5-204f35e923b4', + timestamp: 1616654312804, + auctionEnd: 1616654313090, + auctionStatus: 'completed', + adUnits: [ + { + code: '/19968336/header-bid-tag-1', + mediaTypes: { + banner: { + sizes: [[300, 250]], + }, + }, + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 13144370, + }, + auctionId: 'bc3806e4-873e-453c-8ae5-204f35e923b4', + floorData: { + skipped: false, + skipRate: 0, + modelVersion: 'test model 1.0', + location: 'fetch', + floorProvider: 'PubXFloorProvider', + fetchStatus: 'success', + }, + }, + ], + sizes: [[300, 250]], + transactionId: '41ec8eaf-3e7c-4a8b-8344-ab796ff6e294', }, - 'bids': [{ - 'bidder': 'appnexus', - 'params': { - 'placementId': 13144370 + ], + adUnitCodes: ['/19968336/header-bid-tag-1'], + bidderRequests: [ + { + bidderCode: 'appnexus', + auctionId: 'bc3806e4-873e-453c-8ae5-204f35e923b4', + bidderRequestId: '184cbc05bb90ba', + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 13144370, + }, + auctionId: 'bc3806e4-873e-453c-8ae5-204f35e923b4', + floorData: { + skipped: false, + skipRate: 0, + modelVersion: 'test model 1.0', + location: 'fetch', + floorProvider: 'PubXFloorProvider', + fetchStatus: 'success', + }, + mediaTypes: { + banner: { + sizes: [[300, 250]], + }, + }, + adUnitCode: '/19968336/header-bid-tag-1', + transactionId: '41ec8eaf-3e7c-4a8b-8344-ab796ff6e294', + sizes: [[300, 250]], + bidId: '248f9a4489835e', + bidderRequestId: '184cbc05bb90ba', + src: 'client', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, + }, + ], + ortb2: { + device: { + ext: { + cdep: true, + }, + }, }, - 'auctionId': 'bc3806e4-873e-453c-8ae5-204f35e923b4', - 'floorData': { - 'skipped': false, - 'skipRate': 0, - 'modelVersion': 'test model 1.0', - 'location': 'fetch', - 'floorProvider': 'PubXFloorProvider', - 'fetchStatus': 'success' - } - }], - 'sizes': [ - [ - 300, - 250 - ] - ], - 'transactionId': '41ec8eaf-3e7c-4a8b-8344-ab796ff6e294' - }], - 'adUnitCodes': [ - '/19968336/header-bid-tag-1' + auctionStart: 1603865707180, + timeout: 1000, + refererInfo: { + referer: 'http://local-pnh.net:8080/stream/', + reachedTop: true, + isAmp: false, + numIframes: 0, + stack: ['http://local-pnh.net:8080/stream/'], + canonicalUrl: null, + }, + start: 1603865707182, + }, ], - 'bidderRequests': [{ - 'bidderCode': 'appnexus', - 'auctionId': 'bc3806e4-873e-453c-8ae5-204f35e923b4', - 'bidderRequestId': '184cbc05bb90ba', - 'bids': [{ - 'bidder': 'appnexus', - 'params': { - 'placementId': 13144370 + noBids: [], + bidsReceived: [ + { + bidderCode: 'appnexus', + width: 300, + height: 250, + statusMessage: 'Bid available', + adId: '32780c4bc382cb', + requestId: '248f9a4489835e', + mediaType: 'banner', + source: 'client', + cpm: 0.5, + creativeId: 96846035, + currency: 'USD', + netRevenue: true, + ttl: 300, + adUnitCode: '/19968336/header-bid-tag-1', + appnexus: { + buyerMemberId: 9325, }, - 'auctionId': 'bc3806e4-873e-453c-8ae5-204f35e923b4', - 'floorData': { - 'skipped': false, - 'skipRate': 0, - 'modelVersion': 'test model 1.0', - 'location': 'fetch', - 'floorProvider': 'PubXFloorProvider', - 'fetchStatus': 'success' + meta: { + advertiserId: 2529885, }, - 'mediaTypes': { - 'banner': { - 'sizes': [ - [ - 300, - 250 - ] - ] - } + ad: '', + originalCpm: 0.5, + originalCurrency: 'USD', + floorData: { + fetchStatus: 'success', + floorProvider: 'PubXFloorProvider', + location: 'fetch', + modelVersion: 'test model 1.0', + skipRate: 0, + skipped: false, + floorValue: 0.4, + floorRule: '/19968336/header-bid-tag-1|banner', + floorCurrency: 'USD', + cpmAfterAdjustments: 0.5, + enforcements: { + enforceJS: true, + enforcePBS: false, + floorDeals: true, + bidAdjustment: true, + }, + matchedFields: { + gptSlot: '/19968336/header-bid-tag-1', + mediaType: 'banner', + }, }, - 'adUnitCode': '/19968336/header-bid-tag-1', - 'transactionId': '41ec8eaf-3e7c-4a8b-8344-ab796ff6e294', - 'sizes': [ - [ - 300, - 250 - ] - ], - 'bidId': '248f9a4489835e', - 'bidderRequestId': '184cbc05bb90ba', - 'src': 'client', - 'bidRequestsCount': 1, - 'bidderRequestsCount': 1, - 'bidderWinsCount': 0 - }], - 'auctionStart': 1603865707180, - 'timeout': 1000, - 'refererInfo': { - 'referer': 'http://local-pnh.net:8080/stream/', - 'reachedTop': true, - 'isAmp': false, - 'numIframes': 0, - 'stack': [ - 'http://local-pnh.net:8080/stream/' - ], - 'canonicalUrl': null - }, - 'start': 1603865707182 - }], - 'noBids': [], - 'bidsReceived': [{ - 'bidderCode': 'appnexus', - 'width': 300, - 'height': 250, - 'statusMessage': 'Bid available', - 'adId': '32780c4bc382cb', - 'requestId': '248f9a4489835e', - 'mediaType': 'banner', - 'source': 'client', - 'cpm': 0.5, - 'creativeId': 96846035, - 'currency': 'USD', - 'netRevenue': true, - 'ttl': 300, - 'adUnitCode': '/19968336/header-bid-tag-1', - 'appnexus': { - 'buyerMemberId': 9325 - }, - 'meta': { - 'advertiserId': 2529885 - }, - 'ad': '', - 'originalCpm': 0.5, - 'originalCurrency': 'USD', - 'floorData': { - 'fetchStatus': 'success', - 'floorProvider': 'PubXFloorProvider', - 'location': 'fetch', - 'modelVersion': 'test model 1.0', - 'skipRate': 0, - 'skipped': false, - 'floorValue': 0.4, - 'floorRule': '/19968336/header-bid-tag-1|banner', - 'floorCurrency': 'USD', - 'cpmAfterAdjustments': 0.5, - 'enforcements': { - 'enforceJS': true, - 'enforcePBS': false, - 'floorDeals': true, - 'bidAdjustment': true + auctionId: 'bc3806e4-873e-453c-8ae5-204f35e923b4', + responseTimestamp: 1616654313071, + requestTimestamp: 1616654312804, + bidder: 'appnexus', + timeToRespond: 267, + pbLg: '0.50', + pbMg: '0.50', + pbHg: '0.50', + pbAg: '0.50', + pbDg: '0.50', + pbCg: '0.50', + size: '300x250', + adserverTargeting: { + hb_bidder: 'appnexus', + hb_adid: '32780c4bc382cb', + hb_pb: '0.50', + hb_size: '300x250', + hb_source: 'client', + hb_format: 'banner', }, - 'matchedFields': { - 'gptSlot': '/19968336/header-bid-tag-1', - 'mediaType': 'banner' - } - }, - 'auctionId': 'bc3806e4-873e-453c-8ae5-204f35e923b4', - 'responseTimestamp': 1616654313071, - 'requestTimestamp': 1616654312804, - 'bidder': 'appnexus', - 'timeToRespond': 267, - 'pbLg': '0.50', - 'pbMg': '0.50', - 'pbHg': '0.50', - 'pbAg': '0.50', - 'pbDg': '0.50', - 'pbCg': '0.50', - 'size': '300x250', - 'adserverTargeting': { - 'hb_bidder': 'appnexus', - 'hb_adid': '32780c4bc382cb', - 'hb_pb': '0.50', - 'hb_size': '300x250', - 'hb_source': 'client', - 'hb_format': 'banner' + status: 'rendered', + params: [ + { + placementId: 13144370, + }, + ], }, - 'status': 'rendered', - 'params': [{ - 'placementId': 13144370 - }] - }], - 'winningBids': [], - 'timeout': 1000 + ], + winningBids: [], + timeout: 1000, }, - 'bidWon': { - 'bidderCode': 'appnexus', - 'width': 300, - 'height': 250, - 'statusMessage': 'Bid available', - 'adId': '32780c4bc382cb', - 'requestId': '248f9a4489835e', - 'mediaType': 'banner', - 'source': 'client', - 'cpm': 0.5, - 'creativeId': 96846035, - 'currency': 'USD', - 'netRevenue': true, - 'ttl': 300, - 'adUnitCode': '/19968336/header-bid-tag-1', - 'appnexus': { - 'buyerMemberId': 9325 + bidWon: { + bidderCode: 'appnexus', + width: 300, + height: 250, + statusMessage: 'Bid available', + adId: '32780c4bc382cb', + requestId: '248f9a4489835e', + mediaType: 'banner', + source: 'client', + cpm: 0.5, + creativeId: 96846035, + currency: 'USD', + netRevenue: true, + ttl: 300, + adUnitCode: '/19968336/header-bid-tag-1', + appnexus: { + buyerMemberId: 9325, }, - 'meta': { - 'advertiserId': 2529885 + meta: { + advertiserId: 2529885, }, - 'ad': '', - 'originalCpm': 0.5, - 'originalCurrency': 'USD', - 'floorData': { - 'fetchStatus': 'success', - 'floorProvider': 'PubXFloorProvider', - 'location': 'fetch', - 'modelVersion': 'test model 1.0', - 'skipRate': 0, - 'skipped': false, - 'floorValue': 0.4, - 'floorRule': '/19968336/header-bid-tag-1|banner', - 'floorCurrency': 'USD', - 'cpmAfterAdjustments': 0.5, - 'enforcements': { - 'enforceJS': true, - 'enforcePBS': false, - 'floorDeals': true, - 'bidAdjustment': true + ad: '', + originalCpm: 0.5, + originalCurrency: 'USD', + floorData: { + fetchStatus: 'success', + floorProvider: 'PubXFloorProvider', + location: 'fetch', + modelVersion: 'test model 1.0', + skipRate: 0, + skipped: false, + floorValue: 0.4, + floorRule: '/19968336/header-bid-tag-1|banner', + floorCurrency: 'USD', + cpmAfterAdjustments: 0.5, + enforcements: { + enforceJS: true, + enforcePBS: false, + floorDeals: true, + bidAdjustment: true, + }, + matchedFields: { + gptSlot: '/19968336/header-bid-tag-1', + mediaType: 'banner', }, - 'matchedFields': { - 'gptSlot': '/19968336/header-bid-tag-1', - 'mediaType': 'banner' - } }, - 'auctionId': 'bc3806e4-873e-453c-8ae5-204f35e923b4', - 'responseTimestamp': 1616654313071, - 'requestTimestamp': 1616654312804, - 'bidder': 'appnexus', - 'timeToRespond': 267, - 'pbLg': '0.50', - 'pbMg': '0.50', - 'pbHg': '0.50', - 'pbAg': '0.50', - 'pbDg': '0.50', - 'pbCg': '0.50', - 'size': '300x250', - 'adserverTargeting': { - 'hb_bidder': 'appnexus', - 'hb_adid': '32780c4bc382cb', - 'hb_pb': '0.50', - 'hb_size': '300x250', - 'hb_source': 'client', - 'hb_format': 'banner' + auctionId: 'bc3806e4-873e-453c-8ae5-204f35e923b4', + responseTimestamp: 1616654313071, + requestTimestamp: 1616654312804, + bidder: 'appnexus', + timeToRespond: 267, + pbLg: '0.50', + pbMg: '0.50', + pbHg: '0.50', + pbAg: '0.50', + pbDg: '0.50', + pbCg: '0.50', + size: '300x250', + adserverTargeting: { + hb_bidder: 'appnexus', + hb_adid: '32780c4bc382cb', + hb_pb: '0.50', + hb_size: '300x250', + hb_source: 'client', + hb_format: 'banner', }, - 'status': 'rendered', - 'params': [{ - 'placementId': 13144370 - }] - }, - 'pageDetail': { - 'host': location.host, - 'path': location.pathname, - 'search': location.search + status: 'rendered', + params: [ + { + placementId: 13144370, + }, + ], }, - 'pmcDetail': { - 'bidDensity': storage.getItem('pbx:dpbid'), - 'maxBid': storage.getItem('pbx:mxbid'), - 'auctionId': storage.getItem('pbx:aucid') - } }; let expectedAfterBid = { - 'bids': [{ - 'bidderCode': 'appnexus', - 'bidId': '248f9a4489835e', - 'adUnitCode': '/19968336/header-bid-tag-1', - 'gptSlotCode': getGptSlotInfoForAdUnitCode('/19968336/header-bid-tag-1').gptSlot || null, - 'auctionId': 'bc3806e4-873e-453c-8ae5-204f35e923b4', - 'sizes': '300x250', - 'renderStatus': 2, - 'requestTimestamp': 1616654312804, - 'creativeId': 96846035, - 'currency': 'USD', - 'cpm': 0.5, - 'netRevenue': true, - 'mediaType': 'banner', - 'statusMessage': 'Bid available', - 'floorData': { - 'fetchStatus': 'success', - 'floorProvider': 'PubXFloorProvider', - 'location': 'fetch', - 'modelVersion': 'test model 1.0', - 'skipRate': 0, - 'skipped': false, - 'floorValue': 0.4, - 'floorRule': '/19968336/header-bid-tag-1|banner', - 'floorCurrency': 'USD', - 'cpmAfterAdjustments': 0.5, - 'enforcements': { - 'enforceJS': true, - 'enforcePBS': false, - 'floorDeals': true, - 'bidAdjustment': true + bids: [ + { + bidderCode: 'appnexus', + bidId: '248f9a4489835e', + adUnitCode: '/19968336/header-bid-tag-1', + gptSlotCode: + getGptSlotInfoForAdUnitCode('/19968336/header-bid-tag-1').gptSlot || + null, + auctionId: 'bc3806e4-873e-453c-8ae5-204f35e923b4', + sizes: '300x250', + renderStatus: 2, + requestTimestamp: 1616654312804, + creativeId: 96846035, + currency: 'USD', + cpm: 0.5, + netRevenue: true, + mediaType: 'banner', + statusMessage: 'Bid available', + floorData: { + fetchStatus: 'success', + floorProvider: 'PubXFloorProvider', + location: 'fetch', + modelVersion: 'test model 1.0', + skipRate: 0, + skipped: false, + floorValue: 0.4, + floorRule: '/19968336/header-bid-tag-1|banner', + floorCurrency: 'USD', + cpmAfterAdjustments: 0.5, + enforcements: { + enforceJS: true, + enforcePBS: false, + floorDeals: true, + bidAdjustment: true, + }, + matchedFields: { + gptSlot: '/19968336/header-bid-tag-1', + mediaType: 'banner', + }, }, - 'matchedFields': { - 'gptSlot': '/19968336/header-bid-tag-1', - 'mediaType': 'banner' - } + placementId: null, + timeToRespond: 267, + source: 'client', + responseTimestamp: 1616654313071, }, - 'timeToRespond': 267, - 'responseTimestamp': 1616654313071 - }], - 'pageDetail': { - 'host': location.host, - 'path': location.pathname, - 'search': location.search, - 'adUnits': [ - '/19968336/header-bid-tag-1' - ] + ], + auctionDetail: { + adUnitCodes: ['/19968336/header-bid-tag-1'], + auctionId: 'bc3806e4-873e-453c-8ae5-204f35e923b4', + refreshRank: 0, + timestamp: 1616654312804, + }, + pageDetail: { + host: location.host, + path: location.pathname, + search: location.search, }, - 'floorDetail': { - 'fetchStatus': 'success', - 'floorProvider': 'PubXFloorProvider', - 'location': 'fetch', - 'modelVersion': 'test model 1.0', - 'skipRate': 0, - 'skipped': false + floorDetail: { + fetchStatus: 'success', + floorProvider: 'PubXFloorProvider', + location: 'fetch', + modelVersion: 'test model 1.0', + skipRate: 0, + skipped: false, }, - 'deviceDetail': { - 'platform': navigator.platform, - 'deviceType': getDeviceType(), - 'deviceOS': getOS(), - 'browser': getBrowser() + deviceDetail: { + platform: navigator.platform, + deviceType: getDeviceType(), + deviceOS: getOS(), + browser: getBrowser(), + cdep: true, }, - 'pmcDetail': { - 'bidDensity': storage.getItem('pbx:dpbid'), - 'maxBid': storage.getItem('pbx:mxbid'), - 'auctionId': storage.getItem('pbx:aucid') + userDetail: { + userIdTypes: Object.keys(getGlobal().getUserIds?.() || {}), + }, + consentDetail: { + consentTypes: Object.keys(getGlobal().getConsentMetadata?.() || {}), + }, + pmacDetail: {}, + initOptions: { + ...initOptions, + auctionId: 'bc3806e4-873e-453c-8ae5-204f35e923b4', }, - 'initOptions': initOptions }; let expectedAfterBidWon = { - 'winningBid': { - 'adUnitCode': '/19968336/header-bid-tag-1', - 'gptSlotCode': getGptSlotInfoForAdUnitCode('/19968336/header-bid-tag-1').gptSlot || null, - 'auctionId': 'bc3806e4-873e-453c-8ae5-204f35e923b4', - 'bidderCode': 'appnexus', - 'bidId': '248f9a4489835e', - 'cpm': 0.5, - 'creativeId': 96846035, - 'currency': 'USD', - 'floorData': { - 'fetchStatus': 'success', - 'floorProvider': 'PubXFloorProvider', - 'location': 'fetch', - 'modelVersion': 'test model 1.0', - 'skipRate': 0, - 'skipped': false, - 'floorValue': 0.4, - 'floorRule': '/19968336/header-bid-tag-1|banner', - 'floorCurrency': 'USD', - 'cpmAfterAdjustments': 0.5, - 'enforcements': { - 'enforceJS': true, - 'enforcePBS': false, - 'floorDeals': true, - 'bidAdjustment': true + winningBid: { + adUnitCode: '/19968336/header-bid-tag-1', + gptSlotCode: + getGptSlotInfoForAdUnitCode('/19968336/header-bid-tag-1').gptSlot || + null, + auctionId: 'bc3806e4-873e-453c-8ae5-204f35e923b4', + bidderCode: 'appnexus', + bidId: '248f9a4489835e', + cpm: 0.5, + creativeId: 96846035, + currency: 'USD', + floorData: { + fetchStatus: 'success', + floorProvider: 'PubXFloorProvider', + location: 'fetch', + modelVersion: 'test model 1.0', + skipRate: 0, + skipped: false, + floorValue: 0.4, + floorRule: '/19968336/header-bid-tag-1|banner', + floorCurrency: 'USD', + cpmAfterAdjustments: 0.5, + enforcements: { + enforceJS: true, + enforcePBS: false, + floorDeals: true, + bidAdjustment: true, + }, + matchedFields: { + gptSlot: '/19968336/header-bid-tag-1', + mediaType: 'banner', }, - 'matchedFields': { - 'gptSlot': '/19968336/header-bid-tag-1', - 'mediaType': 'banner' - } }, - 'floorProvider': 'PubXFloorProvider', - 'floorFetchStatus': 'success', - 'floorLocation': 'fetch', - 'floorModelVersion': 'test model 1.0', - 'floorSkipRate': 0, - 'isFloorSkipped': false, - 'isWinningBid': true, - 'mediaType': 'banner', - 'netRevenue': true, - 'placementId': 13144370, - 'renderedSize': '300x250', - 'renderStatus': 4, - 'responseTimestamp': 1616654313071, - 'requestTimestamp': 1616654312804, - 'status': 'rendered', - 'statusMessage': 'Bid available', - 'timeToRespond': 267 + adServerData: {}, + floorProvider: 'PubXFloorProvider', + floorFetchStatus: 'success', + floorLocation: 'fetch', + floorModelVersion: 'test model 1.0', + floorSkipRate: 0, + isFloorSkipped: false, + isWinningBid: true, + mediaType: 'banner', + netRevenue: true, + placementId: 13144370, + renderedSize: '300x250', + sizes: '300x250', + renderStatus: 4, + responseTimestamp: 1616654313071, + requestTimestamp: 1616654312804, + status: 'rendered', + statusMessage: 'Bid available', + timeToRespond: 267, + source: 'client', + }, + auctionDetail: { + adUnitCodes: ['/19968336/header-bid-tag-1'], + auctionId: 'bc3806e4-873e-453c-8ae5-204f35e923b4', + refreshRank: 0, + timestamp: 1616654312804, + }, + pageDetail: { + host: location.host, + path: location.pathname, + search: location.search, }, - 'pageDetail': { - 'host': location.host, - 'path': location.pathname, - 'search': location.search + floorDetail: { + fetchStatus: 'success', + floorProvider: 'PubXFloorProvider', + location: 'fetch', + modelVersion: 'test model 1.0', + skipRate: 0, + skipped: false, }, - 'deviceDetail': { - 'platform': navigator.platform, - 'deviceType': getDeviceType(), - 'deviceOS': getOS(), - 'browser': getBrowser() + deviceDetail: { + platform: navigator.platform, + deviceType: getDeviceType(), + deviceOS: getOS(), + browser: getBrowser(), + cdep: true, }, - 'initOptions': initOptions - } + userDetail: { + userIdTypes: Object.keys(getGlobal().getUserIds?.() || {}), + }, + consentDetail: { + consentTypes: Object.keys(getGlobal().getConsentMetadata?.() || {}), + }, + pmacDetail: {}, + initOptions: { + ...initOptions, + auctionId: 'bc3806e4-873e-453c-8ae5-204f35e923b4', + }, + }; adapterManager.registerAnalyticsAdapter({ code: 'pubxai', - adapter: pubxaiAnalyticsAdapter + adapter: pubxaiAnalyticsAdapter, }); - beforeEach(function() { + beforeEach(() => { adapterManager.enableAnalytics({ provider: 'pubxai', - options: initOptions + options: initOptions, + }); + sinon.stub(navigator, 'sendBeacon').returns(true); + originalVS = document.visibilityState; + document['__defineGetter__']('visibilityState', function () { + return 'hidden'; }); }); - afterEach(function() { + afterEach(() => { pubxaiAnalyticsAdapter.disableAnalytics(); + navigator.sendBeacon.restore(); + delete auctionCache['bc3806e4-873e-453c-8ae5-204f35e923b4']; + delete auctionCache['auction2']; + document['__defineGetter__']('visibilityState', function () { + return originalVS; + }); }); - it('builds and sends auction data', function() { + it('builds and sends auction data', async () => { // Step 1: Send auction init event events.emit(EVENTS.AUCTION_INIT, prebidEvent['auctionInit']); @@ -685,20 +741,331 @@ describe('pubxai analytics adapter', function() { // Step 5: Send auction end event events.emit(EVENTS.AUCTION_END, prebidEvent['auctionEnd']); - expect(server.requests.length).to.equal(1); - - let realAfterBid = JSON.parse(server.requests[0].requestBody); + // Simulate "navigate away" behaviour + document.dispatchEvent(new Event('visibilitychange')); - expect(realAfterBid).to.deep.equal(expectedAfterBid); + expect(navigator.sendBeacon.callCount).to.equal(0); // Step 6: Send auction bid won event events.emit(EVENTS.BID_WON, prebidEvent['bidWon']); - expect(server.requests.length).to.equal(2); + // Simulate end of session + document.dispatchEvent(new Event('visibilitychange')); + + expect(navigator.sendBeacon.callCount).to.equal(2); + + for (const [index, arg] of navigator.sendBeacon.args.entries()) { + const [expectedUrl, expectedData] = arg; + const parsedUrl = new URL(expectedUrl); + expect(parsedUrl.pathname).to.equal( + ['/analytics/bidwon', '/analytics/auction'][index] + ); + expect(Object.fromEntries(parsedUrl.searchParams)).to.deep.equal({ + auctionTimestamp: '1616654312804', + pubxaiAnalyticsVersion: 'v2.0.0', + prebidVersion: '$prebid.version$', + }); + expect(expectedData.type).to.equal('text/json'); + expect(JSON.parse(await readBlobSafariCompat(expectedData))).to.deep.equal([ + [expectedAfterBidWon, expectedAfterBid][index], + ]); + } + }); + + it('auction with no bids', async () => { + // Step 1: Send auction init event + events.emit(EVENTS.AUCTION_INIT, prebidEvent['auctionInit']); + + // Step 2: Send bid requested event + events.emit(EVENTS.BID_REQUESTED, prebidEvent['bidRequested']); + + // Step 3: Send bid time out event + events.emit(EVENTS.BID_TIMEOUT, prebidEvent['bidTimeout']); + + // Simulate "navigate away" behaviour + document.dispatchEvent(new Event('visibilitychange')); + + // Step 4: check the number of calls made to pubx.ai + expect(navigator.sendBeacon.callCount).to.equal(0); + + // Step 5: Send auction end event + events.emit(EVENTS.AUCTION_END, prebidEvent['auctionEnd']); + + // Simulate end of session + document.dispatchEvent(new Event('visibilitychange')); + + // Step 6: check the number of calls made to pubx.ai + expect(navigator.sendBeacon.callCount).to.equal(1); + + // Step 7: check the pathname of the calls is correct (sent only to the auction endpoint) + const [expectedUrl, expectedData] = navigator.sendBeacon.args[0]; + const parsedUrl = new URL(expectedUrl); + expect(parsedUrl.pathname).to.equal('/analytics/auction'); + + // Step 8: check that the meta information in the call is correct + expect(Object.fromEntries(parsedUrl.searchParams)).to.deep.equal({ + auctionTimestamp: '1616654312804', + pubxaiAnalyticsVersion: 'v2.0.0', + prebidVersion: '$prebid.version$', + }); + + // Step 9: check that the data sent in the request is correct + expect(expectedData.type).to.equal('text/json'); + expect(JSON.parse(await readBlobSafariCompat(expectedData))).to.deep.equal([ + { + ...expectedAfterBid, + bids: [], + }, + ]); + }); + + it('2 concurrent auctions', async () => { + // Step 1: Send auction init event for auction 1 + events.emit(EVENTS.AUCTION_INIT, prebidEvent['auctionInit']); + + // Step 2: Send bid requested event for auction 1 + events.emit(EVENTS.BID_REQUESTED, prebidEvent['bidRequested']); + + // Step 3: Send auction init event for auction 2 + events.emit( + EVENTS.AUCTION_INIT, + replaceProperty(prebidEvent['auctionInit'], [ + { + field: 'auctionId', + updated: '"auction2"', + replaced: '"bc3806e4-873e-453c-8ae5-204f35e923b4"', + }, + ]) + ); + + // Step 4: Send bid requested event for auction 2 + events.emit( + EVENTS.BID_REQUESTED, + replaceProperty(prebidEvent['bidRequested'], [ + { + field: 'auctionId', + updated: '"auction2"', + replaced: '"bc3806e4-873e-453c-8ae5-204f35e923b4"', + }, + ]) + ); + + // Step 5: Send bid response event for auction 1 + events.emit(EVENTS.BID_RESPONSE, prebidEvent['bidResponse']); + + // Step 6: Send bid time out event for auction 1 + events.emit(EVENTS.BID_TIMEOUT, prebidEvent['bidTimeout']); + + // Step 7: Send bid response event for auction 2 + events.emit( + EVENTS.BID_RESPONSE, + replaceProperty(prebidEvent['bidResponse'], [ + { + field: 'auctionId', + updated: '"auction2"', + replaced: '"bc3806e4-873e-453c-8ae5-204f35e923b4"', + }, + ]) + ); + + // Step 8: Send auction end event for auction 1 + events.emit(EVENTS.AUCTION_END, prebidEvent['auctionEnd']); + + // Simulate "navigate away" behaviour + document.dispatchEvent(new Event('visibilitychange')); + + // Step 9: check the number of calls made to pubx.ai + expect(navigator.sendBeacon.callCount).to.equal(0); + + // Step 10: Send auction bid won event for auction 1 + events.emit(EVENTS.BID_WON, prebidEvent['bidWon']); + + // Simulate "navigate away" behaviour + document.dispatchEvent(new Event('visibilitychange')); + + // Step 11: check the number of calls made to pubx.ai + expect(navigator.sendBeacon.callCount).to.equal(2); + + // Step 12: Send auction end event for auction 2 + events.emit( + EVENTS.AUCTION_END, + replaceProperty(prebidEvent['auctionEnd'], [ + { + field: 'auctionId', + updated: '"auction2"', + replaced: '"bc3806e4-873e-453c-8ae5-204f35e923b4"', + }, + ]) + ); + + // Simulate "navigate away" behaviour + document.dispatchEvent(new Event('visibilitychange')); - let winEventData = JSON.parse(server.requests[1].requestBody); + // Step 13: check the number of calls made to pubx.ai + expect(navigator.sendBeacon.callCount).to.equal(2); - expect(winEventData).to.deep.equal(expectedAfterBidWon); + // Step 14: Send auction bid won event for auction 2 + events.emit( + EVENTS.BID_WON, + replaceProperty(prebidEvent['bidWon'], [ + { + field: 'auctionId', + updated: '"auction2"', + replaced: '"bc3806e4-873e-453c-8ae5-204f35e923b4"', + }, + ]) + ); + + // Simulate end of session + document.dispatchEvent(new Event('visibilitychange')); + + // Step 15: check the calls made to pubx.ai + expect(navigator.sendBeacon.callCount).to.equal(4); + for (const [index, arg] of navigator.sendBeacon.args.entries()) { + const [expectedUrl, expectedData] = arg; + const parsedUrl = new URL(expectedUrl); + const auctionIdMapFn = index < 2 ? (i, _) => i : replaceProperty; + expect(parsedUrl.pathname).to.equal( + ['/analytics/bidwon', '/analytics/auction'][index % 2] + ); + expect(Object.fromEntries(parsedUrl.searchParams)).to.deep.equal({ + auctionTimestamp: '1616654312804', + pubxaiAnalyticsVersion: 'v2.0.0', + prebidVersion: '$prebid.version$', + }); + expect(expectedData.type).to.equal('text/json'); + expect(JSON.parse(await readBlobSafariCompat(expectedData))).to.deep.equal([ + auctionIdMapFn([expectedAfterBidWon, expectedAfterBid][index % 2], [ + { + field: 'auctionId', + updated: '"auction2"', + replaced: '"bc3806e4-873e-453c-8ae5-204f35e923b4"', + }, + { + field: 'refreshRank', + updated: '1', + replaced: '0', + }, + ]), + ]); + } + }); + + it('2 concurrent auctions with batch sending', async () => { + // Step 1: Send auction init event for auction 1 + events.emit(EVENTS.AUCTION_INIT, prebidEvent['auctionInit']); + + // Step 2: Send bid requested event for auction 1 + events.emit(EVENTS.BID_REQUESTED, prebidEvent['bidRequested']); + + // Step 3: Send auction init event for auction 2 + events.emit( + EVENTS.AUCTION_INIT, + replaceProperty(prebidEvent['auctionInit'], [ + { + field: 'auctionId', + updated: '"auction2"', + replaced: '"bc3806e4-873e-453c-8ae5-204f35e923b4"', + }, + ]) + ); + + // Step 4: Send bid requested event for auction 2 + events.emit( + EVENTS.BID_REQUESTED, + replaceProperty(prebidEvent['bidRequested'], [ + { + field: 'auctionId', + updated: '"auction2"', + replaced: '"bc3806e4-873e-453c-8ae5-204f35e923b4"', + }, + ]) + ); + + // Step 5: Send bid response event for auction 1 + events.emit(EVENTS.BID_RESPONSE, prebidEvent['bidResponse']); + + // Step 6: Send bid time out event for auction 1 + events.emit(EVENTS.BID_TIMEOUT, prebidEvent['bidTimeout']); + + // Step 7: Send bid response event for auction 2 + events.emit( + EVENTS.BID_RESPONSE, + replaceProperty(prebidEvent['bidResponse'], [ + { + field: 'auctionId', + updated: '"auction2"', + replaced: '"bc3806e4-873e-453c-8ae5-204f35e923b4"', + }, + ]) + ); + + // Step 8: Send auction end event for auction 1 + events.emit(EVENTS.AUCTION_END, prebidEvent['auctionEnd']); + + // Step 9: Send auction bid won event for auction 1 + events.emit(EVENTS.BID_WON, prebidEvent['bidWon']); + + // Step 10: Send auction end event for auction 2 + events.emit( + EVENTS.AUCTION_END, + replaceProperty(prebidEvent['auctionEnd'], [ + { + field: 'auctionId', + updated: '"auction2"', + replaced: '"bc3806e4-873e-453c-8ae5-204f35e923b4"', + }, + ]) + ); + + // Step 11: Send auction bid won event for auction 2 + events.emit( + EVENTS.BID_WON, + replaceProperty(prebidEvent['bidWon'], [ + { + field: 'auctionId', + updated: '"auction2"', + replaced: '"bc3806e4-873e-453c-8ae5-204f35e923b4"', + }, + ]) + ); + + // Step 12: check the number of calls made to pubx.ai + expect(navigator.sendBeacon.callCount).to.equal(0); + + // Simulate end of session + document.dispatchEvent(new Event('visibilitychange')); + + // Step 13: check the calls made to pubx.ai + expect(navigator.sendBeacon.callCount).to.equal(2); + for (const [index, arg] of navigator.sendBeacon.args.entries()) { + const [expectedUrl, expectedData] = arg; + const parsedUrl = new URL(expectedUrl); + expect(parsedUrl.pathname).to.equal( + ['/analytics/bidwon', '/analytics/auction'][index] + ); + expect(Object.fromEntries(parsedUrl.searchParams)).to.deep.equal({ + auctionTimestamp: '1616654312804', + pubxaiAnalyticsVersion: 'v2.0.0', + prebidVersion: '$prebid.version$', + }); + expect(expectedData.type).to.equal('text/json'); + expect(JSON.parse(await readBlobSafariCompat(expectedData))).to.deep.equal([ + [expectedAfterBidWon, expectedAfterBid][index], + replaceProperty([expectedAfterBidWon, expectedAfterBid][index], [ + { + field: 'auctionId', + updated: '"auction2"', + replaced: '"bc3806e4-873e-453c-8ae5-204f35e923b4"', + }, + { + field: 'refreshRank', + updated: '1', + replaced: '0', + }, + ]), + ]); + } }); }); }); diff --git a/test/spec/modules/pulsepointBidAdapter_spec.js b/test/spec/modules/pulsepointBidAdapter_spec.js index 8db7e909771..da8b6d8473a 100644 --- a/test/spec/modules/pulsepointBidAdapter_spec.js +++ b/test/spec/modules/pulsepointBidAdapter_spec.js @@ -362,7 +362,7 @@ describe('PulsePoint Adapter Tests', function () { const bidderRequestGdpr = { gdprConsent: { gdprApplies: true, - consentString: 'serialized_gpdr_data' + consentString: 'serialized_gdpr_data' } }; const request = spec.buildRequests(slotConfigs, syncAddFPDToBidderRequest(Object.assign({}, bidderRequest, bidderRequestGdpr))); @@ -372,7 +372,7 @@ describe('PulsePoint Adapter Tests', function () { // user object expect(ortbRequest.user).to.not.equal(null); expect(ortbRequest.user.ext).to.not.equal(null); - expect(ortbRequest.user.ext.consent).to.equal('serialized_gpdr_data'); + expect(ortbRequest.user.ext.consent).to.equal('serialized_gdpr_data'); // regs object expect(ortbRequest.regs).to.not.equal(null); expect(ortbRequest.regs.ext).to.not.equal(null); @@ -518,7 +518,7 @@ describe('PulsePoint Adapter Tests', function () { }, gdprConsent: { gdprApplies: true, - consentString: 'serialized_gpdr_data' + consentString: 'serialized_gdpr_data' }, ortb2: { user: { @@ -545,7 +545,7 @@ describe('PulsePoint Adapter Tests', function () { registered: true, interests: ['cars'] }, - consent: 'serialized_gpdr_data' + consent: 'serialized_gdpr_data' } }); }); diff --git a/test/spec/modules/shinezRtbBidAdapter_spec.js b/test/spec/modules/shinezRtbBidAdapter_spec.js index 93864064dd8..2e4c35cb065 100644 --- a/test/spec/modules/shinezRtbBidAdapter_spec.js +++ b/test/spec/modules/shinezRtbBidAdapter_spec.js @@ -2,6 +2,9 @@ import {expect} from 'chai'; import { spec as adapter, createDomain, + storage +} from 'modules/shinezRtbBidAdapter'; +import { hashCode, extractPID, extractCID, @@ -10,13 +13,12 @@ import { setStorageItem, tryParseJSON, getUniqueDealId, -} from 'modules/shinezRtbBidAdapter'; -import * as utils from 'src/utils.js'; +} from '../../../libraries/vidazooUtils/bidderUtils.js'; +import {parseUrl, deepClone} from 'src/utils.js'; import {version} from 'package.json'; import {useFakeTimers} from 'sinon'; import {BANNER, VIDEO} from '../../../src/mediaTypes'; import {config} from '../../../src/config'; -import {deepAccess} from 'src/utils.js'; export const TEST_ID_SYSTEMS = ['criteoId', 'id5id', 'idl_env', 'lipb', 'netId', 'pubcid', 'tdid', 'pubProvidedId']; @@ -181,7 +183,7 @@ const REQUEST = { function getTopWindowQueryParams() { try { - const parsedUrl = utils.parseUrl(window.top.document.URL, {decodeSearchAsString: true}); + const parsedUrl = parseUrl(window.top.document.URL, {decodeSearchAsString: true}); return parsedUrl.search; } catch (e) { return ''; @@ -328,7 +330,12 @@ describe('ShinezRtbBidAdapter', function () { startdelay: 0 } }, - gpid: '0123456789' + gpid: '0123456789', + cat: [], + contentData: [], + isStorageAllowed: true, + pagecat: [], + userData: [] } }); }); @@ -390,6 +397,11 @@ describe('ShinezRtbBidAdapter', function () { uqs: getTopWindowQueryParams(), 'ext.param1': 'loremipsum', 'ext.param2': 'dolorsitamet', + cat: [], + contentData: [], + isStorageAllowed: true, + pagecat: [], + userData: [] } }); }); @@ -463,7 +475,7 @@ describe('ShinezRtbBidAdapter', function () { }); it('should get meta from response metaData', function () { - const serverResponse = utils.deepClone(SERVER_RESPONSE); + const serverResponse = deepClone(SERVER_RESPONSE); serverResponse.body.results[0].metaData = { advertiserDomains: ['sweetgum.io'], agencyName: 'Agency Name', @@ -496,7 +508,7 @@ describe('ShinezRtbBidAdapter', function () { }); it('should take default TTL', function () { - const serverResponse = utils.deepClone(SERVER_RESPONSE); + const serverResponse = deepClone(SERVER_RESPONSE); delete serverResponse.body.results[0].exp; const responses = adapter.interpretResponse(serverResponse, REQUEST); expect(responses).to.have.length(1); @@ -507,7 +519,7 @@ describe('ShinezRtbBidAdapter', function () { describe('user id system', function () { TEST_ID_SYSTEMS.forEach((idSystemProvider) => { const id = Date.now().toString(); - const bid = utils.deepClone(BID); + const bid = deepClone(BID); const userId = (function () { switch (idSystemProvider) { @@ -565,13 +577,13 @@ describe('ShinezRtbBidAdapter', function () { const key = 'myKey'; let uniqueDealId; beforeEach(() => { - uniqueDealId = getUniqueDealId(key, 0); + uniqueDealId = getUniqueDealId(storage, key, 0); }) it('should get current unique deal id', function (done) { // waiting some time so `now` will become past setTimeout(() => { - const current = getUniqueDealId(key); + const current = getUniqueDealId(storage, key); expect(current).to.be.equal(uniqueDealId); done(); }, 200); @@ -579,7 +591,7 @@ describe('ShinezRtbBidAdapter', function () { it('should get new unique deal id on expiration', function (done) { setTimeout(() => { - const current = getUniqueDealId(key, 100); + const current = getUniqueDealId(storage, key, 100); expect(current).to.not.be.equal(uniqueDealId); done(); }, 200) @@ -603,8 +615,8 @@ describe('ShinezRtbBidAdapter', function () { shouldAdvanceTime: true, now }); - setStorageItem('myKey', 2020); - const {value, created} = getStorageItem('myKey'); + setStorageItem(storage, 'myKey', 2020); + const {value, created} = getStorageItem(storage, 'myKey'); expect(created).to.be.equal(now); expect(value).to.be.equal(2020); expect(typeof value).to.be.equal('number'); @@ -615,7 +627,7 @@ describe('ShinezRtbBidAdapter', function () { it('should get external stored value', function () { const value = 'superman' window.localStorage.setItem('myExternalKey', value); - const item = getStorageItem('myExternalKey'); + const item = getStorageItem(storage, 'myExternalKey'); expect(item).to.be.equal(value); }); diff --git a/test/spec/modules/smaatoBidAdapter_spec.js b/test/spec/modules/smaatoBidAdapter_spec.js index 9052fbbcdfd..302a5fa1aa6 100644 --- a/test/spec/modules/smaatoBidAdapter_spec.js +++ b/test/spec/modules/smaatoBidAdapter_spec.js @@ -12,6 +12,8 @@ import 'modules/consentManagementTcf.js'; import 'modules/consentManagementUsp.js'; import 'modules/schain.js'; +const SYNC_URL = 'https://s.ad.smaato.net/c/?adExInit=p' + const ADTYPE_IMG = 'Img'; const ADTYPE_VIDEO = 'Video'; const ADTYPE_NATIVE = 'Native'; @@ -1667,8 +1669,41 @@ describe('smaatoBidAdapterTest', () => { }); describe('getUserSyncs', () => { - it('returns no pixels', () => { + it('when pixelEnabled false then returns no pixels', () => { expect(spec.getUserSyncs()).to.be.empty }) + + it('when pixelEnabled true then returns pixel', () => { + expect(spec.getUserSyncs({pixelEnabled: true}, null, null, null)).to.deep.equal( + [ + { + type: 'image', + url: SYNC_URL + } + ] + ) + }) + + it('when pixelEnabled true and gdprConsent then returns pixel with gdpr params', () => { + expect(spec.getUserSyncs({pixelEnabled: true}, null, {gdprApplies: true, consentString: CONSENT_STRING}, null)).to.deep.equal( + [ + { + type: 'image', + url: `${SYNC_URL}&gdpr=1&gdpr_consent=${CONSENT_STRING}` + } + ] + ) + }) + + it('when pixelEnabled true and gdprConsent without gdpr then returns pixel with gdpr_consent', () => { + expect(spec.getUserSyncs({pixelEnabled: true}, null, {consentString: CONSENT_STRING}, null), null).to.deep.equal( + [ + { + type: 'image', + url: `${SYNC_URL}&gdpr_consent=${CONSENT_STRING}` + } + ] + ) + }) }) }); diff --git a/test/spec/modules/smarthubBidAdapter_spec.js b/test/spec/modules/smarthubBidAdapter_spec.js index a5e8787e21a..eb5fe58093d 100644 --- a/test/spec/modules/smarthubBidAdapter_spec.js +++ b/test/spec/modules/smarthubBidAdapter_spec.js @@ -106,7 +106,9 @@ describe('SmartHubBidAdapter', function () { const bidderRequest = { uspConsent: '1---', - gdprConsent: 'COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw', + gdprConsent: { + consentString: 'COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw' + }, refererInfo: { page: 'https://test.com' }, @@ -166,7 +168,7 @@ describe('SmartHubBidAdapter', function () { expect(data.host).to.be.a('string'); expect(data.page).to.be.a('string'); expect(data.coppa).to.be.a('number'); - expect(data.gdpr).to.be.a('string'); + expect(data.gdpr.consentString).to.be.a('string'); expect(data.ccpa).to.be.a('string'); expect(data.tmax).to.be.a('number'); expect(data.placements).to.have.lengthOf(3); @@ -212,8 +214,8 @@ describe('SmartHubBidAdapter', function () { serverRequest = spec.buildRequests(bids, bidderRequest); let data = serverRequest[0].data; expect(data.gdpr).to.exist; - expect(data.gdpr).to.be.a('string'); - expect(data.gdpr).to.equal(bidderRequest.gdprConsent); + expect(data.gdpr.consentString).to.be.a('string'); + expect(data.gdpr.consentString).to.equal(bidderRequest.gdprConsent.consentString); expect(data.ccpa).to.not.exist; delete bidderRequest.gdprConsent; }); diff --git a/test/spec/modules/smilewantedBidAdapter_spec.js b/test/spec/modules/smilewantedBidAdapter_spec.js index 99c4034610f..1c71c7bee07 100644 --- a/test/spec/modules/smilewantedBidAdapter_spec.js +++ b/test/spec/modules/smilewantedBidAdapter_spec.js @@ -76,6 +76,49 @@ const DISPLAY_REQUEST_WITH_POSITION_TYPE = [{ }, }]; +const SCHAIN = { + 'ver': '1.0', + 'complete': 1, + 'nodes': [ + { + 'asi': 'exchange1.com', + 'sid': '1234', + 'hp': 1, + 'rid': 'bid-request-1', + 'name': 'publisher', + 'domain': 'publisher.com' + }, + { + 'asi': 'exchange2.com', + 'sid': 'abcd', + 'hp': 1, + 'rid': 'bid-request-2', + 'name': 'intermediary', + 'domain': 'intermediary.com' + } + ] +}; + +const DISPLAY_REQUEST_WITH_SCHAIN = [{ + adUnitCode: 'sw_300x250', + bidId: '12345', + sizes: [ + [300, 250], + [300, 200] + ], + bidder: 'smilewanted', + params: { + zoneId: 1, + }, + requestId: 'request_abcd1234', + ortb2Imp: { + ext: { + tid: 'trans_abcd1234', + } + }, + schain: SCHAIN, +}]; + const BID_RESPONSE_DISPLAY = { body: { cpm: 3, @@ -580,8 +623,21 @@ describe('smilewantedBidAdapterTests', function () { expect(requestContent).to.have.property('positionType').and.to.equal('infeed'); }); + it('SmileWanted - Verify if schain is well passed', function () { + const request = spec.buildRequests(DISPLAY_REQUEST_WITH_SCHAIN, {}); + const requestContent = JSON.parse(request[0].data); + expect(requestContent).to.have.property('schain').and.to.equal('1.0,1!exchange1.com,1234,1,bid-request-1,publisher,publisher.com,!exchange2.com,abcd,1,bid-request-2,intermediary,intermediary.com,'); + }); + + it('SmileWanted - Verify user sync - empty data', function () { + let syncs = spec.getUserSyncs({iframeEnabled: true}, {}, {}, null); + expect(syncs).to.have.lengthOf(1); + expect(syncs[0].type).to.equal('iframe'); + expect(syncs[0].url).to.equal('https://csync.smilewanted.com'); + }); + it('SmileWanted - Verify user sync', function () { - var syncs = spec.getUserSyncs({iframeEnabled: true}, {}, { + let syncs = spec.getUserSyncs({iframeEnabled: true}, {}, { consentString: 'foo' }, '1NYN'); expect(syncs).to.have.lengthOf(1); diff --git a/test/spec/modules/symitriDapRtdProvider_spec.js b/test/spec/modules/symitriDapRtdProvider_spec.js new file mode 100644 index 00000000000..79ebfd707c7 --- /dev/null +++ b/test/spec/modules/symitriDapRtdProvider_spec.js @@ -0,0 +1,600 @@ +import {config} from 'src/config.js'; +import { + dapUtils, + generateRealTimeData, + symitriDapRtdSubmodule, + storage, DAP_MAX_RETRY_TOKENIZE, DAP_SS_ID, DAP_TOKEN, DAP_MEMBERSHIP, DAP_ENCRYPTED_MEMBERSHIP +} from 'modules/symitriDapRtdProvider.js'; +import {server} from 'test/mocks/xhr.js'; +import {hook} from '../../../src/hook.js'; +const responseHeader = {'Content-Type': 'application/json'}; + +describe('symitriDapRtdProvider', function() { + const testReqBidsConfigObj = { + adUnits: [ + { + bids: ['bid1', 'bid2'] + } + ] + }; + + const onDone = function() { return true }; + + const sampleGdprConsentConfig = { + 'gdpr': { + 'consentString': null, + 'vendorData': {}, + 'gdprApplies': true + } + }; + + const sampleUspConsentConfig = { + 'usp': '1YYY' + }; + + const sampleIdentity = { + type: 'dap-signature:1.0.0' + }; + + const cmoduleConfig = { + 'name': 'dap', + 'waitForIt': true, + 'params': { + 'apiHostname': 'prebid.dap.akadns.net', + 'apiVersion': 'x1', + 'domain': 'prebid.org', + 'identityType': 'dap-signature:1.0.0', + 'segtax': 503 + } + } + + const emoduleConfig = { + 'name': 'dap', + 'waitForIt': true, + 'params': { + 'apiHostname': 'prebid.dap.akadns.net', + 'apiVersion': 'x1', + 'domain': 'prebid.org', + 'identityType': 'dap-signature:1.0.0', + 'segtax': 504 + } + } + + const sampleConfig = { + 'api_hostname': 'prebid.dap.akadns.net', + 'api_version': 'x1', + 'domain': 'prebid.org', + 'segtax': 503, + 'identity': sampleIdentity + } + + const esampleConfig = { + 'api_hostname': 'prebid.dap.akadns.net', + 'api_version': 'x1', + 'domain': 'prebid.org', + 'segtax': 504, + 'identity': sampleIdentity + } + let cacheExpiry = Math.round(Date.now() / 1000.0) + 300; // in seconds + const sampleCachedToken = {'expires_at': cacheExpiry, 'token': 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Iiwia2lkIjoicGFzc3dvcmQxIn0..6buzBd2BjtgoyaNbHN8YnQ.l38avCfm3sYNy798-ETYOugz0cOx1cCkjACkAhYszxzrZ0sUJ0AiF-NdDXVTiTyp2Ih3vCWKzS0rKJ8lbS1zhyEVWVu91QwtwseM2fBbwA5ggAgBEo5wV-IXqDLPxVnxsPF0D3hP6cNCiH9Q2c-vULfsLhMhG5zvvZDPBbn4hUY5fKB8LoCBTF9rbuuWGYK1nramnb4AlS5UK82wBsHQea1Ou_Kp5wWCMNZ6TZk5qKIuRBfPIAhQblWvHECaHXkg1wyoM9VASs_yNhne7RR-qkwzbFiPFiMJibNOt9hF3_vPDJO5-06ZBjRTP1BllYGWxI-uQX6InzN18Wtun2WHqg.63sH0SNlIRcsK57v0pMujfB_nhU8Y5CuQbsHqH5MGoM'}; + const cachedEncryptedMembership = {'expires_at': cacheExpiry, 'encryptedSegments': 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Iiwia2lkIjoic29tZXNlY3JldGludmF1bHQifQ..IvnIUQDqWBVYIS0gbcE9bw.Z4NZGvtogWaWlGH4e-GdYKe_PUc15M2x3Bj85rMWsN1A17mIxQIMOfg2hsQ2tgieLu5LggWPmsFu1Wbph6P0k3kOu1dVReoIhOHzxw50rP0DLHKaEZ5mLMJ7Lcosvwh4miIfFuCHlsX7J0sFgOTAp0zGo1S_UsHLtev1JflhjoSB0AoX95ALbAnyctirPuLJM8gZ1vXTiZ01jpvucGyR1lM4cWjPOeD8jPtgwaPGgSRZXE-3X2Cqy7z4Giam5Uqu74LPWTBuKtUQTGyAXA5QJoP7xwTbsU4O1f69lu3fWNqC92GijeTH1A4Zd_C-WXxWuQlDEURjlkWQoaqTHka2OqlnwukEQIf_v0r5KQQX64CTLhEUH91jeD0-E9ClcIP7pwOLxxqiKoaBmx8Mrnm_6Agj5DtTA1rusy3AL63sI_rsUxrmLrVt0Wft4aCfRkW8QpQxu8clFdOmce0NNCGeBCyCPVw9d9izrILlXJ6rItU2cpFrcbz8uw2otamF5eOFCOY3IzHedWVNNuKHFIUVC_xYSlsYvQ8f2QIP1eiMbmukcuPzmTzjw1h1_7IKaj-jJkXrnrY-TdDgX_4-_Z3rmbpXK2yTR7dBrsg-ubqFbgbKic1b4zlQEO_LbBlgPl3DYdWEuJ8CY2NUt1GfpATQGsufS2FTY1YGw_gkPe3q04l_cgLafDoxHvHh_t_0ZgPjciW82gThB_kN4RP7Mc3krVcXl_P6N1VbV07xyx0hCyVsrrxbLslI8q9wYDiLGci7mNmByM5j7SXV9jPwwPkHtn0HfMJlw2PFbIDPjgG3h7sOyLcBIJTTvuUIgpHPIkRWLIl_4FlIucXbJ7orW2nt5BWleBVHgumzGcnl9ZNcZb3W-dsdYPSOmuj0CY28MRTP2oJ1rzLInbDDpIRffJBtR7SS4nYyy7Vi09PtBigod5YNz1Q0WDSJxr8zeH_aKFaXInw7Bfo_U0IAcLiRgcT0ogsMLeQRjRFy27mr4XNJv3NtHhbdjDAwF2aClCktXyXbQaVdsPH2W71v6m2Q9rB5GQWOktw2s5f-4N1-_EBPGq6TgjF-aJZP22MJVwp1pimT50DfOzoeEqDwi862NNwNNoHmcObH0ZfwAXlhRxsgupNBe20-MNNABj2Phlfv4DUrtQbMdfCnNiypzNCmoTb7G7c_o5_JUwoV_GVkwUtvmi_IUm05P4GeMASSUw8zDKVRAj9h31C2cabM8RjMHGhkbCWpUP2pcz9zlJ7Y76Dh3RLnctfTw7DG9U4w4UlaxNZOgLUiSrGwfyapuSiuGUpuOJkBBLiHmEqAGI5C8oJpcVRccNlHxJAYowgXyFopD5Fr-FkXmv8KMkS0h5C9F6KihmDt5sqDD0qnjM0hHJgq01l7wjVnhEmPpyD-6auFQ-xDnbh1uBOJ_0gCVbRad--FSa5p-dXenggegRxOvZXJ0iAtM6Fal5Og-RCjexIHa9WhVbXhQBJpkSTWwAajZJ64eQ.yih49XB51wE-Xob7COT9OYqBrzBmIMVCQbLFx2UdzkI'}; + const cachedMembership = {'expires_at': cacheExpiry, 'said': 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Iiwia2lkIjoicGFzc3dvcmQxIn0..QwvU5h0NVJYaJbs5EqWCKA.XNaJHSlnsH8P-yBIr3gIEqavLONWDIFyj7QCHFwJVkwXH_EYkxrk0_26b0uMPzfJp5URnqxKZusMH9DzEJsmj8EMrKQv1y3IYYMsW5_0BdP5bcAWfG6fzOqtMOwLiYRkYiQOqn1ZVGzhovheHWEmNr2_oCY0LvAr3iN1eG_K-l-bBKvBWnwvuuGKquUfCqO8NMMq6wtkecEXM9blqFRZ7oNYmW2aIG7qcHUsrUW7HMr9Ev2Ik0sIeEUsOYrgf_X_VA64RgKSTRugS9FupMv1p54JkHokwduF9pOFmW8QLQi8itFogKGbbgvOTNnmahxQUX5FcrjjYLqHwKqC8htLdlHnO5LWU9l4A7vLXrRurvoSnh0cAJy0GsdoyEwTqR9bwVFHoPquxlJjQ4buEd7PIxpBj9Qg9oOPH3b2upbMTu5CQ9oj526eXPhP5G54nwGklm2AZ3Vggd7jCQJn45Jjiq0iIfsXAtpqS2BssCLBN8WhmUTnStK8m5sux6WUBdrpDESQjPj-EEHVS-DB5rA7icRUh6EzRxzen2rndvHvnwVhSG_l6cwPYuJ0HE0KBmYHOoqNpKwzoGiKFHrf4ReA06iWB3V2TEGJucGujhtQ9_18WwHCeJ1XtQiiO1eqa3tp5MwAbFXawVFl3FFOBgadrPyvGmkmUJ6FCLU2MSwHiYZmANMnJsokFX_6DwoAgO3U_QnvEHIVSvefc7ReeJ8fBDdmrH3LtuLrUpXsvLvEIMQdWQ_SXhjKIi7tOODR8CfrhUcdIjsp3PZs1DpuOcDB6YJKbGnKZTluLUJi3TyHgyi-DHXdTm-jSE5i_DYJGW-t2Gf23FoQhexv4q7gdrfsKfcRJNrZLp6Gd6jl4zHhUtY.nprKBsy9taQBk6dCPbA7BFF0CiGhQOEF_MazZ2bedqk', 'cohorts': ['9', '11', '13']}; + const rtdUserObj = { + name: 'www.dataprovider3.com', + ext: { + taxonomyname: 'iab_audience_taxonomy' + }, + segment: [ + { + id: '1918' + }, + { + id: '1939' + } + ] + }; + + const encRtdUserObj = { + name: 'www.dataprovider3.com', + ext: { + segtax: 504, + taxonomyname: 'iab_audience_taxonomy' + }, + segment: [] + }; + + const cachedRtd = { + rtd: { + ortb2: { + user: { + data: [rtdUserObj] + } + } + } + }; + + let membership = { + said: cachedMembership.said, + cohorts: cachedMembership.cohorts, + attributes: null + }; + let encMembership = { + encryptedSegments: cachedEncryptedMembership.encryptedSegments + }; + encRtdUserObj.segment.push({ id: encMembership.encryptedSegments }); + const cachedEncRtd = { + rtd: { + ortb2: { + user: { + data: [encRtdUserObj] + } + } + } + }; + + before(() => { + hook.ready(); + }); + + let ortb2, bidConfig; + + beforeEach(function() { + bidConfig = {ortb2Fragments: {}}; + ortb2 = bidConfig.ortb2Fragments.global = {}; + config.resetConfig(); + storage.removeDataFromLocalStorage(DAP_TOKEN); + storage.removeDataFromLocalStorage(DAP_MEMBERSHIP); + storage.removeDataFromLocalStorage(DAP_ENCRYPTED_MEMBERSHIP); + storage.removeDataFromLocalStorage(DAP_SS_ID); + }); + + afterEach(function () { + }); + + describe('symitriDapRtdSubmodule', function() { + it('successfully instantiates', function () { + expect(symitriDapRtdSubmodule.init()).to.equal(true); + }); + }); + + describe('Get Real-Time Data', function() { + it('gets rtd from local storage cache', function() { + let dapGetMembershipFromLocalStorageStub = sinon.stub(dapUtils, 'dapGetMembershipFromLocalStorage').returns(membership) + let dapGetRtdObjStub = sinon.stub(dapUtils, 'dapGetRtdObj').returns(cachedRtd) + let dapGetEncryptedMembershipFromLocalStorageStub = sinon.stub(dapUtils, 'dapGetEncryptedMembershipFromLocalStorage').returns(encMembership) + let dapGetEncryptedRtdObjStub = sinon.stub(dapUtils, 'dapGetEncryptedRtdObj').returns(cachedEncRtd) + let callDapApisStub = sinon.stub(dapUtils, 'callDapAPIs') + try { + storage.setDataInLocalStorage(DAP_TOKEN, JSON.stringify(sampleCachedToken)); + expect(ortb2).to.eql({}); + generateRealTimeData(bidConfig, () => {}, emoduleConfig, {}); + + expect(ortb2.user.data).to.deep.include.members([encRtdUserObj]); + generateRealTimeData(bidConfig, () => {}, cmoduleConfig, {}); + expect(ortb2.user.data).to.deep.include.members([rtdUserObj]); + } finally { + dapGetRtdObjStub.restore() + dapGetMembershipFromLocalStorageStub.restore() + dapGetEncryptedRtdObjStub.restore() + dapGetEncryptedMembershipFromLocalStorageStub.restore() + callDapApisStub.restore() + } + }); + }); + + describe('calling DAP APIs', function() { + it('Calls callDapAPIs for unencrypted segments flow', function() { + storage.setDataInLocalStorage(DAP_TOKEN, JSON.stringify(sampleCachedToken)); + let dapExtractExpiryFromTokenStub = sinon.stub(dapUtils, 'dapExtractExpiryFromToken').returns(cacheExpiry) + try { + expect(ortb2).to.eql({}); + dapUtils.callDapAPIs(bidConfig, () => {}, cmoduleConfig, {}); + let membership = {'cohorts': ['9', '11', '13'], 'said': 'sample-said'} + let membershipRequest = server.requests[0]; + membershipRequest.respond(200, responseHeader, JSON.stringify(membership)); + let tokenWithExpiry = 'Sample-token-with-exp' + let tokenizeRequest = server.requests[1]; + responseHeader['Symitri-DAP-Token'] = tokenWithExpiry; + tokenizeRequest.respond(200, responseHeader, JSON.stringify(tokenWithExpiry)); + let data = dapUtils.dapGetRtdObj(membership, cmoduleConfig.params.segtax); + expect(ortb2.user.data).to.deep.include.members(data.rtd.ortb2.user.data); + } finally { + dapExtractExpiryFromTokenStub.restore(); + } + }); + + it('Calls callDapAPIs for encrypted segments flow', function() { + storage.setDataInLocalStorage(DAP_TOKEN, JSON.stringify(sampleCachedToken)); + let dapExtractExpiryFromTokenStub = sinon.stub(dapUtils, 'dapExtractExpiryFromToken').returns(cacheExpiry) + try { + expect(ortb2).to.eql({}); + dapUtils.callDapAPIs(bidConfig, () => {}, emoduleConfig, {}); + let encMembership = 'Sample-enc-token'; + let membershipRequest = server.requests[0]; + responseHeader['Symitri-DAP-Token'] = encMembership; + membershipRequest.respond(200, responseHeader, JSON.stringify(encMembership)); + let tokenWithExpiry = 'Sample-token-with-exp' + let tokenizeRequest = server.requests[1]; + responseHeader['Symitri-DAP-Token'] = tokenWithExpiry; + tokenizeRequest.respond(200, responseHeader, JSON.stringify(tokenWithExpiry)); + let data = dapUtils.dapGetEncryptedRtdObj({'encryptedSegments': encMembership}, emoduleConfig.params.segtax); + expect(ortb2.user.data).to.deep.include.members(data.rtd.ortb2.user.data); + } finally { + dapExtractExpiryFromTokenStub.restore(); + } + }); + }); + + describe('dapTokenize', function () { + it('dapTokenize error callback', function () { + let configAsync = JSON.parse(JSON.stringify(sampleConfig)); + let submoduleCallback = dapUtils.dapTokenize(configAsync, sampleIdentity, onDone, + function(token, status, xhr, onDone) { + }, + function(xhr, status, error, onDone) { + } + ); + let request = server.requests[0]; + request.respond(400, responseHeader, JSON.stringify('error')); + expect(submoduleCallback).to.equal(undefined); + }); + + it('dapTokenize success callback', function () { + let configAsync = JSON.parse(JSON.stringify(sampleConfig)); + let submoduleCallback = dapUtils.dapTokenize(configAsync, sampleIdentity, onDone, + function(token, status, xhr, onDone) { + }, + function(xhr, status, error, onDone) { + } + ); + let request = server.requests[0]; + request.respond(200, responseHeader, JSON.stringify('success')); + expect(submoduleCallback).to.equal(undefined); + }); + }); + + describe('dapTokenize and dapMembership incorrect params', function () { + it('Onerror and config are null', function () { + expect(dapUtils.dapTokenize(null, 'identity', onDone, null, null)).to.be.equal(undefined); + expect(dapUtils.dapMembership(null, 'identity', onDone, null, null)).to.be.equal(undefined); + expect(dapUtils.dapEncryptedMembership(null, 'identity', onDone, null, null)).to.be.equal(undefined); + const config = { + 'api_hostname': 'prebid.dap.akadns.net', + 'api_version': 1, + 'domain': '', + 'segtax': 503 + }; + const encConfig = { + 'api_hostname': 'prebid.dap.akadns.net', + 'api_version': 1, + 'domain': '', + 'segtax': 504 + }; + let identity = { + type: 'dap-signature:1.0.0' + }; + expect(dapUtils.dapTokenize(config, identity, onDone, null, null)).to.be.equal(undefined); + expect(dapUtils.dapMembership(config, 'token', onDone, null, null)).to.be.equal(undefined); + expect(dapUtils.dapEncryptedMembership(encConfig, 'token', onDone, null, null)).to.be.equal(undefined); + }); + }); + + describe('Getting dapTokenize, dapMembership and dapEncryptedMembership from localstorage', function () { + it('dapGetTokenFromLocalStorage success', function () { + storage.setDataInLocalStorage(DAP_TOKEN, JSON.stringify(sampleCachedToken)); + expect(dapUtils.dapGetTokenFromLocalStorage(60)).to.be.equal(sampleCachedToken.token); + }); + + it('dapGetMembershipFromLocalStorage success', function () { + storage.setDataInLocalStorage(DAP_MEMBERSHIP, JSON.stringify(cachedMembership)); + expect(JSON.stringify(dapUtils.dapGetMembershipFromLocalStorage())).to.be.equal(JSON.stringify(membership)); + }); + + it('dapGetEncryptedMembershipFromLocalStorage success', function () { + storage.setDataInLocalStorage(DAP_ENCRYPTED_MEMBERSHIP, JSON.stringify(cachedEncryptedMembership)); + expect(JSON.stringify(dapUtils.dapGetEncryptedMembershipFromLocalStorage())).to.be.equal(JSON.stringify(encMembership)); + }); + }); + + describe('dapMembership', function () { + it('dapMembership success callback', function () { + let configAsync = JSON.parse(JSON.stringify(sampleConfig)); + let submoduleCallback = dapUtils.dapMembership(configAsync, 'token', onDone, + function(token, status, xhr, onDone) { + }, + function(xhr, status, error, onDone) { + } + ); + let request = server.requests[0]; + request.respond(200, responseHeader, JSON.stringify('success')); + expect(submoduleCallback).to.equal(undefined); + }); + + it('dapMembership error callback', function () { + let configAsync = JSON.parse(JSON.stringify(sampleConfig)); + let submoduleCallback = dapUtils.dapMembership(configAsync, 'token', onDone, + function(token, status, xhr, onDone) { + }, + function(xhr, status, error, onDone) { + } + ); + let request = server.requests[0]; + request.respond(400, responseHeader, JSON.stringify('error')); + expect(submoduleCallback).to.equal(undefined); + }); + }); + + describe('dapEncMembership', function () { + it('dapEncMembership success callback', function () { + let configAsync = JSON.parse(JSON.stringify(esampleConfig)); + let submoduleCallback = dapUtils.dapEncryptedMembership(configAsync, 'token', onDone, + function(token, status, xhr, onDone) { + }, + function(xhr, status, error, onDone) { + } + ); + let request = server.requests[0]; + request.respond(200, responseHeader, JSON.stringify('success')); + expect(submoduleCallback).to.equal(undefined); + }); + + it('dapEncMembership error callback', function () { + let configAsync = JSON.parse(JSON.stringify(esampleConfig)); + let submoduleCallback = dapUtils.dapEncryptedMembership(configAsync, 'token', onDone, + function(token, status, xhr, onDone) { + }, + function(xhr, status, error, onDone) { + } + ); + let request = server.requests[0]; + request.respond(400, responseHeader, JSON.stringify('error')); + expect(submoduleCallback).to.equal(undefined); + }); + }); + + describe('dapMembership', function () { + it('should invoke the getDapToken and getDapMembership', function () { + let membership = { + said: 'item.said1', + cohorts: 'item.cohorts', + attributes: null + }; + + let getDapMembershipStub = sinon.stub(dapUtils, 'dapGetMembershipFromLocalStorage').returns(membership); + let callDapApisStub = sinon.stub(dapUtils, 'callDapAPIs'); + try { + generateRealTimeData(testReqBidsConfigObj, onDone, cmoduleConfig); + expect(getDapMembershipStub.calledOnce).to.be.equal(true); + } finally { + getDapMembershipStub.restore(); + callDapApisStub.restore(); + } + }); + }); + + describe('dapEncMembership test', function () { + it('should invoke the getDapToken and getEncDapMembership', function () { + let encMembership = { + encryptedSegments: 'enc.seg', + }; + + let getDapEncMembershipStub = sinon.stub(dapUtils, 'dapGetEncryptedMembershipFromLocalStorage').returns(encMembership); + let callDapApisStub = sinon.stub(dapUtils, 'callDapAPIs'); + try { + generateRealTimeData(testReqBidsConfigObj, onDone, emoduleConfig); + expect(getDapEncMembershipStub.calledOnce).to.be.equal(true); + } finally { + getDapEncMembershipStub.restore(); + callDapApisStub.restore(); + } + }); + }); + + describe('dapGetRtdObj test', function () { + it('dapGetRtdObj', function () { + const config = { + apiHostname: 'prebid.dap.akadns.net', + apiVersion: 'x1', + domain: 'prebid.org', + segtax: 503 + }; + expect(dapUtils.dapRefreshMembership(ortb2, config, 'token', onDone)).to.equal(undefined) + const membership = {cohorts: ['1', '5', '7']} + expect(dapUtils.dapGetRtdObj(membership, config.segtax)).to.not.equal(undefined); + }); + }); + + describe('checkAndAddRealtimeData test', function () { + it('add realtime data for segtax 503 and 504', function () { + dapUtils.checkAndAddRealtimeData(ortb2, cachedEncRtd, 504); + dapUtils.checkAndAddRealtimeData(ortb2, cachedEncRtd, 504); + expect(ortb2.user.data).to.deep.include.members([encRtdUserObj]); + dapUtils.checkAndAddRealtimeData(ortb2, cachedRtd, 503); + expect(ortb2.user.data).to.deep.include.members([rtdUserObj]); + }); + }); + + describe('dapExtractExpiryFromToken test', function () { + it('test dapExtractExpiryFromToken function', function () { + let tokenWithoutExpiry = 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Iiwia2lkIjoicGFzc3dvcmQxIn0..6buzBd2BjtgoyaNbHN8YnQ.l38avCfm3sYNy798-ETYOugz0cOx1cCkjACkAhYszxzrZ0sUJ0AiF-NdDXVTiTyp2Ih3vCWKzS0rKJ8lbS1zhyEVWVu91QwtwseM2fBbwA5ggAgBEo5wV-IXqDLPxVnxsPF0D3hP6cNCiH9Q2c-vULfsLhMhG5zvvZDPBbn4hUY5fKB8LoCBTF9rbuuWGYK1nramnb4AlS5UK82wBsHQea1Ou_Kp5wWCMNZ6TZk5qKIuRBfPIAhQblWvHECaHXkg1wyoM9VASs_yNhne7RR-qkwzbFiPFiMJibNOt9hF3_vPDJO5-06ZBjRTP1BllYGWxI-uQX6InzN18Wtun2WHqg.63sH0SNlIRcsK57v0pMujfB_nhU8Y5CuQbsHqH5MGoM' + expect(dapUtils.dapExtractExpiryFromToken(tokenWithoutExpiry)).to.equal(undefined); + let tokenWithExpiry = 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Iiwia2lkIjoicGFzc3dvcmQxIiwiZXhwIjoxNjQzODMwMzY5fQ..hTbcSQgmmO0HUJJrQ5fRHw.7zjrQXNNVkb-GD0ZhIVhEPcWbyaDBilHTWv-bp1lFZ9mdkSC0QbcAvUbYteiTD7ya23GUwcL2WOW8WgRSHaWHOJe0B5NDqfdUGTzElWfu7fFodRxRgGmwG8Rq5xxteFKLLGHLf1mFYRJKDtjtgajGNUKIDfn9AEt-c5Qz4KU8VolG_KzrLROx-f6Z7MnoPTcwRCj0WjXD6j2D6RAZ80-mKTNIsMIELdj6xiabHcjDJ1WzwtwCZSE2y2nMs451pSYp8W-bFPfZmDDwrkjN4s9ASLlIXcXgxK-H0GsiEbckQOZ49zsIKyFtasBvZW8339rrXi1js-aBh99M7aS5w9DmXPpUDmppSPpwkeTfKiqF0cQiAUq8tpeEQrGDJuw3Qt2.XI8h9Xw-VZj_NOmKtV19wLM63S4snos7rzkoHf9FXCw' + expect(dapUtils.dapExtractExpiryFromToken(tokenWithExpiry)).to.equal(1643830369); + }); + }); + + describe('dapRefreshToken test', function () { + it('test dapRefreshToken success response', function () { + dapUtils.dapRefreshToken(ortb2, sampleConfig, true, onDone) + let request = server.requests[0]; + responseHeader['Symitri-DAP-Token'] = sampleCachedToken.token; + request.respond(200, responseHeader, JSON.stringify(sampleCachedToken.token)); + expect(JSON.parse(storage.getDataFromLocalStorage(DAP_TOKEN)).token).to.be.equal(sampleCachedToken.token); + }); + + it('test dapRefreshToken success response with deviceid 100', function () { + dapUtils.dapRefreshToken(ortb2, esampleConfig, true, onDone) + let request = server.requests[0]; + responseHeader['Symitri-DAP-100'] = sampleCachedToken.token; + request.respond(200, responseHeader, ''); + expect(storage.getDataFromLocalStorage('dap_deviceId100')).to.be.equal(sampleCachedToken.token); + }); + + it('test dapRefreshToken success response with exp claim', function () { + dapUtils.dapRefreshToken(ortb2, sampleConfig, true, onDone) + let request = server.requests[0]; + let tokenWithExpiry = 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Iiwia2lkIjoicGFzc3dvcmQxIiwiZXhwIjoxNjQzODMwMzY5fQ..hTbcSQgmmO0HUJJrQ5fRHw.7zjrQXNNVkb-GD0ZhIVhEPcWbyaDBilHTWv-bp1lFZ9mdkSC0QbcAvUbYteiTD7ya23GUwcL2WOW8WgRSHaWHOJe0B5NDqfdUGTzElWfu7fFodRxRgGmwG8Rq5xxteFKLLGHLf1mFYRJKDtjtgajGNUKIDfn9AEt-c5Qz4KU8VolG_KzrLROx-f6Z7MnoPTcwRCj0WjXD6j2D6RAZ80-mKTNIsMIELdj6xiabHcjDJ1WzwtwCZSE2y2nMs451pSYp8W-bFPfZmDDwrkjN4s9ASLlIXcXgxK-H0GsiEbckQOZ49zsIKyFtasBvZW8339rrXi1js-aBh99M7aS5w9DmXPpUDmppSPpwkeTfKiqF0cQiAUq8tpeEQrGDJuw3Qt2.XI8h9Xw-VZj_NOmKtV19wLM63S4snos7rzkoHf9FXCw' + responseHeader['Symitri-DAP-Token'] = tokenWithExpiry; + request.respond(200, responseHeader, JSON.stringify(tokenWithExpiry)); + expect(JSON.parse(storage.getDataFromLocalStorage(DAP_TOKEN)).expires_at).to.be.equal(1643830359); + }); + + it('test dapRefreshToken error response', function () { + storage.setDataInLocalStorage(DAP_TOKEN, JSON.stringify(sampleCachedToken)); + dapUtils.dapRefreshToken(ortb2, sampleConfig, false, onDone) + let request = server.requests[0]; + request.respond(400, responseHeader, 'error'); + expect(JSON.parse(storage.getDataFromLocalStorage(DAP_TOKEN)).expires_at).to.be.equal(cacheExpiry);// Since the expiry is same, the token is not updated in the cache + }); + }); + + describe('dapRefreshEncryptedMembership test', function () { + it('test dapRefreshEncryptedMembership success response', function () { + let expiry = Math.round(Date.now() / 1000.0) + 3600; // in seconds + let encMembership = 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Iiwia2lkIjoic29tZXNlY3JldGludmF1bHQifQ..f8_At4OqeQXyQcSwThOJ_w.69ImVQ3bEZ6QP7ROCRpAJjNcKY49SEPYR6qTp_8l7L8kQdPbpi4wmuOzt78j7iBrX64k2wltzmQFjDmVKSxDhrEguxpgx6t-L1tT8ZA0UosMWpVsgmKEZxOn2e9ES3jw8RNCS4WSWocSPQX33xSb51evXjm9E1s0tGoLnwXl0GsUvzRsSU86wQG6RZnAQTi7s-r-M2TKibdDjUqgIt62vJ-aBZ7RWw91MINgOdmDNs1bFfbBX5Cy1kd4-kjvRDz_aJ6zHX4sK_7EmQhGEY3tW-A3_l2I88mw-RSJaPkb_IWg0QpVwXDaE2F2g8NpY1PzCRvG_NIE8r28eK5q44OMVitykHmKmBXGDj7z2JVgoXkfo5u0I-dypZARn4GP_7niK932avB-9JD7Mz3TrlU4GZ7IpYfJ91PMsRhrs5xNPQwLZbpuhF76A7Dp7iss71UjkGCiPTU6udfRb4foyf_7xEF66m1eQVcVaMdxEbMuu9GBfdr-d04TbtJhPfUV8JfxTenvRYoi13n0j5kH0M5OgaSQD9kQ3Mrd9u-Cms-BGtT0vf-N8AaFZY_wn0Y4rkpv5HEaH7z3iT4RCHINWrXb_D0WtjLTKQi2YmF8zMlzUOewNJGwZRwbRwxc7JoDIKEc5RZkJYevfJXOEEOPGXZ7AGZxOEsJawPqFqd_nOUosCZS4akHhcDPcVowoecVAV0hhhoS6JEY66PhPp1snbt6yqA-fQhch7z8Y-DZT3Scibvffww3Scg_KFANWp0KeEvHG0vyv9R2F4o66viSS8y21MDnM7Yjk8C-j7aNMldUQbjN_7Yq1nkfe0jiBX_hsINBRPgJHUY4zCaXuyXs-JZZfU92nwG0RT3A_3RP2rpY8-fXp9d3C2QJjEpnmHvTMsuAZCQSBe5DVrJwN_UKedxcJEoOt0wLz6MaCMyYZPd8tnQeqYK1cd3RgQDXtzKC0HDw1En489DqJXEst4eSSkaaW1lImLeaF8XCOaIqPqoyGk4_6KVLw5Q7OnpczuXqYKMd9UTMovGeuTuo1k0ddfEqTq9QwxkwZL51AiDRnwTCAeYBU1krV8FCJQx-mH_WPB5ftZj-o_3pbvANeRk27QBVmjcS-tgDllJkWBxX-4axRXzLw8pUUUZUT_NOL0OiqUCWVm0qMBEpgRQ57Se42-hkLMTzLhhGJOnVcaXU1j4ep-N7faNvbgREBjf_LgzvaWS90a2NJ9bB_J9FyXelhCN_AMLfdOS3fHkeWlZ0u0PMbn5DxXRMe0l9jB-2VJZhcPQRlWoYyoCO3l4F5ZmuQP5Xh9CU4tvSWih6jlwMDgdVWuTpdfPD5bx8ccog3JDq87enx-QtPzLU3gMgouNARJGgNwKS_GJSE1uPrt2oiqgZ3Z0u_I5MKvPdQPV3o-4rsaE730eB4OwAOF-mkGWpzy8Pbl-Qe5PR9mHBhuyJgZ-WDSCHl5yvet2kfO9mPXZlqBQ26fzTcUYH94MULAZn36og6w.3iKGv-Le-AvRmi26W1v6ibRLGbwKbCR92vs-a9t55hw'; + dapUtils.dapRefreshEncryptedMembership(ortb2, esampleConfig, sampleCachedToken.token, onDone) + let request = server.requests[0]; + responseHeader['Symitri-DAP-Token'] = encMembership; + request.respond(200, responseHeader, encMembership); + let rtdObj = dapUtils.dapGetEncryptedRtdObj({'encryptedSegments': encMembership}, 504) + expect(ortb2.user.data).to.deep.include.members(rtdObj.rtd.ortb2.user.data); + expect(JSON.parse(storage.getDataFromLocalStorage(DAP_ENCRYPTED_MEMBERSHIP)).expires_at).to.equal(expiry); + }); + + it('test dapRefreshEncryptedMembership success response with exp claim', function () { + let encMembership = 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Iiwia2lkIjoic29tZXNlY3JldGludmF1bHQiLCJleHAiOjE2NDM4MzA2NDB9..inYoxwht_aqTIWqGhEm_Gw.wDcCUOCwtqgnNUouaD723gKfm7X7bgkHgtiX4mr07P3tWk25PUQunmwTLhWBB5CYzzGIfIvveG_u4glNRLi_eRSQV4ihKKk1AN-BSSJ3d0CLAdY9I1WG5vX1VmopXyKnV90bl9SLNqnhg4Vxe6YU4ogTYxsKHuIN1EeIH4hpl-HbCQWQ1DQt4mB-MQF8V9AWTfU0D7sFMSK8f9qj6NGmf1__oHdHUlws0t5V2UAn_dhJexsuREK_gh65pczCuly5eEcziZ82LeP-nOhKWSRHB_tS_mKXrRU6_At_EVDgtfA3PSBJ6eQylCii6bTL42vZzz4jZhJv_3eLfRdKqpVT5CWNBzcDoQ2VcQgKgIBtPJ45KFfAYTQ6kdl21QMSjqtu8GTsv1lEZtrqHY6zRiG8_Mu28-PmjEw4LDdZmBDOeroue_MJD6wuE_jlE7J2iVdo8CkVnoRgzFwNbKBo7CK4z0WahV9rhuOm0LKAN5H0jF_gj696U-3fVTDTIb8ndNKNI2_xAhvWs00BFGtUtWgr8QGDGRTDCNGsDgnb_Vva9xCqVOyAE9O3Fq1QYl-tMA-KkBt3zzvmFFpOxpOyH-lUubKLKlsrxKc3GSyVEQ9DDLhrXXJgR5H5BSE4tjlK7p3ODF5qz0FHtIj7oDcgLazFO7z2MuFy2LjJmd3hKl6ujcfYEDiQ4D3pMIo7oiU33aFBD1YpzI4-WzNfJlUt1FoK0-DAXpbbV95s8p08GOD4q81rPw5hRADKJEr0QzrbDwplTWCzT2fKXMg_dIIc5AGqGKnVRUS6UyF1DnHpudNIJWxyWZjWIEw_QNjU0cDFmyPSyKxNrnfq9w8WE2bfbS5KTicxei5QHnC-cnL7Nh7IXp7WOW6R1YHbNPT7Ad4OhnlV-jjrXwkSv4wMAbfwAWoSCchGh7uvENNAeJymuponlJbOgw_GcYM73hMs8Z8W9qxRfbyF4WX5fDKXg61mMlaieHkc0EnoC5q7uKyXuZUehHZ76JLDFmewslLkQq5SkVCttzJePBnY1ouPEHw5ZTzUnG5f01QQOVcjIN-AqXNDbG5IOwq0heyS6vVfq7lZKJdLDVQ21qRjazGPaqYwLzugkWkzCOzPTgyFdbXzgjfmJwylHSOM5Jpnul84GzxEQF-1mHP2A8wtIT-M7_iX24It2wwWvc8qLA6GEqruWCtNyoug8CXo44mKdSSCGeEZHtfMbzXdLIBHCy2jSHz5i8S7DU_R7rE_5Ssrb81CqIYbgsAQBHtOYoyvzduTOruWcci4De0QcULloqImIEHUuIe2lnYO889_LIx5p7nE3UlSvLBo0sPexavFUtHqI6jdG6ye9tdseUEoNBDXW0aWD4D-KXX1JLtAgToPVUtEaXCJI7QavwO9ZG6UZM6jbfuJ5co0fvUXp6qYrFxPQo2dYHkar0nT6s1Zg5l2g8yWlLUJrHdHAzAw_NScUp71OpM4TmNsLnYaPVPcOxMvtJXTanbNWr0VKc8gy9q3k_1XxAnQwiduNs7f5bA-6qCVpayHv5dE7mUhFEwyh1_w95jEaURsQF_hnnd2OqRkADfiok4ZiPU2b38kFW1LXjpI39XXES3JU0e08Rq2uuelyLbCLWuJWq_axuKSZbZvpYeqWtIAde8FjCiO7RPlEc0nyzWBst8RBxQ-Bekg9UXPhxBRcm0HwA.Q2cBSFOQAC-QKDwmjrQXnVQd3jNOppMl9oZfd2yuKeY'; + dapUtils.dapRefreshEncryptedMembership(ortb2, esampleConfig, sampleCachedToken.token, onDone) + let request = server.requests[0]; + responseHeader['Symitri-DAP-Token'] = encMembership; + request.respond(200, responseHeader, encMembership); + let rtdObj = dapUtils.dapGetEncryptedRtdObj({'encryptedSegments': encMembership}, 504) + expect(ortb2.user.data).to.deep.include.members(rtdObj.rtd.ortb2.user.data); + expect(JSON.parse(storage.getDataFromLocalStorage(DAP_ENCRYPTED_MEMBERSHIP)).expires_at).to.equal(1643830630); + }); + + it('test dapRefreshEncryptedMembership error response', function () { + dapUtils.dapRefreshEncryptedMembership(ortb2, esampleConfig, sampleCachedToken.token, onDone) + let request = server.requests[0]; + request.respond(400, responseHeader, 'error'); + expect(ortb2).to.eql({}); + }); + + it('test dapRefreshEncryptedMembership 403 error response', function () { + dapUtils.dapRefreshEncryptedMembership(ortb2, esampleConfig, sampleCachedToken.token, onDone) + let request = server.requests[0]; + request.respond(403, responseHeader, 'error'); + let requestTokenize = server.requests[1]; + responseHeader['Symitri-DAP-Token'] = sampleCachedToken.token; + requestTokenize.respond(200, responseHeader, ''); + let requestMembership = server.requests[2]; + requestMembership.respond(403, responseHeader, 'error'); + expect(server.requests.length).to.be.equal(DAP_MAX_RETRY_TOKENIZE + 2); + }); + }); + + describe('dapRefreshMembership test', function () { + it('test dapRefreshMembership success response', function () { + let membership = {'cohorts': ['9', '11', '13'], 'said': 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Iiwia2lkIjoicGFzc3dvcmQxIn0..17wnrhz6FbWx0Cf6LXpm1A.m9PKVCradk3CZokNKzVHzE06TOqiXYeijgxTQUiQy5Syx-yicnO8DyYX6zQ6rgPcNgUNRt4R4XE5MXuK0laUVQJr9yc9g3vUfQfw69OMYGW_vRlLMPzoNOhF2c4gSyfkRrLr7C0qgALmZO1D11sPflaCTNmO7pmZtRaCOB5buHoWcQhp1bUSJ09DNDb31dX3llimPwjNGSrUhyq_EZl4HopnnjxbM4qVNMY2G_43C_idlVOvbFoTxcDRATd-6MplJoIOIHQLDZEetpIOVcbEYN9gQ_ndBISITwuu5YEgs5C_WPHA25nm6e4BT5R-tawSA8yPyQAupqE8gk4ZWq_2-T0cqyTstIHrMQnZ_vysYN7h6bkzE-KeZRk7GMtySN87_fiu904hLD9QentGegamX6UAbVqQh7Htj7SnMHXkEenjxXAM5mRqQvNCTlw8k-9-VPXs-vTcKLYP8VFf8gMOmuYykgWac1gX-svyAg-24mo8cUbqcsj9relx4Qj5HiXUVyDMBZxK-mHZi-Xz6uv9GlggcsjE13DSszar-j2OetigpdibnJIxRZ-4ew3-vlvZ0Dul3j0LjeWURVBWYWfMjuZ193G7lwR3ohh_NzlNfwOPBK_SYurdAnLh7jJgTW-lVLjH2Dipmi9JwX9s03IQq9opexAn7hlM9oBI6x5asByH8JF8WwZ5GhzDjpDwpSmHPQNGFRSyrx_Sh2CPWNK6C1NJmLkyqAtJ5iw0_al7vPDQyZrKXaLTjBCUnbpJhUZ8dUKtWLzGPjzFXp10muoDIutd1NfyKxk1aWGhx5aerYuLdywv6cT_M8RZTi8924NGj5VA30V5OvEwLLyX93eDhntXZSCbkPHpAfiRZNGXrPY.GhCbWGQz11mIRD4uPKmoAuFXDH7hGnils54zg7N7-TU'} + dapUtils.dapRefreshMembership(ortb2, sampleConfig, sampleCachedToken.token, onDone); + let request = server.requests[0]; + request.respond(200, responseHeader, JSON.stringify(membership)); + let rtdObj = dapUtils.dapGetRtdObj(membership, 503); + expect(ortb2.user.data).to.deep.include.members(rtdObj.rtd.ortb2.user.data); + }); + + it('test dapRefreshMembership success response with exp claim', function () { + let membership = {'cohorts': ['9', '11', '13'], 'said': 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Iiwia2lkIjoicGFzc3dvcmQxIiwiZXhwIjoxNjQ3OTcxNTU4fQ..ptdM5WO-62ypXlKxFXD4FQ.waEo9MHS2NYQCi-zh_p6HgT9BdqGyQbBq4GfGLfsay4nRBgICsTS-VkV6e7xx5U1T8BgpKkRJIZBwTOY5Pkxk9FpK5nnffDSEljRrp1LXLCkNP4qwrlqHInFbZsonNWW4_mW-7aUPlTwIsTbfjTuyHdXHeQa1ALrwFFFWE7QUmPNd2RsHjDwUsxlJPEb5TnHn5W0Mgo_PQZaxvhJInMbxPgtJLoqnJvOqCBEoQY7au7ALZL_nWK8XIwPMF19J7Z3cBg9vQInhr_E3rMdQcAFHEzYfgoNcIYCCR0t1UOqUE3HNtX-E64kZAYKWdlsBb9eW5Gj9hHYyPNL_4Hntjg5eLXGpsocMg0An-qQKGC6hkrxKzeM-GrjpvSaQLNs4iqDpHUtzA02LW_vkLkMNRUiyXVJ3FUZwfyq6uHSRKWZ6UFdAfL0rfJ8q8x8Ll-qJO2Jfyvidlsi9FIs7x1WJrvDCKepfAQM1UXRTonrQljFBAk83PcL2bmWuJDgJZ0lWS4VnZbIf6A7fDourmkDxdVRptvQq5nSjtzCA6whRw0-wGz8ehNJsaJw9H_nG9k4lRKs7A5Lqsyy7TVFrAPjnA_Q1a2H6xF2ULxrtIqoNqdX7k9RjowEZSQlZgZUOAmI4wzjckdcSyC_pUlYBMcBwmlld34mmOJe9EBHAxjdci7Q_9lvj1HTcwGDcQITXnkW9Ux5Jkt9Naw-IGGrnEIADaT2guUAto8W_Gb05TmwHSd6DCmh4zepQCbqeVe6AvPILtVkTgsTTo27Q-NvS7h-XtthJy8425j5kqwxxpZFJ0l0ytc6DUyNCLJXuxi0JFU6-LoSXcROEMVrHa_Achufr9vHIELwacSAIHuwseEvg_OOu1c1WYEwZH8ynBLSjqzy8AnDj24hYgA0YanPAvDqacrYrTUFqURbHmvcQqLBTcYa_gs7uDx4a1EjtP_NvHRlvCgGAaASrjGMhTX8oJxlTqahhQ.pXm-7KqnNK8sbyyczwkVYhcjgiwkpO8LjBBVw4lcyZE'}; + dapUtils.dapRefreshMembership(ortb2, sampleConfig, sampleCachedToken.token, onDone); + let request = server.requests[0]; + request.respond(200, responseHeader, JSON.stringify(membership)); + let rtdObj = dapUtils.dapGetRtdObj(membership, 503) + expect(ortb2.user.data).to.deep.include.members(rtdObj.rtd.ortb2.user.data); + expect(JSON.parse(storage.getDataFromLocalStorage(DAP_MEMBERSHIP)).expires_at).to.be.equal(1647971548); + }); + + it('test dapRefreshMembership 400 error response', function () { + dapUtils.dapRefreshMembership(ortb2, sampleConfig, sampleCachedToken.token, onDone) + let request = server.requests[0]; + request.respond(400, responseHeader, 'error'); + expect(ortb2).to.eql({}); + }); + + it('test dapRefreshMembership 403 error response', function () { + dapUtils.dapRefreshMembership(ortb2, sampleConfig, sampleCachedToken.token, onDone) + let request = server.requests[0]; + request.respond(403, responseHeader, 'error'); + expect(server.requests.length).to.be.equal(DAP_MAX_RETRY_TOKENIZE); + }); + }); + + describe('dapGetEncryptedMembershipFromLocalStorage test', function () { + it('test dapGetEncryptedMembershipFromLocalStorage function with valid cache', function () { + storage.setDataInLocalStorage(DAP_ENCRYPTED_MEMBERSHIP, JSON.stringify(cachedEncryptedMembership)) + expect(JSON.stringify(dapUtils.dapGetEncryptedMembershipFromLocalStorage())).to.equal(JSON.stringify(encMembership)); + }); + + it('test dapGetEncryptedMembershipFromLocalStorage function with invalid cache', function () { + let expiry = Math.round(Date.now() / 1000.0) - 100; // in seconds + let encMembership = {'expiry': expiry, 'encryptedSegments': cachedEncryptedMembership.encryptedSegments} + storage.setDataInLocalStorage(DAP_ENCRYPTED_MEMBERSHIP, JSON.stringify(encMembership)) + expect(dapUtils.dapGetEncryptedMembershipFromLocalStorage()).to.equal(null); + }); + }); + + describe('Symitri-DAP-SS-ID test', function () { + it('Symitri-DAP-SS-ID present in response header', function () { + let expiry = Math.round(Date.now() / 1000.0) + 300; // in seconds + dapUtils.dapRefreshToken(ortb2, sampleConfig, false, onDone) + let request = server.requests[0]; + let sampleSSID = 'Test_SSID_Spec'; + responseHeader['Symitri-DAP-Token'] = sampleCachedToken.token; + responseHeader['Symitri-DAP-SS-ID'] = sampleSSID; + request.respond(200, responseHeader, ''); + expect(storage.getDataFromLocalStorage(DAP_SS_ID)).to.be.equal(JSON.stringify(sampleSSID)); + }); + + it('Test if Symitri-DAP-SS-ID is present in request header', function () { + let expiry = Math.round(Date.now() / 1000.0) + 100; // in seconds + storage.setDataInLocalStorage(DAP_SS_ID, JSON.stringify('Test_SSID_Spec')) + dapUtils.dapRefreshToken(ortb2, sampleConfig, false, onDone) + let request = server.requests[0]; + let ssidHeader = request.requestHeaders['Symitri-DAP-SS-ID']; + responseHeader['Symitri-DAP-Token'] = sampleCachedToken.token; + request.respond(200, responseHeader, ''); + expect(ssidHeader).to.be.equal('Test_SSID_Spec'); + }); + }); + + describe('Test gdpr and usp consent handling', function () { + it('Gdpr applies and gdpr consent string not present', function () { + expect(symitriDapRtdSubmodule.init(null, sampleGdprConsentConfig)).to.equal(false); + }); + + it('Gdpr applies and gdpr consent string is present', function () { + sampleGdprConsentConfig.gdpr.consentString = 'BOJ/P2HOJ/P2HABABMAAAAAZ+A=='; + expect(symitriDapRtdSubmodule.init(null, sampleGdprConsentConfig)).to.equal(true); + }); + + it('USP consent present and user have opted out', function () { + expect(symitriDapRtdSubmodule.init(null, sampleUspConsentConfig)).to.equal(false); + }); + + it('USP consent present and user have not been provided with option to opt out', function () { + expect(symitriDapRtdSubmodule.init(null, {'usp': '1NYY'})).to.equal(false); + }); + + it('USP consent present and user have not opted out', function () { + expect(symitriDapRtdSubmodule.init(null, {'usp': '1YNY'})).to.equal(true); + }); + }); +}); diff --git a/test/spec/modules/tagorasBidAdapter_spec.js b/test/spec/modules/tagorasBidAdapter_spec.js index 7559567dcff..d68088affa1 100644 --- a/test/spec/modules/tagorasBidAdapter_spec.js +++ b/test/spec/modules/tagorasBidAdapter_spec.js @@ -2,6 +2,14 @@ import {expect} from 'chai'; import { spec as adapter, createDomain, + storage +} from 'modules/tagorasBidAdapter'; +import * as utils from 'src/utils.js'; +import {version} from 'package.json'; +import {useFakeTimers} from 'sinon'; +import {BANNER, VIDEO} from '../../../src/mediaTypes'; +import {config} from '../../../src/config'; +import { hashCode, extractPID, extractCID, @@ -10,12 +18,7 @@ import { setStorageItem, tryParseJSON, getUniqueDealId, -} from 'modules/tagorasBidAdapter'; -import * as utils from 'src/utils.js'; -import {version} from 'package.json'; -import {useFakeTimers} from 'sinon'; -import {BANNER, VIDEO} from '../../../src/mediaTypes'; -import {config} from '../../../src/config'; +} from '../../../libraries/vidazooUtils/bidderUtils.js'; export const TEST_ID_SYSTEMS = ['britepoolid', 'criteoId', 'id5id', 'idl_env', 'lipb', 'netId', 'parrableId', 'pubcid', 'tdid', 'pubProvidedId']; @@ -324,7 +327,12 @@ describe('TagorasBidAdapter', function () { startdelay: 0 } }, - gpid: '' + gpid: '', + cat: [], + contentData: [], + isStorageAllowed: true, + pagecat: [], + userData: [] } }); }); @@ -385,6 +393,11 @@ describe('TagorasBidAdapter', function () { uqs: getTopWindowQueryParams(), 'ext.param1': 'loremipsum', 'ext.param2': 'dolorsitamet', + cat: [], + contentData: [], + isStorageAllowed: true, + pagecat: [], + userData: [] } }); }); @@ -527,8 +540,6 @@ describe('TagorasBidAdapter', function () { switch (idSystemProvider) { case 'lipb': return {lipbid: id}; - case 'parrableId': - return {eid: id}; case 'id5id': return {uid: id}; default: @@ -581,13 +592,13 @@ describe('TagorasBidAdapter', function () { const key = 'myKey'; let uniqueDealId; beforeEach(() => { - uniqueDealId = getUniqueDealId(key, 0); + uniqueDealId = getUniqueDealId(storage, key, 0); }) it('should get current unique deal id', function (done) { // waiting some time so `now` will become past setTimeout(() => { - const current = getUniqueDealId(key); + const current = getUniqueDealId(storage, key); expect(current).to.be.equal(uniqueDealId); done(); }, 200); @@ -595,7 +606,7 @@ describe('TagorasBidAdapter', function () { it('should get new unique deal id on expiration', function (done) { setTimeout(() => { - const current = getUniqueDealId(key, 100); + const current = getUniqueDealId(storage, key, 100); expect(current).to.not.be.equal(uniqueDealId); done(); }, 200) @@ -619,8 +630,8 @@ describe('TagorasBidAdapter', function () { shouldAdvanceTime: true, now }); - setStorageItem('myKey', 2020); - const {value, created} = getStorageItem('myKey'); + setStorageItem(storage, 'myKey', 2020); + const {value, created} = getStorageItem(storage, 'myKey'); expect(created).to.be.equal(now); expect(value).to.be.equal(2020); expect(typeof value).to.be.equal('number'); @@ -631,7 +642,7 @@ describe('TagorasBidAdapter', function () { it('should get external stored value', function () { const value = 'superman' window.localStorage.setItem('myExternalKey', value); - const item = getStorageItem('myExternalKey'); + const item = getStorageItem(storage, 'myExternalKey'); expect(item).to.be.equal(value); }); diff --git a/test/spec/modules/targetVideoBidAdapter_spec.js b/test/spec/modules/targetVideoBidAdapter_spec.js index 8180183e6d7..442d7e7ef0b 100644 --- a/test/spec/modules/targetVideoBidAdapter_spec.js +++ b/test/spec/modules/targetVideoBidAdapter_spec.js @@ -1,27 +1,42 @@ import { spec } from '../../../modules/targetVideoBidAdapter.js' describe('TargetVideo Bid Adapter', function() { + const bidder = 'targetVideo'; + const params = { + placementId: 12345, + }; + const bannerRequest = [{ - bidder: 'targetVideo', + bidder, + params, mediaTypes: { banner: { sizes: [[300, 250]], } }, - params: { - placementId: 12345, + }]; + + const videoRequest = [{ + bidder, + params, + mediaTypes: { + video: { + playerSize: [[640, 360]], + context: 'instream', + playbackmethod: [1, 2, 3, 4] + } } }]; it('Test the bid validation function', function() { - const validBid = spec.isBidRequestValid(bannerRequest[0]); + const validBid = spec.isBidRequestValid(bannerRequest[0]) && spec.isBidRequestValid(videoRequest[0]); const invalidBid = spec.isBidRequestValid(null); expect(validBid).to.be.true; expect(invalidBid).to.be.false; }); - it('Test the request processing function', function () { + it('Test the BANNER request processing function', function() { const request = spec.buildRequests(bannerRequest, bannerRequest[0]); expect(request).to.not.be.empty; @@ -36,7 +51,20 @@ describe('TargetVideo Bid Adapter', function() { expect(payload.tags[0].ad_types[0]).to.equal('video'); }); - it('Handle nobid responses', function () { + it('Test the VIDEO request processing function', function() { + const request = spec.buildRequests(videoRequest, videoRequest[0]); + expect(request).to.not.be.empty; + + const payload = JSON.parse(request[0].data); + expect(payload).to.not.be.empty; + expect(payload.sdk).to.deep.equal({ + source: 'pbjs', + version: '$prebid.version$' + }); + expect(payload.imp[0].ext.prebid.storedrequest.id).to.equal(12345); + }) + + it('Handle BANNER nobid responses', function() { const responseBody = { 'version': '0.0.1', 'tags': [{ @@ -48,11 +76,24 @@ describe('TargetVideo Bid Adapter', function() { }; const bidderRequest = null; - const bidResponse = spec.interpretResponse({ body: responseBody }, {bidderRequest}); + const bidResponse = spec.interpretResponse({ body: responseBody }, { bidderRequest }); expect(bidResponse.length).to.equal(0); }); - it('Test the response parsing function', function () { + it('Handle VIDEO nobid responses', function() { + const responseBody = { + 'id': 'test-id', + 'cur': 'USD', + 'seatbid': [], + 'nbr': 0 + }; + const bidderRequest = null; + + const bidResponse = spec.interpretResponse({ body: responseBody }, { bidderRequest }); + expect(bidResponse.length).to.equal(0); + }) + + it('Test the BANNER response parsing function', function() { const responseBody = { 'tags': [{ 'uuid': '84ab500420319d', @@ -82,7 +123,7 @@ describe('TargetVideo Bid Adapter', function() { }] }; - const bidResponse = spec.interpretResponse({ body: responseBody }, {bidderRequest}); + const bidResponse = spec.interpretResponse({ body: responseBody }, { bidderRequest }); expect(bidResponse).to.not.be.empty; const bid = bidResponse[0]; @@ -94,7 +135,43 @@ describe('TargetVideo Bid Adapter', function() { expect(bid.ad).to.include('initPlayer') }); - it('Test GDPR consent information is present in the request', function () { + it('Test the VIDEO response parsing function', function() { + const responseBody = { + 'id': 'test-id', + 'cur': 'USD', + 'seatbid': [{ + 'bid': [{ + 'id': '5044997188309660254', + 'price': 10, + 'adm': 'test ad', + 'adid': '97517771', + 'crid': '97517771', + 'adomain': ['domain.com'], + 'w': 640, + 'h': 480 + }], + 'seat': 'bidder' + }] + }; + const bidderRequest = { + bidderCode: 'brid', + bidderRequestId: '22edbae2733bf6', + bids: videoRequest + }; + + const bidResponse = spec.interpretResponse({ body: responseBody }, { bidderRequest }); + expect(bidResponse).to.not.be.empty; + + const bid = bidResponse[0]; + expect(bid).to.not.be.empty; + expect(bid.ad).to.equal('test ad'); + expect(bid.cpm).to.equal(10); + expect(bid.width).to.equal(640); + expect(bid.height).to.equal(480); + expect(bid.currency).to.equal('USD'); + }) + + it('Test BANNER GDPR consent information is present in the request', function() { let consentString = 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A=='; let bidderRequest = { 'bidderCode': 'targetVideo', @@ -119,7 +196,7 @@ describe('TargetVideo Bid Adapter', function() { expect(payload.gdpr_consent.addtl_consent).to.exist.and.to.deep.equal([7, 12, 35, 62, 66, 70, 89, 93, 108]); }); - it('Test US Privacy string is present in the request', function() { + it('Test BANNER US Privacy string is present in the request', function() { let consentString = '1YA-'; let bidderRequest = { 'bidderCode': 'targetVideo', @@ -136,4 +213,28 @@ describe('TargetVideo Bid Adapter', function() { expect(payload.us_privacy).to.exist; expect(payload.us_privacy).to.exist.and.to.equal(consentString); }); + + it('Test VIDEO GDPR and USP consents are present in the request', function() { + let gdprConsentString = 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A=='; + let uspConsentString = '1YA-'; + let bidderRequest = { + 'bidderCode': 'targetVideo', + 'bidderRequestId': '22edbae2733bf6', + 'timeout': 3000, + 'uspConsent': uspConsentString, + 'gdprConsent': { + consentString: gdprConsentString, + gdprApplies: true, + addtlConsent: '1~7.12.35.62.66.70.89.93.108' + } + }; + bidderRequest.bids = videoRequest; + + const request = spec.buildRequests(videoRequest, bidderRequest); + const payload = JSON.parse(request[0].data); + + expect(payload.user.ext.consent).to.equal(gdprConsentString); + expect(payload.regs.ext.us_privacy).to.equal(uspConsentString); + expect(payload.regs.ext.gdpr).to.equal(1); + }); }); diff --git a/test/spec/modules/twistDigitalBidAdapter_spec.js b/test/spec/modules/twistDigitalBidAdapter_spec.js index 1a73d2f6897..674414bb526 100644 --- a/test/spec/modules/twistDigitalBidAdapter_spec.js +++ b/test/spec/modules/twistDigitalBidAdapter_spec.js @@ -2,12 +2,7 @@ import {expect} from 'chai'; import { spec as adapter, createDomain, - hashCode, - getStorageItem, - setStorageItem, - tryParseJSON, - getUniqueDealId, - webSessionId + storage } from 'modules/twistDigitalBidAdapter.js'; import * as utils from 'src/utils.js'; import {version} from 'package.json'; @@ -18,7 +13,12 @@ import {deepSetValue} from 'src/utils.js'; import { extractPID, extractCID, - extractSubDomain + extractSubDomain, + hashCode, + getStorageItem, + setStorageItem, + tryParseJSON, + getUniqueDealId } from '../../../libraries/vidazooUtils/bidderUtils.js'; export const TEST_ID_SYSTEMS = ['britepoolid', 'criteoId', 'id5id', 'idl_env', 'lipb', 'netId', 'parrableId', 'pubcid', 'tdid', 'pubProvidedId']; @@ -357,7 +357,6 @@ describe('TwistDigitalBidAdapter', function () { uniqueDealId: `${hashUrl}_${Date.now().toString()}`, uqs: getTopWindowQueryParams(), isStorageAllowed: true, - webSessionId: webSessionId, mediaTypes: { video: { api: [2], @@ -455,8 +454,7 @@ describe('TwistDigitalBidAdapter', function () { name: 'example.com', segment: [{id: '243'}], }, - ], - webSessionId: webSessionId + ] } }); }); @@ -542,8 +540,7 @@ describe('TwistDigitalBidAdapter', function () { name: 'example.com', segment: [{id: '243'}], }, - ], - webSessionId: webSessionId + ] }; const REQUEST_DATA2 = utils.deepClone(REQUEST_DATA); @@ -740,8 +737,6 @@ describe('TwistDigitalBidAdapter', function () { switch (idSystemProvider) { case 'lipb': return {lipbid: id}; - case 'parrableId': - return {eid: id}; case 'id5id': return {uid: id}; default: @@ -807,13 +802,13 @@ describe('TwistDigitalBidAdapter', function () { const key = 'myKey'; let uniqueDealId; beforeEach(() => { - uniqueDealId = getUniqueDealId(key, 0); + uniqueDealId = getUniqueDealId(storage, key, 0); }) it('should get current unique deal id', function (done) { // waiting some time so `now` will become past setTimeout(() => { - const current = getUniqueDealId(key); + const current = getUniqueDealId(storage, key); expect(current).to.be.equal(uniqueDealId); done(); }, 200); @@ -821,7 +816,7 @@ describe('TwistDigitalBidAdapter', function () { it('should get new unique deal id on expiration', function (done) { setTimeout(() => { - const current = getUniqueDealId(key, 100); + const current = getUniqueDealId(storage, key, 100); expect(current).to.not.be.equal(uniqueDealId); done(); }, 200) @@ -845,8 +840,8 @@ describe('TwistDigitalBidAdapter', function () { shouldAdvanceTime: true, now }); - setStorageItem('myKey', 2020); - const {value, created} = getStorageItem('myKey'); + setStorageItem(storage, 'myKey', 2020); + const {value, created} = getStorageItem(storage, 'myKey'); expect(created).to.be.equal(now); expect(value).to.be.equal(2020); expect(typeof value).to.be.equal('number'); @@ -857,7 +852,7 @@ describe('TwistDigitalBidAdapter', function () { it('should get external stored value', function () { const value = 'superman' window.localStorage.setItem('myExternalKey', value); - const item = getStorageItem('myExternalKey'); + const item = getStorageItem(storage, 'myExternalKey'); expect(item).to.be.equal(value); }); diff --git a/test/spec/modules/viantOrtbBidAdapter_spec.js b/test/spec/modules/viantOrtbBidAdapter_spec.js index 271c944e6e9..67ae8b07821 100644 --- a/test/spec/modules/viantOrtbBidAdapter_spec.js +++ b/test/spec/modules/viantOrtbBidAdapter_spec.js @@ -1,8 +1,9 @@ -import { spec, converter } from 'modules/viantOrtbBidAdapter.js'; +import {spec, converter} from 'modules/viantOrtbBidAdapter.js'; import {assert, expect} from 'chai'; -import { deepClone } from '../../../src/utils'; +import {deepClone} from '../../../src/utils'; import {buildWindowTree} from '../../helpers/refererDetectionHelper'; import {detectReferer} from '../../../src/refererDetection'; + describe('viantOrtbBidAdapter', function () { function testBuildRequests(bidRequests, bidderRequestBase) { let clonedBidderRequest = deepClone(bidderRequestBase); @@ -10,7 +11,8 @@ describe('viantOrtbBidAdapter', function () { let requests = spec.buildRequests(bidRequests, clonedBidderRequest); return requests } - describe('isBidRequestValid', function() { + + describe('isBidRequestValid', function () { function makeBid() { return { 'bidder': 'viant', @@ -46,9 +48,7 @@ describe('viantOrtbBidAdapter', function () { it('should return true if placementId is not passed ', function () { let bid = makeBid(); delete bid.params.placementId; - bid.ortb2Imp = { - - } + bid.ortb2Imp = {} expect(spec.isBidRequestValid(bid)).to.equal(true); }); @@ -98,6 +98,7 @@ describe('viantOrtbBidAdapter', function () { 'transactionId': '4008d88a-8137-410b-aa35-fbfdabcb478e' } } + it('should return true when required params found', function () { expect(spec.isBidRequestValid(makeBid())).to.equal(true); }); @@ -141,6 +142,7 @@ describe('viantOrtbBidAdapter', function () { 'transactionId': '4008d88a-8137-410b-aa35-fbfdabcb478e' } } + it('should return true when required params found', function () { expect(spec.isBidRequestValid(makeBid())).to.equal(true); }); @@ -180,6 +182,57 @@ describe('viantOrtbBidAdapter', function () { 'src': 'client', 'bidRequestsCount': 1 }]; + const basePMPDealsBidRequests = [{ + 'bidder': 'viant', + 'params': { + 'publisherId': '464', + 'placementId': '1' + }, + 'ortb2Imp': { + 'pmp': { + 'private_auction': 0, + 'deals': [ + { + 'id': '1234567', + 'at': 3, + 'bidfloor': 25, + 'bidfloorcur': 'USD', + 'ext': { + 'must_bid': 1, + 'private_auction': 1 + } + }, + { + 'id': '1234568', + 'at': 3, + 'bidfloor': 25, + 'bidfloorcur': 'USD', + 'ext': { + 'must_bid': 0 + } + } + ] + }, + }, + 'mediaTypes': { + 'banner': { + 'sizes': [[728, 90]] + } + }, + 'gdprConsent': { + 'consentString': 'consentString', + 'gdprApplies': true, + }, + 'uspConsent': '1YYY', + 'sizes': [[728, 90]], + 'transactionId': '1111474f-58b1-4368-b812-84f8c937a099', + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'bidId': '243310435309b5', + 'bidderRequestId': '18084284054531', + 'auctionId': 'e7b34fa3-8654-424e-8c49-03e509e53d8c', + 'src': 'client', + 'bidRequestsCount': 1 + }]; const testWindow = buildWindowTree(['https://www.example.com/test', 'https://www.example.com/other/page', 'https://www.example.com/third/page'], 'https://othersite.com/', 'https://example.com/canonical/page'); const baseBidderRequestReferer = detectReferer(testWindow)(); @@ -215,7 +268,7 @@ describe('viantOrtbBidAdapter', function () { }); it('sends bid requests to the correct endpoint', function () { const url = testBuildRequests(baseBannerBidRequests, baseBidderRequest)[0].url; - expect(url).to.equal('https://bidders-us-east-1.adelphic.net/d/rtb/v25/prebid/bidder'); + expect(url).to.equal('https://bidders-us.adelphic.net/d/rtb/v25/prebid/bidder'); }); it('sends site', function () { @@ -236,6 +289,34 @@ describe('viantOrtbBidAdapter', function () { const requestBody = testBuildRequests(clonedBannerRequests, baseBidderRequest)[0].data; expect(requestBody.imp[0].banner.pos).to.equal(1); }); + it('includes the deals in the bid request', function () { + const requestBody = testBuildRequests(basePMPDealsBidRequests, baseBidderRequest)[0].data; + expect(requestBody.imp[0].pmp).to.be.not.null; + expect(requestBody.imp[0].pmp).to.deep.equal({ + 'private_auction': 0, + 'deals': [ + { + 'id': '1234567', + 'at': 3, + 'bidfloor': 25, + 'bidfloorcur': 'USD', + 'ext': { + 'must_bid': 1, + 'private_auction': 1 + } + }, + { + 'id': '1234568', + 'at': 3, + 'bidfloor': 25, + 'bidfloorcur': 'USD', + 'ext': { + 'must_bid': 0 + } + } + ] + }); + }); }); if (FEATURES.VIDEO) { diff --git a/test/spec/modules/vidazooBidAdapter_spec.js b/test/spec/modules/vidazooBidAdapter_spec.js index c5da6eebdd9..0f4a476ada3 100644 --- a/test/spec/modules/vidazooBidAdapter_spec.js +++ b/test/spec/modules/vidazooBidAdapter_spec.js @@ -92,7 +92,7 @@ const VIDEO_BID = { 'minduration': 0, 'startdelay': 0, 'linearity': 1, - 'api': [2], + 'api': [2, 7], 'placement': 1 } } @@ -157,8 +157,14 @@ const BIDDER_REQUEST = { segment: [{id: '243'}], }, ], + }, + source: { + ext: { + omidpn: 'MyIntegrationPartner', + omidpv: '7.1' + } } - }, + } }; const SERVER_RESPONSE = { @@ -359,7 +365,7 @@ describe('VidazooBidAdapter', function () { webSessionId: webSessionId, mediaTypes: { video: { - api: [2], + api: [2, 7], context: 'instream', linearity: 1, maxduration: 60, @@ -373,7 +379,9 @@ describe('VidazooBidAdapter', function () { protocols: [2, 3, 5, 6], startdelay: 0 } - } + }, + omidpn: 'MyIntegrationPartner', + omidpv: '7.1' } }) ; diff --git a/test/spec/modules/visxBidAdapter_spec.js b/test/spec/modules/visxBidAdapter_spec.js index 0653d7a8ce7..db928e4d802 100755 --- a/test/spec/modules/visxBidAdapter_spec.js +++ b/test/spec/modules/visxBidAdapter_spec.js @@ -4,6 +4,7 @@ import { config } from 'src/config.js'; import { newBidder } from 'src/adapters/bidderFactory.js'; import * as utils from 'src/utils.js'; import { makeSlot } from '../integration/faker/googletag.js'; +import { mergeDeep } from '../../../src/utils.js'; describe('VisxAdapter', function () { const adapter = newBidder(spec); @@ -2161,4 +2162,183 @@ describe('VisxAdapter', function () { expect(request.data.user.ext.vads).to.be.a('string'); }); }); + + describe('ortb2 data', function () { + const bidRequests = [ + { + 'bidder': 'visx', + 'params': { + 'uid': 903535 + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475' + } + ]; + const bidderRequest = { + timeout: 3000, + refererInfo: { + page: 'https://example.com' + }, + 'ortb2': { + 'device': { + 'w': 1259, + 'h': 934, + 'dnt': 0, + 'ua': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36', + 'language': 'tr', + 'sua': { + 'source': 1, + 'platform': { + 'brand': 'macOS' + }, + 'browsers': [ + { + 'brand': 'Chromium', + 'version': [ '124' ] + }, + { + 'brand': 'Google Chrome', + 'version': [ '124' ] + }, + { + 'brand': 'Not-A.Brand', + 'version': [ '99' ] + } + ], + 'mobile': 0 + }, + 'ext': { + 'cdep': 'treatment_1.1' + } + }, + 'site': { + 'domain': 'localhost:9999', + 'publisher': { + 'domain': 'localhost:9999' + }, + 'page': 'http://localhost:9999/integrationExamples/gpt/hello_world.html' + }, + 'user': { + 'keywords': 'x,y', + 'data': [ + { + 'name': 'exampleprovider.de', + 'ext': { + 'segtax': 5 + }, + 'segment': [ + { + 'id': '1' + } + ] + }, + { + 'ext': { + 'segtax': 601, + 'segclass': '5' + }, + 'segment': [ + { + 'id': '140' + } + ], + 'name': 'pa.openx.net' + }, + { + 'ext': { + 'segtax': 601, + 'segclass': '5' + }, + 'segment': [ + { + 'id': '140' + } + ], + 'name': 'ads.pubmatic.com' + } + ], + 'ext': { + 'data': { + 'registered': true, + 'interests': [ + 'ads' + ] + } + } + } + } + }; + + it('should pass interests if ortb2 has interests in user data', function () { + const request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data.user.ext.data.interests).not.to.be.undefined; + }); + + it('should pass device if ortb2 has device', function () { + const request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data.device).not.to.be.undefined; + }); + + it('should pass site if ortb2 has site', function () { + const request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data.site).not.to.be.undefined; + }); + + it('should merge if user object exists', function () { + const user = { + 'ext': { + 'vads': 'cXaIRA425BmynEN1ratEnc_5e', + 'data': { + 'registered': true, + 'interests': [ + 'ads' + ] + } + }, + 'keywords': 'x,y', + 'data': [ + { + 'name': 'exampleprovider.de', + 'ext': { + 'segtax': 5 + }, + 'segment': [ + { + 'id': '1' + } + ] + } + ] + }; + const userOrtb2 = { + 'keywords': 'x,y', + 'data': [ + { + 'name': 'exampleprovider.de', + 'ext': { + 'segtax': 5 + }, + 'segment': [ + { + 'id': '1' + } + ] + } + ], + 'ext': { + 'data': { + 'registered': true, + 'interests': [ + 'ads' + ] + } + } + } + const userReq = mergeDeep(user, userOrtb2); + expect(userReq.ext.vads).not.to.be.undefined; + }); + }); }); diff --git a/test/spec/modules/yandexIdSystem_spec.js b/test/spec/modules/yandexIdSystem_spec.js index d5f614dafb9..8ae7a374bfa 100644 --- a/test/spec/modules/yandexIdSystem_spec.js +++ b/test/spec/modules/yandexIdSystem_spec.js @@ -110,12 +110,17 @@ describe('YandexId module', () => { describe('crypto', () => { it('uses Math.random when crypto is not available', () => { - sandbox.stub(window, 'crypto').value(undefined); + const cryptoTmp = window.crypto; + + // @ts-expect-error -- Crypto is always defined in modern JS. TS yells when trying to delete non-nullable property. + delete window.crypto; yandexIdSubmodule.getId(CORRECT_SUBMODULE_CONFIG); expect(randomStub.calledOnce).to.be.true; expect(getCryptoRandomValuesStub.called).to.be.false; + + window.crypto = cryptoTmp; }); it('uses crypto when it is available', () => { diff --git a/test/spec/modules/zeta_global_sspBidAdapter_spec.js b/test/spec/modules/zeta_global_sspBidAdapter_spec.js index dfa7c9e6984..a903c91ec18 100644 --- a/test/spec/modules/zeta_global_sspBidAdapter_spec.js +++ b/test/spec/modules/zeta_global_sspBidAdapter_spec.js @@ -132,6 +132,9 @@ describe('Zeta Ssp Bid Adapter', function () { userIdAsEids: eids, timeout: 500, ortb2: { + site: { + inventorypartnerdomain: 'disqus.com' + }, device: { sua: { mobile: 1, @@ -709,4 +712,12 @@ describe('Zeta Ssp Bid Adapter', function () { expect(payload.ext.tags.nullTag).to.be.undefined; expect(payload.ext.tags.complexEmptyTag).to.be.undefined; }); + + it('Test that site payload param are merged from ortb2 and params', function () { + const request = spec.buildRequests(bannerRequest, bannerRequest[0]); + const payload = JSON.parse(request.data); + + expect(payload.site.page).to.eql('zetaglobal.com/page'); + expect(payload.site.inventorypartnerdomain).to.eql('disqus.com'); + }); }); diff --git a/test/spec/schainSerializer/schainSerializer_spec.js b/test/spec/schainSerializer/schainSerializer_spec.js new file mode 100644 index 00000000000..d04e6de9847 --- /dev/null +++ b/test/spec/schainSerializer/schainSerializer_spec.js @@ -0,0 +1,138 @@ +import {serializeSupplyChain} from '../../../libraries/schainSerializer/schainSerializer.js' +describe('serializeSupplyChain', () => { + describe('Single Hop - Chain Complete', () => { + it('should serialize a single hop chain with complete information', () => { + const schain = { + ver: '1.0', + complete: 1, + nodes: [ + { + asi: 'exchange1.com', + sid: '1234', + hp: 1, + rid: 'bid-request-1', + name: 'publisher', + domain: 'publisher.com' + } + ] + }; + const nodesProperties = ['asi', 'sid', 'hp', 'rid', 'name', 'domain']; + const expectedResult = '1.0,1!exchange1.com,1234,1,bid-request-1,publisher,publisher.com'; + expect(serializeSupplyChain(schain, nodesProperties)).to.equal(expectedResult); + }); + }); + + describe('Single Hop - Chain Complete, optional fields missing', () => { + it('should serialize a single hop chain with missing optional fields', () => { + const schain = { + ver: '1.0', + complete: 1, + nodes: [ + { + asi: 'exchange1.com', + sid: '1234', + hp: 1 + } + ] + }; + const nodesProperties = ['asi', 'sid', 'hp', 'rid', 'name', 'domain']; + const expectedResult = '1.0,1!exchange1.com,1234,1,,,'; + expect(serializeSupplyChain(schain, nodesProperties)).to.equal(expectedResult); + }); + }); + + describe('Multiple Hops - With all properties supplied', () => { + it('should serialize multiple hops with all properties supplied', () => { + const schain = { + ver: '1.0', + complete: 1, + nodes: [ + { + asi: 'exchange1.com', + sid: '1234', + hp: 1, + rid: 'bid-request-1', + name: 'publisher', + domain: 'publisher.com' + }, + { + asi: 'exchange2.com', + sid: 'abcd', + hp: 1, + rid: 'bid-request-2', + name: 'intermediary', + domain: 'intermediary.com' + } + ] + }; + const nodesProperties = ['asi', 'sid', 'hp', 'rid', 'name', 'domain']; + const expectedResult = '1.0,1!exchange1.com,1234,1,bid-request-1,publisher,publisher.com!exchange2.com,abcd,1,bid-request-2,intermediary,intermediary.com'; + expect(serializeSupplyChain(schain, nodesProperties)).to.equal(expectedResult); + }); + }); + + describe('Multiple Hops - Chain Complete, optional fields missing', () => { + it('should serialize multiple hops with missing optional fields', () => { + const schain = { + ver: '1.0', + complete: 1, + nodes: [ + { + asi: 'exchange1.com', + sid: '1234', + hp: 1 + }, + { + asi: 'exchange2.com', + sid: 'abcd', + hp: 1 + } + ] + }; + const nodesProperties = ['asi', 'sid', 'hp', 'rid', 'name', 'domain']; + const expectedResult = '1.0,1!exchange1.com,1234,1,,,!exchange2.com,abcd,1,,,'; + expect(serializeSupplyChain(schain, nodesProperties)).to.equal(expectedResult); + }); + }); + + describe('Multiple Hops Expected - Chain Incomplete', () => { + it('should serialize multiple hops with chain incomplete', () => { + const schain = { + ver: '1.0', + complete: 0, + nodes: [ + { + asi: 'exchange2.com', + sid: 'abcd', + hp: 1 + } + ] + }; + const nodesProperties = ['asi', 'sid', 'hp', 'rid', 'name', 'domain']; + const expectedResult = '1.0,0!exchange2.com,abcd,1,,,'; + expect(serializeSupplyChain(schain, nodesProperties)).to.equal(expectedResult); + }); + }); + + describe('Single Hop - Chain Complete, encoded values', () => { + it('should serialize a single hop chain with encoded values', () => { + const schain = { + ver: '1.0', + complete: 1, + nodes: [ + { + asi: 'exchange1.com', + sid: '1234!abcd', + hp: 1, + rid: 'bid-request-1', + name: 'publisher, Inc.', + domain: 'publisher.com' + } + ] + }; + const nodesProperties = ['asi', 'sid', 'hp', 'rid', 'name', 'domain']; + const expectedResult = '1.0,1!exchange1.com,1234%21abcd,1,bid-request-1,publisher%2C%20Inc.,publisher.com'; + expect(serializeSupplyChain(schain, nodesProperties)).to.equal(expectedResult); + }); + }); +}); diff --git a/test/spec/unit/core/storageManager_spec.js b/test/spec/unit/core/storageManager_spec.js index edead126c2c..25471a80677 100644 --- a/test/spec/unit/core/storageManager_spec.js +++ b/test/spec/unit/core/storageManager_spec.js @@ -26,15 +26,15 @@ describe('storage manager', function() { hook.ready(); }); - beforeEach(function() { + beforeEach(function () { resetData(); }); - afterEach(function() { + afterEach(function () { config.resetConfig(); }) - it('should allow to set cookie for core modules without checking gdpr enforcements', function() { + it('should allow to set cookie for core modules without checking gdpr enforcements', function () { const coreStorage = getCoreStorageManager(); let date = new Date(); date.setTime(date.getTime() + (24 * 60 * 60 * 1000)); @@ -43,7 +43,7 @@ describe('storage manager', function() { expect(coreStorage.getCookie('hello')).to.equal('world'); }); - it('should add done callbacks to storageCallbacks array', function() { + it('should add done callbacks to storageCallbacks array', function () { let noop = sinon.spy(); const coreStorage = newStorageManager(); @@ -55,11 +55,15 @@ describe('storage manager', function() { coreStorage.getDataFromLocalStorage('foo', noop); coreStorage.removeDataFromLocalStorage('foo', noop); coreStorage.hasLocalStorage(noop); + coreStorage.setDataInSessionStorage('foo', 'bar', noop); + coreStorage.getDataFromSessionStorage('foo', noop); + coreStorage.removeDataFromSessionStorage('foo', noop); + coreStorage.hasSessionStorage(noop); - expect(storageCallbacks.length).to.equal(8); + expect(storageCallbacks.length).to.equal(12); }); - it('should allow bidder to access device if gdpr enforcement module is not included', function() { + it('should allow bidder to access device if gdpr enforcement module is not included', function () { let deviceAccessSpy = sinon.spy(utils, 'hasDeviceAccess'); const storage = newStorageManager(); storage.setCookie('foo1', 'baz1'); @@ -87,12 +91,16 @@ describe('storage manager', function() { })); }); - it('should deny access if activity is denied', () => { - isAllowed.returns(false); - const mgr = mkManager(MODULE_TYPE_PREBID, 'mockMod'); - mgr.setDataInLocalStorage('testKey', 'val'); - expect(mgr.getDataFromLocalStorage('testKey')).to.not.exist; - }); + ['Local', 'Session'].forEach(type => { + describe(`${type} storage`, () => { + it('should deny access if activity is denied', () => { + isAllowed.returns(false); + const mgr = mkManager(MODULE_TYPE_PREBID, 'mockMod'); + mgr[`setDataIn${type}Storage`]('testKey', 'val'); + expect(mgr[`getDataFrom${type}Storage`]('testKey')).to.not.exist; + }); + }) + }) it('should use bidder aliases when possible', () => { adapterManager.registerBidAdapter({callBids: sinon.stub(), getSpec: () => ({})}, 'mockBidder'); @@ -103,57 +111,66 @@ describe('storage manager', function() { [ACTIVITY_PARAM_COMPONENT_NAME]: 'mockAlias' })) }) - }) - - describe('localstorage forbidden access in 3rd-party context', function() { - let errorLogSpy; - let originalLocalStorage; - const localStorageMock = { get: () => { throw Error } }; + }); - beforeEach(function() { - originalLocalStorage = window.localStorage; - Object.defineProperty(window, 'localStorage', localStorageMock); - errorLogSpy = sinon.spy(utils, 'logError'); - }); + ['localStorage', 'sessionStorage'].forEach(storage => { + const Storage = storage.charAt(0).toUpperCase() + storage.substring(1); - afterEach(function() { - Object.defineProperty(window, 'localStorage', { get: () => originalLocalStorage }); - errorLogSpy.restore(); - }) + describe(`${storage} forbidden access in 3rd-party context`, function () { + let errorLogSpy; + let originalStorage; + const storageMock = { + get: () => { + throw Error + } + }; - it('should not throw if the localstorage is not accessible when setting/getting/removing from localstorage', function() { - const coreStorage = newStorageManager(); + beforeEach(function () { + originalStorage = window[storage]; + Object.defineProperty(window, storage, storageMock); + errorLogSpy = sinon.spy(utils, 'logError'); + }); - coreStorage.setDataInLocalStorage('key', 'value'); - const val = coreStorage.getDataFromLocalStorage('key'); - coreStorage.removeDataFromLocalStorage('key'); + afterEach(function () { + Object.defineProperty(window, storage, {get: () => originalStorage}); + errorLogSpy.restore(); + }) - expect(val).to.be.null; - sinon.assert.calledThrice(errorLogSpy); - }) - }) + it('should not throw if storage is not accessible when setting/getting/removing', function () { + const coreStorage = newStorageManager(); - describe('localstorage is enabled', function() { - let localStorage; + coreStorage[`setDataIn${Storage}`]('key', 'value'); + const val = coreStorage[`getDataFrom${Storage}`]('key'); + coreStorage[`removeDataFrom${Storage}`]('key'); - beforeEach(function() { - localStorage = window.localStorage; - localStorage.clear(); + expect(val).to.be.null; + sinon.assert.calledThrice(errorLogSpy); + }); }); + }); - afterEach(function() { - localStorage.clear(); - }) + ['localStorage', 'sessionStorage'].forEach(storage => { + describe(`${storage} is enabled`, function () { + let store; + beforeEach(function () { + store = window[storage]; + store.clear(); + }); - it('should remove side-effect after checking', function () { - const storage = newStorageManager(); + afterEach(function () { + store.clear(); + }) - localStorage.setItem('unrelated', 'dummy'); - const val = storage.localStorageIsEnabled(); + it('should remove side-effect after checking', function () { + const storageMgr = newStorageManager(); - expect(val).to.be.true; - expect(localStorage.length).to.be.eq(1); - expect(localStorage.getItem('unrelated')).to.be.eq('dummy'); + store.setItem('unrelated', 'dummy'); + const val = storageMgr[`${storage}IsEnabled`](); + + expect(val).to.be.true; + expect(store.length).to.be.eq(1); + expect(store.getItem('unrelated')).to.be.eq('dummy'); + }); }); }); diff --git a/test/spec/unit/pbjs_api_spec.js b/test/spec/unit/pbjs_api_spec.js index 962ba1b0178..de267b793b2 100644 --- a/test/spec/unit/pbjs_api_spec.js +++ b/test/spec/unit/pbjs_api_spec.js @@ -26,7 +26,7 @@ import {enrichFPD} from '../../../src/fpd/enrichment.js'; import {mockFpdEnrichments} from '../../helpers/fpd.js'; import {generateUUID} from '../../../src/utils.js'; import {getCreativeRenderer} from '../../../src/creativeRenderers.js'; -import { BID_STATUS, EVENTS, GRANULARITY_OPTIONS, TARGETING_KEYS } from 'src/constants.js'; +import {BID_STATUS, EVENTS, GRANULARITY_OPTIONS, PB_LOCATOR, TARGETING_KEYS} from 'src/constants.js'; import {getBidToRender} from '../../../src/adRendering.js'; var assert = require('chai').assert; @@ -236,6 +236,11 @@ describe('Unit: Prebid Module', function () { getBidToRender.getHooks({hook: getBidToRenderHook}).remove(); }); + it('should insert a locator frame on the page', () => { + $$PREBID_GLOBAL$$.processQueue(); + expect(window.frames[PB_LOCATOR]).to.exist; + }) + describe('and global adUnits', () => { const startingAdUnits = [ { @@ -3752,4 +3757,15 @@ describe('Unit: Prebid Module', function () { sinon.assert.calledOnce(adapterManager.callBidBillableBidder); }); }); + + describe('clearAllAuctions', () => { + after(() => { + resetAuction(); + }); + it('clears auction data', function () { + expect(auctionManager.getBidsReceived().length).to.not.equal(0); + $$PREBID_GLOBAL$$.clearAllAuctions(); + expect(auctionManager.getBidsReceived().length).to.equal(0); + }); + }); }); diff --git a/test/spec/utils_spec.js b/test/spec/utils_spec.js index aaeeee48d83..a6df236ee46 100644 --- a/test/spec/utils_spec.js +++ b/test/spec/utils_spec.js @@ -1223,6 +1223,25 @@ describe('Utils', function () { expect(script.id).to.equal('newId'); }); }); + + describe('safeJSONParse', () => { + it('correctly encodes valid input', () => { + const jsonObj = { + key1: 'val1', + key2: { + key3: 100, + key4: true + } + }; + const result = utils.safeJSONEncode(jsonObj); + expect(result).to.equal(`{"key1":"val1","key2":{"key3":100,"key4":true}}`); + }); + it('return empty string for stringify errors', () => { + const jsonObj = {k: 2n}; + const result = utils.safeJSONEncode(jsonObj); + expect(result).to.equal(''); + }); + }); }); describe('memoize', () => {