diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index cfb29ebdfa9..69e13850258 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,6 +1,8 @@ ARG VARIANT="12" FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:${VARIANT} +RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor > /usr/share/keyrings/yarn-archive-keyring.gpg + # [Optional] Uncomment this section to install additional OS packages. # RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ # && apt-get -y install --no-install-recommends diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 0176b8317b3..104d9a38132 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -16,7 +16,8 @@ // Add the IDs of extensions you want installed when the container is created. "extensions": [ - "nickdodd79.gulptasks" + "nickdodd79.gulptasks", + "dbaeumer.vscode-eslint" ], // 9999 is web server, 9876 is karma diff --git a/.github/workflows/issue_tracker.yml b/.github/workflows/issue_tracker.yml index 05d08b2b0d7..69cf4c5fc7f 100644 --- a/.github/workflows/issue_tracker.yml +++ b/.github/workflows/issue_tracker.yml @@ -14,7 +14,7 @@ jobs: steps: - name: Generate token id: generate_token - uses: tibdex/github-app-token@f717b5ecd4534d3c4df4ce9b5c1c2214f0f7cd06 + uses: tibdex/github-app-token@b62528385c34dbc9f38e5f4225ac829252d1ea92 with: app_id: ${{ secrets.ISSUE_APP_ID }} private_key: ${{ secrets.ISSUE_APP_PEM }} @@ -29,21 +29,30 @@ jobs: gh api graphql -f query=' query($org: String!, $number: Int!) { organization(login: $org){ - projectNext(number: $number) { + projectV2(number: $number) { id fields(first:100) { nodes { - id - name - settings + ... on ProjectV2Field { + id + name + } + ... on ProjectV2SingleSelectField { + id + name + options { + id + name + } + } } } } } }' -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json - echo 'PROJECT_ID='$(jq '.data.organization.projectNext.id' project_data.json) >> $GITHUB_ENV - echo 'DATE_FIELD_ID='$(jq '.data.organization.projectNext.fields.nodes[] | select(.name== "'"$DATE_FIELD"'") | .id' project_data.json) >> $GITHUB_ENV + echo 'PROJECT_ID='$(jq '.data.organization.projectV2.id' project_data.json) >> $GITHUB_ENV + echo 'DATE_FIELD_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name=="'"$DATE_FIELD"'") | .id' project_data.json) >> $GITHUB_ENV - name: Add issue to project env: @@ -52,9 +61,9 @@ jobs: run: | gh api graphql -f query=' mutation($project:ID!, $issue:ID!) { - addProjectNextItem(input: {projectId: $project, contentId: $issue}) { - projectNextItem { - id, + addProjectV2ItemById(input: {projectId: $project, contentId: $issue}) { + item { + id content { ... on Issue { createdAt @@ -67,8 +76,8 @@ jobs: } }' -f project=$PROJECT_ID -f issue=$ISSUE_ID > issue_data.json - echo 'ITEM_ID='$(jq '.data.addProjectNextItem.projectNextItem.id' issue_data.json) >> $GITHUB_ENV - echo 'ITEM_CREATION_DATE='$(jq '.data.addProjectNextItem.projectNextItem.content.createdAt' issue_data.json) >> $GITHUB_ENV + echo 'ITEM_ID='$(jq '.data.addProjectV2ItemById.item.id' issue_data.json) >> $GITHUB_ENV + echo 'ITEM_CREATION_DATE='$(jq '.data.addProjectV2ItemById.item.content.createdAt' issue_data.json | cut -c 2-11) >> $GITHUB_ENV - name: Set fields env: @@ -79,15 +88,17 @@ jobs: $project: ID! $item: ID! $date_field: ID! - $date_value: String! + $date_value: Date! ) { - set_creation_date: updateProjectNextItemField(input: { + set_creation_date: updateProjectV2ItemFieldValue(input: { projectId: $project itemId: $item fieldId: $date_field - value: $date_value + value: { + date: $date_value + } }) { - projectNextItem { + projectV2Item { id } } diff --git a/README.md b/README.md index bbc0d79ab41..fdbb5482ebf 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ [![Build Status](https://circleci.com/gh/prebid/Prebid.js.svg?style=svg)](https://circleci.com/gh/prebid/Prebid.js) [![Percentage of issues still open](http://isitmaintained.com/badge/open/prebid/Prebid.js.svg)](http://isitmaintained.com/project/prebid/Prebid.js "Percentage of issues still open") [![Coverage Status](https://coveralls.io/repos/github/prebid/Prebid.js/badge.svg)](https://coveralls.io/github/prebid/Prebid.js) -[![Total Alerts](https://img.shields.io/lgtm/alerts/g/prebid/Prebid.js.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/prebid/Prebid.js/alerts/) # Prebid.js diff --git a/integrationExamples/gpt/adloox.html b/integrationExamples/gpt/adloox.html index fd61267479d..78fba71f774 100644 --- a/integrationExamples/gpt/adloox.html +++ b/integrationExamples/gpt/adloox.html @@ -147,8 +147,13 @@ realTimeData: { auctionDelay: AUCTION_DELAY, dataProviders: [ + { + name: 'intersection', + waitForIt: true + }, { name: 'adloox', + waitForIt: true, params: { // optional, defaults shown thresholds: [ 50, 60, 70, 80, 90 ], slotinpath: false diff --git a/integrationExamples/gpt/captifyRtdProvider_example.html b/integrationExamples/gpt/captifyRtdProvider_example.html new file mode 100644 index 00000000000..955fbf8be70 --- /dev/null +++ b/integrationExamples/gpt/captifyRtdProvider_example.html @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + +
+

+ Module will add key/value pairs in ad calls. + Check out for captify_segments key in the payload sent to Xandr to endpoint https://ib.adnxs.com/ut/v3/prebid : keywords.key[captify_segments] should have an array of string as value. + This array will have Xandr RTSS segment ids. +

+
+

Basic Prebid.js Example with CaptifyRTD

+
Div-1
+
+ +
+ + + diff --git a/integrationExamples/gpt/gpp_us_hello_world.html b/integrationExamples/gpt/gpp_us_hello_world.html new file mode 100644 index 00000000000..28be86127fc --- /dev/null +++ b/integrationExamples/gpt/gpp_us_hello_world.html @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + +

Prebid.js Test

+
Div-1
+ +
+ +
+ + + \ No newline at end of file diff --git a/integrationExamples/gpt/gpp_us_hello_world_iframe.html b/integrationExamples/gpt/gpp_us_hello_world_iframe.html new file mode 100644 index 00000000000..c0a62f9d72e --- /dev/null +++ b/integrationExamples/gpt/gpp_us_hello_world_iframe.html @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/integrationExamples/gpt/gpp_us_hello_world_iframe_subpage.html b/integrationExamples/gpt/gpp_us_hello_world_iframe_subpage.html new file mode 100644 index 00000000000..8c2096d614d --- /dev/null +++ b/integrationExamples/gpt/gpp_us_hello_world_iframe_subpage.html @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + +

Prebid.js Test

+
Div-1
+ +
+ +
+ + + \ No newline at end of file diff --git a/integrationExamples/gpt/growthcode.html b/integrationExamples/gpt/growthcode.html new file mode 100644 index 00000000000..ede51d2d869 --- /dev/null +++ b/integrationExamples/gpt/growthcode.html @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + +

Prebid.js Test

+
Div-1
+
+ +
+ + diff --git a/integrationExamples/gpt/hello_world.html b/integrationExamples/gpt/hello_world.html old mode 100755 new mode 100644 diff --git a/integrationExamples/gpt/mgidRtdProvider_example.html b/integrationExamples/gpt/mgidRtdProvider_example.html new file mode 100644 index 00000000000..e3e4f720586 --- /dev/null +++ b/integrationExamples/gpt/mgidRtdProvider_example.html @@ -0,0 +1,143 @@ + + + + + + + + + + +JS Bin + + + +

Basic Prebid.js Example

+
Div-1
+ +
+ +
+ + + diff --git a/integrationExamples/gpt/neuwoRtdProvider_example.html b/integrationExamples/gpt/neuwoRtdProvider_example.html new file mode 100644 index 00000000000..8d82d50c3e9 --- /dev/null +++ b/integrationExamples/gpt/neuwoRtdProvider_example.html @@ -0,0 +1,200 @@ + + + + + + + + + + +

Basic Prebid.js Example using neuwoRtdProvider

+
+ Looks like you're not following the testing environment setup, try accessing http://localhost:9999/integrationExamples/gpt/neuwoRtdProvider_example.html + after running commands in the prebid.js source folder that includes libraries/modules/neuwoRtdProvider.js + + npm ci + npm i -g gulp-cli + gulp serve --modules=rtdModule,neuwoRtdProvider,appnexusBidAdapter + +
+
+

Add token and url to use for Neuwo extension configuration

+ + + + +
+ +
Div-1
+
+ Ad spot div-1: This content will be replaced by prebid.js and/or related components once you click "Update" +
+ +
+ +
Div-2
+
+ Ad spot div-2: Replaces this text as well, if everything goes to plan + + +
+ + + \ No newline at end of file diff --git a/integrationExamples/gpt/permutiveRtdProvider_example.html b/integrationExamples/gpt/permutiveRtdProvider_example.html index 118cc678726..554f2081c6d 100644 --- a/integrationExamples/gpt/permutiveRtdProvider_example.html +++ b/integrationExamples/gpt/permutiveRtdProvider_example.html @@ -15,7 +15,8 @@ _papns: ['appnexus1', 'appnexus2'], _psegs: ['1234', '1000001', '1000002'], _ppam: ['ppam1', 'ppam2'], - _pcrprs: ['pcrprs1', 'pcrprs2'] + _pcrprs: ['pcrprs1', 'pcrprs2'], + _pssps: { ssps: ['appnexus', 'some other'], cohorts: ['abcd', 'efgh', 'ijkl'] }, } for (let key in data) { diff --git a/integrationExamples/gpt/topics_frame.html b/integrationExamples/gpt/topics_frame.html new file mode 100644 index 00000000000..7a12b030a6a --- /dev/null +++ b/integrationExamples/gpt/topics_frame.html @@ -0,0 +1,43 @@ + + + + Topics demo + + + + + + + + + \ No newline at end of file diff --git a/integrationExamples/gpt/userId_example.html b/integrationExamples/gpt/userId_example.html index 5a6c80c4adf..4f94c73c281 100644 --- a/integrationExamples/gpt/userId_example.html +++ b/integrationExamples/gpt/userId_example.html @@ -249,7 +249,17 @@ } }, { - "name": "uid2" + "name": "uid2", + "params": { + "uid2Token": { + "advertising_token": "example token", + "refresh_token": "aslkdjaslkjdaslkhj", + "identity_expires": Date.now() + 60*1000, + "refresh_from": Date.now() - 10*1000, + "refresh_expires": Date.now() + 12*60*60*1000, + "refresh_response_key": null + } + } } , { diff --git a/integrationExamples/videoModule/jwplayer/bidMarkedAsUsed.html b/integrationExamples/videoModule/jwplayer/bidMarkedAsUsed.html index 542cab4202e..044b4295e67 100644 --- a/integrationExamples/videoModule/jwplayer/bidMarkedAsUsed.html +++ b/integrationExamples/videoModule/jwplayer/bidMarkedAsUsed.html @@ -76,10 +76,6 @@ console.log('player setup failed: ', e); }); - pbjs.onEvent('videoPlaybackRequest', (e) => { - pbjs.requestBids(adUnits); - }); - pbjs.onEvent('videoBidError', e => { console.log('An Ad Error came from a Bid: ', e); }); @@ -87,6 +83,8 @@ pbjs.onEvent('videoBidImpression', e => { console.log('An Ad Impression came from a Bid: ', e); }); + + pbjs.requestBids(adUnits); }); diff --git a/integrationExamples/videoModule/jwplayer/eventListeners.html b/integrationExamples/videoModule/jwplayer/eventListeners.html index b4f5aaa5443..0b43ff44d6c 100644 --- a/integrationExamples/videoModule/jwplayer/eventListeners.html +++ b/integrationExamples/videoModule/jwplayer/eventListeners.html @@ -87,7 +87,6 @@ pbjs.onEvent('videoPlaybackRequest', (e) => { console.log('videos pb playbackRequest: ', e); - pbjs.requestBids(adUnits); }); pbjs.onEvent('videoAutostartBlocked', (e) => { @@ -222,6 +221,10 @@ console.log('videos pb auction ad load attempt: ', e); }); + pbjs.onEvent('videoAuctionAdLoadQueued', (e) => { + console.log('videos pb auction ad load queued: ', e); + }); + pbjs.onEvent('videoAuctionAdLoadAttempt', event => { console.log('The Video Module is attempting to load an ad into the player! \n', event); }); @@ -233,6 +236,8 @@ pbjs.onEvent('videoBidError', event => { console.log('The ad error resulted from a bid! \n', event); }); + + pbjs.requestBids(adUnits); }); diff --git a/integrationExamples/videoModule/jwplayer/gamAdServerMediation.html b/integrationExamples/videoModule/jwplayer/gamAdServerMediation.html index 4612d03f336..296a3265bd1 100644 --- a/integrationExamples/videoModule/jwplayer/gamAdServerMediation.html +++ b/integrationExamples/videoModule/jwplayer/gamAdServerMediation.html @@ -94,10 +94,6 @@ console.log('player setup failed: ', e); }); - pbjs.onEvent('videoPlaybackRequest', (e) => { - pbjs.requestBids(adUnits); - }); - pbjs.onEvent('videoAdRequest', (e) => { console.log('videos pb ad request: ', e); }); @@ -109,6 +105,8 @@ pbjs.onEvent('videoBidImpression', e => { console.log('An Ad Impression came from a Bid: ', e); }); + + pbjs.requestBids(adUnits); }); diff --git a/integrationExamples/videoModule/jwplayer/mediaMetadata.html b/integrationExamples/videoModule/jwplayer/mediaMetadata.html index 97e35c4de0d..815f5c4d6d7 100644 --- a/integrationExamples/videoModule/jwplayer/mediaMetadata.html +++ b/integrationExamples/videoModule/jwplayer/mediaMetadata.html @@ -56,7 +56,6 @@ pbjs.onEvent('videoSetupComplete', e => { console.log('player setup complete: ', e); - pbjs.requestBids(adUnits); }); pbjs.onEvent('videoSetupFailed', e => { @@ -66,6 +65,8 @@ pbjs.onEvent('videoContentLoaded', (e) => { console.log('videos pb contentLoaded: ', e); }); + + pbjs.requestBids(adUnits); }); diff --git a/integrationExamples/videoModule/jwplayer/playlist.html b/integrationExamples/videoModule/jwplayer/playlist.html index eb9a9b12700..b77a1ec05fc 100644 --- a/integrationExamples/videoModule/jwplayer/playlist.html +++ b/integrationExamples/videoModule/jwplayer/playlist.html @@ -97,7 +97,6 @@ // request a bid when media is loaded pbjs.onEvent('videoContentLoaded', (e) => { console.log('videos pb contentLoaded: ', e); - pbjs.requestBids(adUnits); }); pbjs.onEvent('videoComplete', (e) => { @@ -107,6 +106,8 @@ pbjs.onEvent('videoPlaylistComplete', (e) => { console.log('videos pb playlistComplete: ', e); }); + + pbjs.requestBids(adUnits); }); diff --git a/integrationExamples/videoModule/videojs/bidMarkedAsUsed.html b/integrationExamples/videoModule/videojs/bidMarkedAsUsed.html index 3c21130e8f5..b645a58a4fc 100644 --- a/integrationExamples/videoModule/videojs/bidMarkedAsUsed.html +++ b/integrationExamples/videoModule/videojs/bidMarkedAsUsed.html @@ -101,10 +101,6 @@ console.log('player setup failed: ', e); }); - pbjs.onEvent('videoContentLoaded', (e) => { - pbjs.requestBids(adUnits); - }); - pbjs.onEvent('videoBidError', e => { console.log('An Ad Error came from a Bid: ', e); }); @@ -113,6 +109,7 @@ console.log('An Ad Impression came from a Bid: ', e); }); + pbjs.requestBids(adUnits); }); diff --git a/integrationExamples/videoModule/videojs/eventListeners.html b/integrationExamples/videoModule/videojs/eventListeners.html index 63de878715f..16edaf4da41 100644 --- a/integrationExamples/videoModule/videojs/eventListeners.html +++ b/integrationExamples/videoModule/videojs/eventListeners.html @@ -209,6 +209,10 @@ console.log('videos pb auction ad load attempt: ', e); }); + pbjs.onEvent('videoAuctionAdLoadQueued', (e) => { + console.log('videos pb auction ad load queued: ', e); + }); + pbjs.onEvent('videoAuctionAdLoadAbort', (e) => { console.log('videos pb auction ad load attempt: ', e); }); diff --git a/integrationExamples/videoModule/videojs/gamAdServerMediation.html b/integrationExamples/videoModule/videojs/gamAdServerMediation.html index 72deba861bf..9efd77e9681 100644 --- a/integrationExamples/videoModule/videojs/gamAdServerMediation.html +++ b/integrationExamples/videoModule/videojs/gamAdServerMediation.html @@ -96,8 +96,6 @@ pbjs.addAdUnits(adUnits); - pbjs.requestBids(adUnits); - pbjs.onEvent('videoSetupComplete', e => { // Load media with its Metadata when the video player is done instantiating. videojs('player').loadMedia({ @@ -125,6 +123,7 @@ console.log('An Ad Impression came from a Bid: ', e); }); + pbjs.requestBids(adUnits); }); diff --git a/integrationExamples/videoModule/videojs/playlist.html b/integrationExamples/videoModule/videojs/playlist.html index a9354e06c83..a9e3d1bc99b 100644 --- a/integrationExamples/videoModule/videojs/playlist.html +++ b/integrationExamples/videoModule/videojs/playlist.html @@ -126,15 +126,15 @@ console.log('videos pb playlist: ', e); }); - // request a bid when media is loaded pbjs.onEvent('videoContentLoaded', (e) => { console.log('videos pb contentLoaded: ', e); - pbjs.requestBids(adUnits); }); pbjs.onEvent('videoComplete', (e) => { console.log('videos pb complete: ', e); }); + + pbjs.requestBids(adUnits); }); diff --git a/karma.conf.maker.js b/karma.conf.maker.js index b20f73d74bc..e05d5b08afd 100644 --- a/karma.conf.maker.js +++ b/karma.conf.maker.js @@ -110,7 +110,7 @@ module.exports = function(codeCoverage, browserstack, watchMode, file, disableFe var webpackConfig = newWebpackConfig(codeCoverage, disableFeatures); var plugins = newPluginsArray(browserstack); - var files = file ? ['test/test_deps.js', file] : ['test/test_index.js']; + var files = file ? ['test/test_deps.js', file, 'test/helpers/hookSetup.js'].flatMap(f => f) : ['test/test_index.js']; // This file opens the /debug.html tab automatically. // It has no real value unless you're running --watch, and intend to do some debugging in the browser. if (watchMode) { diff --git a/libraries/analyticsAdapter/AnalyticsAdapter.js b/libraries/analyticsAdapter/AnalyticsAdapter.js index 277a1455a75..b6e270b3c3c 100644 --- a/libraries/analyticsAdapter/AnalyticsAdapter.js +++ b/libraries/analyticsAdapter/AnalyticsAdapter.js @@ -1,47 +1,68 @@ import CONSTANTS from '../../src/constants.json'; -import { ajax } from '../../src/ajax.js'; -import { logMessage, _each } from '../../src/utils.js'; -import * as events from '../../src/events.js' +import {ajax} from '../../src/ajax.js'; +import {logError, logMessage} from '../../src/utils.js'; +import * as events from '../../src/events.js'; export const _internal = { ajax }; - -const { - EVENTS: { - AUCTION_INIT, - AUCTION_END, - REQUEST_BIDS, - BID_REQUESTED, - BID_TIMEOUT, - BID_RESPONSE, - NO_BID, - BID_WON, - BID_ADJUSTMENT, - BIDDER_DONE, - SET_TARGETING, - AD_RENDER_FAILED, - AD_RENDER_SUCCEEDED, - AUCTION_DEBUG, - ADD_AD_UNITS, - BILLABLE_EVENT - } -} = CONSTANTS; - const ENDPOINT = 'endpoint'; const BUNDLE = 'bundle'; +export const DEFAULT_INCLUDE_EVENTS = Object.values(CONSTANTS.EVENTS) + .filter(ev => ev !== CONSTANTS.EVENTS.AUCTION_DEBUG); + +let debounceDelay = 100; + +export function setDebounceDelay(delay) { + debounceDelay = delay; +} + export default function AnalyticsAdapter({ url, analyticsType, global, handler }) { - const _queue = []; - let _eventCount = 0; - let _enableCheck = true; - let _handlers; - let _enabled = false; - let _sampled = true; - - if (analyticsType === ENDPOINT || BUNDLE) { - _emptyQueue(); - } + const queue = []; + let handlers; + let enabled = false; + let sampled = true; + let provider; + + const emptyQueue = (() => { + let running = false; + let timer; + const clearQueue = () => { + if (!running) { + running = true; // needed to avoid recursive re-processing when analytics event handlers trigger other events + try { + let i = 0; + let notDecreasing = 0; + while (queue.length > 0) { + i++; + const len = queue.length; + queue.shift()(); + if (queue.length >= len) { + notDecreasing++; + } else { + notDecreasing = 0 + } + if (notDecreasing >= 10) { + logError('Detected probable infinite loop, discarding events', queue) + queue.length = 0; + return; + } + } + logMessage(`${provider} analytics: processed ${i} events`); + } finally { + running = false; + } + } + }; + return function () { + if (timer != null) { + clearTimeout(timer); + timer = null; + } + debounceDelay === 0 ? clearQueue() : timer = setTimeout(clearQueue, debounceDelay); + } + })(); return Object.defineProperties({ track: _track, @@ -54,7 +75,7 @@ export default function AnalyticsAdapter({ url, analyticsType, global, handler } getUrl: () => url }, { enabled: { - get: () => _enabled + get: () => enabled } }); @@ -72,69 +93,58 @@ export default function AnalyticsAdapter({ url, analyticsType, global, handler } _internal.ajax(url, callback, JSON.stringify({ eventType, args })); } - function _enqueue({ eventType, args }) { - const _this = this; - - if (global && window[global] && eventType && args) { - this.track({ eventType, args }); - } else { - _queue.push(function () { - _eventCount++; - _this.track({ eventType, args }); - }); - } + function _enqueue({eventType, args}) { + queue.push(() => { + this.track({eventType, args}); + }); + emptyQueue(); } function _enable(config) { + provider = config?.provider; var _this = this; if (typeof config === 'object' && typeof config.options === 'object') { - _sampled = typeof config.options.sampling === 'undefined' || Math.random() < parseFloat(config.options.sampling); + sampled = typeof config.options.sampling === 'undefined' || Math.random() < parseFloat(config.options.sampling); } else { - _sampled = true; + sampled = true; } - if (_sampled) { + if (sampled) { + const trackedEvents = (() => { + const {includeEvents = DEFAULT_INCLUDE_EVENTS, excludeEvents = []} = (config || {}); + return new Set( + Object.values(CONSTANTS.EVENTS) + .filter(ev => includeEvents.includes(ev)) + .filter(ev => !excludeEvents.includes(ev)) + ); + })(); + // first send all events fired before enableAnalytics called events.getEvents().forEach(event => { - if (!event) { + if (!event || !trackedEvents.has(event.eventType)) { return; } const { eventType, args } = event; - - if (eventType !== BID_TIMEOUT) { - _enqueue.call(_this, { eventType, args }); - } + _enqueue.call(_this, { eventType, args }); }); // Next register event listeners to send data immediately - - _handlers = { - [REQUEST_BIDS]: args => this.enqueue({ eventType: REQUEST_BIDS, args }), - [BID_REQUESTED]: args => this.enqueue({ eventType: BID_REQUESTED, args }), - [BID_RESPONSE]: args => this.enqueue({ eventType: BID_RESPONSE, args }), - [NO_BID]: args => this.enqueue({ eventType: NO_BID, args }), - [BID_TIMEOUT]: args => this.enqueue({ eventType: BID_TIMEOUT, args }), - [BID_WON]: args => this.enqueue({ eventType: BID_WON, args }), - [BID_ADJUSTMENT]: args => this.enqueue({ eventType: BID_ADJUSTMENT, args }), - [BIDDER_DONE]: args => this.enqueue({ eventType: BIDDER_DONE, args }), - [SET_TARGETING]: args => this.enqueue({ eventType: SET_TARGETING, args }), - [AUCTION_END]: args => this.enqueue({ eventType: AUCTION_END, args }), - [AD_RENDER_FAILED]: args => this.enqueue({ eventType: AD_RENDER_FAILED, args }), - [AD_RENDER_SUCCEEDED]: args => this.enqueue({ eventType: AD_RENDER_SUCCEEDED, args }), - [AUCTION_DEBUG]: args => this.enqueue({ eventType: AUCTION_DEBUG, args }), - [ADD_AD_UNITS]: args => this.enqueue({ eventType: ADD_AD_UNITS, args }), - [BILLABLE_EVENT]: args => this.enqueue({ eventType: BILLABLE_EVENT, args }), - [AUCTION_INIT]: args => { - args.config = typeof config === 'object' ? config.options || {} : {}; // enableAnaltyics configuration object - this.enqueue({ eventType: AUCTION_INIT, args }); - } - }; - - _each(_handlers, (handler, event) => { - events.on(event, handler); - }); + handlers = Object.fromEntries( + Array.from(trackedEvents) + .map((ev) => { + const handler = ev === CONSTANTS.EVENTS.AUCTION_INIT + ? (args) => { + // TODO: remove this special case in v8 + args.config = typeof config === 'object' ? config.options || {} : {}; + this.enqueue({eventType: ev, args}); + } + : (args) => this.enqueue({eventType: ev, args}); + events.on(ev, handler); + return [ev, handler]; + }) + ) } else { logMessage(`Analytics adapter for "${global}" disabled by sampling`); } @@ -144,31 +154,14 @@ export default function AnalyticsAdapter({ url, analyticsType, global, handler } this.enableAnalytics = function _enable() { return logMessage(`Analytics adapter for "${global}" already enabled, unnecessary call to \`enableAnalytics\`.`); }; - _enabled = true; + enabled = true; } function _disable() { - _each(_handlers, (handler, event) => { + Object.entries(handlers || {}).forEach(([event, handler]) => { events.off(event, handler); - }); + }) this.enableAnalytics = this._oldEnable ? this._oldEnable : _enable; - _enabled = false; - } - - function _emptyQueue() { - if (_enableCheck) { - for (var i = 0; i < _queue.length; i++) { - _queue[i](); - } - - // override push to execute the command immediately from now on - _queue.push = function (fn) { - fn(); - }; - - _enableCheck = false; - } - - logMessage(`event count sent to ${global}: ${_eventCount}`); + enabled = false; } } diff --git a/libraries/ortb2.5StrictTranslator/dsl.js b/libraries/ortb2.5StrictTranslator/dsl.js new file mode 100644 index 00000000000..8f9fc79feeb --- /dev/null +++ b/libraries/ortb2.5StrictTranslator/dsl.js @@ -0,0 +1,54 @@ +export const ERR_TYPE = 0; // field has wrong type (only objects, enums, and arrays of objects or enums are checked) +export const ERR_UNKNOWN_FIELD = 1; // field is not defined in ORTB 2.5 spec +export const ERR_ENUM = 2; // field is an enum and its value is not one of those listed in the ORTB 2.5 spec + +// eslint-disable-next-line symbol-description +export const extend = Symbol(); + +export function Obj(primitiveFields, spec = {}) { + const scan = (path, parent, field, value, onError) => { + if (value == null || typeof value !== 'object') { + onError(ERR_TYPE, path, parent, field, value); + return; + } + Object.entries(value).forEach(([k, v]) => { + if (v == null) return; + const kpath = path == null ? k : `${path}.${k}`; + if (spec.hasOwnProperty(k)) { + spec[k](kpath, value, k, v, onError); + return; + } + if (k !== 'ext' && !primitiveFields.includes(k)) { + onError(ERR_UNKNOWN_FIELD, kpath, value, k, v); + } + }); + }; + scan[extend] = (extraPrimitives, specOverride = {}) => + Obj(primitiveFields.concat(extraPrimitives), Object.assign({}, spec, specOverride)); + return scan; +} + +export const ID = Obj(['id']); +export const Named = ID[extend](['name']); + +export function Arr(def) { + return (path, parent, field, value, onError) => { + if (!Array.isArray(value)) { + onError(ERR_TYPE, path, parent, field, value); + } else { + value.forEach((item, i) => def(`${path}.${i}`, value, i, item, onError)); + } + }; +} + +export function IntEnum(min, max) { + return (path, parent, field, value, onError) => { + const errno = (() => { + if (typeof value !== 'number') return ERR_TYPE; + if (isNaN(value) || value > max || value < min) return ERR_ENUM; + })(); + if (errno != null) { + onError(errno, path, parent, field, value); + } + }; +} diff --git a/libraries/ortb2.5StrictTranslator/spec.js b/libraries/ortb2.5StrictTranslator/spec.js new file mode 100644 index 00000000000..0ffb17a2e72 --- /dev/null +++ b/libraries/ortb2.5StrictTranslator/spec.js @@ -0,0 +1,81 @@ +import {Arr, extend, ID, IntEnum, Named, Obj} from './dsl.js'; + +const CatDomain = Named[extend](['cat', 'domain']); +const Segment = Named[extend](['value']); +const Data = Named[extend]([], { + segment: Arr(Segment) +}); +const Content = ID[extend](['episode', 'title', 'series', 'season', 'artist', 'genre', 'album', 'isrc', 'url', 'cat', 'contentrating', 'userrating', 'keywords', 'livestream', 'sourcerelationship', 'len', 'language', 'embeddable'], { + producer: CatDomain, + data: Arr(Data), + prodq: IntEnum(0, 3), + videoquality: IntEnum(0, 3), + context: IntEnum(1, 7), + qagmediarating: IntEnum(1, 3), +}); + +const Client = CatDomain[extend](['sectioncat', 'pagecat', 'privacypolicy', 'keywords'], { + publisher: CatDomain, content: Content, +}); +const Site = Client[extend](['page', 'ref', 'search', 'mobile']); +const App = Client[extend](['bundle', 'storeurl', 'ver', 'paid']); + +const Geo = Obj(['lat', 'lon', 'accuracy', 'lastfix', 'country', 'region', 'regionfips104', 'metro', 'city', 'zip', 'utcoffset'], { + type: IntEnum(1, 3), + ipservice: IntEnum(1, 4) +}); +const Device = Obj(['ua', 'dnt', 'lmt', 'ip', 'ipv6', 'make', 'model', 'os', 'osv', 'hwv', 'h', 'w', 'ppi', 'pxratio', 'js', 'geofetch', 'flashver', 'language', 'carrier', 'mccmnc', 'ifa', 'didsha1', 'didmd5', 'dpidsha1', 'dpidmd5', 'macsha1', 'macmd5'], { + geo: Geo, devicetype: IntEnum(1, 7), connectiontype: IntEnum(0, 6) +}); +const User = ID[extend](['buyeruid', 'yob', 'gender', 'keywords', 'customdata'], { + geo: Geo, data: Arr(Data), +}); + +const Floorable = ID[extend](['bidfloor', 'bidfloorcur']); +const Deal = Floorable[extend](['at', 'wseat', 'wadomain']); +const Pmp = Obj(['private_auction'], { + deals: Arr(Deal), +}); +const Format = Obj(['w', 'h', 'wratio', 'hratio', 'wmin']); +const MediaType = Obj(['mimes'], { + api: Arr(IntEnum(1, 6)), battr: Arr(IntEnum(1, 17)) +}); +const Banner = MediaType[extend](['id', 'w', 'h', 'wmax', 'hmax', 'hmin', 'wmin', 'topframe', 'vcm'], { + format: Arr(Format), btype: Arr(IntEnum(1, 4)), pos: IntEnum(0, 7), expdir: Arr(IntEnum(1, 5)) +}); +const Native = MediaType[extend](['request', 'ver']); +const RichMediaType = MediaType[extend](['minduration', 'maxduration', 'startdelay', 'sequence', 'maxextended', 'minbitrate', 'maxbitrate'], { + protocols: Arr(IntEnum(1, 10)), + delivery: Arr(IntEnum(1, 3)), + companionad: Arr(Banner), + companiontype: Arr(IntEnum(1, 3)), +}); +/* +const Audio = RichMediaType[extend](['maxseq', 'stitched'], { + feed: IntEnum(1, 3), nvol: IntEnum(0, 4), +}); + */ +const Video = RichMediaType[extend](['w', 'h', 'skip', 'skipmin', 'skipafter', 'boxingallowed'], { + pos: IntEnum(0, 7), + protocol: IntEnum(1, 10), + placement: IntEnum(1, 5), + linearity: IntEnum(1, 2), + playbackmethod: Arr(IntEnum(1, 6)), + playbackend: IntEnum(1, 3), +}); +const Metric = Obj(['type', 'value', 'vendor']); +const Imp = (() => { + const spec = { + metric: Arr(Metric), banner: Banner, video: Video, pmp: Pmp, + }; + if (FEATURES.NATIVE) { + spec.native = Native; + } + return Floorable[extend](['displaymanager', 'displaymanagerver', 'instl', 'tagid', 'clickbrowser', 'secure', 'iframebuster', 'exp'], spec); +})(); + +const Regs = Obj(['coppa']); +const Source = Obj(['fd', 'tid', 'pchain']); +export const BidRequest = ID[extend](['test', 'at', 'tmax', 'wseat', 'bseat', 'allimps', 'cur', 'wlang', 'bcat', 'badv', 'bapp'], { + imp: Arr(Imp), site: Site, app: App, device: Device, user: User, source: Source, regs: Regs +}); diff --git a/libraries/ortb2.5StrictTranslator/translator.js b/libraries/ortb2.5StrictTranslator/translator.js new file mode 100644 index 00000000000..c6f651e2476 --- /dev/null +++ b/libraries/ortb2.5StrictTranslator/translator.js @@ -0,0 +1,37 @@ +import {BidRequest} from './spec.js'; +import {logWarn} from '../../src/utils.js'; +import {toOrtb25} from '../ortb2.5Translator/translator.js'; + +function deleteField(errno, path, obj, field, value) { + logWarn(`${path} is not valid ORTB 2.5, field will be removed from request:`, value); + Array.isArray(obj) ? obj.splice(field, 1) : delete obj[field]; +} + +/** + * Translates an ortb request to 2.5, and removes from the result any field that is: + * - not defined in the 2.5 spec, or + * - defined as an enum, but has a value that is not listed in the 2.5 spec. + * + * `ortb2` is modified in place and returned. + * + * Note that using this utility will cause your adapter to pull in an additional ~3KB after minification. + * If possible, consider making your endpoint tolerant to unrecognized or invalid fields instead. + * + * + * @param ortb2 ORTB request + * @param translator translation function. The default moves 2.x fields that have a known standard location in 2.5. + * See the `ortb2.5Translator` library. + * @param onError a function invoked once for each field that is not valid according to the 2.5 spec; it takes + * (errno, path, obj, field, value), where: + * - errno is an error code (defined in dsl.js) + * - path is the JSON path of the offending field, for example `regs.gdpr` + * - obj is the object containing the offending field, for example `ortb2.regs` + * - field is the field name, for example `'gdpr'` + * - value is `obj[field]`. + * The default logs a warning and deletes the offending field. + */ +export function toOrtb25Strict(ortb2, translator = toOrtb25, onError = deleteField) { + ortb2 = translator(ortb2); + BidRequest(null, null, null, ortb2, onError); + return ortb2; +} diff --git a/libraries/ortb2.5Translator/translator.js b/libraries/ortb2.5Translator/translator.js new file mode 100644 index 00000000000..1afad516ef0 --- /dev/null +++ b/libraries/ortb2.5Translator/translator.js @@ -0,0 +1,82 @@ +import {deepAccess, deepSetValue, logError} from '../../src/utils.js'; + +export const EXT_PROMOTIONS = [ + 'source.schain', + 'regs.gdpr', + 'regs.us_privacy', + 'regs.gpp', + 'user.consent', + 'user.eids' +]; + +export function splitPath(path) { + const parts = path.split('.'); + const prefix = parts.slice(0, parts.length - 1).join('.'); + const field = parts[parts.length - 1]; + return [prefix, field]; +} + +/** + * @param sourcePath a JSON path such as `regs.us_privacy` + * @param dest {function(String, String): String} a function taking (prefix, field) and returning a destination path; + * for example, ('regs', 'us_privacy') => 'regs.ext.us_privacy' + * @return {(function({}): (function(): void|undefined))|*} a function that takes an object and, if it contains + * sourcePath, copies its contents to destinationPath, returning a function that deletes the original sourcePath. + */ +export function moveRule(sourcePath, dest = (prefix, field) => `${prefix}.ext.${field}`) { + const [prefix, field] = splitPath(sourcePath); + dest = dest(prefix, field); + return (ortb2) => { + const obj = deepAccess(ortb2, prefix); + if (obj?.[field] != null) { + deepSetValue(ortb2, dest, obj[field]); + return () => delete obj[field]; + } + }; +} + +function kwarrayRule(section) { + // move 2.6 `kwarray` into 2.5 comma-separated `keywords`. + return (ortb2) => { + const kwarray = ortb2[section]?.kwarray; + if (kwarray != null) { + let kw = (ortb2[section].keywords || '').split(','); + if (Array.isArray(kwarray)) kw.push(...kwarray); + ortb2[section].keywords = kw.join(','); + return () => delete ortb2[section].kwarray; + } + }; +} + +export const DEFAULT_RULES = Object.freeze([ + ...EXT_PROMOTIONS.map((f) => moveRule(f)), + ...['app', 'content', 'site', 'user'].map(kwarrayRule) +]); + +/** + * Factory for ORTB 2.5 translation functions. + * + * @param deleteFields if true, the translation function will remove fields that have been translated (transferred somewhere else within the request) + * @param rules translation rules; an array of functions of the type returned by `moveRule` + * @return {function({}): {}} a translation function that takes an ORTB object, modifies it in place, and returns it. + */ +export function ortb25Translator(deleteFields = true, rules = DEFAULT_RULES) { + return function (ortb2) { + rules.forEach(f => { + try { + const deleter = f(ortb2); + if (typeof deleter === 'function' && deleteFields) deleter(); + } catch (e) { + logError('Error translating request to ORTB 2.5', e); + } + }) + return ortb2; + } +} + +/** + * Translate an ortb request to version 2.5 by moving 2.6 (and later) fields that have a standardized 2.5 extension. + * + * The request is modified in place and returned. + */ +export const toOrtb25 = ortb25Translator(); diff --git a/libraries/ortbConverter/processors/default.js b/libraries/ortbConverter/processors/default.js index 70acb7c9953..1d6bfb8424e 100644 --- a/libraries/ortbConverter/processors/default.js +++ b/libraries/ortbConverter/processors/default.js @@ -1,4 +1,4 @@ -import {deepSetValue, getDefinedParams, getDNT, mergeDeep} from '../../../src/utils.js'; +import {deepSetValue, logWarn, mergeDeep} from '../../../src/utils.js'; import {bannerResponseProcessor, fillBannerImp} from './banner.js'; import {fillVideoImp, fillVideoResponse} from './video.js'; import {setResponseMediaType} from './mediaType.js'; @@ -20,13 +20,9 @@ export const DEFAULT_PROCESSORS = { appFpd: fpdFromTopLevelConfig('app'), siteFpd: fpdFromTopLevelConfig('site'), deviceFpd: fpdFromTopLevelConfig('device'), - device: { - // sets device w / h / ua / language - fn: setDevice - }, - site: { - // sets site.domain, page, and ref from refererInfo - fn: setSite + onlyOneClient: { + priority: -99, + fn: onlyOneClientSection }, props: { // sets request properties id, tmax, test, source.tid @@ -41,15 +37,7 @@ export const DEFAULT_PROCESSORS = { } deepSetValue(ortbRequest, 'source.tid', ortbRequest.source?.tid || bidderRequest.auctionId); } - }, - coppa: { - fn(ortbRequest) { - const coppa = config.getConfig('coppa'); - if (typeof coppa === 'boolean') { - deepSetValue(ortbRequest, 'regs.coppa', coppa ? 1 : 0); - } - } - }, + } }, [IMP]: { fpd: { @@ -144,24 +132,22 @@ function fpdFromTopLevelConfig(prop) { fn(ortbRequest) { const data = config.getConfig(prop); if (typeof data === 'object') { - ortbRequest[prop] = data; + ortbRequest[prop] = mergeDeep({}, ortbRequest[prop], data); } } } } -export function setDevice(ortbRequest) { - ortbRequest.device = Object.assign({ - w: window.innerWidth, - h: window.innerHeight, - dnt: getDNT() ? 1 : 0, - ua: window.navigator.userAgent, - language: window.navigator.language.split('-').shift() - }, ortbRequest.device); -} - -export function setSite(ortbRequest, bidderRequest) { - if (bidderRequest.refererInfo) { - ortbRequest.site = Object.assign(getDefinedParams(bidderRequest.refererInfo, ['page', 'domain', 'ref']), ortbRequest.site); - } +export function onlyOneClientSection(ortbRequest) { + ['dooh', 'app', 'site'].reduce((found, section) => { + if (ortbRequest[section] != null && Object.keys(ortbRequest[section]).length > 0) { + if (found != null) { + logWarn(`ORTB request specifies both '${found}' and '${section}'; dropping the latter.`) + delete ortbRequest[section]; + } else { + found = section; + } + } + return found; + }, null); } diff --git a/libraries/pbsExtensions/processors/adUnitCode.js b/libraries/pbsExtensions/processors/adUnitCode.js new file mode 100644 index 00000000000..f936e0f662f --- /dev/null +++ b/libraries/pbsExtensions/processors/adUnitCode.js @@ -0,0 +1,13 @@ +import {deepSetValue} from '../../../src/utils.js'; + +export function setImpAdUnitCode(imp, bidRequest) { + const adUnitCode = bidRequest.adUnitCode; + + if (adUnitCode) { + deepSetValue( + imp, + `ext.prebid.adunitcode`, + adUnitCode + ); + } +} diff --git a/libraries/pbsExtensions/processors/pbs.js b/libraries/pbsExtensions/processors/pbs.js index 56a2a391c76..0ed2d12fad8 100644 --- a/libraries/pbsExtensions/processors/pbs.js +++ b/libraries/pbsExtensions/processors/pbs.js @@ -3,6 +3,7 @@ import {deepAccess, isPlainObject, isStr, mergeDeep} from '../../../src/utils.js import {extPrebidMediaType} from './mediaType.js'; import {setRequestExtPrebidAliases} from './aliases.js'; import {setImpBidParams} from './params.js'; +import {setImpAdUnitCode} from './adUnitCode.js'; import {setRequestExtPrebid, setRequestExtPrebidChannel} from './requestExtPrebid.js'; import {setBidResponseVideoCache} from './video.js'; @@ -26,6 +27,10 @@ export const PBS_PROCESSORS = { // sets bid ext.prebid.bidder.[bidderCode] with bidRequest.params, passed through transformBidParams if necessary fn: setImpBidParams }, + adUnitCode: { + // sets bid ext.prebid.adunitcode + fn: setImpAdUnitCode + } }, [BID_RESPONSE]: { mediaType: { diff --git a/libraries/video/constants/enums.js b/libraries/video/constants/constants.js similarity index 65% rename from libraries/video/constants/enums.js rename to libraries/video/constants/constants.js index b0755020580..55e3785ccc2 100644 --- a/libraries/video/constants/enums.js +++ b/libraries/video/constants/constants.js @@ -1,3 +1,5 @@ +export const videoKey = 'video'; + export const PLAYBACK_MODE = { VOD: 0, LIVE: 1, diff --git a/libraries/video/constants/events.js b/libraries/video/constants/events.js index 5be594b1b48..b7932adf621 100644 --- a/libraries/video/constants/events.js +++ b/libraries/video/constants/events.js @@ -52,6 +52,7 @@ export const allVideoEvents = [ ]; export const AUCTION_AD_LOAD_ATTEMPT = 'auctionAdLoadAttempt'; +export const AUCTION_AD_LOAD_QUEUED = 'auctionAdLoadQueued'; export const AUCTION_AD_LOAD_ABORT = 'auctionAdLoadAbort'; export const BID_IMPRESSION = 'bidImpression'; export const BID_ERROR = 'bidError'; diff --git a/libraries/video/shared/helpers.js b/libraries/video/shared/helpers.js new file mode 100644 index 00000000000..1b87f3bf1f3 --- /dev/null +++ b/libraries/video/shared/helpers.js @@ -0,0 +1,5 @@ +import { videoKey } from '../constants/constants.js' + +export function getExternalVideoEventName(eventName) { + return videoKey + eventName.replace(/^./, eventName[0].toUpperCase()); +} diff --git a/libraries/video/shared/parentModule.js b/libraries/video/shared/parentModule.js index e96113fd894..06c71ebd75b 100644 --- a/libraries/video/shared/parentModule.js +++ b/libraries/video/shared/parentModule.js @@ -72,7 +72,6 @@ export function SubmoduleBuilder(submoduleDirectory_, sharedUtils_) { } const submodule = submoduleFactory(config, sharedUtils); - submodule && submodule.init && submodule.init(); return submodule; } diff --git a/modules/.submodules.json b/modules/.submodules.json index e4678a86b71..226673488cf 100644 --- a/modules/.submodules.json +++ b/modules/.submodules.json @@ -7,7 +7,7 @@ "amxIdSystem", "britepoolIdSystem", "connectIdSystem", - "cpexIdSystem", + "czechAdIdSystem", "criteoIdSystem", "dacIdSystem", "deepintentDpesIdSystem", @@ -52,10 +52,14 @@ ], "rtdModule": [ "1plusXRtdProvider", + "aaxBlockmeterRtdProvider", "airgridRtdProvider", "akamaiDapRtdProvider", + "arcspanRtdProvider", "blueconicRtdProvider", "browsiRtdProvider", + "captifyRtdProvider", + "confiantRtdProvider", "dgkeywordRtdProvider", "geoedgeRtdProvider", "hadronRtdProvider", @@ -63,16 +67,17 @@ "iasRtdProvider", "jwplayerRtdProvider", "medianetRtdProvider", + "mgidRtdProvider", "oneKeyRtdProvider", "optimeraRtdProvider", "permutiveRtdProvider", "reconciliationRtdProvider", "sirdataRtdProvider", "timeoutRtdProvider", - "weboramaRtdProvider" + "weboramaRtdProvider", + "zeusPrimeRtdProvider" ], "fpdModule": [ - "enrichmentFpdModule", "validationFpdModule", "topicsFpdModule" ], diff --git a/modules/33acrossBidAdapter.js b/modules/33acrossBidAdapter.js index d9524a281f8..e9901794ff9 100644 --- a/modules/33acrossBidAdapter.js +++ b/modules/33acrossBidAdapter.js @@ -167,7 +167,8 @@ function buildRequests(bidRequests, bidderRequest) { ttxSettings, gdprConsent, uspConsent, - pageUrl + pageUrl, + referer } = _buildRequestParams(bidRequests, bidderRequest); const groupedRequests = _buildRequestGroups(ttxSettings, bidRequests); @@ -181,6 +182,7 @@ function buildRequests(bidRequests, bidderRequest) { gdprConsent, uspConsent, pageUrl, + referer, ttxSettings }) ) @@ -199,7 +201,9 @@ function _buildRequestParams(bidRequests, bidderRequest) { const uspConsent = bidderRequest && bidderRequest.uspConsent; - const pageUrl = bidderRequest?.refererInfo?.page + const pageUrl = bidderRequest?.refererInfo?.page; + + const referer = bidderRequest?.refererInfo?.ref; adapterState.uniqueSiteIds = bidRequests.map(req => req.params.siteId).filter(uniques); @@ -207,7 +211,8 @@ function _buildRequestParams(bidRequests, bidderRequest) { ttxSettings, gdprConsent, uspConsent, - pageUrl + pageUrl, + referer } } @@ -241,7 +246,7 @@ function _getMRAKey(bidRequest) { } // Infer the necessary data from valid bid for a minimal ttxRequest and create HTTP request -function _createServerRequest({ bidRequests, gdprConsent = {}, uspConsent, pageUrl, ttxSettings }) { +function _createServerRequest({ bidRequests, gdprConsent = {}, uspConsent, pageUrl, referer, ttxSettings }) { const ttxRequest = {}; const firstBidRequest = bidRequests[0]; const { siteId, test } = firstBidRequest.params; @@ -262,6 +267,10 @@ function _createServerRequest({ bidRequests, gdprConsent = {}, uspConsent, pageU ttxRequest.site.page = pageUrl; } + if (referer) { + ttxRequest.site.ref = referer; + } + ttxRequest.id = firstBidRequest.auctionId; if (gdprConsent.consentString) { diff --git a/modules/33acrossIdSystem.js b/modules/33acrossIdSystem.js index 3763fee5124..5e07fe9523d 100644 --- a/modules/33acrossIdSystem.js +++ b/modules/33acrossIdSystem.js @@ -13,6 +13,7 @@ import { uspDataHandler } from '../src/adapterManager.js'; const MODULE_NAME = '33acrossId'; const API_URL = 'https://lexicon.33across.com/v1/envelope'; const AJAX_TIMEOUT = 10000; +const CALLER_NAME = 'pbjs'; function getEnvelope(response) { if (!response.succeeded) { @@ -36,6 +37,8 @@ function calculateQueryStringParams(pid, gdprConsentData) { const params = { pid, gdpr: Number(gdprApplies), + src: CALLER_NAME, + ver: '$prebid.version$' }; if (uspString) { diff --git a/modules/aaxBlockmeterRtdProvider.js b/modules/aaxBlockmeterRtdProvider.js new file mode 100644 index 00000000000..a3b7b4812a7 --- /dev/null +++ b/modules/aaxBlockmeterRtdProvider.js @@ -0,0 +1,59 @@ +import {isEmptyStr, isStr, logError, isFn, logWarn} from '../src/utils.js'; +import {submodule} from '../src/hook.js'; +import { loadExternalScript } from '../src/adloader.js'; + +export const _config = { + MODULE: 'aaxBlockmeter', + ADSERVER_TARGETING_KEY: 'atk', + BLOCKMETER_URL: 'c.aaxads.com/aax.js', + VERSION: '1.2' +}; + +window.aax = window.aax || {}; + +function loadBlockmeter(_rtdConfig) { + if (!(_rtdConfig.params && _rtdConfig.params.pub) || !isStr(_rtdConfig.params && _rtdConfig.params.pub) || isEmptyStr(_rtdConfig.params && _rtdConfig.params.pub)) { + logError(`${_config.MODULE}: params.pub should be a string`); + return false; + } + + const params = []; + params.push(`pub=${_rtdConfig.params.pub}`); + params.push(`dn=${window.location.hostname}`); + + let url = _rtdConfig.params.url; + if (!url || isEmptyStr(url)) { + logWarn(`${_config.MODULE}: params.url is missing, using default url.`); + url = `${_config.BLOCKMETER_URL}?ver=${_config.VERSION}`; + } + + const scriptUrl = `https://${url}&${params.join('&')}`; + loadExternalScript(scriptUrl, _config.MODULE); + return true; +} + +function markAdBlockInventory(codes, _rtdConfig, _userConsent) { + return codes.reduce((targets, code) => { + targets[code] = targets[code] || {}; + const getAaxTargets = () => isFn(window.aax.getTargetingData) + ? window.aax.getTargetingData(code, _rtdConfig, _userConsent) + : {}; + targets[code] = { + [_config.ADSERVER_TARGETING_KEY]: code, + ...getAaxTargets() + }; + return targets; + }, {}); +} + +export const aaxBlockmeterRtdModule = { + name: _config.MODULE, + init: loadBlockmeter, + getTargetingData: markAdBlockInventory, +}; + +function registerSubModule() { + submodule('realTimeData', aaxBlockmeterRtdModule); +} + +registerSubModule(); diff --git a/modules/aaxBlockmeterRtdProvider.md b/modules/aaxBlockmeterRtdProvider.md new file mode 100644 index 00000000000..0a317f85b85 --- /dev/null +++ b/modules/aaxBlockmeterRtdProvider.md @@ -0,0 +1,48 @@ +## Overview + +Module Name: AAX Blockmeter Realtime Data Module +Module Type: Rtd Provider +Maintainer: product@aax.media + +## Description + +The module enables publishers to measure traffic coming from visitors using adblockers. + +AAX can also help publishers monetize this traffic by allowing them to serve [acceptable ads](https://acceptableads.com/about/) to these adblock visitors and recover their lost revenue. [Reach out to us](https://www.aax.media/try-blockmeter/) to know more. + +## Integration + +Build the AAX Blockmeter Realtime Data Module into the Prebid.js package with: + +``` +gulp build --modules=aaxBlockmeterRtdProvider,rtdModule +``` + +## Configuration + +This module is configured as part of the `realTimeData.dataProviders` object. + +| Name | Scope | Description | Example | Type | +|:----------:|:--------:|:-----------------------------|:---------------:|:------:| +| `name` | required | Real time data module name | `'aaxBlockmeter'` | `string` | +| `params` | required | | | `Object` | +| `params.pub` | required | AAX to share pub ID, [Reach out to us](https://www.aax.media/try-blockmeter/) to know more! | `'AAX00000'` | `string` | +| `params.url` | optional | AAX Blockmeter Script Url. Defaults to `'c.aaxads.com/aax.js?ver=1.2'` | `'c.aaxads.com/aax.js?ver=1.2'` | `string` | + +### Example + +```javascript +pbjs.setConfig({ + "realTimeData": { + "dataProviders": [ + { + "name": "aaxBlockmeter", + "params": { + "pub": "AAX00000", + "url": "c.aaxads.com/aax.js?ver=1.2", + } + } + ] + } +}) +``` diff --git a/modules/adagioBidAdapter.js b/modules/adagioBidAdapter.js index e59fd341bae..798ff499206 100644 --- a/modules/adagioBidAdapter.js +++ b/modules/adagioBidAdapter.js @@ -15,6 +15,7 @@ import { isFn, isInteger, isNumber, + isArrayOfNums, logError, logInfo, logWarn, @@ -32,6 +33,7 @@ import {Renderer} from '../src/Renderer.js'; import {OUTSTREAM} from '../src/video.js'; import { getGlobal } from '../src/prebidGlobal.js'; import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; +import { userSync } from '../src/userSync.js'; const BIDDER_CODE = 'adagio'; const LOG_PREFIX = 'Adagio:'; @@ -48,33 +50,32 @@ const ADAGIO_PUBKEY = 'AL16XT44Sfp+8SHVF1UdC7hydPSMVLMhsYknKDdwqq+0ToDSJrP0+Qh0k const ADAGIO_PUBKEY_E = 65537; const CURRENCY = 'USD'; -// This provide a whitelist and a basic validation -// of OpenRTB 2.5 options used by the Adagio SSP. -// https://www.iab.com/wp-content/uploads/2016/03/OpenRTB-API-Specification-Version-2-5-FINAL.pdf +// This provide a whitelist and a basic validation of OpenRTB 2.6 options used by the Adagio SSP. +// https://iabtechlab.com/wp-content/uploads/2022/04/OpenRTB-2-6_FINAL.pdf export const ORTB_VIDEO_PARAMS = { 'mimes': (value) => Array.isArray(value) && value.length > 0 && value.every(v => typeof v === 'string'), 'minduration': (value) => isInteger(value), 'maxduration': (value) => isInteger(value), - 'protocols': (value) => Array.isArray(value) && value.every(v => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].indexOf(v) !== -1), + 'protocols': (value) => isArrayOfNums(value), 'w': (value) => isInteger(value), 'h': (value) => isInteger(value), 'startdelay': (value) => isInteger(value), - 'placement': (value) => Array.isArray(value) && value.every(v => [1, 2, 3, 4, 5].indexOf(v) !== -1), - 'linearity': (value) => [1, 2].indexOf(value) !== -1, - 'skip': (value) => [0, 1].indexOf(value) !== -1, + 'placement': (value) => isInteger(value), + 'linearity': (value) => isInteger(value), + 'skip': (value) => isInteger(value), 'skipmin': (value) => isInteger(value), 'skipafter': (value) => isInteger(value), 'sequence': (value) => isInteger(value), - 'battr': (value) => Array.isArray(value) && value.every(v => Array.from({length: 17}, (_, i) => i + 1).indexOf(v) !== -1), + 'battr': (value) => isArrayOfNums(value), 'maxextended': (value) => isInteger(value), 'minbitrate': (value) => isInteger(value), 'maxbitrate': (value) => isInteger(value), - 'boxingallowed': (value) => [0, 1].indexOf(value) !== -1, - 'playbackmethod': (value) => Array.isArray(value) && value.every(v => [1, 2, 3, 4, 5, 6].indexOf(v) !== -1), - 'playbackend': (value) => [1, 2, 3].indexOf(value) !== -1, - 'delivery': (value) => [1, 2, 3].indexOf(value) !== -1, - 'pos': (value) => [0, 1, 2, 3, 4, 5, 6, 7].indexOf(value) !== -1, - 'api': (value) => Array.isArray(value) && value.every(v => [1, 2, 3, 4, 5, 6].indexOf(v) !== -1) + 'boxingallowed': (value) => isInteger(value), + 'playbackmethod': (value) => isArrayOfNums(value), + 'playbackend': (value) => isInteger(value), + 'delivery': (value) => isInteger(value), + 'pos': (value) => isInteger(value), + 'api': (value) => isArrayOfNums(value) }; let currentWindow; @@ -669,10 +670,8 @@ function autoFillParams(bid) { } // extra params - setExtraParam(bid, 'environment'); setExtraParam(bid, 'pagetype'); setExtraParam(bid, 'category'); - setExtraParam(bid, 'subcategory'); } function getPageDimensions() { @@ -761,46 +760,51 @@ function getSlotPosition(adUnitElementId) { position.x = Math.round(sfGeom.t); position.y = Math.round(sfGeom.l); } else if (canAccessTopWindow()) { - // window.top based computing - const wt = getWindowTop(); - const d = wt.document; + try { + // window.top based computing + const wt = getWindowTop(); + const d = wt.document; - let domElement; + let domElement; - if (inIframe() === true) { - const ws = getWindowSelf(); - const currentElement = ws.document.getElementById(adUnitElementId); - domElement = internal.getElementFromTopWindow(currentElement, ws); - } else { - domElement = wt.document.getElementById(adUnitElementId); - } + if (inIframe() === true) { + const ws = getWindowSelf(); + const currentElement = ws.document.getElementById(adUnitElementId); + domElement = internal.getElementFromTopWindow(currentElement, ws); + } else { + domElement = wt.document.getElementById(adUnitElementId); + } - if (!domElement) { - return ''; - } + if (!domElement) { + return ''; + } - let box = domElement.getBoundingClientRect(); - - const docEl = d.documentElement; - const body = d.body; - const clientTop = d.clientTop || body.clientTop || 0; - const clientLeft = d.clientLeft || body.clientLeft || 0; - const scrollTop = wt.pageYOffset || docEl.scrollTop || body.scrollTop; - const scrollLeft = wt.pageXOffset || docEl.scrollLeft || body.scrollLeft; - - const elComputedStyle = wt.getComputedStyle(domElement, null); - const elComputedDisplay = elComputedStyle.display || 'block'; - const mustDisplayElement = elComputedDisplay === 'none'; - - if (mustDisplayElement) { - domElement.style = domElement.style || {}; - const originalDisplay = domElement.style.display; - domElement.style.display = 'block'; - box = domElement.getBoundingClientRect(); - domElement.style.display = originalDisplay || null; + let box = domElement.getBoundingClientRect(); + + const docEl = d.documentElement; + const body = d.body; + const clientTop = d.clientTop || body.clientTop || 0; + const clientLeft = d.clientLeft || body.clientLeft || 0; + const scrollTop = wt.pageYOffset || docEl.scrollTop || body.scrollTop; + const scrollLeft = wt.pageXOffset || docEl.scrollLeft || body.scrollLeft; + + const elComputedStyle = wt.getComputedStyle(domElement, null); + const elComputedDisplay = elComputedStyle.display || 'block'; + const mustDisplayElement = elComputedDisplay === 'none'; + + if (mustDisplayElement) { + domElement.style = domElement.style || {}; + const originalDisplay = domElement.style.display; + domElement.style.display = 'block'; + box = domElement.getBoundingClientRect(); + domElement.style.display = originalDisplay || null; + } + position.x = Math.round(box.left + scrollLeft - clientLeft); + position.y = Math.round(box.top + scrollTop - clientTop); + } catch (err) { + logError(LOG_PREFIX, err); + return ''; } - position.x = Math.round(box.left + scrollLeft - clientLeft); - position.y = Math.round(box.top + scrollTop - clientTop); } else { return ''; } @@ -909,6 +913,8 @@ export const spec = { const coppa = _getCoppa(); const schain = _getSchain(validBidRequests[0]); const eids = _getEids(validBidRequests[0]) || []; + const syncEnabled = deepAccess(config.getConfig('userSync'), 'syncEnabled') + const usIfr = syncEnabled && userSync.canBidderRegisterSync('iframe', 'adagio') const adUnits = _map(validBidRequests, (bidRequest) => { const globalFeatures = GlobalExchange.getOrSetGlobalFeatures(); @@ -1027,7 +1033,8 @@ export const spec = { eids: eids }, prebidVersion: '$prebid.version$', - featuresVersion: FEATURES_VERSION + featuresVersion: FEATURES_VERSION, + usIfr: usIfr }, options: { contentType: 'text/plain' @@ -1089,8 +1096,6 @@ export const spec = { bidObj.placement = bidReq.params.placement; bidObj.pagetype = bidReq.params.pagetype; bidObj.category = bidReq.params.category; - bidObj.subcategory = bidReq.params.subcategory; - bidObj.environment = bidReq.params.environment; } bidResponses.push(bidObj); }); diff --git a/modules/adagioBidAdapter.md b/modules/adagioBidAdapter.md index 9b48caa8233..e65a044c2fa 100644 --- a/modules/adagioBidAdapter.md +++ b/modules/adagioBidAdapter.md @@ -10,30 +10,63 @@ Connects to Adagio demand source to fetch bids. ## Configuration +### User Sync + +Add the following code to enable user sync. Adagio strongly recommends enabling user syncing through iframes. This functionality improves DSP user match rates and increases the bid rate and bid price. Be sure to call `pbjs.setConfig()` only once. + +```javascript +pbjs.setConfig({ + userSync: { + iframeEnabled: true, + filterSettings: { + iframe: { + bidders: ['adagio'], + filter: 'include' + } + } + } +}); +``` + +### Bidder Settings + +The Adagio bid adapter uses browser local storage. Since Prebid.js 7.x, the access to it must be explicitly set. + +```js +// https://docs.prebid.org/dev-docs/publisher-api-reference/bidderSettings.html +pbjs.bidderSettings = { + adagio: { + storageAllowed: true + } +} +``` + +### Params configuration + Adagio require several params. These params must be set at Prebid.js BidderConfig config level or at adUnit level. Below, the list of Adagio params and where they can be set. -| Param name | Global config | AdUnit config | -| ---------- | ------------- | ------------- | -| siteId | x | -| organizationId (obsolete) | | x -| site (obsolete) | | x -| pagetype | x | x -| environment | x | x -| category | x | x -| subcategory | x | x -| useAdUnitCodeAsAdUnitElementId | x | x -| useAdUnitCodeAsPlacement | x | x -| placement | | x -| adUnitElementId | | x -| debug | | x -| video | | x -| native | | x - -### Global configuration - -The global configuration is used to store params once instead of duplicate them to each adUnit. The values will be used as "params" in the ad-request. +| Param name | Global config | AdUnit config | +| ------------------------------ | ------------- | ------------- | +| siteId | x | | +| organizationId * | | x | +| site * | | x | +| pagetype | x | x | +| category | x | x | +| useAdUnitCodeAsAdUnitElementId | x | x | +| useAdUnitCodeAsPlacement | x | x | +| placement | | x | +| adUnitElementId | | x | +| debug | | x | +| video | | x | +| native | | x | + +_* These params are deprecated in favor the Global configuration setup, see below._ + +#### Global Adagio configuration + +The global Adagio configuration is used to store params once instead of duplicate them to each adUnit. The values will be used as "params" in the ad-request. Be sure to call `pbjs.setConfig()` only once. ```javascript pbjs.setConfig({ @@ -49,27 +82,14 @@ pbjs.setConfig({ // - underscores `_` // Also, each param can have at most 50 unique active values (case-insensitive). pagetype: 'article', // Highly recommended. The pagetype describes what kind of content will be present in the page. - environment: 'mobile', // Recommended. Environment where the page is displayed. category: 'sport', // Recommended. Category of the content displayed in the page. - subcategory: 'handball', // Optional. Subcategory of the content displayed in the page. useAdUnitCodeAsAdUnitElementId: false, // Optional. Use it by-pass adUnitElementId and use the adUnit code as value useAdUnitCodeAsPlacement: false, // Optional. Use it to by-pass placement and use the adUnit code as value - }, + } }); ``` -#### Note on FPD support - -Adagio will use FPD data as fallback for the params below: -- pagetype -- environment -- category -- subcategory - -If the FPD value is an array, the 1st value of this array will be used. - -### adUnit configuration - +#### Ad-unit configuration ```javascript var adUnits = [ { @@ -85,8 +105,10 @@ var adUnits = [ cpm: 3.00 // default to 1.00 }, video: { + api: [2, 7], // Required - Your video player must at least support the value 2 and/or 7. + playbackMethod: [6], // Highly recommended skip: 0 - // OpenRTB 2.5 video options defined here override ones defined in mediaTypes. + // OpenRTB video options defined here override ones defined in mediaTypes. }, native: { // Optional OpenRTB Native 1.2 request object. Only `context`, `plcmttype` fields are supported. @@ -99,6 +121,14 @@ var adUnits = [ ]; ``` +#### Note on FPD support + +Adagio will use FPD data as fallback for the params below: +- pagetype +- category + +If the FPD value is an array, the 1st value of this array will be used. + ## Test Parameters ```javascript @@ -107,11 +137,17 @@ var adUnits = [ debug: true, adagio: { pagetype: 'article', - environment: 'mobile', category: 'sport', - subcategory: 'handball', useAdUnitCodeAsAdUnitElementId: false, useAdUnitCodeAsPlacement: false, + }, + userSync: { + filterSettings: { + iframe: { + bidders: ['adagio'], + filter: 'include' + } + } } }); @@ -208,12 +244,6 @@ var adUnits = [ return bidResponse.site; } }, - { - key: "environment", - val: function (bidResponse) { - return bidResponse.environment; - } - }, { key: "placement", val: function (bidResponse) { @@ -231,12 +261,6 @@ var adUnits = [ val: function (bidResponse) { return bidResponse.category; } - }, - { - key: "subcategory", - val: function (bidResponse) { - return bidResponse.subcategory; - } } ] } diff --git a/modules/adhashBidAdapter.js b/modules/adhashBidAdapter.js index 977d161b214..33a85a81525 100644 --- a/modules/adhashBidAdapter.js +++ b/modules/adhashBidAdapter.js @@ -1,10 +1,12 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {includes} from '../src/polyfill.js'; -import {BANNER} from '../src/mediaTypes.js'; +import { getStorageManager } from '../src/storageManager.js'; +import { includes } from '../src/polyfill.js'; +import { BANNER } from '../src/mediaTypes.js'; -const VERSION = '1.0'; +const VERSION = '3.2'; const BAD_WORD_STEP = 0.1; const BAD_WORD_MIN = 0.2; +const ADHASH_BIDDER_CODE = 'adhash'; /** * Function that checks the page where the ads are being served for brand safety. @@ -54,43 +56,92 @@ function brandSafety(badWords, maxScore) { return positive ? result : -result; }; + /** + * Checks what rule will match in the given array with words + * @param {string} rule rule type (full, partial, starts, ends, regexp) + * @param {string} decodedWord decoded word + * @param {array} wordsToMatch array to find a match + * @returns {object|boolean} matched rule and occurances. If nothing is matched returns false + */ + const wordsMatchedWithRule = function (rule, decodedWord, wordsToMatch) { + if (rule === 'full' && wordsToMatch && wordsToMatch.includes(decodedWord)) { + return { rule, occurances: wordsToMatch.filter(element => element === decodedWord).length }; + } else if (rule === 'partial' && wordsToMatch && wordsToMatch.some(element => element.indexOf(decodedWord) > -1)) { + return { rule, occurances: wordsToMatch.filter(element => element.indexOf(decodedWord) > -1).length }; + } else if (rule === 'starts' && wordsToMatch && wordsToMatch.some(word => word.startsWith(decodedWord))) { + return { rule, occurances: wordsToMatch.filter(element => element.startsWith(decodedWord)).length }; + } else if (rule === 'ends' && wordsToMatch && wordsToMatch.some(word => word.endsWith(decodedWord))) { + return { rule, occurances: wordsToMatch.filter(element => element.endsWith(decodedWord)).length }; + } else if (rule === 'regexp' && wordsToMatch && wordsToMatch.some(element => element.match(new RegExp(decodedWord, 'i')))) { + return { rule, occurances: wordsToMatch.filter(element => element.match(new RegExp(decodedWord, 'i'))).length }; + } + return false; + }; + // Default parameters if the bidder is unable to send some of them badWords = badWords || []; maxScore = parseInt(maxScore) || 10; try { let score = 0; + const decodedUrl = decodeURI(window.top.location.href.substring(window.top.location.origin.length)); + const wordsAndNumbersInUrl = decodedUrl + .replaceAll(/[-,\._/\?=&#%]/g, ' ') + .replaceAll(/\s\s+/g, ' ') + .toLowerCase() + .trim(); const content = window.top.document.body.innerText.toLowerCase(); - const words = content.trim().split(/\s+/).length; + const contentWords = content.trim().split(/\s+/).length; + // \p{L} matches a single unicode code point in the category 'letter'. Matches any kind of letter from any language. + const regexp = new RegExp('[\\p{L}]+', 'gu'); + const words = content.match(regexp); + const wordsInUrl = wordsAndNumbersInUrl.match(regexp); + for (const [word, rule, points] of badWords) { - if (rule === 'full' && new RegExp('\\b' + rot13(word) + '\\b', 'i').test(content)) { - const occurances = content.match(new RegExp('\\b' + rot13(word) + '\\b', 'g')).length; - score += scoreCalculator(points, occurances); - } else if (rule === 'partial' && content.indexOf(rot13(word.toLowerCase())) > -1) { - const occurances = content.match(new RegExp(rot13(word), 'g')).length; - score += scoreCalculator(points, occurances); + const decodedWord = rot13(word.toLowerCase()); + + // Checks the words in the url of the page only for negative words. Don't serve any ad when at least one match is found + if (points > 0) { + const matchedRuleInUrl = wordsMatchedWithRule(rule, decodedWord, wordsInUrl); + if (matchedRuleInUrl.rule) { + return false; + } + } + + // Check if site content's words match any of our brand safety rules + const matchedRule = wordsMatchedWithRule(rule, decodedWord, words); + if (matchedRule.rule === 'full') { + score += scoreCalculator(points, matchedRule.occurances); + } else if (matchedRule.rule === 'partial') { + score += scoreCalculator(points, matchedRule.occurances); + } else if (matchedRule.rule === 'starts') { + score += scoreCalculator(points, matchedRule.occurances); + } else if (matchedRule.rule === 'ends') { + score += scoreCalculator(points, matchedRule.occurances); + } else if (matchedRule.rule === 'regexp') { + score += scoreCalculator(points, matchedRule.occurances); } } - return score < maxScore * words / 500; + return score < (maxScore * contentWords) / 1000; } catch (e) { return true; } } export const spec = { - code: 'adhash', - url: 'https://bidder.adhash.com/rtb?version=' + VERSION + '&prebid=true', + code: ADHASH_BIDDER_CODE, supportedMediaTypes: [ BANNER ], isBidRequestValid: (bid) => { try { - const { publisherId, platformURL } = bid.params; + const { publisherId, platformURL, bidderURL } = bid.params; return ( includes(Object.keys(bid.mediaTypes), BANNER) && typeof publisherId === 'string' && publisherId.length === 42 && typeof platformURL === 'string' && - platformURL.length >= 13 + platformURL.length >= 13 && + (!bidderURL || bidderURL.indexOf('https://') === 0) ); } catch (error) { return false; @@ -98,24 +149,51 @@ export const spec = { }, buildRequests: (validBidRequests, bidderRequest) => { + const storage = getStorageManager({ bidderCode: ADHASH_BIDDER_CODE }); const { gdprConsent } = bidderRequest; - const { url } = spec; const bidRequests = []; - let referrer = ''; - if (bidderRequest && bidderRequest.refererInfo) { - // TODO: is 'page' the right value here? - referrer = bidderRequest.refererInfo.page; - } - for (var i = 0; i < validBidRequests.length; i++) { - var index = Math.floor(Math.random() * validBidRequests[i].sizes.length); - var size = validBidRequests[i].sizes[index].join('x'); + const body = document.body; + const html = document.documentElement; + const pageHeight = Math.max( + body.scrollHeight, + body.offsetHeight, + html.clientHeight, + html.scrollHeight, + html.offsetHeight + ); + const pageWidth = Math.max(body.scrollWidth, body.offsetWidth, html.clientWidth, html.scrollWidth, html.offsetWidth); + + for (let i = 0; i < validBidRequests.length; i++) { + const bidderURL = validBidRequests[i].params.bidderURL || 'https://bidder.adhash.com'; + const url = `${bidderURL}/rtb?version=${VERSION}&prebid=true`; + const index = Math.floor(Math.random() * validBidRequests[i].sizes.length); + const size = validBidRequests[i].sizes[index].join('x'); + + let recentAds = []; + if (storage.localStorageIsEnabled()) { + const prefix = validBidRequests[i].params.prefix || 'adHash'; + recentAds = JSON.parse(storage.getDataFromLocalStorage(prefix + 'recentAds') || '[]'); + } + + // Needed for the ad density calculation + var adHeight = validBidRequests[i].sizes[index][1]; + var adWidth = validBidRequests[i].sizes[index][0]; + if (!window.adsCount) { + window.adsCount = 0; + } + if (!window.adsTotalSurface) { + window.adsTotalSurface = 0; + } + window.adsTotalSurface += adHeight * adWidth; + window.adsCount++; + bidRequests.push({ method: 'POST', url: url + '&publisher=' + validBidRequests[i].params.publisherId, bidRequest: validBidRequests[i], data: { timezone: new Date().getTimezoneOffset() / 60, - location: referrer, + location: bidderRequest.refererInfo ? bidderRequest.refererInfo.topmostLocation : '', publisherId: validBidRequests[i].params.publisherId, size: { screenWidth: window.screen.width, @@ -131,10 +209,14 @@ export const spec = { position: validBidRequests[i].adUnitCode }], blockedCreatives: [], - currentTimestamp: new Date().getTime(), - recentAds: [], + currentTimestamp: (new Date().getTime() / 1000) | 0, + recentAds: recentAds, GDPRApplies: gdprConsent ? gdprConsent.gdprApplies : null, - GDPR: gdprConsent ? gdprConsent.consentString : null + GDPR: gdprConsent ? gdprConsent.consentString : null, + servedAdsCount: window.adsCount, + adsTotalSurface: window.adsTotalSurface, + pageHeight: pageHeight, + pageWidth: pageWidth }, options: { withCredentials: false, @@ -157,7 +239,11 @@ export const spec = { } const publisherURL = JSON.stringify(request.bidRequest.params.platformURL); + const bidderURL = request.bidRequest.params.bidderURL || 'https://bidder.adhash.com'; const oneTimeId = request.bidRequest.adUnitCode + Math.random().toFixed(16).replace('0.', '.'); + const globalScript = !request.bidRequest.params.globalScript + ? `` + : ''; const bidderResponse = JSON.stringify({ responseText: JSON.stringify(responseBody) }); const requestData = JSON.stringify(request.data); @@ -165,8 +251,7 @@ export const spec = { requestId: request.bidRequest.bidId, cpm: responseBody.creatives[0].costEUR, ad: - `
- + `
${globalScript} `, width: request.bidRequest.sizes[0][0], height: request.bidRequest.sizes[0][1], diff --git a/modules/adhashBidAdapter.md b/modules/adhashBidAdapter.md index 4ee6ed3dc83..acca5a1e651 100644 --- a/modules/adhashBidAdapter.md +++ b/modules/adhashBidAdapter.md @@ -3,7 +3,7 @@ ``` Module Name: AdHash Bidder Adapter Module Type: Bidder Adapter -Maintainer: damyan@adhash.org +Maintainer: damyan@adhash.com ``` # Description @@ -14,8 +14,6 @@ Here is what you need for Prebid integration with AdHash: 3. Use the Publisher ID and Platform URL as parameters in params. Please note that a number of AdHash functionalities are not supported in the Prebid.js integration: -* Cookie-less frequency and recency capping; -* Audience segments; * Price floors and passback tags, as they are not needed in the Prebid.js setup; * Reservation for direct deals only, as bids are evaluated based on their price. diff --git a/modules/adkernelBidAdapter.js b/modules/adkernelBidAdapter.js index b0449418a87..5736c7c19ba 100644 --- a/modules/adkernelBidAdapter.js +++ b/modules/adkernelBidAdapter.js @@ -97,7 +97,8 @@ export const spec = { {code: 'motionspots'}, {code: 'sonic_twist'}, {code: 'displayioads'}, - {code: 'rtbdemand_com'} + {code: 'rtbdemand_com'}, + {code: 'bidbuddy'} ], supportedMediaTypes: [BANNER, VIDEO, NATIVE], diff --git a/modules/adlooxAnalyticsAdapter.md b/modules/adlooxAnalyticsAdapter.md index 203b118652e..d77ee25ab5f 100644 --- a/modules/adlooxAnalyticsAdapter.md +++ b/modules/adlooxAnalyticsAdapter.md @@ -34,19 +34,21 @@ When tracking video you have two options: To view an [example of an Adloox integration](../integrationExamples/gpt/adloox.html): - gulp serve --nolint --notest --modules=gptPreAuction,categoryTranslation,dfpAdServerVideo,rtdModule,instreamTracking,rubiconBidAdapter,spotxBidAdapter,adlooxAnalyticsAdapter,adlooxAdServerVideo,adlooxRtdProvider + gulp serve --nolint --notest --modules=gptPreAuction,categoryTranslation,dfpAdServerVideo,intersectionRtdProvider,rtdModule,instreamTracking,rubiconBidAdapter,spotxBidAdapter,adlooxAnalyticsAdapter,adlooxAdServerVideo,adlooxRtdProvider **N.B.** `categoryTranslation` is required by `dfpAdServerVideo` that otherwise causes a JavaScript console warning +**N.B.** `intersectionRtdProvider` is used by `adlooxRtdProvider` to provide (above-the-fold) ATF measurement, if not enabled the `atf` segment will not be available + Now point your browser at: http://localhost:9999/integrationExamples/gpt/adloox.html?pbjs_debug=true ### Public Example -The example is published publically at: https://storage.googleapis.com/adloox-ads-js-test/prebid.html?pbjs_debug=true +The example is published publicly at: https://storage.googleapis.com/adloox-ads-js-test/prebid.html?pbjs_debug=true **N.B.** this will show a [CORS error](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors) for the request `https://p.adlooxtracking.com/q?...` that is safe to ignore on the public example page; it is related to the [RTD integration](./adlooxRtdProvider.md) which requires pre-registration of your sites -It is recommended you use [Google Chrome's 'Local Overrides' located in the Developer Tools panel](https://www.trysmudford.com/blog/chrome-local-overrides/) to explore the example without the inconvience of having to run your own web server. +It is recommended you use [Google Chrome's 'Local Overrides' located in the Developer Tools panel](https://www.trysmudford.com/blog/chrome-local-overrides/) to explore the example without the inconvenience of having to run your own web server. #### Pre-built `prebid.js` diff --git a/modules/adlooxRtdProvider.js b/modules/adlooxRtdProvider.js index 8862ac8ac47..c2037429185 100644 --- a/modules/adlooxRtdProvider.js +++ b/modules/adlooxRtdProvider.js @@ -6,11 +6,13 @@ * @module modules/adlooxRtdProvider * @requires module:modules/realTimeData * @requires module:modules/adlooxAnalyticsAdapter + * @optional module:modules/intersectionRtdProvider */ /* eslint standard/no-callback-literal: "off" */ /* eslint prebid/validate-imports: "off" */ +import {auctionManager} from '../src/auctionManager.js'; import {command as analyticsCommand, COMMAND} from './adlooxAnalyticsAdapter.js'; import {submodule} from '../src/hook.js'; import {ajax} from '../src/ajax.js'; @@ -18,142 +20,31 @@ import {getGlobal} from '../src/prebidGlobal.js'; import {getRefererInfo} from '../src/refererDetection.js'; import { _each, + _map, + buildUrl, deepAccess, + deepClone, deepSetValue, - getAdUnitSizes, getGptSlotInfoForAdUnitCode, isArray, isBoolean, isInteger, isPlainObject, - isStr, logError, logInfo, logWarn, - mergeDeep + mergeDeep, + parseUrl, + safeJSONParse } from '../src/utils.js'; -import {includes} from '../src/polyfill.js'; const MODULE_NAME = 'adloox'; const MODULE = `${MODULE_NAME}RtdProvider`; const API_ORIGIN = 'https://p.adlooxtracking.com'; const SEGMENT_HISTORIC = { 'a': 'aud', 'd': 'dis', 'v': 'vid' }; -const SEGMENT_HISTORIC_VALUES = Object.keys(SEGMENT_HISTORIC).map(k => SEGMENT_HISTORIC[k]); -const ADSERVER_TARGETING_PREFIX = 'adl_'; - -const CREATIVE_WIDTH_MIN = 20; -const CREATIVE_HEIGHT_MIN = 20; -const CREATIVE_AREA_MIN = CREATIVE_WIDTH_MIN * CREATIVE_HEIGHT_MIN; -// try to avoid using IntersectionObserver as it has unbounded (observed multi-second) latency -let intersectionObserver = window == top ? false : undefined; -const intersectionObserverElements = []; -// .map/.findIndex are safe here as they are only used for intersectionObserver -function atf(adUnit, cb) { - analyticsCommand(COMMAND.TOSELECTOR, { bid: { adUnitCode: adUnit.code } }, function(selector) { - const element = document.querySelector(selector); - if (!element) return cb(null); - - if (window.getComputedStyle(element)['display'] == 'none') return cb(NaN); - - try { - // short circuit for cross-origin - if (intersectionObserver) throw false; - - // Google's advice is to collapse slots on no fill but - // we have to cater to clients that grow slots on fill - const rect = (function(rect) { - const sizes = getAdUnitSizes(adUnit); - - if (sizes.length == 0) return false; - // interstitial (0x0, 1x1) - if (sizes.length == 1 && (sizes[0][0] * sizes[0][1]) <= 1) return true; - // try to catch premium slots (coord=0,0) as they will likely bounce into view - if (rect.top <= -window.pageYOffset && rect.left <= -window.pageXOffset && rect.top == rect.bottom) return true; - - // pick the smallest creative size as many publishers will just leave the element unbounded in the vertical - let width = Infinity; - let height = Infinity; - for (let i = 0; i < sizes.length; i++) { - const area = sizes[i][0] * sizes[i][1]; - if (area < CREATIVE_AREA_MIN) continue; - if (area < (width * height)) { - width = sizes[i][0]; - height = sizes[i][1]; - } - } - // we also scale the smallest size to the size of the slot as publishers resize units depending on viewport - const scale = Math.min(1, (rect.right - rect.left) / width); - - return { - left: rect.left, - right: rect.left + Math.max(CREATIVE_WIDTH_MIN, scale * width), - top: rect.top, - bottom: rect.top + Math.max(CREATIVE_HEIGHT_MIN, scale * height) - }; - })(element.getBoundingClientRect()); - - if (rect === false) return cb(NaN); - if (rect === true) return cb(1); - - const W = rect.right - rect.left; - const H = rect.bottom - rect.top; - - if (W * H < CREATIVE_AREA_MIN) return cb(NaN); - - let el; - let win = window; - while (1) { - // https://stackoverflow.com/a/8876069 - const vw = Math.max(win.document.documentElement.clientWidth || 0, win.innerWidth || 0); - const vh = Math.max(win.document.documentElement.clientHeight || 0, win.innerHeight || 0); - - // cut to viewport - rect.left = Math.min(Math.max(rect.left, 0), vw); - rect.right = Math.min(Math.max(rect.right, 0), vw); - rect.top = Math.min(Math.max(rect.top, 0), vh); - rect.bottom = Math.min(Math.max(rect.bottom, 0), vh); - - if (win == top) return cb(((rect.right - rect.left) * (rect.bottom - rect.top)) / (W * H)); - el = win.frameElement; - if (!el) throw false; // cross-origin - win = win.parent; - - // transpose to frame element - const frameElementRect = el.getBoundingClientRect(); - rect.left += frameElementRect.left; - rect.right = Math.min(rect.right + frameElementRect.left, frameElementRect.right); - rect.top += frameElementRect.top; - rect.bottom = Math.min(rect.bottom + frameElementRect.top, frameElementRect.bottom); - } - } catch (_) { - if (intersectionObserver === undefined) { - try { - intersectionObserver = new IntersectionObserver(function(entries) { - entries.forEach(entry => { - const ratio = entry.intersectionRect.width * entry.intersectionRect.height < CREATIVE_AREA_MIN ? NaN : entry.intersectionRatio; - const idx = intersectionObserverElements.findIndex(x => x.element == entry.target); - intersectionObserverElements[idx].cb.forEach(cb => cb(ratio)); - intersectionObserverElements.splice(idx, 1); - intersectionObserver.unobserve(entry.target); - }); - }); - } catch (_) { - intersectionObserver = false; - } - } - if (!intersectionObserver) return cb(null); - const idx = intersectionObserverElements.findIndex(x => x.element == element); - if (idx == -1) { - intersectionObserverElements.push({ element, cb: [ cb ] }); - intersectionObserver.observe(element); - } else { - intersectionObserverElements[idx].cb.push(cb); - } - } - }); -} +const ADSERVER_TARGETING_PREFIX = 'adl'; function init(config, userConsent) { logInfo(MODULE, 'init', config, userConsent); @@ -167,10 +58,6 @@ function init(config, userConsent) { logError(MODULE, 'invalid params'); return false; } - if (!(config.params.api_origin === undefined || isStr(config.params.api_origin))) { - logError(MODULE, 'invalid api_origin params value'); - return false; - } if (!(config.params.imps === undefined || (isInteger(config.params.imps) && config.params.imps > 0))) { logError(MODULE, 'invalid imps params value'); return false; @@ -213,193 +100,110 @@ function init(config, userConsent) { } function getBidRequestData(reqBidsConfigObj, callback, config, userConsent) { - // gptPreAuction runs *after* RTD so pbadslot may not be populated... (╯°□°)╯ ┻━┻ - const adUnits = (reqBidsConfigObj.adUnits || getGlobal().adUnits).map(adUnit => { - return { - gpid: deepAccess(adUnit, 'ortb2Imp.ext.gpid') || deepAccess(adUnit, 'ortb2Imp.ext.data.pbadslot') || getGptSlotInfoForAdUnitCode(adUnit.code).gptSlot || adUnit.code, - unit: adUnit - }; - }).filter(adUnit => !!adUnit.gpid); - - let response = {}; - function setSegments() { - function val(v, k) { - if (!((SEGMENT_HISTORIC[k] || k == 'atf') && v >= 0)) return v; - return config.params.thresholds.filter(t => t <= v); - } - - const ortb2 = reqBidsConfigObj.ortb2Fragments?.global || {}; - const dataSite = deepAccess(ortb2, 'site.ext.data') || {}; - const dataUser = deepAccess(ortb2, 'user.ext.data') || {}; - - _each(response, (v0, k0) => { - if (k0 == '_') return; - const k = SEGMENT_HISTORIC[k0] || k0; - const v = val(v0, k0); - deepSetValue(k == k0 ? dataUser : dataSite, `${MODULE_NAME}_rtd.${k}`, v); - }); - deepSetValue(dataSite, `${MODULE_NAME}_rtd.ok`, true); + const adUnits0 = reqBidsConfigObj.adUnits || getGlobal().adUnits; + // adUnits must be ordered according to adUnitCodes for stable 's' param usage and handling the response below + const adUnits = reqBidsConfigObj.adUnitCodes.map(code => adUnits0.find(unit => unit.code == code)); + + // buildUrl creates PHP style multi-parameters and includes undefined... (╯°□°)╯ ┻━┻ + const url = buildUrl(mergeDeep(parseUrl(`${API_ORIGIN}/q`), { search: { + 'v': `pbjs-${getGlobal().version}`, + 'c': config.params.clientid, + 'p': config.params.platformid, + 't': config.params.tagid, + 'imp': config.params.imps, + 'fc_ip': config.params.freqcap_ip, + 'fc_ipua': config.params.freqcap_ipua, + 'pn': (getRefererInfo().page || '').substr(0, 300).split(/[?#]/)[0], + 's': _map(adUnits, function(unit) { + // gptPreAuction runs *after* RTD so pbadslot may not be populated... (╯°□°)╯ ┻━┻ + const gpid = deepAccess(unit, 'ortb2Imp.ext.gpid') || + deepAccess(unit, 'ortb2Imp.ext.data.pbadslot') || + getGptSlotInfoForAdUnitCode(unit.code).gptSlot || + unit.code; + const ref = [ gpid ]; + if (!config.params.slotinpath) ref.push(unit.code); + return ref.join('\t'); + }) + } })).replace(/\[\]|[^?&]+=undefined/g, '').replace(/([?&])&+/g, '$1'); + + ajax(url, + function(responseText, q) { + function val(v, k) { + if (!(SEGMENT_HISTORIC[k] && v >= 0)) return v; + return config.params.thresholds.filter(t => t <= v); + } - deepSetValue(ortb2, 'site.ext.data', dataSite); - deepSetValue(ortb2, 'user.ext.data', dataUser); - deepSetValue(reqBidsConfigObj, 'ortb2Fragments.global', ortb2); + const response = safeJSONParse(responseText); + if (!response) { + logError(MODULE, 'unexpected response'); + return callback(); + } - adUnits.forEach((adUnit, i) => { - _each(response['_'][i], (v0, k0) => { + const { site: ortb2site, user: ortb2user } = reqBidsConfigObj.ortb2Fragments.global; + _each(response, function(v0, k0) { + if (k0 == '_') return; const k = SEGMENT_HISTORIC[k0] || k0; const v = val(v0, k0); - deepSetValue(adUnit.unit, `ortb2Imp.ext.data.${MODULE_NAME}_rtd.${k}`, v); + deepSetValue(k == k0 ? ortb2user : ortb2site, `ext.data.${MODULE_NAME}_rtd.${k}`, v); }); - }); - }; - - // mergeDeep does not handle merging deep arrays... (╯°□°)╯ ┻━┻ - function mergeDeep(target, ...sources) { - function emptyValue(v) { - if (isPlainObject(v)) { - return {}; - } else if (isArray(v)) { - return []; - } else { - return undefined; - } - } - if (!sources.length) return target; - const source = sources.shift(); - - if (isPlainObject(target) && isPlainObject(source)) { - Object.keys(source).forEach(key => { - if (!(key in target)) target[key] = emptyValue(source[key]); - target[key] = target[key] !== undefined ? mergeDeep(target[key], source[key]) : source[key]; - }); - } else if (isArray(target) && isArray(source)) { - source.forEach((v, i) => { - if (!(i in target)) target[i] = emptyValue(v); - target[i] = target[i] !== undefined ? mergeDeep(target[i], v) : v; + _each(response._, function(segments, i) { + _each(segments, function(v0, k0) { + const k = SEGMENT_HISTORIC[k0] || k0; + const v = val(v0, k0); + deepSetValue(adUnits[i], `ortb2Imp.ext.data.${MODULE_NAME}_rtd.${k}`, v); + }); }); - } else { - target = source; - } - return mergeDeep(target, ...sources); - } + deepSetValue(ortb2site, `ext.data.${MODULE_NAME}_rtd.ok`, true); - let semaphore = 1; - function semaphoreInc(inc) { - if (semaphore == 0) return; - semaphore += inc; - if (semaphore == 0) { - setSegments() callback(); } - } - - const refererInfo = getRefererInfo(); - const args = [ - [ 'v', `pbjs-${getGlobal().version}` ], - [ 'c', config.params.clientid ], - [ 'p', config.params.platformid ], - [ 't', config.params.tagid ], - [ 'imp', config.params.imps ], - [ 'fc_ip', config.params.freqcap_ip ], - [ 'fc_ipua', config.params.freqcap_ipua ], - [ 'pn', (refererInfo.page || '').substr(0, 300).split(/[?#]/)[0] ] - ]; - - if (!adUnits.length) { - logWarn(MODULE, 'no suitable adUnits (missing pbadslot?)'); - } - const atfQueue = []; - adUnits.map((adUnit, i) => { - const ref = [ adUnit.gpid ]; - if (!config.params.slotinpath) ref.push(adUnit.unit.code); - args.push(['s', ref.join('\t')]); - - semaphoreInc(1); - atfQueue.push(function() { - atf(adUnit.unit, function(x) { - let viewable = document.visibilityState === undefined || document.visibilityState == 'visible'; - try { viewable = viewable && top.document.hasFocus() } catch (_) {} - logInfo(MODULE, `atf code=${adUnit.unit.code} has area=${x}, viewable=${viewable}`); - const atfList = []; atfList[i] = { atf: parseInt(x * 100) }; - response = mergeDeep(response, { _: atfList }); - semaphoreInc(-1); - }); - }); - }); - function atfCb() { - atfQueue.forEach(x => x()); - } - if (document.readyState == 'loading') { - document.addEventListener('DOMContentLoaded', atfCb, false); - } else { - atfCb(); - } - - analyticsCommand(COMMAND.URL, { - url: (config.params.api_origin || API_ORIGIN) + '/q?', - args: args - }, function(url) { - ajax(url, { - success: function(responseText, q) { - try { - if (q.getResponseHeader('content-type') == 'application/json') { - response = mergeDeep(response, JSON.parse(responseText)); - } else { - throw false; - } - } catch (_) { - logError(MODULE, 'unexpected response'); - } - semaphoreInc(-1); - }, - error: function(statusText, q) { - logError(MODULE, 'request failed'); - semaphoreInc(-1); - } - }); - }); + ); } function getTargetingData(adUnitArray, config, userConsent, auction) { - function targetingNormalise(v) { + function val(v) { if (isArray(v) && v.length == 0) return undefined; if (isBoolean(v)) v = ~~v; if (!v) return undefined; // empty string and zero return v; } - const ortb2 = auction.getFPD().global || {}; - const dataSite = deepAccess(ortb2, `site.ext.data.${MODULE_NAME}_rtd`) || {}; - if (!dataSite.ok) return {}; + const { site: ortb2site, user: ortb2user } = auctionManager.index.getAuction(auction).getFPD().global; - const dataUser = deepAccess(ortb2, `user.ext.data.${MODULE_NAME}_rtd`) || {}; - return getGlobal().adUnits.filter(adUnit => includes(adUnitArray, adUnit.code)).reduce((a, adUnit) => { - a[adUnit.code] = {}; + const ortb2base = {}; + _each(deepAccess(mergeDeep(ortb2site, ortb2user), `ext.data.${MODULE_NAME}_rtd`), function(v0, k) { + const v = val(v0); + if (v) ortb2base[`${ADSERVER_TARGETING_PREFIX}_${k}`] = v; + }); - _each(dataSite, (v0, k) => { - if (includes(SEGMENT_HISTORIC_VALUES, k)) return; // ignore site average viewability - const v = targetingNormalise(v0); - if (v) a[adUnit.code][ADSERVER_TARGETING_PREFIX + k] = v; - }); + const targeting = {}; + _each(auction.adUnits.filter(unit => adUnitArray.includes(unit.code)), function(unit) { + targeting[unit.code] = deepClone(ortb2base); - const adUnitSegments = deepAccess(adUnit, `ortb2Imp.ext.data.${MODULE_NAME}_rtd`, {}); - _each(Object.assign({}, dataUser, adUnitSegments), (v0, k) => { - const v = targetingNormalise(v0); - if (v) a[adUnit.code][ADSERVER_TARGETING_PREFIX + k] = v; + const ortb2imp = deepAccess(unit, `ortb2Imp.ext.data.${MODULE_NAME}_rtd`); + _each(ortb2imp, function(v0, k) { + const v = val(v0); + if (v) targeting[unit.code][`${ADSERVER_TARGETING_PREFIX}_${k}`] = v; }); - return a; - }, {}); + // ATF results shamelessly exfiltrated from intersectionRtdProvider + const bid = unit.bids.find(bid => !!bid.intersection); + if (bid) { + const v = val(config.params.thresholds.filter(t => t <= (bid.intersection.intersectionRatio * 100))); + if (v) targeting[unit.code][`${ADSERVER_TARGETING_PREFIX}_atf`] = v; + } + }); + + return targeting; } export const subModuleObj = { name: MODULE_NAME, init, getBidRequestData, - getTargetingData, - atf // used by adlooxRtdProvider_spec.js + getTargetingData }; submodule('realTimeData', subModuleObj); diff --git a/modules/adlooxRtdProvider.md b/modules/adlooxRtdProvider.md index 466f8ed1ba2..9d6a20a01a7 100644 --- a/modules/adlooxRtdProvider.md +++ b/modules/adlooxRtdProvider.md @@ -19,12 +19,7 @@ This provider fetches segments and populates the [First Party Data](https://docs * AdUnit segments are placed into `AdUnit.ortb2Imp.ext.data.adloox_rtd`: * **`{dis,vid,aud}`:** an list of integers describing the likelihood the AdUnit will be visible * **`atf`:** an list of integers describing the percentage of pixels visible at auction - * measured only once at pre-auction - * usable when the publisher uses the strategy of collapsing ad slots on no-fill - * using the reverse strategy, growing ad slots on fill, invalidates the measurement the position of all content (including the slots) changes post-auction - * works best when your page loads your ad slots have their actual size rendered (ie. not zero height) - * uses the smallest ad unit (above a threshold area of 20x20) supplied by the [publisher to Prebid.js](https://docs.prebid.org/dev-docs/examples/basic-example.html) and measures viewability as if that size to be used - * when used in cross-origin (unfriendly) IFRAME environments the ad slot is directly measured as is (ignoring publisher provided sizes) due to limitations in using [IntersectionObserver](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver) + * measured at pre-auction time using the [Intersection Module](https://docs.prebid.org/dev-docs/modules/intersectionRtdProvider.html); if not enabled then this measurement is not available **N.B.** this provider does not offer or utilise any user orientated data @@ -57,8 +52,13 @@ To use this, you *must* also integrate the [Adloox Analytics Adapter](./adlooxAn realTimeData: { auctionDelay: 100, // see below for guidance dataProviders: [ + { + name: 'intersection', + waitForIt: true + }, { name: 'adloox', + waitForIt: true, params: { // optional, defaults shown thresholds: [ 50, 60, 70, 80, 90 ], slotinpath: false diff --git a/modules/admaruBidAdapter.js b/modules/admaruBidAdapter.js index 65f62c77e26..f681a9a4191 100644 --- a/modules/admaruBidAdapter.js +++ b/modules/admaruBidAdapter.js @@ -5,6 +5,7 @@ const ADMARU_ENDPOINT = 'https://p1.admaru.net/AdCall'; const BIDDER_CODE = 'admaru'; const DEFAULT_BID_TTL = 360; +const SYNC_URL = 'https://p2.admaru.net/UserSync/sync' function parseBid(rawBid, currency) { const bid = {}; @@ -75,7 +76,24 @@ export const spec = { } return bidResponses; - } + }, + + getUserSyncs: function (syncOptions, responses) { + if (syncOptions.iframeEnabled) { + return [{ + type: 'iframe', + url: SYNC_URL + }]; + } + if (syncOptions.pixelEnabled) { + return [{ + type: 'image', + url: SYNC_URL + }]; + } + + return []; + }, } registerBidder(spec); diff --git a/modules/admaticBidAdapter.js b/modules/admaticBidAdapter.js new file mode 100644 index 00000000000..808c788fcb9 --- /dev/null +++ b/modules/admaticBidAdapter.js @@ -0,0 +1,206 @@ +import { getValue, logError, deepAccess, getBidIdParameter, isArray } from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { config } from '../src/config.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; +let SYNC_URL = ''; +const BIDDER_CODE = 'admatic'; +export const spec = { + code: BIDDER_CODE, + aliases: [ + {code: 'pixad'} + ], + supportedMediaTypes: [BANNER, VIDEO], + /** f + * @param {object} bid + * @return {boolean} + */ + isBidRequestValid: (bid) => { + let isValid = false; + if (bid?.params) { + const isValidNetworkId = _validateId(getValue(bid.params, 'networkId')); + const isValidHost = _validateString(getValue(bid.params, 'host')); + isValid = isValidNetworkId && isValidHost; + } + + if (!isValid) { + logError(`${bid.bidder} networkId and host parameters are required. Bid aborted.`); + } + return isValid; + }, + + /** + * @param {BidRequest[]} validBidRequests + * @return {ServerRequest} + */ + buildRequests: (validBidRequests, bidderRequest) => { + const bids = validBidRequests.map(buildRequestObject); + const networkId = getValue(validBidRequests[0].params, 'networkId'); + const host = getValue(validBidRequests[0].params, 'host'); + const currency = config.getConfig('currency.adServerCurrency') || 'TRY'; + const bidderName = validBidRequests[0].bidder; + + const payload = { + user: { + ua: navigator.userAgent + }, + blacklist: [], + site: { + page: location.href, + ref: location.origin, + publisher: { + name: location.hostname, + publisherId: networkId + } + }, + imp: bids, + ext: { + cur: currency, + bidder: bidderName + } + }; + + if (payload) { + switch (bidderName) { + case 'pixad': + SYNC_URL = 'https://static.pixad.com.tr/sync.html'; + break; + default: + SYNC_URL = 'https://cdn.serve.admatic.com.tr/showad/sync.html'; + break; + } + + return { method: 'POST', url: `https://${host}/pb?bidder=${bidderName}`, data: payload, options: { contentType: 'application/json' } }; + } + }, + + getUserSyncs: function (syncOptions, responses) { + if (syncOptions.iframeEnabled) { + return [{ + type: 'iframe', + url: SYNC_URL + }]; + } + }, + + /** + * @param {*} response + * @param {ServerRequest} request + * @return {Bid[]} + */ + interpretResponse: (response, request) => { + const body = response.body || response; + const bidResponses = []; + if (body && body?.data && isArray(body.data)) { + body.data.forEach(bid => { + const resbid = { + requestId: bid.id, + cpm: bid.price, + width: bid.width, + height: bid.height, + currency: body.cur || 'TRY', + netRevenue: true, + ad: bid.party_tag, + creativeId: bid.creative_id, + meta: { + advertiserDomains: bid && bid.adomain ? bid.adomain : [] + }, + ttl: 360, + bidder: bid.bidder + }; + + bidResponses.push(resbid); + }); + } + return bidResponses; + } +}; + +function enrichSlotWithFloors(slot, bidRequest) { + try { + const slotFloors = {}; + + if (bidRequest.getFloor) { + if (bidRequest.mediaTypes?.banner) { + slotFloors.banner = {}; + const bannerSizes = parseSizes(deepAccess(bidRequest, 'mediaTypes.banner.sizes')) + bannerSizes.forEach(bannerSize => slotFloors.banner[parseSize(bannerSize).toString()] = bidRequest.getFloor({ size: bannerSize, mediaType: BANNER })); + } + + if (bidRequest.mediaTypes?.video) { + slotFloors.video = {}; + const videoSizes = parseSizes(deepAccess(bidRequest, 'mediaTypes.video.playerSize')) + videoSizes.forEach(videoSize => slotFloors.video[parseSize(videoSize).toString()] = bidRequest.getFloor({ size: videoSize, mediaType: VIDEO })); + } + + if (Object.keys(slotFloors).length > 0) { + if (!slot) { + slot = {} + } + Object.assign(slot, { + floors: slotFloors + }); + } + } + } catch (e) { + logError('Could not parse floors from Prebid: ' + e); + } +} + +function parseSizes(sizes, parser = s => s) { + if (sizes == undefined) { + return []; + } + if (Array.isArray(sizes[0])) { // is there several sizes ? (ie. [[728,90],[200,300]]) + return sizes.map(size => parser(size)); + } + return [parser(sizes)]; // or a single one ? (ie. [728,90]) +} + +function parseSize(size) { + return size[0] + 'x' + size[1]; +} + +function buildRequestObject(bid) { + const reqObj = {}; + reqObj.size = getSizes(bid); + reqObj.id = getBidIdParameter('bidId', bid); + + enrichSlotWithFloors(reqObj, bid); + + return reqObj; +} + +function getSizes(bid) { + return concatSizes(bid); +} + +function concatSizes(bid) { + let playerSize = deepAccess(bid, 'mediaTypes.video.playerSize'); + let videoSizes = deepAccess(bid, 'mediaTypes.video.sizes'); + let bannerSizes = deepAccess(bid, 'mediaTypes.banner.sizes'); + + if (isArray(bannerSizes) || isArray(playerSize) || isArray(videoSizes)) { + let mediaTypesSizes = [bannerSizes, videoSizes, playerSize]; + return mediaTypesSizes + .reduce(function(acc, currSize) { + if (isArray(currSize)) { + if (isArray(currSize[0])) { + currSize.forEach(function (childSize) { + acc.push({ w: childSize[0], h: childSize[1] }); + }) + } + } + return acc; + }, []); + } +} + +function _validateId(id) { + return (parseInt(id) > 0); +} + +function _validateString(str) { + return (typeof str == 'string'); +} + +registerBidder(spec); diff --git a/modules/admaticBidAdapter.md b/modules/admaticBidAdapter.md new file mode 100644 index 00000000000..2bf9afb3cdc --- /dev/null +++ b/modules/admaticBidAdapter.md @@ -0,0 +1,48 @@ +# Overview + +**Module Name**: Admatic Bidder Adapter +**Module Type**: Bidder Adapter +**Maintainer**: prebid@admatic.com.tr + +# Description + +Use `admatic` as bidder. + +`networkId` is required and must be integer. + +## AdUnits configuration example +``` + var adUnits = [{ + code: 'your-slot_1-div', //use exactly the same code as your slot div id. + sizes: [[300, 250]], + bids: [{ + bidder: 'admatic', + params: { + networkId: 12345, + host: 'layer.serve.admatic.com.tr' + } + }] + },{ + code: 'your-slot_2-div', //use exactly the same code as your slot div id. + sizes: [[600, 800]], + bids: [{ + bidder: 'admatic', + params: { + networkId: 12345, + host: 'layer.serve.admatic.com.tr' + } + }] + }]; +``` + +## UserSync example + +``` +pbjs.setConfig({ + userSync: { + iframeEnabled: true, + syncEnabled: true, + syncDelay: 1 + } +}); +``` diff --git a/modules/admediaBidAdapter.js b/modules/admediaBidAdapter.js new file mode 100644 index 00000000000..42593a36159 --- /dev/null +++ b/modules/admediaBidAdapter.js @@ -0,0 +1,98 @@ +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {BANNER} from '../src/mediaTypes.js'; + +const BIDDER_CODE = 'admedia'; +const ENDPOINT_URL = 'https://prebid.admedia.com/bidder/'; + +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.placementId); + }, + + /** + * Make a server request from the list of BidRequests. + * + * @return Array Info describing the request to the server. + * @param validBidRequests + * @param bidderRequest + */ + buildRequests: function (validBidRequests, bidderRequest) { + if (validBidRequests.length === 0) { + return []; + } + return validBidRequests.map(bidRequest => { + let sizes = [] + if (bidRequest.mediaTypes && bidRequest.mediaTypes[BANNER] && bidRequest.mediaTypes[BANNER].sizes) { + sizes = bidRequest.mediaTypes[BANNER].sizes; + } + + var tagData = []; + for (var i = 0, j = sizes.length; i < j; i++) { + let tag = {}; + tag.sizes = []; + tag.id = bidRequest.params.placementId; + tag.aid = bidRequest.params.aid; + tag.sizes.push(sizes[i].toString().replace(',', 'x')); + tagData.push(tag); + } + + const payload = { + id: bidRequest.params.placementId, + aid: bidRequest.params.aid, + tags: tagData, + bidId: bidRequest.bidId, + referer: encodeURIComponent(bidderRequest.refererInfo.page) + }; + + return { + method: 'POST', + url: ENDPOINT_URL, + data: payload + }; + }); + }, + + /** + * Unpack the response from the server into a list of bids. + * + * @param {ServerResponse} serverResponse A successful response from the server. + * @param bidRequest + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: function (serverResponse, bidRequest) { + const requiredKeys = ['requestId', 'cpm', 'width', 'height', 'ad', 'ttl', 'creativeId', 'netRevenue', 'currency', 'meta']; + const validBidResponses = []; + serverResponse = serverResponse.body.tags; + + if (serverResponse && (serverResponse.length > 0)) { + serverResponse.forEach((bid) => { + const bidResponse = {}; + for (const requiredKey of requiredKeys) { + if (!bid.hasOwnProperty(requiredKey)) { + return []; + } + bidResponse[requiredKey] = bid[requiredKey]; + } + if (!(typeof bid.meta.advertiserDomains !== 'undefined' && bid.meta.advertiserDomains.length > 0)) { + return []; + } + validBidResponses.push(bidResponse); + }); + } + return validBidResponses; + }, + getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) {}, + onTimeout: function(timeoutData) {}, + onBidWon: function (bid) {} +}; + +registerBidder(spec); diff --git a/modules/admediaBidAdapter.md b/modules/admediaBidAdapter.md new file mode 100644 index 00000000000..fe4378e9f61 --- /dev/null +++ b/modules/admediaBidAdapter.md @@ -0,0 +1,35 @@ +# Overview + +**Module Name**: Admedia Bidder Adapter +**Module Type**: Bidder Adapter +**Maintainer**: developers@admedia.com + +# Description + +Module that connects to Admedia's bidder for bids. + +# Test Parameters +``` +var adUnits = [ + { + code: 'ad-div', + mediaTypes: { + banner: { + sizes: [[300, 250]], + } + }, + bids: [{ + + bidder: 'admedia', + params: { + placementId: '782332', + aid: '86858', + }, + refererInfo: { + page: "http://addreferrerhere.com" + } + + }] + } +]; +``` \ No newline at end of file diff --git a/modules/admixerBidAdapter.js b/modules/admixerBidAdapter.js index 8fcee60f9f9..8dbcfdafd32 100644 --- a/modules/admixerBidAdapter.js +++ b/modules/admixerBidAdapter.js @@ -1,12 +1,14 @@ -import { logError } from '../src/utils.js'; +import {logError} from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {config} from '../src/config.js'; import {BANNER, VIDEO, NATIVE} from '../src/mediaTypes.js'; -import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; +import {convertOrtbRequestToProprietaryNative} from '../src/native.js'; const BIDDER_CODE = 'admixer'; -const ALIASES = ['go2net', 'adblender', 'adsyield', 'futureads']; +const BIDDER_CODE_ADX = 'admixeradx'; +const ALIASES = ['go2net', 'adblender', 'adsyield', 'futureads', 'admixeradx']; const ENDPOINT_URL = 'https://inv-nets.admixer.net/prebid.1.2.aspx'; +const ADX_ENDPOINT_URL = 'https://inv-nets.admixer.net/adxprebid.1.2.aspx'; export const spec = { code: BIDDER_CODE, aliases: ALIASES, @@ -57,6 +59,10 @@ export const spec = { if (bidderRequest.uspConsent) { payload.uspConsent = bidderRequest.uspConsent; } + let bidFloor = getBidFloor(bidderRequest); + if (bidFloor) { + payload.bidFloor = bidFloor; + } } validRequest.forEach((bid) => { let imp = {}; @@ -65,7 +71,11 @@ export const spec = { }); return { method: 'POST', - url: endpointUrl || ENDPOINT_URL, + url: + endpointUrl || + (bidderRequest.bidderCode === BIDDER_CODE_ADX + ? ADX_ENDPOINT_URL + : ENDPOINT_URL), data: payload, }; }, @@ -96,4 +106,16 @@ export const spec = { return pixels; } }; +function getBidFloor(bid) { + try { + const bidFloor = bid.getFloor({ + currency: 'USD', + mediaType: '*', + size: '*', + }); + return bidFloor.floor; + } catch (_) { + return 0; + } +} registerBidder(spec); diff --git a/modules/adnuntiusBidAdapter.js b/modules/adnuntiusBidAdapter.js index 0ae8411c073..ea3b723b316 100644 --- a/modules/adnuntiusBidAdapter.js +++ b/modules/adnuntiusBidAdapter.js @@ -1,6 +1,6 @@ import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; -import { isStr, deepAccess, logInfo } from '../src/utils.js'; +import { isStr, deepAccess } from '../src/utils.js'; import { config } from '../src/config.js'; import { getStorageManager } from '../src/storageManager.js'; @@ -8,6 +8,7 @@ const BIDDER_CODE = 'adnuntius'; const ENDPOINT_URL = 'https://ads.adnuntius.delivery/i'; const GVLID = 855; const DEFAULT_VAST_VERSION = 'vast4' +// const DEFAULT_NATIVE = 'native' const checkSegment = function (segment) { if (isStr(segment)) return segment; @@ -27,6 +28,32 @@ const getSegmentsFromOrtb = function (ortb2) { return segments } +// function createNative(ad) { +// const native = {}; +// const assets = ad.assets +// native.title = ad.text.title.content; +// native.image = { +// url: assets.image.cdnId, +// height: assets.image.height, +// width: assets.image.width, +// }; +// if (assets.icon) { +// native.icon = { +// url: assets.icon.cdnId, +// height: assets.icon.height, +// width: assets.icon.width, +// }; +// } + +// native.sponsoredBy = ad.text.sponsoredBy?.content || ''; +// native.body = ad.text.body?.content || ''; +// native.cta = ad.text.cta?.content || ''; +// native.clickUrl = ad.destinationUrls.destination || ''; +// native.impressionTrackers = ad.impressionTrackingUrls || [ad.renderedPixel]; + +// return native; +// } + const handleMeta = function () { const storage = getStorageManager({ gvlid: GVLID, bidderCode: BIDDER_CODE }) let adnMeta = null @@ -82,6 +109,10 @@ export const spec = { network += '_video' } + // if (bid.mediaTypes && bid.mediaTypes.native) { + // network += '_native' + // } + bidRequests[network] = bidRequests[network] || []; bidRequests[network].push(bid); @@ -99,6 +130,7 @@ export const spec = { const network = networkKeys[j]; const networkRequest = [...request] if (network.indexOf('_video') > -1) { networkRequest.push('tt=' + DEFAULT_VAST_VERSION) } + // if (network.indexOf('_native') > -1) { networkRequest.push('tt=' + DEFAULT_NATIVE) } requests.push({ method: 'POST', url: ENDPOINT_URL + '?' + networkRequest.join('&'), @@ -137,13 +169,14 @@ export const spec = { if (adUnit.vastXml) { adResponse[adUnit.targetId].vastXml = adUnit.vastXml - adResponse[adUnit.targetId].mediaType = 'video' + adResponse[adUnit.targetId].mediaType = VIDEO + // } else if (ad.assets && ad.assets.image && ad.text && ad.text.title && ad.text.body && ad.destinationUrls && ad.destinationUrls.destination) { + // adResponse[adUnit.targetId].native = createNative(ad); + // adResponse[adUnit.targetId].mediaType = NATIVE; } else { adResponse[adUnit.targetId].ad = adUnit.html } - logInfo('BID', adResponse) - return adResponse } else return response }, {}); diff --git a/modules/aduptechBidAdapter.js b/modules/aduptechBidAdapter.js index 5d8b69af77f..c39d9e14f17 100644 --- a/modules/aduptechBidAdapter.js +++ b/modules/aduptechBidAdapter.js @@ -1,4 +1,4 @@ -import {deepAccess, getAdUnitSizes} from '../src/utils.js'; +import {getAdUnitSizes, isArray, isBoolean, isEmpty, isFn, isPlainObject} from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, NATIVE} from '../src/mediaTypes.js'; import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; @@ -23,7 +23,7 @@ export const internal = { if (bidderRequest && bidderRequest.gdprConsent) { return { consentString: bidderRequest.gdprConsent.consentString, - consentRequired: (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') ? bidderRequest.gdprConsent.gdprApplies : true + consentRequired: (isBoolean(bidderRequest.gdprConsent.gdprApplies)) ? bidderRequest.gdprConsent.gdprApplies : true }; } @@ -60,8 +60,26 @@ export const internal = { */ extractBannerConfig: (bidRequest) => { const sizes = getAdUnitSizes(bidRequest); - if (Array.isArray(sizes) && sizes.length > 0) { - return { sizes: sizes }; + if (isArray(sizes) && !isEmpty(sizes)) { + const banner = { sizes: sizes }; + + // try to add floor for each banner size + banner.sizes.forEach(size => { + const floor = internal.getFloor(bidRequest, { mediaType: BANNER, size }); + if (floor) { + size.push(floor.floor); + size.push(floor.currency); + } + }); + + // try to add default floor for banner + const floor = internal.getFloor(bidRequest, { mediaType: BANNER, size: '*' }); + if (floor) { + banner.floorPrice = floor.floor; + banner.floorCurrency = floor.currency; + } + + return banner; } return null; @@ -74,8 +92,17 @@ export const internal = { * @returns {null|Object.} */ extractNativeConfig: (bidRequest) => { - if (bidRequest && deepAccess(bidRequest, 'mediaTypes.native')) { - return bidRequest.mediaTypes.native; + if (bidRequest?.mediaTypes?.native) { + const native = bidRequest.mediaTypes.native; + + // try to add default floor for native + const floor = internal.getFloor(bidRequest, { mediaType: NATIVE, size: '*' }); + if (floor) { + native.floorPrice = floor.floor; + native.floorCurrency = floor.currency; + } + + return native; } return null; @@ -96,27 +123,25 @@ export const internal = { }, /** - * Extracts the floor price params from given bidRequest + * Try to get floor information via bidRequest.getFloor() * * @param {BidRequest} bidRequest - * @returns {undefined|float} + * @param {Object} options + * @returns {null|Object.} */ - extractFloorPrice: (bidRequest) => { - let floorPrice; - if (bidRequest && bidRequest.params && bidRequest.params.floor) { - // if there is a manual floorPrice set - floorPrice = !isNaN(parseInt(bidRequest.params.floor)) ? bidRequest.params.floor : undefined; - } - if (typeof bidRequest.getFloor === 'function') { - // use prebid floor module - let floorInfo; - try { - floorInfo = bidRequest.getFloor(); - } catch (e) {} - floorPrice = typeof floorInfo === 'object' && !isNaN(parseInt(floorInfo.floor)) ? floorInfo.floor : floorPrice; + getFloor: (bidRequest, options) => { + if (!isFn(bidRequest?.getFloor)) { + return null; } - return floorPrice; + try { + const floor = bidRequest.getFloor(options); + if (isPlainObject(floor) && !isNaN(floor.floor)) { + return floor; + } + } catch {} + + return null; }, /** @@ -128,11 +153,11 @@ export const internal = { groupBidRequestsByPublisher: (bidRequests) => { const groupedBidRequests = {}; - if (!bidRequests || bidRequests.length === 0) { + if (!bidRequests || isEmpty(bidRequests)) { return groupedBidRequests; } - bidRequests.forEach((bidRequest) => { + bidRequests.forEach(bidRequest => { const publisher = internal.extractParams(bidRequest).publisher; if (!publisher) { return; @@ -205,7 +230,7 @@ export const spec = { const requests = []; // stop here on invalid or empty data - if (!bidderRequest || !validBidRequests || validBidRequests.length === 0) { + if (!bidderRequest || !validBidRequests || isEmpty(validBidRequests)) { return requests; } @@ -237,7 +262,7 @@ export const spec = { } // handle multiple bids per request - groupedBidRequests[publisher].forEach((bidRequest) => { + groupedBidRequests[publisher].forEach(bidRequest => { const bid = { bidId: bidRequest.bidId, transactionId: bidRequest.transactionId, @@ -257,10 +282,11 @@ export const spec = { bid.native = nativeConfig; } - // add floor price - const floorPrice = internal.extractFloorPrice(bidRequest); - if (floorPrice) { - bid.floorPrice = floorPrice; + // try to add default floor + const floor = internal.getFloor(bidRequest, { mediaType: '*', size: '*' }); + if (floor) { + bid.floorPrice = floor.floor; + bid.floorCurrency = floor.currency; } request.data.imp.push(bid); @@ -282,12 +308,12 @@ export const spec = { const bidResponses = []; // stop here on invalid or empty data - if (!response || !deepAccess(response, 'body.bids') || response.body.bids.length === 0) { + if (!response?.body?.bids || isEmpty(response.body.bids)) { return bidResponses; } // parse multiple bids per response - response.body.bids.forEach((bid) => { + response.body.bids.forEach(bid => { if (!bid || !bid.bid || !bid.creative) { return; } diff --git a/modules/adyoulikeBidAdapter.js b/modules/adyoulikeBidAdapter.js index f7473b3bad4..e6cdc7698bf 100644 --- a/modules/adyoulikeBidAdapter.js +++ b/modules/adyoulikeBidAdapter.js @@ -126,6 +126,8 @@ export const spec = { payload.userId = createEidsArray(bidderRequest.userId); } + payload.pbjs_version = '$prebid.version$'; + const data = JSON.stringify(payload); const options = { withCredentials: true diff --git a/modules/aidemBidAdapter.js b/modules/aidemBidAdapter.js new file mode 100644 index 00000000000..e4d5c618b77 --- /dev/null +++ b/modules/aidemBidAdapter.js @@ -0,0 +1,521 @@ +import {_each, contains, deepAccess, deepSetValue, getDNT, isBoolean, isStr, isNumber, logError, logInfo} from '../src/utils.js'; +import {config} from '../src/config.js'; +import {BANNER, VIDEO} from '../src/mediaTypes.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {getRefererInfo} from '../src/refererDetection.js'; +import {ajax} from '../src/ajax.js'; + +const BIDDER_CODE = 'aidem'; +const BASE_URL = 'https://zero.aidemsrv.com'; +const LOCAL_BASE_URL = 'http://127.0.0.1:8787'; + +const AVAILABLE_CURRENCIES = ['USD']; +const DEFAULT_CURRENCY = ['USD']; // NOTE - USD is the only supported currency right now; Hardcoded for bids +const SUPPORTED_MEDIA_TYPES = [BANNER, VIDEO]; +const REQUIRED_VIDEO_PARAMS = [ 'mimes', 'protocols', 'context' ]; + +export const ERROR_CODES = { + BID_SIZE_INVALID_FORMAT: 1, + BID_SIZE_NOT_INCLUDED: 2, + PROPERTY_NOT_INCLUDED: 3, + SITE_ID_INVALID_VALUE: 4, + MEDIA_TYPE_NOT_SUPPORTED: 5, + PUBLISHER_ID_INVALID_VALUE: 6, + INVALID_RATELIMIT: 7, + PLACEMENT_ID_INVALID_VALUE: 8, +}; + +const endpoints = { + request: `${BASE_URL}/bid/request`, + notice: { + win: `${BASE_URL}/notice/win`, + timeout: `${BASE_URL}/notice/timeout`, + error: `${BASE_URL}/notice/error`, + } +}; + +export function setEndPoints(env = null, path = '', mediaType = BANNER) { + switch (env) { + case 'local': + endpoints.request = mediaType === BANNER ? `${LOCAL_BASE_URL}${path}/bid/request` : `${LOCAL_BASE_URL}${path}/bid/videorequest`; + endpoints.notice.win = `${LOCAL_BASE_URL}${path}/notice/win`; + endpoints.notice.error = `${LOCAL_BASE_URL}${path}/notice/error`; + endpoints.notice.timeout = `${LOCAL_BASE_URL}${path}/notice/timeout`; + break; + case 'main': + endpoints.request = mediaType === BANNER ? `${BASE_URL}${path}/bid/request` : `${BASE_URL}${path}/bid/videorequest`; + endpoints.notice.win = `${BASE_URL}${path}/notice/win`; + endpoints.notice.error = `${BASE_URL}${path}/notice/error`; + endpoints.notice.timeout = `${BASE_URL}${path}/notice/timeout`; + break; + } + return endpoints; +} + +config.getConfig('aidem', function (config) { + if (config.aidem.env) { setEndPoints(config.aidem.env, config.aidem.path, config.aidem.mediaType); } +}); + +// AIDEM Custom FN +function recur(obj) { + var result = {}; var _tmp; + for (var i in obj) { + // enabledPlugin is too nested, also skip functions + if (!(i === 'enabledPlugin' || typeof obj[i] === 'function')) { + if (typeof obj[i] === 'object' && obj[i] !== null) { + // get props recursively + _tmp = recur(obj[i]); + // if object is not {} + if (Object.keys(_tmp).length) { + result[i] = _tmp; + } + } else { + // string, number or boolean + result[i] = obj[i]; + } + } + } + return result; +} + +// ================================================================================= +function getConnectionType() { + const connection = navigator.connection || navigator.webkitConnection; + if (!connection) { + return 0; + } + switch (connection.type) { + case 'ethernet': + return 1; + case 'wifi': + return 2; + case 'cellular': + switch (connection.effectiveType) { + case 'slow-2g': + return 4; + case '2g': + return 4; + case '3g': + return 5; + case '4g': + return 6; + case '5g': + return 7; + default: + return 3; + } + default: + return 0; + } +} + +function getDevice() { + const language = navigator.language || navigator.browserLanguage || navigator.userLanguage || navigator.systemLanguage; + return { + ua: navigator.userAgent, + dnt: !!getDNT(), + language: language, + connectiontype: getConnectionType(), + screen_width: screen.width, + screen_height: screen.height + }; +} + +function getRegs() { + let regs = {}; + const consentManagement = config.getConfig('consentManagement'); + const coppa = config.getConfig('coppa'); + if (consentManagement && !!(consentManagement.gdpr)) { + deepSetValue(regs, 'gdpr_applies', !!consentManagement.gdpr); + } else { + deepSetValue(regs, 'gdpr_applies', false); + } + if (consentManagement && deepAccess(consentManagement, 'usp.cmpApi') === 'static') { + deepSetValue(regs, 'usp_applies', !!deepAccess(consentManagement, 'usp')); + deepSetValue(regs, 'us_privacy', deepAccess(consentManagement, 'usp.consentData.getUSPData.uspString')); + } else { + deepSetValue(regs, 'usp_applies', false); + } + + if (isBoolean(coppa)) { + deepSetValue(regs, 'coppa_applies', !!coppa); + } else { + deepSetValue(regs, 'coppa_applies', false); + } + + return regs; +} + +function getPageUrl(bidderRequest) { + return bidderRequest?.refererInfo?.page; +} + +function buildWinNotice(bid) { + const params = bid.params[0]; + return { + publisherId: params.publisherId, + siteId: params.siteId, + placementId: params.placementId, + burl: deepAccess(bid, 'meta.burl'), + cpm: bid.cpm, + currency: bid.currency, + impid: deepAccess(bid, 'meta.impid'), + dsp_id: deepAccess(bid, 'meta.dsp_id'), + adUnitCode: bid.adUnitCode, + auctionId: bid.auctionId, + transactionId: bid.transactionId, + ttl: bid.ttl, + requestTimestamp: bid.requestTimestamp, + responseTimestamp: bid.responseTimestamp, + }; +} + +function buildErrorNotice(prebidErrorResponse) { + return { + message: `Prebid.js: Server call for ${prebidErrorResponse.bidderCode} failed.`, + url: encodeURIComponent(getPageUrl(prebidErrorResponse)), + auctionId: prebidErrorResponse.auctionId, + bidderRequestId: prebidErrorResponse.bidderRequestId, + metrics: {} + }; +} + +function hasValidFloor(obj) { + if (!obj) return false; + const hasValue = !isNaN(Number(obj.value)); + const hasCurrency = contains(AVAILABLE_CURRENCIES, obj.currency); + return hasValue && hasCurrency; +} + +function getMediaType(bidRequest) { + if ((bidRequest.mediaTypes && bidRequest.mediaTypes.hasOwnProperty('video')) || bidRequest.params.hasOwnProperty('video')) { return VIDEO; } + return BANNER; +} + +function getPrebidRequestFields(bidderRequest, bidRequests) { + const payload = {}; + // Base Payload Data + deepSetValue(payload, 'id', bidderRequest.auctionId); + // Impressions + setPrebidImpressionObject(bidRequests, payload); + // Device + deepSetValue(payload, 'device', getDevice()); + // Timeout + deepSetValue(payload, 'tmax', bidderRequest.timeout); + // Currency + deepSetValue(payload, 'cur', DEFAULT_CURRENCY); + // Timezone + deepSetValue(payload, 'tz', new Date().getTimezoneOffset()); + // Privacy Regs + deepSetValue(payload, 'regs', getRegs()); + // Site + setPrebidSiteObject(bidderRequest, payload); + // Environment + setPrebidRequestEnvironment(payload); + // AT auction type + deepSetValue(payload, 'at', 1); + + return payload; +} + +function setPrebidImpressionObject(bidRequests, payload) { + payload.imp = []; + _each(bidRequests, function (bidRequest) { + const impressionObject = {}; + // Placement or ad tag used to initiate the auction + deepSetValue(impressionObject, 'id', bidRequest.bidId); + // Transaction id + deepSetValue(impressionObject, 'tid', deepAccess(bidRequest, 'transactionId')); + // placement id + deepSetValue(impressionObject, 'tagid', deepAccess(bidRequest, 'params.placementId', null)); + // Publisher id + deepSetValue(payload, 'site.publisher.id', deepAccess(bidRequest, 'params.publisherId')); + // Site id + deepSetValue(payload, 'site.id', deepAccess(bidRequest, 'params.siteId')); + const mediaType = getMediaType(bidRequest); + switch (mediaType) { + case 'banner': + setPrebidImpressionObjectBanner(bidRequest, impressionObject); + break; + case 'video': + setPrebidImpressionObjectVideo(bidRequest, impressionObject); + break; + } + + // Floor (optional) + setPrebidImpressionObjectFloor(bidRequest, impressionObject); + + impressionObject.imp_ext = {}; + + payload.imp.push(impressionObject); + }); +} + +function setPrebidSiteObject(bidderRequest, payload) { + deepSetValue(payload, 'site.domain', deepAccess(bidderRequest, 'refererInfo.domain')); + deepSetValue(payload, 'site.page', deepAccess(bidderRequest, 'refererInfo.page')); + deepSetValue(payload, 'site.referer', deepAccess(bidderRequest, 'refererInfo.ref')); + deepSetValue(payload, 'site.cat', deepAccess(bidderRequest, 'ortb2.site.cat')); + deepSetValue(payload, 'site.sectioncat', deepAccess(bidderRequest, 'ortb2.site.sectioncat')); + deepSetValue(payload, 'site.keywords', deepAccess(bidderRequest, 'ortb2.site.keywords')); + deepSetValue(payload, 'site.site_ext', deepAccess(bidderRequest, 'ortb2.site.ext')); // see https://docs.prebid.org/features/firstPartyData.html +} + +function setPrebidRequestEnvironment(payload) { + const __navigator = JSON.parse(JSON.stringify(recur(navigator))); + delete __navigator.plugins; + deepSetValue(payload, 'environment.ri', getRefererInfo()); + deepSetValue(payload, 'environment.hl', window.history.length); + deepSetValue(payload, 'environment.nav', __navigator); + deepSetValue(payload, 'environment.inp.euc', window.encodeURIComponent.name === 'encodeURIComponent' && typeof window.encodeURIComponent.prototype === 'undefined'); + deepSetValue(payload, 'environment.inp.eu', window.encodeURI.name === 'encodeURI' && typeof window.encodeURI.prototype === 'undefined'); + deepSetValue(payload, 'environment.inp.js', window.JSON.stringify.name === 'stringify' && typeof window.JSON.stringify.prototype === 'undefined'); + deepSetValue(payload, 'environment.inp.jp', window.JSON.parse.name === 'parse' && typeof window.JSON.parse.prototype === 'undefined'); + deepSetValue(payload, 'environment.inp.ofe', window.Object.fromEntries.name === 'fromEntries' && typeof window.Object.fromEntries.prototype === 'undefined'); + deepSetValue(payload, 'environment.inp.oa', window.Object.assign.name === 'assign' && typeof window.Object.assign.prototype === 'undefined'); + deepSetValue(payload, 'environment.wpar.innerWidth', window.innerWidth); + deepSetValue(payload, 'environment.wpar.innerHeight', window.innerHeight); +} + +function setPrebidImpressionObjectFloor(bidRequest, impressionObject) { + const floor = deepAccess(bidRequest, 'params.floor'); + if (hasValidFloor(floor)) { + deepSetValue(impressionObject, 'floor.value', floor.value); + deepSetValue(impressionObject, 'floor.currency', floor.currency); + } +} + +function setPrebidImpressionObjectBanner(bidRequest, impressionObject) { + deepSetValue(impressionObject, 'mediatype', BANNER); + deepSetValue(impressionObject, 'banner.topframe', 1); + deepSetValue(impressionObject, 'banner.format', []); + _each(bidRequest.mediaTypes.banner.sizes, function (bannerFormat) { + const format = {}; + deepSetValue(format, 'w', bannerFormat[0]); + deepSetValue(format, 'h', bannerFormat[1]); + deepSetValue(format, 'format_ext', {}); + impressionObject.banner.format.push(format); + }); +} + +function setPrebidImpressionObjectVideo(bidRequest, impressionObject) { + deepSetValue(impressionObject, 'mediatype', VIDEO); + deepSetValue(impressionObject, 'video.format', []); + deepSetValue(impressionObject, 'video.mimes', bidRequest.mediaTypes.video.mimes); + deepSetValue(impressionObject, 'video.minDuration', bidRequest.mediaTypes.video.minduration); + deepSetValue(impressionObject, 'video.maxDuration', bidRequest.mediaTypes.video.maxduration); + deepSetValue(impressionObject, 'video.protocols', bidRequest.mediaTypes.video.protocols); + deepSetValue(impressionObject, 'video.context', bidRequest.mediaTypes.video.context); + deepSetValue(impressionObject, 'video.playbackmethod', bidRequest.mediaTypes.video.playbackmethod); + deepSetValue(impressionObject, 'skip', bidRequest.mediaTypes.video.skip); + deepSetValue(impressionObject, 'skipafter', bidRequest.mediaTypes.video.skipafter); + deepSetValue(impressionObject, 'video.pos', bidRequest.mediaTypes.video.pos); + _each(bidRequest.mediaTypes.video.playerSize, function (videoPlayerSize) { + const format = {}; + deepSetValue(format, 'w', videoPlayerSize[0]); + deepSetValue(format, 'h', videoPlayerSize[1]); + deepSetValue(format, 'format_ext', {}); + impressionObject.video.format.push(format); + }); +} + +function getPrebidResponseBidObject(openRTBResponseBidObject) { + const prebidResponseBidObject = {}; + // Common properties + deepSetValue(prebidResponseBidObject, 'requestId', openRTBResponseBidObject.impid); + deepSetValue(prebidResponseBidObject, 'cpm', parseFloat(openRTBResponseBidObject.price)); + deepSetValue(prebidResponseBidObject, 'creativeId', openRTBResponseBidObject.crid); + deepSetValue(prebidResponseBidObject, 'currency', openRTBResponseBidObject.cur ? openRTBResponseBidObject.cur.toUpperCase() : DEFAULT_CURRENCY); + deepSetValue(prebidResponseBidObject, 'width', openRTBResponseBidObject.w); + deepSetValue(prebidResponseBidObject, 'height', openRTBResponseBidObject.h); + deepSetValue(prebidResponseBidObject, 'dealId', openRTBResponseBidObject.dealid); + deepSetValue(prebidResponseBidObject, 'netRevenue', true); + deepSetValue(prebidResponseBidObject, 'ttl', 60000); + + if (openRTBResponseBidObject.mediatype === VIDEO) { + logInfo('bidObject.mediatype == VIDEO'); + deepSetValue(prebidResponseBidObject, 'mediaType', VIDEO); + deepSetValue(prebidResponseBidObject, 'vastUrl', openRTBResponseBidObject.adm); + } else { + logInfo('bidObject.mediatype == BANNER'); + deepSetValue(prebidResponseBidObject, 'mediaType', BANNER); + deepSetValue(prebidResponseBidObject, 'ad', openRTBResponseBidObject.adm); + } + setPrebidResponseBidObjectMeta(prebidResponseBidObject, openRTBResponseBidObject); + return prebidResponseBidObject; +} + +function setPrebidResponseBidObjectMeta(prebidResponseBidObject, openRTBResponseBidObject) { + logInfo('AIDEM Bid Adapter meta', openRTBResponseBidObject); + deepSetValue(prebidResponseBidObject, 'meta.advertiserDomains', deepAccess(openRTBResponseBidObject, 'meta.advertiserDomains')); + if (openRTBResponseBidObject.cat && Array.isArray(openRTBResponseBidObject.cat)) { + const primaryCatId = openRTBResponseBidObject.cat.shift(); + deepSetValue(prebidResponseBidObject, 'meta.primaryCatId', primaryCatId); + deepSetValue(prebidResponseBidObject, 'meta.secondaryCatIds', openRTBResponseBidObject.cat); + } + deepSetValue(prebidResponseBidObject, 'meta.id', openRTBResponseBidObject.id); + deepSetValue(prebidResponseBidObject, 'meta.dsp_id', openRTBResponseBidObject.dsp_id); + deepSetValue(prebidResponseBidObject, 'meta.adid', openRTBResponseBidObject.adid); + deepSetValue(prebidResponseBidObject, 'meta.burl', openRTBResponseBidObject.burl); + deepSetValue(prebidResponseBidObject, 'meta.impid', openRTBResponseBidObject.impid); + deepSetValue(prebidResponseBidObject, 'meta.cat', openRTBResponseBidObject.cat); + deepSetValue(prebidResponseBidObject, 'meta.cid', openRTBResponseBidObject.cid); +} + +function hasValidMediaType(bidRequest) { + const supported = hasBannerMediaType(bidRequest) || hasVideoMediaType(bidRequest); + if (!supported) { + logError('AIDEM Bid Adapter: media type not supported', { bidder: BIDDER_CODE, code: ERROR_CODES.MEDIA_TYPE_NOT_SUPPORTED }); + } + return supported; +} + +function hasBannerMediaType(bidRequest) { + return !!deepAccess(bidRequest, 'mediaTypes.banner'); +} + +function hasVideoMediaType(bidRequest) { + return !!deepAccess(bidRequest, 'mediaTypes.video'); +} + +function hasValidBannerMediaType(bidRequest) { + const sizes = deepAccess(bidRequest, 'mediaTypes.banner.sizes'); + if (!sizes) { + logError('AIDEM Bid Adapter: media type sizes missing', { bidder: BIDDER_CODE, code: ERROR_CODES.PROPERTY_NOT_INCLUDED }); + return false; + } + return true; +} + +function hasValidVideoMediaType(bidRequest) { + const sizes = deepAccess(bidRequest, 'mediaTypes.video.playerSize'); + if (!sizes) { + logError('AIDEM Bid Adapter: media type playerSize missing', { bidder: BIDDER_CODE, code: ERROR_CODES.PROPERTY_NOT_INCLUDED }); + return false; + } + return true; +} + +function hasValidVideoParameters(bidRequest) { + let valid = true; + const adUnitsParameters = deepAccess(bidRequest, 'mediaTypes.video'); + const bidderParameter = deepAccess(bidRequest, 'params.video'); + for (let property of REQUIRED_VIDEO_PARAMS) { + const hasAdUnitParameter = adUnitsParameters.hasOwnProperty(property); + const hasBidderParameter = bidderParameter && bidderParameter.hasOwnProperty(property); + if (!hasAdUnitParameter && !hasBidderParameter) { + logError(`AIDEM Bid Adapter: ${property} is not included in either the adunit or params level`, { bidder: BIDDER_CODE, code: ERROR_CODES.PROPERTY_NOT_INCLUDED }); + valid = false; + } + } + + return valid; +} + +function passesRateLimit(bidRequest) { + const rateLimit = deepAccess(bidRequest, 'params.rateLimit', 1); + if (!isNumber(rateLimit) || rateLimit > 1 || rateLimit < 0) { + logError('AIDEM Bid Adapter: invalid rateLimit (must be a number between 0 and 1)', { bidder: BIDDER_CODE, code: ERROR_CODES.INVALID_RATELIMIT }); + return false; + } + if (rateLimit !== 1) { + const randomRateValue = Math.random(); + if (randomRateValue > rateLimit) { + return false; + } + } + return true; +} + +function hasValidParameters(bidRequest) { + // Assigned from AIDEM to a publisher website + const siteId = deepAccess(bidRequest, 'params.siteId'); + const publisherId = deepAccess(bidRequest, 'params.publisherId'); + + if (!isStr(siteId)) { + logError('AIDEM Bid Adapter: siteId must valid string', { bidder: BIDDER_CODE, code: ERROR_CODES.SITE_ID_INVALID_VALUE }); + return false; + } + + if (!isStr(publisherId)) { + logError('AIDEM Bid Adapter: publisherId must valid string', { bidder: BIDDER_CODE, code: ERROR_CODES.PUBLISHER_ID_INVALID_VALUE }); + return false; + } + + return true; +} + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: SUPPORTED_MEDIA_TYPES, + isBidRequestValid: function(bidRequest) { + logInfo('bid: ', bidRequest); + + // check if request has valid mediaTypes + if (!hasValidMediaType(bidRequest)) return false; + + // check if request has valid media type parameters at adUnit level + if (hasBannerMediaType(bidRequest) && !hasValidBannerMediaType(bidRequest)) { + return false; + } + + if (hasVideoMediaType(bidRequest) && !hasValidVideoMediaType(bidRequest)) { + return false; + } + + if (hasVideoMediaType(bidRequest) && !hasValidVideoParameters(bidRequest)) { + return false; + } + + if (!hasValidParameters(bidRequest)) { + return false; + } + + return passesRateLimit(bidRequest); + }, + + buildRequests: function(validBidRequests, bidderRequest) { + logInfo('validBidRequests: ', validBidRequests); + logInfo('bidderRequest: ', bidderRequest); + const prebidRequest = getPrebidRequestFields(bidderRequest, validBidRequests); + const payloadString = JSON.stringify(prebidRequest); + + return { + method: 'POST', + url: endpoints.request, + data: payloadString, + options: { + withCredentials: true + } + }; + }, + + interpretResponse: function (serverResponse) { + const bids = []; + logInfo('serverResponse: ', serverResponse); + _each(serverResponse.body.bid, function (bidObject) { + logInfo('bidObject: ', bidObject); + if (!bidObject.price || !bidObject.adm) { + return; + } + logInfo('CPM OK'); + const bid = getPrebidResponseBidObject(bidObject); + bids.push(bid); + }); + return bids; + }, + + onBidWon: function(bid) { + // Bidder specific code + logInfo('onBidWon bid: ', bid); + const notice = buildWinNotice(bid); + ajax(endpoints.notice.win, null, JSON.stringify(notice), { method: 'POST', withCredentials: true }); + }, + + onBidderError: function({ bidderRequest }) { + // Bidder specific code + const notice = buildErrorNotice(bidderRequest); + ajax(endpoints.notice.error, null, JSON.stringify(notice), { method: 'POST', withCredentials: true }); + }, +}; +registerBidder(spec); diff --git a/modules/aidemBidAdapter.md b/modules/aidemBidAdapter.md new file mode 100644 index 00000000000..b59014c76ed --- /dev/null +++ b/modules/aidemBidAdapter.md @@ -0,0 +1,191 @@ +# Overview + +``` +name: AIDEM Adapter +type: Bidder Adapter +support: prebid@aidem.com +biddercode: aidem +``` + +# Description +This module connects publishers to AIDEM demand. + +This module is GDPR and CCPA compliant, and no 3rd party userIds are allowed. + + +## Global Bid Params +| Name | Scope | Description | Example | Type | +|---------------|----------|-------------------------|------------|----------| +| `siteId` | required | Unique site ID | `'ABCDEF'` | `String` | +| `publisherId` | required | Unique publisher ID | `'ABCDEF'` | `String` | +| `placementId` | optional | Unique publisher tag ID | `'ABCDEF'` | `String` | +| `rateLimit` | optional | Limit the volume sent to AIDEM. Must be between 0 and 1 | `0.6` | `Number` | + + +### Banner Bid Params +| Name | Scope | Description | Example | Type | +|------------|----------|--------------------------|---------------------------|---------| +| `sizes` | required | List of the sizes wanted | `[[300, 250], [300,600]]` | `Array` | + + +### Video Bid Params +| Name | Scope | Description | Example | Type | +|---------------|----------|-----------------------------------------|-----------------|-----------| +| `context` | required | One of instream, outstream, adpod | `'instream'` | `String` | +| `playerSize` | required | Width and height of the player | `'[640, 480]'` | `Array` | +| `maxduration` | required | Maximum video ad duration, in seconds | `30` | `Integer` | +| `minduration` | required | Minimum video ad duration, in seconds | `5` | `Integer` | +| `mimes` | required | List of the content MIME types supported by the player | `["video/mp4"]` | `Array` | +| `protocols` | required | An array of supported video protocols. At least one supported protocol must be specified, where: `2` = VAST 2.0 `3` = VAST 3.0 `5` = VAST 2.0 wrapper `6` = VAST 3.0 wrapper | `2` | `Array` | + + +### Additional Config +| Name | Scope | Description | Example | Type | +|---------------------|----------|---------------------------------------------------------|---------|-----------| +| `coppa` | optional | Child Online Privacy Protection Act | `true` | `Boolean` | +| `consentManagement` | optional | [Consent Management Object](#consent-management-object) | `{}` | `Object` | + + +### Consent Management Object +| Name | Scope | Description | Example | Type | +|--------|----------|--------------------------------------------------------------------------------------------------|---------|----------| +| `gdpr` | optional | GDPR Object see [Prebid.js doc](https://docs.prebid.org/dev-docs/modules/consentManagement.html) | `{}` | `Object` | +| `usp` | optional | USP Object see [Prebid.js doc](https://docs.prebid.org/dev-docs/modules/consentManagementUsp.html) | `{}` | `Object` | + + +### Example Banner ad unit +```javascript +var adUnits = [{ + code: 'banner-prebid-test-site', + mediaTypes: { + banner: { + sizes: [ + [300, 600], + [300, 250] + ] + } + }, + bids: [{ + bidder: 'aidem', + params: { + siteId: 'prebid-test-siteId', + publisherId: 'prebid-test-publisherId', + }, + }] +}]; +``` + +### Example Video ad unit +```javascript +var adUnits = [{ + code: 'video-prebid-test-site', + mediaTypes: { + video: { + context: 'instream', + playerSize: [640, 480], + maxduration: 30, + minduration: 5, + mimes: ["video/mp4"], + protocols: 2 + } + }, + bids: [{ + bidder: 'aidem', + params: { + siteId: 'prebid-test-siteId', + publisherId: 'prebid-test-publisherId', + }, + }] +}]; +``` + +### Example GDPR Consent Management +```javascript +var pbjs = pbjs || {}; +pbjs.que = pbjs.que || []; + +pbjs.que.push(function (){ + pbjs.setConfig({ + consentManagement: { + gdpr:{ + cmpApi: 'iab' + } + } + }); +}) +``` + + +### Example USP Consent Management +```javascript +var pbjs = pbjs || {}; +pbjs.que = pbjs.que || []; + +pbjs.que.push(function (){ + pbjs.setConfig({ + consentManagement: { + usp:{ + cmpApi: 'static', + consentData:{ + getUSPData:{ + uspString: '1YYY' + } + } + } + } + }); +}) +``` + + +### Setting First Party Data (FPD) +```javascript +var pbjs = pbjs || {}; +pbjs.que = pbjs.que || []; + +pbjs.que.push(function (){ + pbjs.setConfig({ + ortb2: { + site: { + cat: ['IAB2'], + sectioncat: ['IAB2-2'], + keywords: 'power tools, drills' + }, + } + }); +}) +``` + +### Supported Media Types +| Type | Support | +|--------|--------------------------------------------------------------------| +| Banner | Support all [AIDEM Sizes](https://kb.aidem.com/ssp/lists/adsizes/) | +| Video | Support all [AIDEM Sizes](https://kb.aidem.com/ssp/lists/adsizes/) | + + +# Setup / Dev Guide +```shell +nvm use + +npm install + +gulp build --modules=aidemBidAdapter + +gulp serve --modules=aidemBidAdapter + +# Open a chrome browser with no ad blockers enabled, and paste in this URL. The `pbjs_debug=true` is needed if you want to enable `loggerInfo` output on the `console` tab of Chrome Developer Tools. +http://localhost:9999/integrationExamples/gpt/hello_world.html?pbjs_debug=true +``` + +If you need to run the tests suite but do *not* want to have to build the full adapter and serve it, simply run: +```shell +gulp test --file "test/spec/modules/aidemBidAdapter_spec.js" +``` + + +For video: gulp serve --modules=aidemBidAdapter,dfpAdServerVideo + +# FAQs +### How do I view AIDEM bid request? +Navigate to a page where AIDEM is setup to bid. In the network tab, +search for requests to `zero.aidemsrv.com/bid/request`. diff --git a/modules/ajaBidAdapter.js b/modules/ajaBidAdapter.js index 121dc2ef96f..67b448eb484 100644 --- a/modules/ajaBidAdapter.js +++ b/modules/ajaBidAdapter.js @@ -1,4 +1,4 @@ -import { getBidIdParameter, tryAppendQueryString, createTrackPixelHtml, logError, logWarn } from '../src/utils.js'; +import { getBidIdParameter, tryAppendQueryString, createTrackPixelHtml, logError, logWarn, deepAccess } from '../src/utils.js'; import { Renderer } from '../src/Renderer.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { VIDEO, BANNER, NATIVE } from '../src/mediaTypes.js'; @@ -64,6 +64,11 @@ export const spec = { })) } + const sua = deepAccess(bidRequest, 'ortb2.device.sua'); + if (sua) { + queryString = tryAppendQueryString(queryString, 'sua', JSON.stringify(sua)); + } + bidRequests.push({ method: 'GET', url: URL, diff --git a/modules/alkimiBidAdapter.js b/modules/alkimiBidAdapter.js index fe5a050f436..69b3fdae3d8 100644 --- a/modules/alkimiBidAdapter.js +++ b/modules/alkimiBidAdapter.js @@ -1,8 +1,8 @@ -import { registerBidder } from '../src/adapters/bidderFactory.js'; -import { deepClone, deepAccess } from '../src/utils.js'; -import { ajax } from '../src/ajax.js'; -import { VIDEO } from '../src/mediaTypes.js'; -import { config } from '../src/config.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {deepClone, deepAccess} from '../src/utils.js'; +import {ajax} from '../src/ajax.js'; +import {VIDEO} from '../src/mediaTypes.js'; +import {config} from '../src/config.js'; const BIDDER_CODE = 'alkimi'; export const ENDPOINT = 'https://exchange.alkimi-onboarding.com/bid?prebid=true'; @@ -20,18 +20,19 @@ export const spec = { let bidIds = []; let eids; validBidRequests.forEach(bidRequest => { - let sizes = prepareSizes(bidRequest.sizes) + let formatTypes = getFormatType(bidRequest) if (bidRequest.userIdAsEids) { eids = eids || bidRequest.userIdAsEids } + bids.push({ token: bidRequest.params.token, pos: bidRequest.params.pos, - bidFloor: bidRequest.params.bidFloor, - width: sizes[0].width, - height: sizes[0].height, - impMediaType: getFormatType(bidRequest), + bidFloor: getBidFloor(bidRequest, formatTypes), + sizes: prepareSizes(deepAccess(bidRequest, 'mediaTypes.banner.sizes')), + playerSizes: prepareSizes(deepAccess(bidRequest, 'mediaTypes.video.playerSize')), + impMediaTypes: formatTypes, adUnitCode: bidRequest.adUnitCode }) bidIds.push(bidRequest.bidId) @@ -41,7 +42,7 @@ export const spec = { let payload = { requestId: bidderRequest.auctionId, - signRequest: { bids, randomUUID: alkimiConfig && alkimiConfig.randomUUID }, + signRequest: {bids, randomUUID: alkimiConfig && alkimiConfig.randomUUID}, bidIds, referer: bidderRequest.refererInfo.page, signature: alkimiConfig && alkimiConfig.signature, @@ -85,7 +86,7 @@ export const spec = { return []; } - const { prebidResponse } = serverBody; + const {prebidResponse} = serverBody; if (!prebidResponse || typeof prebidResponse !== 'object') { return []; } @@ -113,7 +114,7 @@ export const spec = { let winUrl; if (bid.winUrl || bid.vastUrl) { winUrl = bid.winUrl ? bid.winUrl : bid.vastUrl; - winUrl = winUrl.replace(/\$\{AUCTION_PRICE\}/, bid.cpm); + winUrl = winUrl.replace(/\$\{AUCTION_PRICE}/, bid.cpm); } else if (bid.ad) { let trackImg = bid.ad.match(/(?!^)/); bid.ad = bid.ad.replace(trackImg[0], ''); @@ -129,13 +130,34 @@ export const spec = { } function prepareSizes(sizes) { - return sizes && sizes.map(size => ({ width: size[0], height: size[1] })); + return sizes ? sizes.map(size => ({width: size[0], height: size[1]})) : [] +} + +function prepareBidFloorSize(sizes) { + return sizes && sizes.length === 1 ? sizes : ['*']; +} + +function getBidFloor(bidRequest, formatTypes) { + let minFloor + if (typeof bidRequest.getFloor === 'function') { + const bidFloorSizes = prepareBidFloorSize(bidRequest.sizes) + formatTypes.forEach(formatType => { + bidFloorSizes.forEach(bidFloorSize => { + const floor = bidRequest.getFloor({currency: 'USD', mediaType: formatType.toLowerCase(), size: bidFloorSize}); + if (floor && !isNaN(floor.floor) && (floor.currency === 'USD')) { + minFloor = !minFloor || floor.floor < minFloor ? floor.floor : minFloor + } + }) + }) + } + return minFloor || bidRequest.params.bidFloor; } const getFormatType = bidRequest => { - if (deepAccess(bidRequest, 'mediaTypes.banner')) return 'Banner' - if (deepAccess(bidRequest, 'mediaTypes.video')) return 'Video' - if (deepAccess(bidRequest, 'mediaTypes.audio')) return 'Audio' + let formats = [] + if (deepAccess(bidRequest, 'mediaTypes.banner')) formats.push('Banner') + if (deepAccess(bidRequest, 'mediaTypes.video')) formats.push('Video') + return formats } registerBidder(spec); diff --git a/modules/amxBidAdapter.js b/modules/amxBidAdapter.js index d1bd2edeee4..c7bc99b6aa6 100644 --- a/modules/amxBidAdapter.js +++ b/modules/amxBidAdapter.js @@ -207,6 +207,7 @@ const isTrue = (boolValue) => export const spec = { code: BIDDER_CODE, + gvlid: 737, supportedMediaTypes: [BANNER, VIDEO], isBidRequestValid(bid) { diff --git a/modules/amxIdSystem.md b/modules/amxIdSystem.md index 9de93c761a1..f67fefe261e 100644 --- a/modules/amxIdSystem.md +++ b/modules/amxIdSystem.md @@ -1,6 +1,6 @@ -# AMX RTB ID +# AMX ID -For help adding this module, please contact [prebid@amxrtb.com](prebid@amxrtb.com). +For help adding this module, please contact [info@amxdt.net](info@amxdt.net). ### Prebid Configuration @@ -41,11 +41,3 @@ The following settings are available for the `storage` property in the `userSync | name | Required | String | Where the ID will be stored | `"amxId"` | | type | Required | String | This must be `"html5"` | `"html5"` | | expires | Required | Number <= 30 | number of days until the stored ID expires. **Must be less than or equal to 30** | `14` | - -### Params - -The following options are available in the `params` property in `userSync.userIds[]`: - -| Param under `params` | Scope | Type | Description | Example | -| -------------------- | -------- | ------ | ------------------------------------------------------------------------- | ---------------- | -| tagId | Optional | String | Your AMX tagId (optional) | `cHJlYmlkLm9yZw` | diff --git a/modules/aolBidAdapter.js b/modules/aolBidAdapter.js index d38c373ff1f..d15a5434e0c 100644 --- a/modules/aolBidAdapter.js +++ b/modules/aolBidAdapter.js @@ -35,7 +35,7 @@ const SUPPORTED_USER_ID_SOURCES = [ 'adserver.org', 'adtelligent.com', 'akamai.com', - 'amxrtb.com', + 'amxdt.net', 'audigent.com', 'britepool.com', 'criteo.com', @@ -159,6 +159,13 @@ export const spec = { if (bidderRequest) { consentData.gdpr = bidderRequest.gdprConsent; consentData.uspConsent = bidderRequest.uspConsent; + consentData.gppConsent = bidderRequest.gppConsent; + if (!consentData.gppConsent && bidderRequest.ortb2?.regs?.gpp) { + consentData.gppConsent = { + gppString: bidderRequest.ortb2.regs.gpp, + applicableSections: bidderRequest.ortb2.regs.gpp_sid + } + } } return bids.map(bid => { @@ -373,6 +380,11 @@ export const spec = { params.us_privacy = consentData.uspConsent; } + if (consentData.gppConsent && consentData.gppConsent.gppString) { + params.gpp = consentData.gppConsent.gppString; + params.gpp_sid = consentData.gppConsent.applicableSections; + } + return params; }, parsePixelItems(pixels) { diff --git a/modules/appnexusBidAdapter.js b/modules/appnexusBidAdapter.js index 77ffe0f6b94..f354eb053b1 100644 --- a/modules/appnexusBidAdapter.js +++ b/modules/appnexusBidAdapter.js @@ -44,7 +44,7 @@ const URL_SIMPLE = 'https://ib.adnxs-simple.com/ut/v3/prebid'; const VIDEO_TARGETING = ['id', 'minduration', 'maxduration', 'skippable', 'playback_method', 'frameworks', 'context', 'skipoffset']; const VIDEO_RTB_TARGETING = ['minduration', 'maxduration', 'skip', 'skipafter', 'playbackmethod', 'api', 'startdelay']; -const USER_PARAMS = ['age', 'externalUid', 'segments', 'gender', 'dnt', 'language']; +const USER_PARAMS = ['age', 'externalUid', 'external_uid', 'segments', 'gender', 'dnt', 'language']; const APP_DEVICE_PARAMS = ['geo', 'device_id']; // appid is collected separately const DEBUG_PARAMS = ['enabled', 'dongle', 'member_id', 'debug_timeout']; const DEBUG_QUERY_PARAM_MAP = { @@ -120,7 +120,9 @@ export const spec = { * @return boolean True if this is a valid bid, and false otherwise. */ isBidRequestValid: function (bid) { - return !!(bid.params.placementId || (bid.params.member && bid.params.invCode)); + return !!( + (bid.params.placementId || bid.params.placement_id) || + (bid.params.member && (bid.params.invCode || bid.params.inv_code))); }, /** @@ -304,6 +306,18 @@ export const spec = { payload.us_privacy = bidderRequest.uspConsent; } + if (bidderRequest?.gppConsent) { + payload.privacy = { + gpp: bidderRequest.gppConsent.gppString, + gpp_sid: bidderRequest.gppConsent.applicableSections + } + } else if (bidderRequest?.ortb2?.regs?.gpp) { + payload.privacy = { + gpp: bidderRequest.ortb2.regs.gpp, + gpp_sid: bidderRequest.ortb2.regs.gpp_sid + } + } + if (bidderRequest && bidderRequest.refererInfo) { let refererinfo = { // TODO: are these the correct referer values? @@ -331,20 +345,18 @@ export const spec = { if (bidRequests[0].userId) { let eids = []; - - addUserId(eids, deepAccess(bidRequests[0], `userId.criteoId`), 'criteo.com', null); - addUserId(eids, deepAccess(bidRequests[0], `userId.netId`), 'netid.de', null); - addUserId(eids, deepAccess(bidRequests[0], `userId.idl_env`), 'liveramp.com', null); - addUserId(eids, deepAccess(bidRequests[0], `userId.tdid`), 'adserver.org', 'TDID'); - addUserId(eids, deepAccess(bidRequests[0], `userId.uid2.id`), 'uidapi.com', 'UID2'); - if (bidRequests[0].userId.pubProvidedId) { - bidRequests[0].userId.pubProvidedId.forEach(ppId => { - ppId.uids.forEach(uid => { - eids.push({ source: ppId.source, id: uid.id }); - }); + bidRequests[0].userIdAsEids.forEach(eid => { + if (!eid || !eid.uids || eid.uids.length < 1) { return; } + eid.uids.forEach(uid => { + let tmp = {'source': eid.source, 'id': uid.id}; + if (eid.source == 'adserver.org') { + tmp.rti_partner = 'TDID'; + } else if (eid.source == 'uidapi.com') { + tmp.rti_partner = 'UID2'; + } + eids.push(tmp); }); - } - + }); if (eids.length) { payload.eids = eids; } @@ -424,8 +436,17 @@ export const spec = { } }, - getUserSyncs: function (syncOptions, responses, gdprConsent) { - if (syncOptions.iframeEnabled && hasPurpose1Consent(gdprConsent)) { + getUserSyncs: function (syncOptions, responses, gdprConsent, uspConsent, gppConsent) { + function checkGppStatus(gppConsent) { + // this is a temporary measure to supress usersync in US-based GPP regions + // this logic will be revised when proper signals (akin to purpose1 from TCF2) can be determined for US GPP + if (gppConsent && Array.isArray(gppConsent.applicableSections)) { + return gppConsent.applicableSections.every(sec => typeof sec === 'number' && sec <= 5); + } + return true; + } + + if (syncOptions.iframeEnabled && hasPurpose1Consent(gdprConsent) && checkGppStatus(gppConsent)) { return [{ type: 'iframe', url: 'https://acdn.adnxs.com/dmp/async_usersync.html' @@ -463,9 +484,6 @@ export const spec = { }, params); if (isOpenRtb) { - params.use_pmt_rule = (typeof params.usePaymentRule === 'boolean') ? params.usePaymentRule : false; - if (params.usePaymentRule) { delete params.usePaymentRule; } - if (isPopulatedArray(params.keywords)) { params.keywords.forEach(deleteValues); } @@ -477,6 +495,9 @@ export const spec = { delete params[paramKey]; } }); + + params.use_pmt_rule = (typeof params.use_payment_rule === 'boolean') ? params.use_payment_rule : false; + if (params.use_payment_rule) { delete params.use_payment_rule; } } return params; @@ -604,9 +625,8 @@ function newBid(serverBid, rtbBid, bidderRequest) { } }; - // WE DON'T FULLY SUPPORT THIS ATM - future spot for adomain code; creating a stub for 5.0 compliance if (rtbBid.adomain) { - bid.meta = Object.assign({}, bid.meta, { advertiserDomains: [] }); + bid.meta = Object.assign({}, bid.meta, { advertiserDomains: [rtbBid.adomain] }); } if (rtbBid.advertiser_id) { @@ -710,6 +730,7 @@ function newBid(serverBid, rtbBid, bidderRequest) { displayUrl: nativeAd.displayurl, clickTrackers: nativeAd.link.click_trackers, impressionTrackers: nativeAd.impression_trackers, + video: nativeAd.video, javascriptTrackers: jsTrackers }; if (nativeAd.main_img) { @@ -750,17 +771,25 @@ function newBid(serverBid, rtbBid, bidderRequest) { function bidToTag(bid) { const tag = {}; + Object.keys(bid.params).forEach(paramKey => { + let convertedKey = convertCamelToUnderscore(paramKey); + if (convertedKey !== paramKey) { + bid.params[convertedKey] = bid.params[paramKey]; + delete bid.params[paramKey]; + } + }); tag.sizes = transformSizes(bid.sizes); tag.primary_size = tag.sizes[0]; tag.ad_types = []; tag.uuid = bid.bidId; - if (bid.params.placementId) { - tag.id = parseInt(bid.params.placementId, 10); + if (bid.params.placement_id) { + tag.id = parseInt(bid.params.placement_id, 10); } else { - tag.code = bid.params.invCode; + tag.code = bid.params.inv_code; } - tag.allow_smaller_sizes = bid.params.allowSmallerSizes || false; - tag.use_pmt_rule = bid.params.usePaymentRule || false; + tag.allow_smaller_sizes = bid.params.allow_smaller_sizes || false; + tag.use_pmt_rule = (typeof bid.params.use_payment_rule === 'boolean') ? bid.params.use_payment_rule + : (typeof bid.params.use_pmt_rule === 'boolean') ? bid.params.use_pmt_rule : false; tag.prebid = true; tag.disable_psa = true; let bidFloor = getBidFloor(bid); @@ -777,26 +806,26 @@ function bidToTag(bid) { tag.position = (mediaTypePos === 3) ? 2 : mediaTypePos; } } - if (bid.params.trafficSourceCode) { - tag.traffic_source_code = bid.params.trafficSourceCode; + if (bid.params.traffic_source_code) { + tag.traffic_source_code = bid.params.traffic_source_code; } - if (bid.params.privateSizes) { - tag.private_sizes = transformSizes(bid.params.privateSizes); + if (bid.params.private_sizes) { + tag.private_sizes = transformSizes(bid.params.private_sizes); } - if (bid.params.supplyType) { - tag.supply_type = bid.params.supplyType; + if (bid.params.supply_type) { + tag.supply_type = bid.params.supply_type; } - if (bid.params.pubClick) { - tag.pubclick = bid.params.pubClick; + if (bid.params.pub_click) { + tag.pubclick = bid.params.pub_click; } - if (bid.params.extInvCode) { - tag.ext_inv_code = bid.params.extInvCode; + if (bid.params.ext_inv_code) { + tag.ext_inv_code = bid.params.ext_inv_code; } - if (bid.params.publisherId) { - tag.publisher_id = parseInt(bid.params.publisherId, 10); + if (bid.params.publisher_id) { + tag.publisher_id = parseInt(bid.params.publisher_id, 10); } - if (bid.params.externalImpId) { - tag.external_imp_id = bid.params.externalImpId; + if (bid.params.external_imp_id) { + tag.external_imp_id = bid.params.external_imp_id; } let ortb2ImpKwStr = deepAccess(bid, 'ortb2Imp.ext.data.keywords'); @@ -1197,17 +1226,6 @@ function parseMediaType(rtbBid) { } } -function addUserId(eids, id, source, rti) { - if (id) { - if (rti) { - eids.push({ source, id, rti_partner: rti }); - } else { - eids.push({ source, id }); - } - } - return eids; -} - function getBidFloor(bid) { if (!isFn(bid.getFloor)) { return (bid.params.reserve) ? bid.params.reserve : null; diff --git a/modules/appnexusBidAdapter.md b/modules/appnexusBidAdapter.md index 7ac70e67584..e8c57b782ec 100644 --- a/modules/appnexusBidAdapter.md +++ b/modules/appnexusBidAdapter.md @@ -3,7 +3,7 @@ ``` Module Name: Appnexus Bid Adapter Module Type: Bidder Adapter -Maintainer: prebid-js@xandr.com +Maintainer: prebid@microsoft.com ``` # Description diff --git a/modules/appushBidAdapter.js b/modules/appushBidAdapter.js new file mode 100644 index 00000000000..1ad8fe27e42 --- /dev/null +++ b/modules/appushBidAdapter.js @@ -0,0 +1,188 @@ +import { isFn, deepAccess, logMessage, logError } from '../src/utils.js'; +import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; + +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; +import { config } from '../src/config.js'; + +const BIDDER_CODE = 'appush'; +const AD_URL = 'https://hb.appush.com/pbjs'; + +function isBidResponseValid(bid) { + if (!bid.requestId || !bid.cpm || !bid.creativeId || !bid.ttl || !bid.currency) { + return false; + } + + switch (bid.mediaType) { + case BANNER: + return Boolean(bid.width && bid.height && bid.ad); + case VIDEO: + return Boolean(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 } = bid; + const schain = bid.schain || {}; + const { placementId, endpointId } = params; + const bidfloor = getBidFloor(bid); + + const placement = { + bidId, + schain, + bidfloor + }; + + if (placementId) { + placement.placementId = placementId; + placement.type = 'publisher'; + } else if (endpointId) { + placement.endpointId = endpointId; + placement.type = 'network'; + } + + if (mediaTypes && mediaTypes[BANNER]) { + placement.adFormat = BANNER; + placement.sizes = mediaTypes[BANNER].sizes; + } else if (mediaTypes && mediaTypes[VIDEO]) { + placement.adFormat = VIDEO; + placement.playerSize = mediaTypes[VIDEO].playerSize; + placement.minduration = mediaTypes[VIDEO].minduration; + placement.maxduration = mediaTypes[VIDEO].maxduration; + placement.mimes = mediaTypes[VIDEO].mimes; + placement.protocols = mediaTypes[VIDEO].protocols; + placement.startdelay = mediaTypes[VIDEO].startdelay; + placement.placement = mediaTypes[VIDEO].placement; + placement.skip = mediaTypes[VIDEO].skip; + placement.skipafter = mediaTypes[VIDEO].skipafter; + placement.minbitrate = mediaTypes[VIDEO].minbitrate; + placement.maxbitrate = mediaTypes[VIDEO].maxbitrate; + placement.delivery = mediaTypes[VIDEO].delivery; + placement.playbackmethod = mediaTypes[VIDEO].playbackmethod; + placement.api = mediaTypes[VIDEO].api; + placement.linearity = mediaTypes[VIDEO].linearity; + } else if (mediaTypes && mediaTypes[NATIVE]) { + placement.native = mediaTypes[NATIVE]; + placement.adFormat = NATIVE; + } + + return placement; +} + +function getBidFloor(bid) { + if (!isFn(bid.getFloor)) { + return deepAccess(bid, 'params.bidfloor', 0); + } + + try { + const bidFloor = bid.getFloor({ + currency: 'USD', + mediaType: '*', + size: '*', + }); + return bidFloor.floor; + } catch (err) { + logError(err); + return 0; + } +} + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER, VIDEO, NATIVE], + + isBidRequestValid: (bid = {}) => { + const { params, bidId, mediaTypes } = bid; + let valid = Boolean(bidId && params && (params.placementId || params.endpointId)); + + 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; + } + return valid; + }, + + buildRequests: (validBidRequests = [], bidderRequest = {}) => { + // convert Native ORTB definition to old-style prebid native definition + validBidRequests = convertOrtbRequestToProprietaryNative(validBidRequests); + + 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); + } + // TODO: does the fallback make sense here? + 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; + const placements = []; + const request = { + deviceWidth, + deviceHeight, + language, + secure, + host, + page, + placements, + coppa: config.getConfig('coppa') === true ? 1 : 0, + ccpa: bidderRequest.uspConsent || undefined, + gdpr: bidderRequest.gdprConsent || undefined, + tmax: config.getConfig('bidderTimeout') + }; + + const len = validBidRequests.length; + for (let i = 0; i < len; i++) { + const bid = validBidRequests[i]; + placements.push(getPlacementReqData(bid)); + } + + return { + method: 'POST', + url: AD_URL, + 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/appushBidAdapter.md b/modules/appushBidAdapter.md new file mode 100644 index 00000000000..7c04c3a6425 --- /dev/null +++ b/modules/appushBidAdapter.md @@ -0,0 +1,79 @@ +# Overview + +``` +Module Name: Appush Bidder Adapter +Module Type: Appush Bidder Adapter +Maintainer: support@appush.com +``` + +# Description + +Connects to Appush exchange for bids. +Appush bid adapter supports Banner, Video (instream and outstream) and Native. + +# Test Parameters +``` + var adUnits = [ + // Will return static test banner + { + code: 'adunit1', + mediaTypes: { + banner: { + sizes: [ [300, 250], [320, 50] ], + } + }, + bids: [ + { + bidder: 'appush', + params: { + placementId: 'testBanner', + } + } + ] + }, + { + code: 'addunit2', + mediaTypes: { + video: { + playerSize: [ [640, 480] ], + context: 'instream', + minduration: 5, + maxduration: 60, + } + }, + bids: [ + { + bidder: 'appush', + params: { + placementId: 'testVideo', + } + } + ] + }, + { + code: 'addunit3', + mediaTypes: { + native: { + title: { + required: true + }, + body: { + required: true + }, + icon: { + required: true, + size: [64, 64] + } + } + }, + bids: [ + { + bidder: 'appush', + params: { + placementId: 'testNative', + } + } + ] + } + ]; +``` \ No newline at end of file diff --git a/modules/arcspanRtdProvider.js b/modules/arcspanRtdProvider.js new file mode 100644 index 00000000000..a7ffa059279 --- /dev/null +++ b/modules/arcspanRtdProvider.js @@ -0,0 +1,73 @@ +import { submodule } from '../src/hook.js'; +import { mergeDeep } from '../src/utils.js'; +import {loadExternalScript} from '../src/adloader.js'; + +/** @type {string} */ +const MODULE_NAME = 'realTimeData'; +const SUBMODULE_NAME = 'arcspan'; + +/** @type {RtdSubmodule} */ +export const arcspanSubmodule = { + name: SUBMODULE_NAME, + init: init, + getBidRequestData: alterBidRequests, +}; + +function init(config, userConsent) { + if (typeof config.params.silo === 'undefined') { + return false; + } + if (typeof window.arcobj2 === 'undefined') { + var scriptUrl; + if (config.params.silo === 'test') { + scriptUrl = 'https://localhost:8080/as.js'; + } else { + scriptUrl = 'https://silo' + config.params.silo + '.p7cloud.net/as.js'; + } + loadExternalScript(scriptUrl, SUBMODULE_NAME); + } + return true; +} + +function alterBidRequests(reqBidsConfigObj, callback, config, userConsent) { + var _v1 = []; + var _v1s = []; + var _v2 = []; + var arcobj1 = window.arcobj1; + if (typeof arcobj1 != 'undefined') { + if (typeof arcobj1.page_iab_codes.text != 'undefined') { _v1 = _v1.concat(arcobj1.page_iab_codes.text); } + if (typeof arcobj1.page_iab_codes.images != 'undefined') { _v1 = _v1.concat(arcobj1.page_iab_codes.images); } + if (typeof arcobj1.page_iab.text != 'undefined') { _v1s = _v1s.concat(arcobj1.page_iab.text); } + if (typeof arcobj1.page_iab.images != 'undefined') { _v1s = _v1s.concat(arcobj1.page_iab.images); } + if (typeof arcobj1.page_iab_newcodes.text != 'undefined') { _v2 = [...new Set([..._v2, ...arcobj1.page_iab_newcodes.text])]; } + if (typeof arcobj1.page_iab_newcodes.images != 'undefined') { _v2 = [...new Set([..._v2, ...arcobj1.page_iab_newcodes.images])]; } + + var _content = {}; + _content.data = []; + var p = {}; + p.name = 'arcspan'; + p.segment = []; + p.ext = { segtax: 6 }; + _v2.forEach(function (e) { + p.segment = p.segment.concat({ id: e }); + }); + _content.data = _content.data.concat(p); + var _ortb2 = { + site: { + name: 'arcspan', + domain: new URL(location.href).hostname, + cat: _v1, + sectioncat: _v1, + pagecat: _v1, + page: location.href, + ref: document.referrer, + keywords: _v1s.toString(), + content: _content, + }, + }; + mergeDeep(reqBidsConfigObj.ortb2Fragments.global, _ortb2); + } + callback(); +} + +submodule(MODULE_NAME, arcspanSubmodule); diff --git a/modules/arcspanRtdProvider.md b/modules/arcspanRtdProvider.md new file mode 100644 index 00000000000..4aa1de02acf --- /dev/null +++ b/modules/arcspanRtdProvider.md @@ -0,0 +1,11 @@ +# Overview + +Module Name: ArcSpan Rtd Provider + +Module Type: Rtd Provider + +Maintainer: engineering@arcspan.com + +# Description + +RTD provider for ArcSpan Technologies. Contact jcabalugaz@arcspan.com for more information. diff --git a/modules/asoBidAdapter.js b/modules/asoBidAdapter.js index 83b182e4ca5..39c42f193b2 100644 --- a/modules/asoBidAdapter.js +++ b/modules/asoBidAdapter.js @@ -10,11 +10,11 @@ import { parseSizesInput, tryAppendQueryString } 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 {Renderer} from '../src/Renderer.js'; -import {parseDomain} from '../src/refererDetection.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { config } from '../src/config.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import { Renderer } from '../src/Renderer.js'; +import { parseDomain } from '../src/refererDetection.js'; const BIDDER_CODE = 'aso'; const DEFAULT_SERVER_URL = 'https://srv.aso1.net'; @@ -27,6 +27,9 @@ export const spec = { code: BIDDER_CODE, supportedMediaTypes: [BANNER, VIDEO], + aliases: [ + {code: 'bcmint'} + ], isBidRequestValid: bid => { return !!bid.params && !!bid.params.zone; diff --git a/modules/beopBidAdapter.js b/modules/beopBidAdapter.js index f8a53a293de..4ee5aaec5be 100644 --- a/modules/beopBidAdapter.js +++ b/modules/beopBidAdapter.js @@ -1,4 +1,4 @@ -import { deepAccess, isArray, logWarn, triggerPixel, buildUrl, logInfo, getValue, getBidIdParameter } from '../src/utils.js'; +import { deepAccess, isArray, isStr, logWarn, triggerPixel, buildUrl, logInfo, getValue, getBidIdParameter } from '../src/utils.js'; import { getRefererInfo } from '../src/refererDetection.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { config } from '../src/config.js'; @@ -40,6 +40,19 @@ export const spec = { const pageUrl = getPageUrl(bidderRequest.refererInfo, window); const gdpr = bidderRequest.gdprConsent; const firstSlot = slots[0]; + const kwdsFromRequest = firstSlot.kwds; + let keywords = []; + if (kwdsFromRequest) { + if (isArray(kwdsFromRequest)) { + keywords = kwdsFromRequest; + } else if (isStr(kwdsFromRequest)) { + if (kwdsFromRequest.indexOf(',') != -1) { + keywords = kwdsFromRequest.split(',').map((e) => { return e.trim() }); + } else { + keywords.push(kwdsFromRequest); + } + } + } const payloadObject = { at: new Date().toString(), nid: firstSlot.nid, @@ -47,12 +60,13 @@ export const spec = { pid: firstSlot.pid, url: pageUrl, lang: (window.navigator.language || window.navigator.languages[0]), - kwds: bidderRequest.ortb2?.site?.keywords || [], + kwds: keywords, dbg: false, slts: slots, is_amp: deepAccess(bidderRequest, 'referrerInfo.isAmp'), tc_string: (gdpr && gdpr.gdprApplies) ? gdpr.consentString : null, }; + const payloadString = JSON.stringify(payloadObject); return { method: 'POST', @@ -129,6 +143,7 @@ function beOpRequestSlotsMaker(bid) { sizes: isArray(bannerSizes) ? bannerSizes : bid.sizes, flr: floor, pid: getValue(bid.params, 'accountId'), + kwds: getValue(bid.params, 'keywords'), nid: getValue(bid.params, 'networkId'), nptnid: getValue(bid.params, 'networkPartnerId'), bid: getBidIdParameter('bidId', bid), diff --git a/modules/bidViewability.js b/modules/bidViewability.js index 362401e6d1c..a5cab99b1a7 100644 --- a/modules/bidViewability.js +++ b/modules/bidViewability.js @@ -7,7 +7,7 @@ import * as events from '../src/events.js'; import CONSTANTS from '../src/constants.json'; import {isFn, logWarn, triggerPixel} from '../src/utils.js'; import {getGlobal} from '../src/prebidGlobal.js'; -import adapterManager, {gdprDataHandler, uspDataHandler} from '../src/adapterManager.js'; +import adapterManager, {gdprDataHandler, uspDataHandler, gppDataHandler} from '../src/adapterManager.js'; import {find} from '../src/polyfill.js'; const MODULE_NAME = 'bidViewability'; @@ -44,6 +44,11 @@ export let fireViewabilityPixels = (globalModuleConfig, bid) => { const uspConsent = uspDataHandler.getConsentData(); if (uspConsent) { queryParams.us_privacy = uspConsent; } + const gppConsent = gppDataHandler.getConsentData(); + if (gppConsent) { + // TODO - need to know what to set here for queryParams... + } + bid[BID_VURL_ARRAY].forEach(url => { // add '?' if not present in URL if (Object.keys(queryParams).length > 0 && url.indexOf('?') === -1) { diff --git a/modules/bliinkBidAdapter.js b/modules/bliinkBidAdapter.js index 127b534c989..ee814807331 100644 --- a/modules/bliinkBidAdapter.js +++ b/modules/bliinkBidAdapter.js @@ -125,7 +125,7 @@ export const buildBid = (bidResponse) => { requestId: deepAccess(bidResponse, 'extras.transaction_id'), width: deepAccess(bidResponse, `creative.${bid.mediaType}.width`) || 1, height: deepAccess(bidResponse, `creative.${bid.mediaType}.height`) || 1, - ttl: 3600, + ttl: 300, netRevenue: true, }); }; diff --git a/modules/brightcomBidAdapter.js b/modules/brightcomBidAdapter.js index bbe0203772a..15b4175b59a 100644 --- a/modules/brightcomBidAdapter.js +++ b/modules/brightcomBidAdapter.js @@ -9,6 +9,7 @@ const URL = 'https://brightcombid.marphezis.com/hb'; export const spec = { code: BIDDER_CODE, supportedMediaTypes: [BANNER], + gvlid: 883, isBidRequestValid, buildRequests, interpretResponse, diff --git a/modules/brightcomSSPBidAdapter.js b/modules/brightcomSSPBidAdapter.js new file mode 100644 index 00000000000..b7a9aa3fdc9 --- /dev/null +++ b/modules/brightcomSSPBidAdapter.js @@ -0,0 +1,323 @@ +import { + getBidIdParameter, + isArray, + getWindowTop, + getUniqueIdentifierStr, + deepSetValue, + logError, + logWarn, + createTrackPixelHtml, + getWindowSelf, + isFn, + isPlainObject, +} from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {BANNER} from '../src/mediaTypes.js'; +import {config} from '../src/config.js'; +import {ajax} from '../src/ajax.js'; + +const BIDDER_CODE = 'bcmssp'; +const URL = 'https://rt.marphezis.com/hb'; +const TRACK_EVENT_URL = 'https://rt.marphezis.com/prebid' + +export const spec = { + code: BIDDER_CODE, + gvlid: 883, + supportedMediaTypes: [BANNER], + isBidRequestValid, + buildRequests, + interpretResponse, + onBidderError, + onTimeout, + onBidWon, + getUserSyncs, +}; + +function buildRequests(bidReqs, bidderRequest) { + try { + const impressions = bidReqs.map(bid => { + let bidSizes = bid?.mediaTypes?.banner?.sizes || bid.sizes; + bidSizes = ((isArray(bidSizes) && isArray(bidSizes[0])) ? bidSizes : [bidSizes]); + bidSizes = bidSizes.filter(size => isArray(size)); + const processedSizes = bidSizes.map(size => ({w: parseInt(size[0], 10), h: parseInt(size[1], 10)})); + + const element = document.getElementById(bid.adUnitCode); + const minSize = _getMinSize(processedSizes); + const viewabilityAmount = _isViewabilityMeasurable(element) ? _getViewability(element, getWindowTop(), minSize) : 'na'; + const viewabilityAmountRounded = isNaN(viewabilityAmount) ? viewabilityAmount : Math.round(viewabilityAmount); + + const imp = { + id: bid.bidId, + banner: { + format: processedSizes, + ext: { + viewability: viewabilityAmountRounded + } + }, + tagid: String(bid.adUnitCode) + }; + + const bidFloor = _getBidFloor(bid); + + if (bidFloor) { + imp.bidfloor = bidFloor; + } + + return imp; + }) + + const referrer = bidderRequest?.refererInfo?.page || ''; + const publisherId = getBidIdParameter('publisherId', bidReqs[0].params); + + const payload = { + id: getUniqueIdentifierStr(), + imp: impressions, + site: { + domain: bidderRequest?.refererInfo?.domain || '', + page: referrer, + publisher: { + id: publisherId + } + }, + device: { + devicetype: _getDeviceType(), + w: screen.width, + h: screen.height + }, + tmax: config.getConfig('bidderTimeout') + }; + + if (bidderRequest?.gdprConsent) { + deepSetValue(payload, 'regs.ext.gdpr', +bidderRequest.gdprConsent.gdprApplies); + deepSetValue(payload, 'user.ext.consent', bidderRequest.gdprConsent.consentString); + } + + if (bidderRequest?.uspConsent) { + deepSetValue(payload, 'regs.ext.us_privacy', bidderRequest.uspConsent); + } + + if (config.getConfig('coppa') === true) { + deepSetValue(payload, 'regs.coppa', 1); + } + + if (bidReqs?.[0]?.schain) { + deepSetValue(payload, 'source.ext.schain', bidReqs[0].schain) + } + + if (bidReqs?.[0]?.userIdAsEids) { + deepSetValue(payload, 'user.ext.eids', bidReqs[0].userIdAsEids || []) + } + + if (bidReqs?.[0].userId) { + deepSetValue(payload, 'user.ext.ids', bidReqs[0].userId || []) + } + + return { + method: 'POST', + url: URL, + data: JSON.stringify(payload), + options: {contentType: 'text/plain', withCredentials: false} + }; + } catch (e) { + logError(e, {bidReqs, bidderRequest}); + } +} + +function isBidRequestValid(bid) { + if (bid.bidder !== BIDDER_CODE || !bid.params || !bid.params.publisherId) { + return false; + } + + return true; +} + +function interpretResponse(serverResponse) { + let response = []; + if (!serverResponse.body || typeof serverResponse.body != 'object') { + logWarn('Brightcom server returned empty/non-json response: ' + JSON.stringify(serverResponse.body)); + return response; + } + + const {body: {id, seatbid}} = serverResponse; + + try { + if (id && seatbid && seatbid.length > 0 && seatbid[0].bid && seatbid[0].bid.length > 0) { + response = seatbid[0].bid.map(bid => { + return { + requestId: bid.impid, + cpm: parseFloat(bid.price), + width: parseInt(bid.w), + height: parseInt(bid.h), + creativeId: bid.crid || bid.id, + currency: 'USD', + netRevenue: true, + mediaType: BANNER, + ad: _getAdMarkup(bid), + ttl: 60, + meta: { + advertiserDomains: bid?.adomain || [] + } + }; + }); + } + } catch (e) { + logError(e, {id, seatbid}); + } + + return response; +} + +// Don't do user sync for now +function getUserSyncs(syncOptions, responses, gdprConsent) { + return []; +} + +function onTimeout(timeoutData) { + if (timeoutData === null) { + return; + } + + _trackEvent('timeout', timeoutData); +} + +function onBidderError(errorData) { + if (errorData === null || !errorData.bidderRequest) { + return; + } + + _trackEvent('error', errorData.bidderRequest) +} + +function onBidWon(bid) { + if (bid === null) { + return; + } + + _trackEvent('bidwon', bid) +} + +function _trackEvent(endpoint, data) { + ajax(`${TRACK_EVENT_URL}/${endpoint}`, null, JSON.stringify(data), { + method: 'POST', + withCredentials: false + }); +} + +function _isMobile() { + return (/(ios|ipod|ipad|iphone|android)/i).test(navigator.userAgent); +} + +function _isConnectedTV() { + return (/(smart[-]?tv|hbbtv|appletv|googletv|hdmi|netcast\.tv|viera|nettv|roku|\bdtv\b|sonydtv|inettvbrowser|\btv\b)/i).test(navigator.userAgent); +} + +function _getDeviceType() { + return _isMobile() ? 1 : _isConnectedTV() ? 3 : 2; +} + +function _getAdMarkup(bid) { + let adm = bid.adm; + if ('nurl' in bid) { + adm += createTrackPixelHtml(bid.nurl); + } + return adm; +} + +function _isViewabilityMeasurable(element) { + return !_isIframe() && element !== null; +} + +function _getViewability(element, topWin, {w, h} = {}) { + return getWindowTop().document.visibilityState === 'visible' ? _getPercentInView(element, topWin, {w, h}) : 0; +} + +function _isIframe() { + try { + return getWindowSelf() !== getWindowTop(); + } catch (e) { + return true; + } +} + +function _getMinSize(sizes) { + return sizes.reduce((min, size) => size.h * size.w < min.h * min.w ? size : min); +} + +function _getBoundingBox(element, {w, h} = {}) { + let {width, height, left, top, right, bottom} = element.getBoundingClientRect(); + + if ((width === 0 || height === 0) && w && h) { + width = w; + height = h; + right = left + w; + bottom = top + h; + } + + return {width, height, left, top, right, bottom}; +} + +function _getIntersectionOfRects(rects) { + const bbox = { + left: rects[0].left, right: rects[0].right, top: rects[0].top, bottom: rects[0].bottom + }; + + for (let i = 1; i < rects.length; ++i) { + bbox.left = Math.max(bbox.left, rects[i].left); + bbox.right = Math.min(bbox.right, rects[i].right); + + if (bbox.left >= bbox.right) { + return null; + } + + bbox.top = Math.max(bbox.top, rects[i].top); + bbox.bottom = Math.min(bbox.bottom, rects[i].bottom); + + if (bbox.top >= bbox.bottom) { + return null; + } + } + + bbox.width = bbox.right - bbox.left; + bbox.height = bbox.bottom - bbox.top; + + return bbox; +} + +function _getPercentInView(element, topWin, {w, h} = {}) { + const elementBoundingBox = _getBoundingBox(element, {w, h}); + + // Obtain the intersection of the element and the viewport + const elementInViewBoundingBox = _getIntersectionOfRects([{ + left: 0, top: 0, right: topWin.innerWidth, bottom: topWin.innerHeight + }, elementBoundingBox]); + + let elementInViewArea, elementTotalArea; + + if (elementInViewBoundingBox !== null) { + // Some or all of the element is in view + elementInViewArea = elementInViewBoundingBox.width * elementInViewBoundingBox.height; + elementTotalArea = elementBoundingBox.width * elementBoundingBox.height; + + return ((elementInViewArea / elementTotalArea) * 100); + } + + // No overlap between element and the viewport; therefore, the element + // lies completely out of view + return 0; +} + +function _getBidFloor(bid) { + if (!isFn(bid.getFloor)) { + return bid.params.bidFloor ? bid.params.bidFloor : null; + } + + let floor = bid.getFloor({ + currency: 'USD', mediaType: '*', size: '*' + }); + if (isPlainObject(floor) && !isNaN(floor.floor) && floor.currency === 'USD') { + return floor.floor; + } + return null; +} + +registerBidder(spec); diff --git a/modules/brightcomSSPBidAdapter.md b/modules/brightcomSSPBidAdapter.md new file mode 100644 index 00000000000..8d0e4ec70dc --- /dev/null +++ b/modules/brightcomSSPBidAdapter.md @@ -0,0 +1,46 @@ +# Overview + +``` +Module Name: Brightcom SSP Bid Adapter +Module Type: Bidder Adapter +Maintainer: alexandruc@brightcom.com +``` + +# Description + +Brightcom's adapter integration to the Prebid library. + +# Test Parameters + +``` +var adUnits = [ + { + code: 'test-leaderboard', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + bids: [{ + bidder: 'bcmssp', + params: { + publisherId: 2141020, + bidFloor: 0.01 + } + }] + }, { + code: 'test-banner', + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + bids: [{ + bidder: 'bcmssp', + params: { + publisherId: 2141020 + } + }] + } +] +``` diff --git a/modules/browsiRtdProvider.js b/modules/browsiRtdProvider.js index 0996fc9905b..31b2d709f35 100644 --- a/modules/browsiRtdProvider.js +++ b/modules/browsiRtdProvider.js @@ -59,10 +59,12 @@ export function addBrowsiTag(data) { export function sendPageviewEvent(eventType) { if (eventType === 'PAGEVIEW') { - events.emit(CONSTANTS.EVENTS.BILLABLE_EVENT, { - vendor: 'browsi', - type: 'pageview', - billingId: generateUUID() + window.addEventListener('browsi_pageview', () => { + events.emit(CONSTANTS.EVENTS.BILLABLE_EVENT, { + vendor: 'browsi', + type: 'pageview', + billingId: generateUUID() + }) }) } } diff --git a/modules/bucksenseBidAdapter.js b/modules/bucksenseBidAdapter.js index fcf99179993..7b6c3911ea1 100644 --- a/modules/bucksenseBidAdapter.js +++ b/modules/bucksenseBidAdapter.js @@ -4,7 +4,7 @@ import { BANNER } from '../src/mediaTypes.js'; const WHO = 'BKSHBID-005'; const BIDDER_CODE = 'bucksense'; -const URL = 'https://prebid.bksn.se/prebidjs/'; +const URL = 'https://directo.prebidserving.com/prebidjs/'; export const spec = { code: BIDDER_CODE, diff --git a/modules/captifyRtdProvider.js b/modules/captifyRtdProvider.js new file mode 100644 index 00000000000..b97aa49a48e --- /dev/null +++ b/modules/captifyRtdProvider.js @@ -0,0 +1,146 @@ +/** + * This module adds Captify real time data provider module + * The {@link module:modules/realTimeData} module is required + * The module will fetch segments (page-centric) from Captify live-classification server + * @module modules/captifyRtdProvider + * @requires module:modules/realTimeData + */ +import { submodule } from '../src/hook.js'; +import { getRefererInfo } from '../src/refererDetection.js'; +import { ajax } from '../src/ajax.js'; +import { config } from '../src/config.js'; +import {deepAccess, isArray, isEmptyStr, isNumber, logError} from '../src/utils.js'; +import {getGlobal} from '../src/prebidGlobal.js'; + +const MODULE_NAME = 'realTimeData'; +const SUBMODULE_NAME = 'CaptifyRTDModule'; +const DEFAULT_LC_URL = 'https://live-classification.cpx.to/prebid-segments'; + +const STATUS = { + SUCCESS: 200, + ACCEPTED: 202, +}; + +/** + * Set `appnexusAuctionKeywords` that appnexus bidder will read and send in request to Xandr + * @param {Array} segments captify segments for Appnexus(Xandr) system, in form of [id1, id2, id3] + * where id1, id2, id3 - actual Xandr segment ids with keywords enabled + */ +export function setAppnexusSegments(segments) { + config.setConfig({ + appnexusAuctionKeywords: { + 'captify_segments': segments, + }, + }) +} + +/** + * Function returns only bidders that contained both, in moduleConfig and at least one adUnit. + * @param {Array} bidders Contains list of bidders, to set targeting for + * @param {Object} data Response of live-classification service + */ +export function addSegmentData(bidders, data) { + for (const bidder of bidders) { + if (bidder === 'appnexus') { setAppnexusSegments(data['xandr']) } + } +} + +/** + * Function returns only bidders that contained in both, moduleConfig and at least one adUnit. + * @param {Object} moduleConfig Config object passed to the module + * @param {Object} reqBidsConfigObj Config object for the bidders; each adapter has its own entry + */ +export function getMatchingBidders(moduleConfig, reqBidsConfigObj) { + const biddersFromConf = deepAccess(moduleConfig, 'params.bidders'); + + const adUnitBidders = reqBidsConfigObj.adUnits + .flatMap(({bids}) => bids.map(({bidder}) => bidder)) + .filter((e, i, a) => a.indexOf(e) === i); + + if (!isArray(adUnitBidders) || !adUnitBidders.length) { + logError(SUBMODULE_NAME, 'Missing parameter bidders in bidRequestConfig'); + return []; + } + + return biddersFromConf.filter(bidder => adUnitBidders.includes(bidder)); +} + +/** + * Main function that sets Captify targeting for various bidders + * @param {Object} moduleConfig Config object passed to the module + * @param {Function} onDone callback function that executed when everything is done + * @param {Object} reqBidsConfigObj Config object for the bidders; each adapter has its own entry + * @param {Object} gcv contains data related to user consent, if applies + */ +export function setCaptifyTargeting(reqBidsConfigObj, onDone, moduleConfig, gcv) { + const pbjsVer = getGlobal(); + const ref = getRefererInfo().referer; + const url = document.URL; + const pubId = moduleConfig.params.pubId; + const bidders = getMatchingBidders(moduleConfig, reqBidsConfigObj) + const requestBody = { + pubId, + ref, + url, + pbjsVer, + gcv + }; + let requestUrl = moduleConfig.params.url; + if (!requestUrl || isEmptyStr(requestUrl)) { + requestUrl = DEFAULT_LC_URL; + } + + if (!bidders.length) { + logError(SUBMODULE_NAME, 'There are no matched bidders to work with'); + return; + } + + ajax(requestUrl, { + success: function (response, req) { + if (req.status === STATUS.SUCCESS) { + try { + const data = JSON.parse(response); + if (data) { + addSegmentData(bidders, data); + } + } catch (e) { + logError(SUBMODULE_NAME, 'Unable to parse live-classification data' + e); + } + } + onDone(); + }, + error: function () { + onDone(); + logError(SUBMODULE_NAME, 'Unable to get live-classification data'); + } + }, + JSON.stringify(requestBody), + { + contentType: 'application/json', + method: 'POST', + }); +} + +export function init(moduleConfig, userConsent) { + // Validate bidders + const biddersFromConf = deepAccess(moduleConfig, 'params.bidders'); + if (!isArray(biddersFromConf) || !biddersFromConf.length) { + logError(SUBMODULE_NAME, 'Missing parameter bidders in moduleConfig'); + return false + } + const publisherId = deepAccess(moduleConfig, 'params.pubId'); + // Publisher Id + if (!isNumber(publisherId)) { + logError(SUBMODULE_NAME, 'Missing parameter pubId in moduleConfig'); + return false + } + return true +} + +export const captifySubmodule = { + name: SUBMODULE_NAME, + init: init, + setCaptifyTargeting +}; + +submodule(MODULE_NAME, captifySubmodule); diff --git a/modules/captifyRtdProvider.md b/modules/captifyRtdProvider.md new file mode 100644 index 00000000000..a1a8e9c273f --- /dev/null +++ b/modules/captifyRtdProvider.md @@ -0,0 +1,68 @@ +# Captify Real-Time Data Submodule + +# Overview + + Module Name: Captify Rtd Provider + Module Type: Rtd Provider + Layout: integrationExamples/gpt/captifyRtdProvider_example.html + Maintainer: prebid@captify.tech + +# Description + +Captify uses publisher first-party on-site search data to power machine learning algorithms to create a suite of +contextual based targeting solutions that activate in a cookieless environment. + +The RTD submodule allows bid requests to be classified by our live-classification service on the first ad call, +maximising value for publishers by increasing scale for advertisers. + +Segments will be attached to bid request objects sent to different SSPs in order to optimize targeting. + +Contact prebid@captify.tech for information. + +### Publisher Usage + +Compile the Captify RTD module into your Prebid build: + +`npm ci && gulp build --modules=rtdModule,appnexusBidAdapter,captifyRtdProvider` + +Add the Captify RTD provider to your Prebid config. + +```javascript +pbjs.setConfig({ + realTimeData: { + auctionDelay: 1000, + dataProviders: [ + { + name: "CaptifyRTDModule", + waitForIt: true, + params: { + pubId: 123456, + bidders: ['appnexus'], + } + } + ] + } +}); +``` + +### Parameter Description +This module is configured as part of the `realTimeData.dataProviders` object. + +| Name |Type | Description |Mandatory | Notes | +| :------------- | :------------ | :------------------------------------------------------------------ |:---------|:------------ | +| name | String | Real time data module name | yes | Always 'CaptifyRTDModule' | +| waitForIt | Boolean | Should be `true` if there's an `auctionDelay` defined (recommended) | no | Default `false` | +| params | Object | | | | +| params.pubId | Integer | Partner ID, required to get results and provided by Captify | yes | Use 123456 for tests and speak to your Captify account manager to receive your pubId | +| params.bidders | Array | List of bidders for which you would like data to be set | yes | Currently only 'appnexus' supported | +| params.url | String | Captify live-classification service url | no | Defaults to `https://live-classification.cpx.to/prebid-segments` + +### Testing + +To view an example of available segments returned by Captify: + +`gulp serve --modules=rtdModule,captifyRtdProvider,appnexusBidAdapter` + +and then point your browser at: + +`http://localhost:9999/integrationExamples/gpt/captifyRtdProvider_example.html?pbjs_debug=true` diff --git a/modules/ccxBidAdapter.js b/modules/ccxBidAdapter.js index 7c6b0411023..28f3fe3a166 100644 --- a/modules/ccxBidAdapter.js +++ b/modules/ccxBidAdapter.js @@ -5,6 +5,7 @@ import {getStorageManager} from '../src/storageManager.js'; const BIDDER_CODE = 'ccx' const storage = getStorageManager({bidderCode: BIDDER_CODE}); const BID_URL = 'https://delivery.clickonometrics.pl/ortb/prebid/bid' +const GVLID = 773; const SUPPORTED_VIDEO_PROTOCOLS = [2, 3, 5, 6] const SUPPORTED_VIDEO_MIMES = ['video/mp4', 'video/x-flv'] const SUPPORTED_VIDEO_PLAYBACK_METHODS = [1, 2, 3, 4] @@ -19,8 +20,7 @@ function _getDeviceObj () { function _getSiteObj (bidderRequest) { let site = {} - // TODO: does the fallback to window.location make sense? - let url = bidderRequest?.refererInfo?.page || window.location.href + let url = bidderRequest?.refererInfo?.page || '' if (url.length > 0) { url = url.split('?')[0] } @@ -140,6 +140,7 @@ function _buildResponse (bid, currency, ttl) { export const spec = { code: BIDDER_CODE, + gvlid: GVLID, supportedMediaTypes: ['banner', 'video'], isBidRequestValid: function (bid) { diff --git a/modules/cointrafficBidAdapter.js b/modules/cointrafficBidAdapter.js index ce366cbecc8..380e1f5fc77 100644 --- a/modules/cointrafficBidAdapter.js +++ b/modules/cointrafficBidAdapter.js @@ -4,19 +4,20 @@ import { BANNER } from '../src/mediaTypes.js' import { config } from '../src/config.js' const BIDDER_CODE = 'cointraffic'; -const ENDPOINT_URL = 'https://apps-pbd.ctengine.io/pb/tmp'; +const ENDPOINT_URL = 'https://apps-pbd.ctraffic.io/pb/tmp'; const DEFAULT_CURRENCY = 'EUR'; const ALLOWED_CURRENCIES = [ 'EUR', 'USD', 'JPY', 'BGN', 'CZK', 'DKK', 'GBP', 'HUF', 'PLN', 'RON', 'SEK', 'CHF', 'ISK', 'NOK', 'HRK', 'RUB', 'TRY', 'AUD', 'BRL', 'CAD', 'CNY', 'HKD', 'IDR', 'ILS', 'INR', 'KRW', 'MXN', 'MYR', 'NZD', 'PHP', 'SGD', 'THB', 'ZAR', ]; +/** @type {BidderSpec} */ export const spec = { code: BIDDER_CODE, supportedMediaTypes: [BANNER], /** - * Determines whether or not the given bid request is valid. + * Determines whether 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. @@ -50,8 +51,7 @@ export const spec = { currency: currency, sizes: sizes, bidId: bidRequest.bidId, - // TODO: is 'page' the right value here? - referer: bidderRequest.refererInfo.page, + referer: bidderRequest.refererInfo.ref, }; return { diff --git a/modules/colossussspBidAdapter.js b/modules/colossussspBidAdapter.js index c1560680a6e..082fb0ac4db 100644 --- a/modules/colossussspBidAdapter.js +++ b/modules/colossussspBidAdapter.js @@ -87,6 +87,11 @@ export const spec = { logMessage(e); } + const firstPartyData = bidderRequest.ortb2 || {}; + const userObj = firstPartyData.user; + const siteObj = firstPartyData.site; + const appObj = firstPartyData.app; + // TODO: does the fallback to window.location make sense? const location = refferLocation || winLocation; let placements = []; @@ -97,6 +102,9 @@ export const spec = { secure: location.protocol === 'https:' ? 1 : 0, host: location.host, page: location.pathname, + userObj, + siteObj, + appObj, placements: placements }; @@ -214,7 +222,7 @@ export const spec = { }, getUserSyncs: (syncOptions, serverResponses, gdprConsent, uspConsent) => { - let syncType = syncOptions.iframeEnabled ? 'html' : 'hms.gif'; + let syncType = syncOptions.iframeEnabled ? 'iframe' : 'image'; let syncUrl = G_URL_SYNC + `/${syncType}?pbjs=1`; if (gdprConsent && gdprConsent.consentString) { if (typeof gdprConsent.gdprApplies === 'boolean') { diff --git a/modules/concertBidAdapter.js b/modules/concertBidAdapter.js index fc6fc23c26d..dcea60d5231 100644 --- a/modules/concertBidAdapter.js +++ b/modules/concertBidAdapter.js @@ -1,4 +1,4 @@ -import { logWarn, logMessage, debugTurnedOn, generateUUID } from '../src/utils.js'; +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'; @@ -34,6 +34,9 @@ export const spec = { buildRequests: function(validBidRequests, bidderRequest) { logMessage(validBidRequests); logMessage(bidderRequest); + + const eids = []; + let payload = { meta: { prebidVersion: '$prebid.version$', @@ -49,6 +52,10 @@ export const spec = { }; payload.slots = validBidRequests.map(bidRequest => { + collectEid(eids, bidRequest); + const adUnitElement = document.getElementById(bidRequest.adUnitCode) + const coordinates = getOffset(adUnitElement) + let slot = { name: bidRequest.adUnitCode, bidId: bidRequest.bidId, @@ -59,12 +66,15 @@ export const spec = { adSlot: bidRequest.params.slot || bidRequest.adUnitCode, placementId: bidRequest.params.placementId || '', site: bidRequest.params.site || bidderRequest.refererInfo.page, - ref: bidderRequest.refererInfo.ref - }; + ref: bidderRequest.refererInfo.ref, + offsetCoordinates: { x: coordinates?.left, y: coordinates?.top } + } return slot; }); + payload.meta.eids = eids.filter(Boolean); + logMessage(payload); return { @@ -168,7 +178,7 @@ export const spec = { registerBidder(spec); -const storage = getStorageManager({bidderCode: BIDDER_CODE}); +export const storage = getStorageManager({bidderCode: BIDDER_CODE}); /** * Check or generate a UID for the current user. @@ -178,10 +188,24 @@ function getUid(bidderRequest) { return false; } - const CONCERT_UID_KEY = 'c_uid'; + const sharedId = deepAccess(bidderRequest, 'userId._sharedid.id'); + + if (sharedId) { + return sharedId; + } + + const LEGACY_CONCERT_UID_KEY = 'c_uid'; + const CONCERT_UID_KEY = 'vmconcert_uid'; + const legacyUid = storage.getDataFromLocalStorage(LEGACY_CONCERT_UID_KEY); let uid = storage.getDataFromLocalStorage(CONCERT_UID_KEY); + if (legacyUid) { + uid = legacyUid; + storage.setDataInLocalStorage(CONCERT_UID_KEY, uid); + storage.removeDataFromLocalStorage(LEGACY_CONCERT_UID_KEY); + } + if (!uid) { uid = generateUUID(); storage.setDataInLocalStorage(CONCERT_UID_KEY, uid); @@ -216,3 +240,35 @@ function consentAllowsPpid(bidderRequest) { return (uspConsent || gdprConsent); } + +function collectEid(eids, bid) { + if (bid.userId) { + const eid = getUserId(bid.userId.uid2 && bid.userId.uid2.id, 'uidapi.com', undefined, 3) + eids.push(eid) + } +} + +function getUserId(id, source, uidExt, atype) { + if (id) { + const uid = { id, atype }; + + if (uidExt) { + uid.ext = uidExt; + } + + return { + source, + uids: [ uid ] + }; + } +} + +function getOffset(el) { + if (el) { + const rect = el.getBoundingClientRect(); + return { + left: rect.left + window.scrollX, + top: rect.top + window.scrollY + }; + } +} diff --git a/modules/confiantRtdProvider.js b/modules/confiantRtdProvider.js new file mode 100644 index 00000000000..2c13ad87d75 --- /dev/null +++ b/modules/confiantRtdProvider.js @@ -0,0 +1,128 @@ +/** + * This module provides comprehensive detection of security, quality, and privacy threats by Confiant Inc, + * the industry leader in real-time detecting and blocking of bad ads + * + * The {@link module:modules/realTimeData} module is required + * The module will inject a Confiant Inc. script into the page to monitor ad impressions + * @module modules/confiantRtdProvider + * @requires module:modules/realTimeData + */ + +import { submodule } from '../src/hook.js'; +import { logError, generateUUID } from '../src/utils.js'; +import { loadExternalScript } from '../src/adloader.js'; +import * as events from '../src/events.js'; +import CONSTANTS from '../src/constants.json'; + +/** + * Injects the Confiant Inc. configuration script into the page, based on proprtyId provided + * @param {string} propertyId + */ +function injectConfigScript(propertyId) { + const scriptSrc = `https://cdn.confiant-integrations.net/${propertyId}/gpt_and_prebid/config.js`; + + loadExternalScript(scriptSrc, 'confiant', () => {}); +} + +/** + * Set up page with Confiant integration + * @param {Object} config + */ +function setupPage(config) { + const propertyId = config?.params?.propertyId; + if (!propertyId) { + logError('Confiant pbjs module: no propertyId provided'); + return false; + } + + const confiant = window.confiant || Object.create(null); + confiant[propertyId] = confiant[propertyId] || Object.create(null); + confiant[propertyId].clientSettings = confiant[propertyId].clientSettings || Object.create(null); + confiant[propertyId].clientSettings.isMGBL = true; + confiant[propertyId].clientSettings.prebidExcludeBidders = config?.params?.prebidExcludeBidders; + confiant[propertyId].clientSettings.prebidNameSpace = config?.params?.prebidNameSpace; + + if (config?.params?.shouldEmitBillableEvent) { + if (window.frames['cnftComm']) { + subscribeToConfiantCommFrame(window); + } else { + setUpMutationObserver(); + } + } + + injectConfigScript(propertyId); + return true; +} + +/** + * Subscribe to window's message events to report Billable events + * @param {Window} targetWindow window instance to subscribe to + */ +function subscribeToConfiantCommFrame(targetWindow) { + targetWindow.addEventListener('message', reportBillableEvents); +} + +let mutationObserver; +/** + * Set up mutation observer to subscribe to Confiant's communication channel ASAP + */ +function setUpMutationObserver() { + mutationObserver = new MutationObserver((mutations) => { + mutations.forEach((mutation) => { + mutation.addedNodes.forEach((addedNode) => { + if (addedNode.nodeName === 'IFRAME' && addedNode.name === 'cnftComm' && !addedNode.pbjsModuleSubscribed) { + addedNode.pbjsModuleSubscribed = true; + mutationObserver.disconnect(); + mutationObserver = null; + const iframeWindow = addedNode.contentWindow; + subscribeToConfiantCommFrame(iframeWindow); + } + }); + }); + }); + mutationObserver.observe(document.head, { childList: true, subtree: true }); +} + +/** + * Emit billable event when Confiant integration reports that it has monitored an impression + */ +function reportBillableEvents (e) { + events.emit(CONSTANTS.EVENTS.BILLABLE_EVENT, { + auctionId: e.data.auctionId, + billingId: generateUUID(), + transactionId: e.data.transactionId, + type: 'impression', + vendor: 'confiant' + }); +} + +/** + * Confiant submodule registration + */ +function registerConfiantSubmodule() { + submodule('realTimeData', { + name: 'confiant', + init: (config) => { + try { + return setupPage(config); + } catch (err) { + logError(err.message); + if (mutationObserver) { + mutationObserver.disconnect(); + } + return false; + } + } + }); +} + +registerConfiantSubmodule(); + +export default { + injectConfigScript, + setupPage, + subscribeToConfiantCommFrame, + setUpMutationObserver, + reportBillableEvents, + registerConfiantSubmodule +}; diff --git a/modules/confiantRtdProvider.md b/modules/confiantRtdProvider.md new file mode 100644 index 00000000000..e92c0aabcba --- /dev/null +++ b/modules/confiantRtdProvider.md @@ -0,0 +1,45 @@ +# Overview + +``` +Module Name: Confiant Inc. Rtd provider +Module Type: Rtd Provider +Maintainer: +``` + +Confiant’s module provides comprehensive detection of security, quality, and privacy threats across your ad stack. +Confiant is the industry leader in real-time detecting and blocking of bad ads when it comes to protecting your users and brand reputation. + +To start using this module, please contact [Confiant](https://www.confiant.com/contact) to get an account and customer key. + + +# Integration + +1) Build Prebid bundle with Confiant module included: + + +``` +gulp build --modules=confiantRtdProvider,... +``` + +2) Include the resulting bundle on your page. + +# Configuration + +Configuration of Confiant module is plain simple: + +```javascript +pbjs.setConfig({ + realTimeData: { + dataProviders: [{ + name: 'confiant', + params: { + // so please get in touch with us so we could help you to set up the module with proper parameters + propertyId: '', // required, string param, obtained from Confiant Inc. + prebidExcludeBidders: '', // optional, comma separated list of bidders to exclude from Confiant's prebid.js integration + prebidNameSpace: '', // optional, string param, namespace for prebid.js integration + shouldEmitBillableEvent: false, // optional, boolean param, upon being set to true enables firing of the BillableEvent upon Confiant's impression scanning + } + }] + } +}); +``` diff --git a/modules/connectIdSystem.js b/modules/connectIdSystem.js index 4fad832302f..38c9c00b0ed 100644 --- a/modules/connectIdSystem.js +++ b/modules/connectIdSystem.js @@ -15,18 +15,7 @@ const VENDOR_ID = 25; const PLACEHOLDER = '__PIXEL_ID__'; const UPS_ENDPOINT = `https://ups.analytics.yahoo.com/ups/${PLACEHOLDER}/fed`; const OVERRIDE_OPT_OUT_KEY = 'connectIdOptOut'; - -function isEUConsentRequired(consentData) { - return !!(consentData && consentData.gdpr && consentData.gdpr.gdprApplies); -} - -function userHasOptedOut() { - try { - return localStorage.getItem(OVERRIDE_OPT_OUT_KEY) === '1'; - } catch { - return false; - } -} +const INPUT_PARAM_KEYS = ['pixelId', 'he', 'puid']; /** @type {Submodule} */ export const connectIdSubmodule = { @@ -45,7 +34,7 @@ export const connectIdSubmodule = { * @returns {{connectId: string} | undefined} */ decode(value) { - if (userHasOptedOut()) { + if (connectIdSubmodule.userHasOptedOut()) { return undefined; } return (typeof value === 'object' && value.connectid) @@ -59,28 +48,35 @@ export const connectIdSubmodule = { * @returns {IdResponse|undefined} */ getId(config, consentData) { - if (userHasOptedOut()) { + if (connectIdSubmodule.userHasOptedOut()) { return; } const params = config.params || {}; - if (!params || typeof params.he !== 'string' || - (typeof params.pixelId === 'undefined' && typeof params.endpoint === 'undefined')) { - logError('The connectId submodule requires the \'he\' and \'pixelId\' parameters to be defined.'); + if (!params || (typeof params.he !== 'string' && typeof params.puid !== 'string') || + (typeof params.pixelId === 'undefined' && typeof params.endpoint === 'undefined')) { + logError('The connectId submodule requires the \'pixelId\' and at least one of the \'he\' ' + + 'or \'puid\' parameters to be defined.'); return; } const data = { '1p': includes([1, '1', true], params['1p']) ? '1' : '0', - he: params.he, - gdpr: isEUConsentRequired(consentData) ? '1' : '0', - gdpr_consent: isEUConsentRequired(consentData) ? consentData.gdpr.consentString : '', + gdpr: connectIdSubmodule.isEUConsentRequired(consentData) ? '1' : '0', + gdpr_consent: connectIdSubmodule.isEUConsentRequired(consentData) ? consentData.gdpr.consentString : '', us_privacy: consentData && consentData.uspConsent ? consentData.uspConsent : '' }; - if (params.pixelId) { - data.pixelId = params.pixelId + if (connectIdSubmodule.isUnderGPPJurisdiction(consentData)) { + data.gpp = consentData.gppConsent.gppString; + data.gpp_sid = encodeURIComponent(consentData.gppConsent.applicableSections.join(',')); } + INPUT_PARAM_KEYS.forEach(key => { + if (typeof params[key] != 'undefined') { + data[key] = params[key]; + } + }); + const resp = function (callback) { const callbacks = { success: response => { @@ -106,6 +102,37 @@ export const connectIdSubmodule = { return {callback: resp}; }, + /** + * Utility function that returns a boolean flag indicating if the opportunity + * is subject to GDPR + * @returns {Boolean} + */ + isEUConsentRequired(consentData) { + return !!(consentData && consentData.gdpr && consentData.gdpr.gdprApplies); + }, + + /** + * Utility function that returns a boolean flag indicating if the opportunity + * is subject to GPP jurisdiction. + * @returns {Boolean} + */ + isUnderGPPJurisdiction(consentData) { + return !!(consentData && consentData.gppConsent && consentData.gppConsent.gppString); + }, + + /** + * Utility function that returns a boolean flag indicating if the user + * has opeted out via the Yahoo easy-opt-out mechanism. + * @returns {Boolean} + */ + userHasOptedOut() { + try { + return localStorage.getItem(OVERRIDE_OPT_OUT_KEY) === '1'; + } catch { + return false; + } + }, + /** * Return the function used to perform XHR calls. * Utilised for each of testing. diff --git a/modules/connectIdSystem.md b/modules/connectIdSystem.md index f2153e1b6cb..c671c036b77 100644 --- a/modules/connectIdSystem.md +++ b/modules/connectIdSystem.md @@ -29,5 +29,6 @@ The below parameters apply only to the Yahoo ConnectID user ID Module. | --- | --- | --- | --- | --- | | name | Required | String | ID value for the Yahoo ConnectID module - `"connectId"` | `"connectId"` | | params | Required | Object | Data for Yahoo ConnectID initialization. | | -| params.pixelId | Required | Number | The Yahoo supplied publisher specific pixel Id | `8976` | -| params.he | Required | String | The SHA-256 hashed user email address | `"529cb86de31e9547a712d9f380146e98bbd39beec"` | +| params.pixelId | Required | Number | The Yahoo supplied publisher specific pixel Id. | `8976` | +| params.he | Optional | String | The SHA-256 hashed user email address. One of either the `he` parameter or the `puid` parameter must be supplied. | `"529cb86de31e9547a712d9f380146e98bbd39beec"` | +| params.puid | Optional | String | The publisher-supplied user identifier. One of either the `he` parameter or the `puid` parameter must be supplied. | `"P-975484817"` | diff --git a/modules/consentManagement.js b/modules/consentManagement.js index 95d622e55e4..44e8d39b832 100644 --- a/modules/consentManagement.js +++ b/modules/consentManagement.js @@ -10,6 +10,7 @@ import {gdprDataHandler} from '../src/adapterManager.js'; import {includes} from '../src/polyfill.js'; import {timedAuctionHook} from '../src/utils/perfMetrics.js'; import {registerOrtbProcessor, REQUEST} from '../src/pbjsORTB.js'; +import {enrichFPD} from '../src/fpd/enrichment.js'; const DEFAULT_CMP = 'iab'; const DEFAULT_CONSENT_TIMEOUT = 10000; @@ -19,10 +20,10 @@ export let userCMP; export let consentTimeout; export let gdprScope; export let staticConsentData; +let actionTimeout; let consentData; let addedConsentHook = false; -let provisionalConsent; // add new CMPs here, with their dedicated lookup function const cmpCallMap = { @@ -45,7 +46,7 @@ function lookupStaticConsentData({onSuccess, onError}) { * @param {function({})} onSuccess acts as a success callback when CMP returns a value; pass along consentObjectfrom CMP * @param {function(string, ...{}?)} cmpError acts as an error callback while interacting with CMP; pass along an error message (string) and any extra error arguments (purely for logging) */ -function lookupIabConsent({onSuccess, onError}) { +function lookupIabConsent({onSuccess, onError, onEvent}) { function findCMP() { let f = window; let cmpFrame; @@ -79,10 +80,9 @@ function lookupIabConsent({onSuccess, onError}) { function cmpResponseCallback(tcfData, success) { logInfo('Received a response from CMP', tcfData); if (success) { + onEvent(tcfData); if (tcfData.gdprApplies === false || tcfData.eventStatus === 'tcloaded' || tcfData.eventStatus === 'useractioncomplete') { processCmpData(tcfData, {onSuccess, onError}); - } else { - provisionalConsent = tcfData; } } else { onError('CMP unable to register callback function. Please check CMP setup.'); @@ -93,7 +93,7 @@ function lookupIabConsent({onSuccess, onError}) { const { cmpFrame, cmpFunction } = findCMP(); if (!cmpFrame) { - return onError('CMP not found.'); + return onError('TCF2 CMP not found.'); } // to collect the consent information from the user, we perform two calls to the CMP in parallel: // first to collect the user's consent choices represented in an encoded string (via getConsentData) @@ -164,11 +164,24 @@ function lookupIabConsent({onSuccess, onError}) { function loadConsentData(cb) { let isDone = false; let timer = null; + let onTimeout, provisionalConsent; + let cmpLoaded = false; - function done(consentData, shouldCancelAuction, errMsg, ...extraArgs) { + function resetTimeout(timeout) { if (timer != null) { clearTimeout(timer); } + if (!isDone && timeout != null) { + if (timeout === 0) { + onTimeout() + } else { + timer = setTimeout(onTimeout, timeout); + } + } + } + + function done(consentData, shouldCancelAuction, errMsg, ...extraArgs) { + resetTimeout(null); isDone = true; gdprDataHandler.setConsentData(consentData); if (typeof cb === 'function') { @@ -185,25 +198,30 @@ function loadConsentData(cb) { onSuccess: (data) => done(data, false), onError: function (msg, ...extraArgs) { done(null, true, msg, ...extraArgs); + }, + onEvent: function (consentData) { + provisionalConsent = consentData; + if (cmpLoaded) return; + cmpLoaded = true; + if (actionTimeout != null) { + resetTimeout(actionTimeout); + } } } - cmpCallMap[userCMP](callbacks); - if (!isDone) { - const onTimeout = () => { - const continueToAuction = (data) => { - done(data, false, 'CMP did not load, continuing auction...'); - } - processCmpData(provisionalConsent, { - onSuccess: continueToAuction, - onError: () => continueToAuction(storeConsentData(undefined)) - }) - } - if (consentTimeout === 0) { - onTimeout(); - } else { - timer = setTimeout(onTimeout, consentTimeout); + onTimeout = () => { + const continueToAuction = (data) => { + done(data, false, `${cmpLoaded ? 'Timeout waiting for user action on CMP' : 'CMP did not load'}, continuing auction...`); } + processCmpData(provisionalConsent, { + onSuccess: continueToAuction, + onError: () => continueToAuction(storeConsentData(undefined)), + }) + } + + cmpCallMap[userCMP](callbacks); + if (!(actionTimeout != null && cmpLoaded)) { + resetTimeout(consentTimeout); } } @@ -313,11 +331,11 @@ export function resetConsentData() { * @param {{cmp:string, timeout:number, allowAuctionWithoutConsent:boolean, defaultGdprScope:boolean}} config required; consentManagement module config settings; cmp (string), timeout (int), allowAuctionWithoutConsent (boolean) */ export function setConsentConfig(config) { - // if `config.gdpr` or `config.usp` exist, assume new config format. + // if `config.gdpr`, `config.usp` or `config.gpp` exist, assume new config format. // else for backward compatability, just use `config` - config = config && (config.gdpr || config.usp ? config.gdpr : config); + config = config && (config.gdpr || config.usp || config.gpp ? config.gdpr : config); if (!config || typeof config !== 'object') { - logWarn('consentManagement config not defined, exiting consent manager'); + logWarn('consentManagement (gdpr) config not defined, exiting consent manager'); return; } if (isStr(config.cmpApi)) { @@ -334,6 +352,8 @@ export function setConsentConfig(config) { logInfo(`consentManagement config did not specify timeout. Using system default setting (${DEFAULT_CONSENT_TIMEOUT}).`); } + actionTimeout = isNumber(config.actionTimeout) ? config.actionTimeout : null; + // if true, then gdprApplies should be set to true gdprScope = config.defaultGdprScope === true; @@ -356,22 +376,27 @@ export function setConsentConfig(config) { } config.getConfig('consentManagement', config => setConsentConfig(config.consentManagement)); -export function setOrtbGdpr(ortbRequest, bidderRequest) { - const consent = bidderRequest.gdprConsent; - if (consent) { - if (typeof consent.gdprApplies === 'boolean') { - deepSetValue(ortbRequest, 'regs.ext.gdpr', consent.gdprApplies ? 1 : 0); +export function enrichFPDHook(next, fpd) { + return next(fpd.then(ortb2 => { + const consent = gdprDataHandler.getConsentData(); + if (consent) { + if (typeof consent.gdprApplies === 'boolean') { + deepSetValue(ortb2, 'regs.ext.gdpr', consent.gdprApplies ? 1 : 0); + } + deepSetValue(ortb2, 'user.ext.consent', consent.consentString); } - deepSetValue(ortbRequest, 'user.ext.consent', consent.consentString); - } + return ortb2; + })); } +enrichFPD.before(enrichFPDHook); + export function setOrtbAdditionalConsent(ortbRequest, bidderRequest) { + // this is not a standardized name for addtlConsent, so keep this as an ORTB library processor rather than an FPD enrichment const addtl = bidderRequest.gdprConsent?.addtlConsent; if (addtl && typeof addtl === 'string') { deepSetValue(ortbRequest, 'user.ext.ConsentedProvidersSettings.consented_providers', addtl); } } -registerOrtbProcessor({type: REQUEST, name: 'gdpr', fn: setOrtbGdpr}); registerOrtbProcessor({type: REQUEST, name: 'gdprAddtlConsent', fn: setOrtbAdditionalConsent}) diff --git a/modules/consentManagementGpp.js b/modules/consentManagementGpp.js new file mode 100644 index 00000000000..8a9c3f999f0 --- /dev/null +++ b/modules/consentManagementGpp.js @@ -0,0 +1,386 @@ +/** + * This module adds GPP consentManagement support to prebid.js. It interacts with + * supported CMPs (Consent Management Platforms) to grab the user's consent information + * and make it available for any GPP supported adapters to read/pass this information to + * their system and for various other features/modules in Prebid.js. + */ +import {deepSetValue, isNumber, isPlainObject, isStr, logError, logInfo, logWarn} from '../src/utils.js'; +import {config} from '../src/config.js'; +import {gppDataHandler} from '../src/adapterManager.js'; +import {includes} from '../src/polyfill.js'; +import {timedAuctionHook} from '../src/utils/perfMetrics.js'; +import { enrichFPD } from '../src/fpd/enrichment.js'; + +const DEFAULT_CMP = 'iab'; +const DEFAULT_CONSENT_TIMEOUT = 10000; +const CMP_VERSION = 1; + +export let userCMP; +export let consentTimeout; +export let staticConsentData; + +let consentData; +let addedConsentHook = false; + +// add new CMPs here, with their dedicated lookup function +const cmpCallMap = { + 'iab': lookupIabConsent, + 'static': lookupStaticConsentData +}; + +/** + * This function checks the state of the IAB gppData's applicableSection field (to ensure it's populated and has a valid value). + * section === 0 represents a CMP's default value when CMP is loading, it shoud not be used a real user's section. + * + * TODO --- The initial version of the GPP CMP API spec used this naming convention, but it was later changed as an update to the spec. + * CMPs should adjust their logic to use the new format (applicableSecctions), but that may not be the case with the initial release. + * Added support just in case for this transition period, can likely be removed at a later date... + * @param gppData represents the IAB gppData object + * @returns true|false + */ +function checkApplicableSectionIsReady(gppData) { + return gppData && Array.isArray(gppData.applicableSection) && gppData.applicableSection.length > 0 && gppData.applicableSection[0] !== 0; +} + +/** + * This function checks the state of the IAB gppData's applicableSections field (to ensure it's populated and has a valid value). + * section === 0 represents a CMP's default value when CMP is loading, it shoud not be used a real user's section. + * @param gppData represents the IAB gppData object + * @returns true|false + */ +function checkApplicableSectionsIsReady(gppData) { + return gppData && Array.isArray(gppData.applicableSections) && gppData.applicableSections.length > 0 && gppData.applicableSections[0] !== 0; +} + +/** + * This function reads the consent string from the config to obtain the consent information of the user. + * @param {function({})} onSuccess acts as a success callback when the value is read from config; pass along consentObject from CMP + */ +function lookupStaticConsentData({onSuccess, onError}) { + processCmpData(staticConsentData, {onSuccess, onError}); +} + +/** + * This function handles interacting with an IAB compliant CMP to obtain the consent information of the user. + * Given the async nature of the CMP's API, we pass in acting success/error callback functions to exit this function + * based on the appropriate result. + * @param {function({})} onSuccess acts as a success callback when CMP returns a value; pass along consentObjectfrom CMP + * @param {function(string, ...{}?)} cmpError acts as an error callback while interacting with CMP; pass along an error message (string) and any extra error arguments (purely for logging) + */ +function lookupIabConsent({onSuccess, onError}) { + const cmpApiName = '__gpp'; + const cmpCallbacks = {}; + let registeredPostMessageResponseListener = false; + + function findCMP() { + let f = window; + let cmpFrame; + let cmpDirectAccess = false; + while (true) { + try { + if (typeof f[cmpApiName] === 'function') { + cmpFrame = f; + cmpDirectAccess = true; + break; + } + } catch (e) {} + + // need separate try/catch blocks due to the exception errors thrown when trying to check for a frame that doesn't exist in 3rd party env + try { + if (f.frames['__gppLocator']) { + cmpFrame = f; + break; + } + } catch (e) {} + + if (f === window.top) break; + f = f.parent; + } + + return { + cmpFrame, + cmpDirectAccess + }; + } + + const {cmpFrame, cmpDirectAccess} = findCMP(); + + if (!cmpFrame) { + return onError('GPP CMP not found.'); + } + + const invokeCMP = (cmpDirectAccess) ? invokeCMPDirect : invokeCMPFrame; + + function invokeCMPDirect({command, callback, parameter, version = CMP_VERSION}, resultCb) { + if (typeof resultCb === 'function') { + resultCb(cmpFrame[cmpApiName](command, callback, parameter, version)); + } else { + cmpFrame[cmpApiName](command, callback, parameter, version); + } + } + + function invokeCMPFrame({command, callback, parameter, version = CMP_VERSION}, resultCb) { + const callName = `${cmpApiName}Call`; + if (!registeredPostMessageResponseListener) { + // when we get the return message, call the stashed callback; + window.addEventListener('message', readPostMessageResponse, false); + registeredPostMessageResponseListener = true; + } + + // call CMP via postMessage + const callId = Math.random().toString(); + const msg = { + [callName]: { + command: command, + parameter, + version, + callId: callId + } + }; + + // TODO? - add logic to check if random was already used in the same session, and roll another if so? + cmpCallbacks[callId] = (typeof callback === 'function') ? callback : resultCb; + cmpFrame.postMessage(msg, '*'); + + function readPostMessageResponse(event) { + const cmpDataPkgName = `${cmpApiName}Return`; + const json = (typeof event.data === 'string' && event.data.includes(cmpDataPkgName)) ? JSON.parse(event.data) : event.data; + if (json[cmpDataPkgName] && json[cmpDataPkgName].callId) { + const payload = json[cmpDataPkgName]; + + if (cmpCallbacks.hasOwnProperty(payload.callId)) { + cmpCallbacks[payload.callId](payload.returnValue); + } + } + } + } + + const startupMsg = (cmpDirectAccess) ? 'Detected GPP CMP API is directly accessible, calling it now...' + : 'Detected GPP CMP is outside the current iframe where Prebid.js is located, calling it now...'; + logInfo(startupMsg); + + invokeCMP({ + command: 'addEventListener', + callback: function (evt) { + if (evt) { + logInfo(`Received a ${(cmpDirectAccess ? 'direct' : 'postmsg')} response from GPP CMP for event`, evt); + if (evt.eventName === 'sectionChange' || evt.pingData.cmpStatus === 'loaded') { + invokeCMP({command: 'getGPPData'}, function (gppData) { + logInfo(`Received a ${cmpDirectAccess ? 'direct' : 'postmsg'} response from GPP CMP for getGPPData`, gppData); + processCmpData(gppData, {onSuccess, onError}); + }); + } else if (evt.pingData.cmpStatus === 'error') { + onError('CMP returned with a cmpStatus:error response. Please check CMP setup.'); + } + } + } + }); +} + +/** + * Look up consent data and store it in the `consentData` global as well as `adapterManager.js`' gdprDataHandler. + * + * @param cb A callback that takes: a boolean that is true if the auction should be canceled; an error message and extra + * error arguments that will be undefined if there's no error. + */ +function loadConsentData(cb) { + let isDone = false; + let timer = null; + + function done(consentData, shouldCancelAuction, errMsg, ...extraArgs) { + if (timer != null) { + clearTimeout(timer); + } + isDone = true; + gppDataHandler.setConsentData(consentData); + if (typeof cb === 'function') { + cb(shouldCancelAuction, errMsg, ...extraArgs); + } + } + + if (!includes(Object.keys(cmpCallMap), userCMP)) { + done(null, false, `GPP CMP framework (${userCMP}) is not a supported framework. Aborting consentManagement module and resuming auction.`); + return; + } + + const callbacks = { + onSuccess: (data) => done(data, false), + onError: function (msg, ...extraArgs) { + done(null, true, msg, ...extraArgs); + } + } + cmpCallMap[userCMP](callbacks); + + if (!isDone) { + const onTimeout = () => { + const continueToAuction = (data) => { + done(data, false, 'GPP CMP did not load, continuing auction...'); + } + processCmpData(consentData, { + onSuccess: continueToAuction, + onError: () => continueToAuction(storeConsentData(undefined)) + }) + } + if (consentTimeout === 0) { + onTimeout(); + } else { + timer = setTimeout(onTimeout, consentTimeout); + } + } +} + +/** + * Like `loadConsentData`, but cache and re-use previously loaded data. + * @param cb + */ +function loadIfMissing(cb) { + if (consentData) { + logInfo('User consent information already known. Pulling internally stored information...'); + // eslint-disable-next-line standard/no-callback-literal + cb(false); + } else { + loadConsentData(cb); + } +} + +/** + * If consentManagement module is enabled (ie included in setConfig), this hook function will attempt to fetch the + * user's encoded consent string from the supported CMP. Once obtained, the module will store this + * data as part of a gppConsent object which gets transferred to adapterManager's gppDataHandler object. + * This information is later added into the bidRequest object for any supported adapters to read/pass along to their system. + * @param {object} reqBidsConfigObj required; This is the same param that's used in pbjs.requestBids. + * @param {function} fn required; The next function in the chain, used by hook.js + */ +export const requestBidsHook = timedAuctionHook('gpp', function requestBidsHook(fn, reqBidsConfigObj) { + loadIfMissing(function (shouldCancelAuction, errMsg, ...extraArgs) { + if (errMsg) { + let log = logWarn; + if (shouldCancelAuction) { + log = logError; + errMsg = `${errMsg} Canceling auction as per consentManagement config.`; + } + log(errMsg, ...extraArgs); + } + + if (shouldCancelAuction) { + fn.stopTiming(); + if (typeof reqBidsConfigObj.bidsBackHandler === 'function') { + reqBidsConfigObj.bidsBackHandler(); + } else { + logError('Error executing bidsBackHandler'); + } + } else { + fn.call(this, reqBidsConfigObj); + } + }); +}); + +/** + * This function checks the consent data provided by CMP to ensure it's in an expected state. + * If it's bad, we call `onError` + * If it's good, then we store the value and call `onSuccess` + */ +function processCmpData(consentObject, {onSuccess, onError}) { + function checkData() { + const gppString = consentObject && consentObject.gppString; + const gppSection = (checkApplicableSectionsIsReady(consentObject)) ? consentObject.applicableSections + : (checkApplicableSectionIsReady(consentObject)) ? consentObject.applicableSection : []; + + return !!( + (!Array.isArray(gppSection)) || + (Array.isArray(gppSection) && (!gppString || !isStr(gppString))) + ); + } + + if (checkData()) { + onError(`CMP returned unexpected value during lookup process.`, consentObject); + } else { + onSuccess(storeConsentData(consentObject)); + } +} + +/** + * Stores CMP data locally in module to make information available in adaptermanager.js for later in the auction + * @param {object} cmpConsentObject required; an object representing user's consent choices (can be undefined in certain use-cases for this function only) + */ +function storeConsentData(cmpConsentObject) { + consentData = { + gppString: (cmpConsentObject) ? cmpConsentObject.gppString : undefined, + + fullGppData: (cmpConsentObject) || undefined, + }; + consentData.applicableSections = (checkApplicableSectionsIsReady(cmpConsentObject)) ? cmpConsentObject.applicableSections + : (checkApplicableSectionIsReady(cmpConsentObject)) ? cmpConsentObject.applicableSection : []; + consentData.apiVersion = CMP_VERSION; + return consentData; +} + +/** + * Simply resets the module's consentData variable back to undefined, mainly for testing purposes + */ +export function resetConsentData() { + consentData = undefined; + userCMP = undefined; + consentTimeout = undefined; + gppDataHandler.reset(); +} + +/** + * A configuration function that initializes some module variables, as well as add a hook into the requestBids function + * @param {{cmp:string, timeout:number, allowAuctionWithoutConsent:boolean, defaultGdprScope:boolean}} config required; consentManagement module config settings; cmp (string), timeout (int), allowAuctionWithoutConsent (boolean) + */ +export function setConsentConfig(config) { + config = config && config.gpp; + if (!config || typeof config !== 'object') { + logWarn('consentManagement.gpp config not defined, exiting consent manager module'); + return; + } + + if (isStr(config.cmpApi)) { + userCMP = config.cmpApi; + } else { + userCMP = DEFAULT_CMP; + logInfo(`consentManagement.gpp config did not specify cmp. Using system default setting (${DEFAULT_CMP}).`); + } + + if (isNumber(config.timeout)) { + consentTimeout = config.timeout; + } else { + consentTimeout = DEFAULT_CONSENT_TIMEOUT; + logInfo(`consentManagement.gpp config did not specify timeout. Using system default setting (${DEFAULT_CONSENT_TIMEOUT}).`); + } + + if (userCMP === 'static') { + if (isPlainObject(config.consentData)) { + staticConsentData = config.consentData; + consentTimeout = 0; + } else { + logError(`consentManagement.gpp config with cmpApi: 'static' did not specify consentData. No consents will be available to adapters.`); + } + } + + logInfo('consentManagement.gpp module has been activated...'); + + if (!addedConsentHook) { + $$PREBID_GLOBAL$$.requestBids.before(requestBidsHook, 50); + } + addedConsentHook = true; + gppDataHandler.enable(); + loadConsentData(); // immediately look up consent data to make it available without requiring an auction +} +config.getConfig('consentManagement', config => setConsentConfig(config.consentManagement)); + +export function enrichFPDHook(next, fpd) { + return next(fpd.then(ortb2 => { + const consent = gppDataHandler.getConsentData(); + if (consent) { + if (Array.isArray(consent.applicableSections)) { + deepSetValue(ortb2, 'regs.gpp_sid', consent.applicableSections); + } + deepSetValue(ortb2, 'regs.gpp', consent.gppString); + } + return ortb2; + })); +} + +enrichFPD.before(enrichFPDHook); diff --git a/modules/consentManagementUsp.js b/modules/consentManagementUsp.js index 1e77dd4ef48..fcc13152aa9 100644 --- a/modules/consentManagementUsp.js +++ b/modules/consentManagementUsp.js @@ -6,10 +6,10 @@ */ import {deepSetValue, isFn, isNumber, isPlainObject, isStr, logError, logInfo, logWarn} from '../src/utils.js'; import {config} from '../src/config.js'; -import {uspDataHandler} from '../src/adapterManager.js'; -import {registerOrtbProcessor, REQUEST} from '../src/pbjsORTB.js'; +import adapterManager, {uspDataHandler} from '../src/adapterManager.js'; import {timedAuctionHook} from '../src/utils/perfMetrics.js'; import {getHook} from '../src/hook.js'; +import {enrichFPD} from '../src/fpd/enrichment.js'; const DEFAULT_CONSENT_API = 'iab'; const DEFAULT_CONSENT_TIMEOUT = 50; @@ -100,6 +100,14 @@ function lookupUspConsent({onSuccess, onError}) { return onError('USP CMP not found.'); } + function registerDataDelHandler(invoker, arg2) { + try { + invoker('registerDeletion', arg2, adapterManager.callDataDeletionRequest); + } catch (e) { + logError('Error invoking CMP `registerDeletion`:', e); + } + } + // to collect the consent information from the user, we perform a call to USPAPI // to collect the user's consent choices represented as a string (via getUSPData) @@ -115,6 +123,7 @@ function lookupUspConsent({onSuccess, onError}) { USPAPI_VERSION, callbackHandler.consentDataCallback ); + registerDataDelHandler(uspapiFunction, USPAPI_VERSION); } else { logInfo( 'Detected USP CMP is outside the current iframe where Prebid.js is located, calling it now...' @@ -124,12 +133,13 @@ function lookupUspConsent({onSuccess, onError}) { uspapiFrame, callbackHandler.consentDataCallback ); + registerDataDelHandler(callUspApiWhileInIframe, uspapiFrame); } + let listening = false; + function callUspApiWhileInIframe(commandName, uspapiFrame, moduleCallback) { - /* Setup up a __uspapi function to do the postMessage and stash the callback. - This function behaves, from the caller's perspective, identicially to the in-frame __uspapi call (although it is not synchronous) */ - window.__uspapi = function (cmd, ver, callback) { + function callUsp(cmd, ver, callback) { let callId = Math.random() + ''; let msg = { __uspapiCall: { @@ -144,10 +154,13 @@ function lookupUspConsent({onSuccess, onError}) { }; /** when we get the return message, call the stashed callback */ - window.addEventListener('message', readPostMessageResponse, false); + if (!listening) { + window.addEventListener('message', readPostMessageResponse, false); + listening = true; + } // call uspapi - window.__uspapi(commandName, USPAPI_VERSION, moduleCallback); + callUsp(commandName, USPAPI_VERSION, moduleCallback); function readPostMessageResponse(event) { const res = event && event.data && event.data.__uspapiReturn; @@ -310,10 +323,14 @@ config.getConfig('consentManagement', config => setConsentConfig(config.consentM getHook('requestBids').before(requestBidsHook, 50); -export function setOrtbUsp(ortbRequest, bidderRequest) { - if (bidderRequest.uspConsent) { - deepSetValue(ortbRequest, 'regs.ext.us_privacy', bidderRequest.uspConsent); - } +export function enrichFPDHook(next, fpd) { + return next(fpd.then(ortb2 => { + const consent = uspDataHandler.getConsentData(); + if (consent) { + deepSetValue(ortb2, 'regs.ext.us_privacy', consent) + } + return ortb2; + })) } -registerOrtbProcessor({type: REQUEST, name: 'usp', fn: setOrtbUsp}); +enrichFPD.before(enrichFPDHook); diff --git a/modules/consumableBidAdapter.js b/modules/consumableBidAdapter.js index c91f1a7f906..4e2a92fb594 100644 --- a/modules/consumableBidAdapter.js +++ b/modules/consumableBidAdapter.js @@ -180,12 +180,26 @@ export const spec = { return bidResponses; }, - getUserSyncs: function(syncOptions, serverResponses) { + getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) { + let syncUrl = 'https://sync.serverbid.com/ss/' + siteId + '.html'; + if (syncOptions.iframeEnabled) { + if (gdprConsent && gdprConsent.consentString) { + if (typeof gdprConsent.gdprApplies === 'boolean') { + syncUrl = appendUrlParam(syncUrl, `gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`); + } else { + syncUrl = appendUrlParam(syncUrl, `gdpr=0&gdpr_consent=${gdprConsent.consentString}`); + } + } + + if (uspConsent && uspConsent.consentString) { + syncUrl = appendUrlParam(syncUrl, `us_privacy=${uspConsent.consentString}`); + } + if (!serverResponses || serverResponses.length === 0 || !serverResponses[0].body.bdr || serverResponses[0].body.bdr !== 'cx') { return [{ type: 'iframe', - url: 'https://sync.serverbid.com/ss/' + siteId + '.html' + url: syncUrl }]; } } @@ -294,4 +308,8 @@ function getBidFloor(bid, sizes) { return floor; } +function appendUrlParam(url, queryString) { + return `${url}${url.indexOf('?') > -1 ? '&' : '?'}${queryString}`; +} + registerBidder(spec); diff --git a/modules/conversantAnalyticsAdapter.js b/modules/conversantAnalyticsAdapter.js index 6e88f403bae..e934f1bb153 100644 --- a/modules/conversantAnalyticsAdapter.js +++ b/modules/conversantAnalyticsAdapter.js @@ -3,20 +3,25 @@ import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import CONSTANTS from '../src/constants.json'; import {getGlobal} from '../src/prebidGlobal.js'; import adapterManager from '../src/adapterManager.js'; -import {logInfo, logError, logMessage, deepAccess, isInteger} from '../src/utils.js'; +import {logInfo, logWarn, logError, logMessage, deepAccess, isInteger} from '../src/utils.js'; +import {getRefererInfo} from '../src/refererDetection.js'; const { - EVENTS: { AUCTION_END, AD_RENDER_FAILED, BID_TIMEOUT, BID_WON } + EVENTS: { AUCTION_END, AD_RENDER_FAILED, BID_TIMEOUT, BID_WON, BIDDER_ERROR } } = CONSTANTS; +// STALE_RENDER, TCF2_ENFORCEMENT would need to add extra calls for these as they likely occur after AUCTION_END? const GVLID = 24; const ANALYTICS_TYPE = 'endpoint'; // for local testing set domain to 127.0.0.1:8290 -const URL = 'https://web.hb.ad.cpe.dotomi.com/cvx/event/prebidanalytics'; +const DOMAIN = 'https://web.hb.ad.cpe.dotomi.com/'; +const ANALYTICS_URL = DOMAIN + 'cvx/event/prebidanalytics'; +const ERROR_URL = DOMAIN + 'cvx/event/prebidanalyticerrors'; const ANALYTICS_CODE = 'conversant'; export const CNVR_CONSTANTS = { LOG_PREFIX: 'Conversant analytics adapter: ', + ERROR_MISSING_DATA_PREFIX: 'Parsing method failed because of missing data: ', // Maximum time to keep an item in the cache before it gets purged MAX_MILLISECONDS_IN_CACHE: 30000, // How often cache cleanup will run @@ -41,6 +46,7 @@ let conversantAnalyticsEnabled = false; export const cnvrHelper = { // Turns on sampling for an instance of prebid analytics. doSample: true, + doSendErrorData: false, /** * Used to hold data for RENDER FAILED events so we can send a payload back that will match our original auction data. @@ -67,7 +73,12 @@ export const cnvrHelper = { /** * Lookup of auction IDs to auction start timestamps */ - auctionIdTimestampCache: {} + auctionIdTimestampCache: {}, + + /** + * Capture any bidder errors and bundle them with AUCTION_END + */ + bidderErrorCache: {} }; /** @@ -77,33 +88,99 @@ export const cnvrHelper = { let cacheCleanupInterval; let conversantAnalytics = Object.assign( - adapter({URL, ANALYTICS_TYPE}), + adapter({URL: ANALYTICS_URL, ANALYTICS_TYPE}), { track({eventType, args}) { - if (cnvrHelper.doSample) { - logMessage(CNVR_CONSTANTS.LOG_PREFIX + ' track(): ' + eventType, args); - switch (eventType) { - case AUCTION_END: - onAuctionEnd(args); - break; - case AD_RENDER_FAILED: - onAdRenderFailed(args); - break; - case BID_WON: - onBidWon(args); - break; - case BID_TIMEOUT: - onBidTimeout(args); - break; - } // END switch - } else { - logMessage(CNVR_CONSTANTS.LOG_PREFIX + ' - ' + eventType + ': skipped due to sampling'); - }// END IF(cnvrHelper.doSample) + try { + if (cnvrHelper.doSample) { + logMessage(CNVR_CONSTANTS.LOG_PREFIX + ' track(): ' + eventType, args); + switch (eventType) { + case AUCTION_END: + onAuctionEnd(args); + break; + case AD_RENDER_FAILED: + onAdRenderFailed(args); + break; + case BID_WON: + onBidWon(args); + break; + case BID_TIMEOUT: + onBidTimeout(args); + break; + case BIDDER_ERROR: + onBidderError(args) + } // END switch + } else { + logMessage(CNVR_CONSTANTS.LOG_PREFIX + ' - ' + eventType + ': skipped due to sampling'); + }// END IF(cnvrHelper.doSample) + } catch (e) { + // e = {stack:"...",message:"..."} + logError(CNVR_CONSTANTS.LOG_PREFIX + 'Caught error in handling ' + eventType + ' event: ' + e.message); + cnvrHelper.sendErrorData(eventType, e); + } } // END track() } ); // ================================================== EVENT HANDLERS =================================================== + +/** + * Handler for BIDDER_ERROR events, tries to capture as much data, save it in cache which is then picked up by + * AUCTION_END event and included in that payload. Was not able to see an easy way to get adUnitCode in this event + * so not including it for now. + * https://docs.prebid.org/dev-docs/bidder-adaptor.html#registering-on-bidder-error + * Trigger when the HTTP response status code is not between 200-299 and not equal to 304. + { + error: XMLHttpRequest, https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest + bidderRequest: { https://docs.prebid.org/dev-docs/bidder-adaptor.html#registering-on-bidder-error + { + auctionId: "b06c5141-fe8f-4cdf-9d7d-54415490a917", + auctionStart: 1579746300522, + bidderCode: "myBidderCode", + bidderRequestId: "15246a574e859f", + bids: [{...}], + gdprConsent: {consentString: "BOtmiBKOtmiBKABABAENAFAAAAACeAAA", vendorData: {...}, gdprApplies: true}, + refererInfo: { + canonicalUrl: null, + page: "http://mypage.org?pbjs_debug=true", + domain: "mypage.org", + ref: null, + numIframes: 0, + reachedTop: true, + isAmp: false, + stack: ["http://mypage.org?pbjs_debug=true"] + } + } + } +} + */ +function onBidderError(args) { + if (!cnvrHelper.doSendErrorData) { + logWarn(CNVR_CONSTANTS.LOG_PREFIX + 'Skipping bidder error parsing due to config disabling error logging, bidder error status = ' + args.error.status + ', Message = ' + args.error.statusText); + return; + } + + let error = args.error; + let bidRequest = args.bidderRequest; + let auctionId = bidRequest.auctionId; + let bidderCode = bidRequest.bidderCode; + logWarn(CNVR_CONSTANTS.LOG_PREFIX + 'onBidderError(): error received from bidder ' + bidderCode + '. Status = ' + error.status + ', Message = ' + error.statusText); + let errorObj = { + status: error.status, + message: error.statusText, + bidderCode: bidderCode, + url: cnvrHelper.getPageUrl(), + }; + if (cnvrHelper.bidderErrorCache[auctionId]) { + cnvrHelper.bidderErrorCache[auctionId]['errors'].push(errorObj); + } else { + cnvrHelper.bidderErrorCache[auctionId] = { + errors: [errorObj], + timeReceived: Date.now() + }; + } +} + /** * We get the list of timeouts before the endAution, cache them temporarily in a global cache and the endAuction event * will pick them up. Uses getLookupKey() to create the key to the entry from auctionId, adUnitCode and bidderCode. @@ -145,8 +222,13 @@ function onBidWon(args) { // Make sure we have all the data we need if (!bidderCode || !adUnitCode || !auctionId) { - logError(CNVR_CONSTANTS.LOG_PREFIX + 'onBidWon() did not get all the necessary data to process the event.'); - return; + let errorReason = 'auction id'; + if (!bidderCode) { + errorReason = 'bidder code'; + } else if (!adUnitCode) { + errorReason = 'ad unit code' + } + throw new Error(CNVR_CONSTANTS.ERROR_MISSING_DATA_PREFIX + errorReason); } if (cnvrHelper.auctionIdTimestampCache[auctionId]) { @@ -193,8 +275,12 @@ function onAdRenderFailed(args) { // Make sure we have all the data we need, adId is optional so it's not guaranteed, without that we can't match it up // to our adIdLookup data. if (!adId || !cnvrHelper.adIdLookup[adId]) { - logError(CNVR_CONSTANTS.LOG_PREFIX + "onAdRenderFailed(): Unable to process RENDER FAILED because adId is missing or doesn't match a record in our cache."); - return; // Either no adId to match against a bidWon event, or no data saved from a bidWon event that matches the adId + let errorMsg = 'ad id'; + if (adId) { + errorMsg = 'no lookup data for ad id'; + } + // Either no adId to match against a bidWon event, or no data saved from a bidWon event that matches the adId + throw new Error(CNVR_CONSTANTS.ERROR_MISSING_DATA_PREFIX + errorMsg); } const adIdObj = cnvrHelper.adIdLookup[adId]; const adUnitCode = adIdObj['adUnitCode']; @@ -203,8 +289,13 @@ function onAdRenderFailed(args) { delete cnvrHelper.adIdLookup[adId]; // cleanup our cache if (!bidderCode || !adUnitCode || !auctionId) { - logError(CNVR_CONSTANTS.LOG_PREFIX + 'onAdRenderFailed(): Unable to process RENDER FAILED because lookup cache did not have all the data we required.'); - return; + let errorReason = 'auction id'; + if (!bidderCode) { + errorReason = 'bidder code'; + } else if (!adUnitCode) { + errorReason = 'ad unit code' + } + throw new Error(CNVR_CONSTANTS.ERROR_MISSING_DATA_PREFIX + errorReason); } let timestamp = Date.now(); @@ -230,8 +321,7 @@ function onAdRenderFailed(args) { function onAuctionEnd(args) { const auctionId = args.auctionId; if (!auctionId) { - logError(CNVR_CONSTANTS.LOG_PREFIX + 'onAuctionEnd(): No auctionId in args supplied so unable to process event.'); - return; + throw new Error(CNVR_CONSTANTS.ERROR_MISSING_DATA_PREFIX + 'auction id'); } const auctionTimestamp = args.timestamp ? args.timestamp : Date.now(); @@ -240,8 +330,13 @@ function onAuctionEnd(args) { const auctionEndPayload = cnvrHelper.createPayload('auction_end', auctionId, auctionTimestamp); // Get bid request information from adUnits if (!Array.isArray(args.adUnits)) { - logError(CNVR_CONSTANTS.LOG_PREFIX + 'onAuctionEnd(): adUnits not defined in arguments.'); - return; + throw new Error(CNVR_CONSTANTS.ERROR_MISSING_DATA_PREFIX + 'no adUnits in event args'); + } + + // Write out any bid errors + if (cnvrHelper.bidderErrorCache[auctionId]) { + auctionEndPayload.bidderErrors = cnvrHelper.bidderErrorCache[auctionId].errors; + delete cnvrHelper.bidderErrorCache[auctionId]; } args.adUnits.forEach(adUnit => { @@ -298,7 +393,7 @@ function onAuctionEnd(args) { } }); } else { - logError(CNVR_CONSTANTS.LOG_PREFIX + 'onAuctionEnd(): noBids not defined in arguments.'); + logWarn(CNVR_CONSTANTS.LOG_PREFIX + 'onAuctionEnd(): noBids not defined in arguments.'); } // Get bid data from bids sent @@ -321,7 +416,7 @@ function onAuctionEnd(args) { } }); } else { - logError(CNVR_CONSTANTS.LOG_PREFIX + 'onAuctionEnd(): bidsReceived not defined in arguments.'); + logWarn(CNVR_CONSTANTS.LOG_PREFIX + 'onAuctionEnd(): bidsReceived not defined in arguments.'); } // We need to remove any duplicate ad sizes from merging ad-slots or overlap in different media types and also // media-types from merged ad-slots in twin bids. @@ -423,7 +518,8 @@ cnvrHelper.createPayload = function(payloadType, auctionId, timestamp) { sid: initOptions.site_id, auctionTimestamp: timestamp }, - adUnits: {} + adUnits: {}, + bidderErrors: [] }; }; @@ -488,13 +584,49 @@ cnvrHelper.getSampleRate = function(parentObj, propNm, defaultSampleRate) { return sampleRate; } +/** + * Helper to encapsulate logic for getting best known page url. Small but helpful in debugging/testing and if we ever want + * to add more logic to this. + * + * From getRefererInfo(): page = the best candidate for the current page URL: `canonicalUrl`, falling back to `location` + * @returns {*} Best guess at top URL based on logic from RefererInfo. + */ +cnvrHelper.getPageUrl = function() { + return getRefererInfo().page; +} + +/** + * Packages up an error that occured in analytics handling and sends it back to our servers for logging + * @param eventType = original event that was fired + * @param exception = {stack:"...",message:"..."}, exception that was triggered + */ +cnvrHelper.sendErrorData = function(eventType, exception) { + if (!cnvrHelper.doSendErrorData) { + logWarn(CNVR_CONSTANTS.LOG_PREFIX + 'Skipping sending error data due to config disabling error logging, error thrown = ' + exception); + return; + } + + let error = { + event: eventType, + siteId: initOptions.site_id, + message: exception.message, + stack: exception.stack, + prebidVersion: '$$REPO_AND_VERSION$$', // testing val sample: prebid_prebid_7.27.0-pre' + userAgent: navigator.userAgent, + url: cnvrHelper.getPageUrl() + }; + + // eslint-disable-next-line no-undef + ajax(ERROR_URL, function () {}, JSON.stringify(error), {contentType: 'text/plain'}); +} + /** * Helper function to send data back to server. Need to make sure we don't trigger a CORS preflight by not adding * extra header params. * @param payload our JSON payload from either AUCTION END, BID WIN, RENDER FAILED */ function sendData(payload) { - ajax(URL, function () {}, JSON.stringify(payload), {contentType: 'text/plain'}); + ajax(ANALYTICS_URL, function () {}, JSON.stringify(payload), {contentType: 'text/plain'}); } // =============================== BOILERPLATE FOR PRE-BID ANALYTICS SETUP ============================================ @@ -515,6 +647,7 @@ conversantAnalytics.enableAnalytics = function (config) { cnvrHelper.cleanCache(cnvrHelper.adIdLookup, currTime); cnvrHelper.cleanCache(cnvrHelper.timeoutCache, currTime); cnvrHelper.cleanCache(cnvrHelper.auctionIdTimestampCache, currTime); + cnvrHelper.cleanCache(cnvrHelper.bidderErrorCache, currTime); }, CNVR_CONSTANTS.CACHE_CLEANUP_TIME_IN_MILLIS ); @@ -529,6 +662,10 @@ conversantAnalytics.enableAnalytics = function (config) { // Math.random() pseudo-random number in the range 0 to less than 1 (inclusive of 0, but not 1) cnvrHelper.doSample = Math.random() < initOptions.cnvr_sample_rate; + if (initOptions.send_error_data !== undefined && initOptions.send_error_data !== null) { + cnvrHelper.doSendErrorData = !!initOptions.send_error_data; // Forces data into boolean type + } + conversantAnalyticsEnabled = true; conversantAnalytics.originEnableAnalytics(config); // call the base class function }; @@ -546,6 +683,7 @@ conversantAnalytics.disableAnalytics = function () { cnvrHelper.timeoutCache = {}; cnvrHelper.adIdLookup = {}; cnvrHelper.auctionIdTimestampCache = {}; + cnvrHelper.bidderErrorCache = {}; conversantAnalyticsEnabled = false; conversantAnalytics.originDisableAnalytics(); diff --git a/modules/conversantAnalyticsAdapter.md b/modules/conversantAnalyticsAdapter.md index 51db983a8bd..2f026cbcbb9 100644 --- a/modules/conversantAnalyticsAdapter.md +++ b/modules/conversantAnalyticsAdapter.md @@ -1,37 +1,36 @@ # Overview -- Module Name: Conversant Bidder Adapter +- Module Name: Epsilon Analytics Adapter - Module Type: Analytics Adapter -- Maintainer: mediapsr@conversantmedia.com +- Maintainer: mediapsr@epsilon.com ## Description -Analytics adapter for Conversant is used to track performance of Prebid auctions. See the usage below for how to +Analytics adapter for Epsilon (formerly Conversant) is used to track performance of Prebid auctions. See the usage below for how to configure the adapter for your webpage. To enable analytics and gain access to the data publishers will need - to contact their Conversant representative. + to contact their Epsilon representative (publishersupport@epsilon.com). ## Setup -Before any analytics are recorded for your website you will need to have a Conversant representative turn +Before any analytics are recorded for your website you will need to have an Epsilon representative turn on Prebid analytics for your website. -The simplest configuration to add Conversant Prebid analytics to your page is as follows: +The simplest configuration to add Epsilon Prebid analytics to your page is as follows: ``` pbjs.que.push(function() { pbjs.enableAnalytics({ provider: 'conversant', options: { - site_id: '' + site_id: } }) }); ``` -Additionally the following options are supported: +Additionally, the following options are supported: -- **sampleRate**: Expects an integer from 0 to 100. By default only 50% (corresponds to a value of 50) of instances are enabled -for Conversant Prebid Analytics. This field allows the publisher to override that percentage to sample -at a higher or lower rate. '0' would completely disable sampling and '100' would capture every instance. +- **cnvr_sampling**: Sample rate for analytics data. Value should be between 0 and 1 (inclusive), 0 == never sample, +1 == always sample, 0.5 == send analytics 50% of the time. ### Complete Example ``` @@ -39,8 +38,8 @@ at a higher or lower rate. '0' would completely disable sampling and '100' would pbjs.enableAnalytics({ provider: 'conversant', options: { - site_id: '1234', - sampleRate: 90 + site_id: 1234, + cnvr_sampling: 0.9 } }) }); diff --git a/modules/conversantBidAdapter.md b/modules/conversantBidAdapter.md index 07d9abf918b..baf8b756aca 100644 --- a/modules/conversantBidAdapter.md +++ b/modules/conversantBidAdapter.md @@ -1,12 +1,12 @@ # Overview -- Module Name: Conversant Bidder Adapter +- Module Name: Epsilon Bidder Adapter - Module Type: Bidder Adapter -- Maintainer: mediapsr@conversantmedia.com +- Maintainer: mediapsr@epsilon.com # Description -Module that connects to Conversant's demand sources. Supports banners and videos. +Module that connects to Epsilon's (formerly Conversant) demand sources. Supports banners and videos. # Test Parameters ``` diff --git a/modules/cpexIdSystem.md b/modules/cpexIdSystem.md deleted file mode 100644 index 8aceb7fe4ec..00000000000 --- a/modules/cpexIdSystem.md +++ /dev/null @@ -1,27 +0,0 @@ -## CPEx User ID Submodule - -CPExID is provided by [Czech Publisher Exchange](https://www.cpex.cz/), or CPEx. It is a user ID for ad targeting by using first party cookie, or localStorage mechanism. Please contact CPEx before using this ID. - -## Building Prebid with CPExID Support - -First, make sure to add the cpexId to your Prebid.js package with: - -``` -gulp build --modules=cpexIdSystem -``` - -The following configuration parameters are available: - -```javascript -pbjs.setConfig({ - userSync: { - userIds: [{ - name: 'cpexId' - }] - } -}); -``` - -| Param under userSync.userIds[] | Scope | Type | Description | Example | -| --- | --- | --- | --- | --- | -| name | Required | String | The name of this module. | `"cpexId"` | diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js index 622c42c9cb7..f7ba82d3e06 100644 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -11,7 +11,7 @@ import { getRefererInfo } from '../src/refererDetection.js'; import { hasPurpose1Consent } from '../src/utils/gpdr.js'; const GVLID = 91; -export const ADAPTER_VERSION = 34; +export const ADAPTER_VERSION = 35; const BIDDER_CODE = 'criteo'; const CDB_ENDPOINT = 'https://bidder.criteo.com/cdb'; const PROFILE_ID_INLINE = 207; @@ -27,7 +27,7 @@ const LOG_PREFIX = 'Criteo: '; Unminified source code can be found in the privately shared repo: https://github.com/Prebid-org/prebid-js-external-js-criteo/blob/master/dist/prod.js */ const FAST_BID_VERSION_PLACEHOLDER = '%FAST_BID_VERSION%'; -export const FAST_BID_VERSION_CURRENT = 130; +export const FAST_BID_VERSION_CURRENT = 135; const FAST_BID_VERSION_LATEST = 'latest'; const FAST_BID_VERSION_NONE = 'none'; const PUBLISHER_TAG_URL_TEMPLATE = 'https://static.criteo.net/js/ld/publishertag.prebid' + FAST_BID_VERSION_PLACEHOLDER + '.js'; @@ -523,9 +523,8 @@ function buildCdbRequest(context, bidRequests, bidderRequest) { } }; }; - request.user = { - ext: bidderRequest.userExt - }; + request.user = bidderRequest.ortb2?.user || {}; + request.site = bidderRequest.ortb2?.site || {}; if (bidderRequest && bidderRequest.ceh) { request.user.ceh = bidderRequest.ceh; } @@ -672,18 +671,18 @@ function enrichSlotWithFloors(slot, bidRequest) { if (bidRequest.mediaTypes?.banner) { slotFloors.banner = {}; const bannerSizes = parseSizes(deepAccess(bidRequest, 'mediaTypes.banner.sizes')) - bannerSizes.forEach(bannerSize => slotFloors.banner[parseSize(bannerSize).toString()] = getFloor({ size: bannerSize, mediaType: BANNER })); + bannerSizes.forEach(bannerSize => slotFloors.banner[parseSize(bannerSize).toString()] = getFloor.call(bidRequest, { size: bannerSize, mediaType: BANNER })); } if (bidRequest.mediaTypes?.video) { slotFloors.video = {}; const videoSizes = parseSizes(deepAccess(bidRequest, 'mediaTypes.video.playerSize')) - videoSizes.forEach(videoSize => slotFloors.video[parseSize(videoSize).toString()] = getFloor({ size: videoSize, mediaType: VIDEO })); + videoSizes.forEach(videoSize => slotFloors.video[parseSize(videoSize).toString()] = getFloor.call(bidRequest, { size: videoSize, mediaType: VIDEO })); } if (bidRequest.mediaTypes?.native) { slotFloors.native = {}; - slotFloors.native['*'] = getFloor({ size: '*', mediaType: NATIVE }); + slotFloors.native['*'] = getFloor.call(bidRequest, { size: '*', mediaType: NATIVE }); } if (Object.keys(slotFloors).length > 0) { diff --git a/modules/cwireBidAdapter.js b/modules/cwireBidAdapter.js index a11899609bc..604d7235d0f 100644 --- a/modules/cwireBidAdapter.js +++ b/modules/cwireBidAdapter.js @@ -1,307 +1,234 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; import {getStorageManager} from '../src/storageManager.js'; -import {BANNER, VIDEO} from '../src/mediaTypes.js'; -import {OUTSTREAM} from '../src/video.js'; -import { - deepAccess, - generateUUID, - getBidIdParameter, - getParameterByName, - getValue, - isArray, - isNumber, - isStr, - logError, - logWarn, - parseSizesInput, -} from '../src/utils.js'; -import {Renderer} from '../src/Renderer.js'; -import {find} from '../src/polyfill.js'; +import {BANNER} from '../src/mediaTypes.js'; +import {generateUUID, getParameterByName, isNumber, logError, logInfo} from '../src/utils.js'; // ------------------------------------ const BIDDER_CODE = 'cwire'; -export const ENDPOINT_URL = 'https://embed.cwi.re/delivery/prebid'; -export const RENDERER_URL = 'https://cdn.cwi.re/prebid/renderer/LATEST/renderer.min.js'; -// ------------------------------------ -export const CW_PAGE_VIEW_ID = generateUUID(); -const LS_CWID_KEY = 'cw_cwid'; -const CW_GROUPS_QUERY = 'cwgroups'; -const CW_CREATIVE_QUERY = 'cwcreative'; +const CWID_KEY = 'cw_cwid'; -const storage = getStorageManager({bidderCode: BIDDER_CODE}); +export const BID_ENDPOINT = 'https://prebid.cwi.re/v1/bid'; +export const EVENT_ENDPOINT = 'https://prebid.cwi.re/v1/event'; /** - * ------------------------------------ - * ------------------------------------ - * @param bid - * @returns {Array} + * Allows limiting ad impressions per site render. Unique per prebid instance ID. */ -export function getSlotSizes(bid) { - return parseSizesInput(getAllMediaSizes(bid)); -} +export const pageViewId = generateUUID(); + +export const storage = getStorageManager({bidderCode: BIDDER_CODE}); /** - * ------------------------------------ - * ------------------------------------ + * Retrieve dimensions and CSS max height/width from a given slot and attach the properties to the bidRequest. * @param bid - * @returns {*[]} + * @returns {*&{cwExt: {dimensions: {width: number, height: number}, style: {maxWidth: number, maxHeight: number}}}} */ -export function getAllMediaSizes(bid) { - let playerSizes = deepAccess(bid, 'mediaTypes.video.playerSize'); - let videoSizes = deepAccess(bid, 'mediaTypes.video.sizes'); - let bannerSizes = deepAccess(bid, 'mediaTypes.banner.sizes'); - - const sizes = []; - - if (isArray(playerSizes)) { - playerSizes.forEach((s) => { - sizes.push(s); - }) - } - - if (isArray(videoSizes)) { - videoSizes.forEach((s) => { - sizes.push(s); - }) +function slotDimensions(bid) { + let adUnitCode = bid.adUnitCode; + let slotEl = document.getElementById(adUnitCode); + + if (slotEl) { + logInfo(`Slot element found: ${adUnitCode}`) + const slotW = slotEl.offsetWidth + const slotH = slotEl.offsetHeight + const cssMaxW = slotEl.style?.maxWidth; + const cssMaxH = slotEl.style?.maxHeight; + logInfo(`Slot dimensions (w/h): ${slotW} / ${slotH}`) + logInfo(`Slot Styles (maxW/maxH): ${cssMaxW} / ${cssMaxH}`) + + bid = { + ...bid, + cwExt: { + dimensions: { + width: slotW, + height: slotH, + }, + style: { + ...(cssMaxW) && { + maxWidth: cssMaxW + }, + ...(cssMaxH) && { + maxHeight: cssMaxH + } + } + } + } } + return bid +} - if (isArray(bannerSizes)) { - bannerSizes.forEach((s) => { - sizes.push(s); - }) +/** + * Extracts feature flags from a comma-separated url parameter `cwfeatures`. + * + * @returns *[] + */ +function getFeatureFlags() { + let ffParam = getParameterByName('cwfeatures') + if (ffParam) { + return ffParam.split(',') } - return sizes; + return [] } -const getQueryVariable = (variable) => { - let value = getParameterByName(variable); - if (value === '') { - value = null; +function getRefGroups() { + const groups = getParameterByName('cwgroups') + if (groups) { + return groups.split(',') } - return value; -}; + return [] +} /** - * ------------------------------------ - * ------------------------------------ - * @param validBidRequests - * @returns {*[]} + * Reads the CWID from local storage. */ -export const mapSlotsData = function(validBidRequests) { - const slots = []; - validBidRequests.forEach(bid => { - const bidObj = {}; - // get testing / debug params - let cwcreative = getValue(bid.params, 'cwcreative'); - let refgroups = getValue(bid.params, 'refgroups'); - let cwapikey = getValue(bid.params, 'cwapikey'); +function getCwid() { + return storage.localStorageIsEnabled() ? storage.getDataFromLocalStorage(CWID_KEY) : null; +} - // get the pacement and page ids - let placementId = getValue(bid.params, 'placementId'); - let pageId = getValue(bid.params, 'pageId'); - // get the rest of the auction/bid/transaction info - bidObj.auctionId = getBidIdParameter('auctionId', bid); - bidObj.adUnitCode = getBidIdParameter('adUnitCode', bid); - bidObj.bidId = getBidIdParameter('bidId', bid); - bidObj.bidderRequestId = getBidIdParameter('bidderRequestId', bid); - bidObj.placementId = placementId; - bidObj.pageId = pageId; - bidObj.mediaTypes = getBidIdParameter('mediaTypes', bid); - bidObj.transactionId = getBidIdParameter('transactionId', bid); - bidObj.sizes = getSlotSizes(bid); - bidObj.cwcreative = cwcreative; - bidObj.refgroups = refgroups; - bidObj.cwapikey = cwapikey; - slots.push(bidObj); - }); +function hasCwid() { + return storage.localStorageIsEnabled() && storage.getDataFromLocalStorage(CWID_KEY); +} - return slots; -}; +/** + * Store the CWID to local storage. + */ +function updateCwid(cwid) { + if (storage.localStorageIsEnabled()) { + storage.setDataInLocalStorage(CWID_KEY, cwid) + } else { + logInfo(`Could not set CWID ${cwid} in localstorage`); + } +} + +/** + * Extract and collect cwire specific extensions. + */ +function getCwExtension() { + const cwId = getCwid(); + const cwCreative = getParameterByName('cwcreative') + const cwGroups = getRefGroups() + const cwFeatures = getFeatureFlags(); + // Enable debug flag by passing ?cwdebug=true as url parameter. + // Note: pbjs_debug=true enables it on prebid level + // More info: https://docs.prebid.org/troubleshooting/troubleshooting-guide.html#turn-on-prebidjs-debug-messages + const debug = getParameterByName('cwdebug'); + + return { + ...(cwId) && { + cwid: cwId + }, + ...(cwGroups.length > 0) && { + refgroups: cwGroups + }, + ...(cwFeatures.length > 0) && { + featureFlags: cwFeatures + }, + ...(cwCreative) && { + cwcreative: cwCreative + }, + ...(debug) && { + debug: true + } + }; +} export const spec = { code: BIDDER_CODE, - supportedMediaTypes: [BANNER, VIDEO], + supportedMediaTypes: [BANNER], + /** - * Determines whether or not the given bid request is valid. + * Determines whether 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) { - bid.params = bid.params || {}; - - if (bid.params.cwcreative && !isStr(bid.params.cwcreative)) { - logError('cwcreative must be of type string!'); - return false; - } - - if (!bid.params.placementId || !isNumber(bid.params.placementId)) { - logError('placementId not provided or invalid'); + isBidRequestValid: function (bid) { + if (!bid.params?.placementId || !isNumber(bid.params.placementId)) { + logError('placementId not provided or not a number'); return false; } - if (!bid.params.pageId || !isNumber(bid.params.pageId)) { - logError('pageId not provided'); + if (!bid.params?.pageId || !isNumber(bid.params.pageId)) { + logError('pageId not provided or not a number'); return false; } - return true; }, /** - * ------------------------------------ - * itterate trough slots array and try - * to extract first occurence of a given - * key, if not found - return null - * ------------------------------------ - */ - getFirstValueOrNull: function(slots, key) { - const found = slots.find((item) => { - return (typeof item[key] !== 'undefined'); - }); - - return (found) ? found[key] : null; - }, - - /** - * ------------------------------------ - * Make a server request from the - * list of BidRequests. - * ------------------------------------ - * @param {validBidRequests[]} - an array of bids + * Make a server request from the list of BidRequests. + * + * @param {validBidRequests[]} validBidRequests An array of bids. * @return ServerRequest Info describing the request to the server. */ - buildRequests: function(validBidRequests, bidderRequest) { - let slots = []; - let referer; - try { - referer = bidderRequest?.refererInfo?.page; - slots = mapSlotsData(validBidRequests); - } catch (e) { - logWarn(e); - } + buildRequests: function (validBidRequests, bidderRequest) { + // There are more fields on the refererInfo object + let referrer = bidderRequest?.refererInfo?.page - let refgroups = []; - - const cwCreative = getQueryVariable(CW_CREATIVE_QUERY) || null; - const cwCreativeIdFromConfig = this.getFirstValueOrNull(slots, 'cwcreative'); - const refGroupsFromConfig = this.getFirstValueOrNull(slots, 'refgroups'); - const cwApiKeyFromConfig = this.getFirstValueOrNull(slots, 'cwapikey'); - const rgQuery = getQueryVariable(CW_GROUPS_QUERY); - - if (refGroupsFromConfig !== null) { - refgroups = refGroupsFromConfig.split(','); - } - - if (rgQuery !== null) { - // override if query param is present - refgroups = []; - refgroups = rgQuery.split(','); - } - - const localStorageCWID = storage.localStorageIsEnabled() ? storage.getDataFromLocalStorage(LS_CWID_KEY) : null; + // process bid requests + let processed = validBidRequests + .map(bid => slotDimensions(bid)) + // Flattens the pageId and placement Id for backwards compatibility. + .map((bid) => ({...bid, pageId: bid.params?.pageId, placementId: bid.params?.placementId})); + const extensions = getCwExtension(); const payload = { - cwid: localStorageCWID, - refgroups, - cwcreative: cwCreative || cwCreativeIdFromConfig, - slots: slots, - cwapikey: cwApiKeyFromConfig, - httpRef: referer || '', - pageViewId: CW_PAGE_VIEW_ID, + slots: processed, + httpRef: referrer, + // TODO: Verify whether the auctionId and the usage of pageViewId make sense. + pageViewId: pageViewId, + sdk: { + version: '$prebid.version$' + }, + ...extensions }; - + const payloadString = JSON.stringify(payload); return { method: 'POST', - url: ENDPOINT_URL, - data: payload + url: BID_ENDPOINT, + data: payloadString, }; }, - /** * 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, bidRequest) { - const bidResponses = []; - - try { - if (typeof bidRequest.data === 'string') { - bidRequest.data = JSON.parse(bidRequest.data); + interpretResponse: function (serverResponse, bidRequest) { + if (!hasCwid()) { + const cwid = serverResponse.body?.cwid + if (cwid) { + updateCwid(cwid); } - const serverBody = serverResponse.body; - serverBody.bids.forEach((br) => { - const bidReq = find(bidRequest.data.slots, bid => bid.bidId === br.requestId); - - let mediaType = BANNER; - - const bidResponse = { - requestId: br.requestId, - cpm: br.cpm, - bidderCode: BIDDER_CODE, - width: br.dimensions[0], - height: br.dimensions[1], - creativeId: br.creativeId, - currency: br.currency, - netRevenue: br.netRevenue, - ttl: br.ttl, - meta: { - advertiserDomains: br.adomains ? br.advertiserDomains : [], - }, - - }; - - // ------------------------------------ - // IF BANNER - // ------------------------------------ - - if (deepAccess(bidReq, 'mediaTypes.banner')) { - bidResponse.ad = br.html; - } - // ------------------------------------ - // IF VIDEO - // ------------------------------------ - if (deepAccess(bidReq, 'mediaTypes.video')) { - mediaType = VIDEO; - bidResponse.vastXml = br.vastXml; - bidResponse.videoScript = br.html; - const mediaTypeContext = deepAccess(bidReq, 'mediaTypes.video.context'); - if (mediaTypeContext === OUTSTREAM) { - const r = Renderer.install({ - id: bidResponse.requestId, - adUnitCode: bidReq.adUnitCode, - url: RENDERER_URL, - loaded: false, - config: { - ...deepAccess(bidReq, 'mediaTypes.video'), - ...deepAccess(br, 'outstream', {}) - } - }); + } - // set renderer - try { - bidResponse.renderer = r; - bidResponse.renderer.setRender(function(bid) { - if (window.CWIRE && window.CWIRE.outstream) { - window.CWIRE.outstream.renderAd(bid); - } - }); - } catch (err) { - logWarn('Prebid Error calling setRender on newRenderer', err); - } - } - } + // Rename `html` response property to `ad` as used by prebid. + const bids = serverResponse.body?.bids.map(({html, ...rest}) => ({...rest, ad: html})); + return bids || []; + }, - bidResponse.mediaType = mediaType; - bidResponses.push(bidResponse); - }); - } catch (e) { - logWarn(e); + onBidWon: function (bid) { + logInfo(`Bid won.`) + const event = { + type: 'BID_WON', + payload: { + bid: bid + } } + navigator.sendBeacon(EVENT_ENDPOINT, JSON.stringify(event)) + }, - return bidResponses; + onBidderError: function (error, bidderRequest) { + logInfo(`Bidder error: ${error}`) + const event = { + type: 'BID_ERROR', + payload: { + error: error, + bidderRequest: bidderRequest + } + } + navigator.sendBeacon(EVENT_ENDPOINT, JSON.stringify(event)) }, + }; registerBidder(spec); diff --git a/modules/cwireBidAdapter.md b/modules/cwireBidAdapter.md index 188894cd202..9804250b906 100644 --- a/modules/cwireBidAdapter.md +++ b/modules/cwireBidAdapter.md @@ -1,25 +1,27 @@ # Overview -Module Name: C-WIRE Bid Adapter -Module Type: Adagio Adapter -Maintainer: publishers@cwire.ch +``` +Module Name: C-WIRE Bid Adapter +Module Type: Bidder Adapter +Maintainer: devs@cwire.com +``` ## Description -Connects to C-WIRE demand source to fetch bids. +Prebid.js Adapter for C-Wire. ## Configuration - Below, the list of C-WIRE params and where they can be set. -| Param name | Global config | AdUnit config | Type | Required | -| ---------- | ------------- | ------------- |--------| ---------| -| pageId | | x | number | YES | -| placementId | | x | number | YES | -| refgroups | | x | string | NO | -| cwcreative | | x | string | NO | -| cwapikey | | x | string | NO | +| Param name | URL parameter | AdUnit config | Type | Required | +|-------------|:-------------:|:-------------:|:--------:|:-------------:| +| pageId | | x | number | YES | +| placementId | | x | number | YES | +| cwgroups | x | | string | NO | +| cwcreative | x | | string | NO | +| cwdebug | x | | boolean | NO | +| cwfeatures | x | | string | NO | ### adUnit configuration @@ -32,17 +34,22 @@ var adUnits = [ bidder: 'cwire', mediaTypes: { banner: { - sizes: [[1, 1]], + sizes: [[400, 600]], } }, params: { pageId: 1422, // required - number placementId: 2211521, // required - number - cwcreative: '42', // optional - id of creative to force - refgroups: 'test-user', // optional - name of group or coma separated list of groups to force - cwapikey: 'api_key_xyz', // optional - api key for integration testing } }] } ]; ``` + +### URL parameters + +For debugging and testing purposes url parameters can be set. + +**Example:** + +`https://www.some-site.com/article.html?cwdebug=true&cwfeatures=feature1,feature2&cwcreative=1234` diff --git a/modules/cpexIdSystem.js b/modules/czechAdIdSystem.js similarity index 82% rename from modules/cpexIdSystem.js rename to modules/czechAdIdSystem.js index 5c2e6bc212d..7354ed2e483 100644 --- a/modules/cpexIdSystem.js +++ b/modules/czechAdIdSystem.js @@ -1,7 +1,7 @@ /** * This module adds 'caid' to the User ID module * The {@link module:modules/userId} module is required - * @module modules/cpexIdSystem + * @module modules/czechAdIdSystem * @requires module:modules/userId */ @@ -9,19 +9,19 @@ import { submodule } from '../src/hook.js' import { getStorageManager } from '../src/storageManager.js' // Returns StorageManager -export const storage = getStorageManager({ gvlid: 570, moduleName: 'cpexId' }) +export const storage = getStorageManager({ gvlid: 570, moduleName: 'czechAdId' }) // Returns the id string from either cookie or localstorage const readId = () => { return storage.getCookie('czaid') || storage.getDataFromLocalStorage('czaid') } /** @type {Submodule} */ -export const cpexIdSubmodule = { - version: '0.0.5', +export const czechAdIdSubmodule = { + version: '0.1.0', /** * used to link submodule with config * @type {string} */ - name: 'cpexId', + name: 'czechAdId', /** * Vendor ID of Czech Publisher Exchange * @type {Number} @@ -32,7 +32,7 @@ export const cpexIdSubmodule = { * @function decode * @returns {(Object|undefined)} */ - decode () { return { cpexId: readId() } }, + decode () { return { czechAdId: readId() } }, /** * performs action to obtain id and return a value in the callback's response argument * @function @@ -44,4 +44,4 @@ export const cpexIdSubmodule = { } } -submodule('userId', cpexIdSubmodule) +submodule('userId', czechAdIdSubmodule) diff --git a/modules/czechAdIdSystem.md b/modules/czechAdIdSystem.md new file mode 100644 index 00000000000..5614016f524 --- /dev/null +++ b/modules/czechAdIdSystem.md @@ -0,0 +1,27 @@ +## CzechAdId User ID Submodule + +Czech Ad ID is a joint project of publishers of the [CPEx alliance](https://www.cpex.cz/) and [Seznam.cz](https://www.seznam.cz). It is a deterministic user ID that offers cross-domain and cross-device identification. For more information see [czechadid.cz](https://www.czechadid.cz)). + +## Building Prebid with CzechAdId Support + +First, make sure to add the czechAdId to your Prebid.js package with: + +``` +gulp build --modules=czechAdIdSystem +``` + +The following configuration parameters are available: + +```javascript +pbjs.setConfig({ + userSync: { + userIds: [{ + name: 'czechAdId' + }] + } +}); +``` + +| Param under userSync.userIds[] | Scope | Type | Description | Example | +| --- | --- | --- | --- | --- | +| name | Required | String | The name of this module. | `"czechAdId"` | diff --git a/modules/datawrkzBidAdapter.js b/modules/datawrkzBidAdapter.js index 71870d6437d..193a1723403 100644 --- a/modules/datawrkzBidAdapter.js +++ b/modules/datawrkzBidAdapter.js @@ -1,4 +1,4 @@ -import { deepAccess, getBidIdParameter, isArray, getUniqueIdentifierStr, contains } from '../src/utils.js'; +import { deepAccess, getBidIdParameter, isArray, getUniqueIdentifierStr, contains, isFn, isPlainObject } from '../src/utils.js'; import { config } from '../src/config.js'; import { Renderer } from '../src/Renderer.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; @@ -84,7 +84,7 @@ export const spec = { /* Generate bid request for banner adunit */ function buildBannerRequest(bidRequest, bidderRequest) { - let bidFloor = Number(getBidIdParameter('bidfloor', bidRequest.params)); + let bidFloor = getBidFloor(bidRequest); let adW = 0; let adH = 0; @@ -135,7 +135,7 @@ function buildNativeRequest(bidRequest, bidderRequest) { let counter = 0; let assets = []; - let bidFloor = Number(getBidIdParameter('bidfloor', bidRequest.params)); + let bidFloor = getBidFloor(bidRequest); let title = deepAccess(bidRequest, 'mediaTypes.native.title'); if (title && title.len) { @@ -196,7 +196,7 @@ function buildNativeRequest(bidRequest, bidderRequest) { /* Generate bid request for video adunit */ function buildVideoRequest(bidRequest, bidderRequest) { - let bidFloor = Number(getBidIdParameter('bidfloor', bidRequest.params)); + let bidFloor = getBidFloor(bidRequest); let sizeObj = getVideoAdUnitSize(bidRequest); @@ -414,6 +414,7 @@ function buildBannerResponse(bidRequest, bidResponse) { } let bidSizes = (deepAccess(bidRequest, 'mediaTypes.banner.sizes')) ? deepAccess(bidRequest, 'mediaTypes.banner.sizes') : bidRequest.sizes; bidResponse.requestId = bidRequest.bidId; + bidResponse.auctionId = bidRequest.auctionId; bidResponse.transactionId = bidRequest.transactionId; bidResponse.placementCode = placementCode; bidResponse.cpm = responseCPM; @@ -455,6 +456,7 @@ function buildNativeResponse(bidRequest, response) { return; } bidResponse.requestId = bidRequest.bidId; + bidResponse.auctionId = bidRequest.auctionId; bidResponse.transactionId = bidRequest.transactionId; bidResponse.placementCode = placementCode; bidResponse.cpm = responseCPM; @@ -507,6 +509,7 @@ function buildVideoResponse(bidRequest, response) { let context = bidRequest.mediaTypes.video.context; bidResponse.requestId = bidRequest.bidId; + bidResponse.auctionId = bidRequest.auctionId; bidResponse.transactionId = bidRequest.transactionId; bidResponse.placementCode = placementCode; bidResponse.cpm = responseCPM; @@ -630,4 +633,21 @@ function getNativeAssestObj(obj, assets) { } } +// BUILD REQUESTS: BIDFLOORS +function getBidFloor(bid) { + if (!isFn(bid.getFloor)) { + return (bid.params.bidfloor) ? bid.params.bidfloor : null; + } + + let floor = bid.getFloor({ + currency: 'USD', + mediaType: '*', + size: '*' + }); + if (isPlainObject(floor) && !isNaN(floor.floor) && floor.currency === 'USD') { + return floor.floor; + } + return null; +} + registerBidder(spec); diff --git a/modules/dfpAdServerVideo.js b/modules/dfpAdServerVideo.js index 072715b4bd6..71c9c7aa341 100644 --- a/modules/dfpAdServerVideo.js +++ b/modules/dfpAdServerVideo.js @@ -8,7 +8,7 @@ import { deepAccess, isEmpty, logError, parseSizesInput, formatQS, parseUrl, bui import { config } from '../src/config.js'; import { getHook, submodule } from '../src/hook.js'; import { auctionManager } from '../src/auctionManager.js'; -import { gdprDataHandler, uspDataHandler } from '../src/adapterManager.js'; +import { gdprDataHandler, uspDataHandler, gppDataHandler } from '../src/adapterManager.js'; import * as events from '../src/events.js'; import CONSTANTS from '../src/constants.json'; import {getPPID} from '../src/adserver.js'; @@ -119,6 +119,11 @@ export function buildDfpVideoUrl(options) { const uspConsent = uspDataHandler.getConsentData(); if (uspConsent) { queryParams.us_privacy = uspConsent; } + const gppConsent = gppDataHandler.getConsentData(); + if (gppConsent) { + // TODO - need to know what to set here for queryParams... + } + if (!queryParams.ppid) { const ppid = getPPID(); if (ppid != null) { diff --git a/modules/dgkeywordRtdProvider.js b/modules/dgkeywordRtdProvider.js index 032cb4a780a..99df3b18a39 100644 --- a/modules/dgkeywordRtdProvider.js +++ b/modules/dgkeywordRtdProvider.js @@ -41,7 +41,7 @@ export function getDgKeywordsAndSet(reqBidsConfigObj, callback, moduleConfig, us } else { logMessage('[dgkeyword sub module] dgkeyword targets:', setKeywordTargetBidders); logMessage('[dgkeyword sub module] get targets from profile api start.'); - ajax(getProfileApiUrl(moduleConfig?.params?.url, moduleConfig?.params?.disableReadFpid), { + ajax(getProfileApiUrl(moduleConfig?.params?.url, moduleConfig?.params?.enableReadFpid), { success: function(response) { const res = JSON.parse(response); if (!isFinish) { @@ -96,9 +96,9 @@ export function getDgKeywordsAndSet(reqBidsConfigObj, callback, moduleConfig, us } } -export function getProfileApiUrl(customeUrl, disableReadFpid) { +export function getProfileApiUrl(customeUrl, enableReadFpid) { const URL = 'https://mediaconsortium.profiles.tagger.opecloud.com/api/v1'; - const fpid = (disableReadFpid) ? '' : readFpidFromLocalStrage(); + const fpid = (enableReadFpid) ? readFpidFromLocalStrage() : ''; let url = customeUrl || URL; url = url + '?url=' + encodeURIComponent(window.location.href) + ((fpid) ? `&fpid=${fpid}` : ''); return url; diff --git a/modules/discoveryBidAdapter.js b/modules/discoveryBidAdapter.js index 4f22a41cf9f..8145c9d25e7 100644 --- a/modules/discoveryBidAdapter.js +++ b/modules/discoveryBidAdapter.js @@ -12,7 +12,8 @@ let itemMaps = {}; const MEDIATYPE = [BANNER, NATIVE]; /* ----- _ss_pp_id:start ------ */ -const COOKIE_KEY_MGUID = '_ss_pp_id'; +const COOKIE_KEY_SSPPID = '_ss_pp_id'; +const COOKIE_KEY_MGUID = '__mguid_'; const NATIVERET = { id: 'id', @@ -39,7 +40,7 @@ const NATIVERET = { title: { len: 75, }, - } + }, ], plcmttype: 1, privacy: 1, @@ -58,14 +59,20 @@ const NATIVERET = { * @return {string} */ const getUserID = () => { - const i = storage.getCookie(COOKIE_KEY_MGUID); + let idd = storage.getCookie(COOKIE_KEY_SSPPID); + let idm = storage.getCookie(COOKIE_KEY_MGUID); - if (i === null) { + if (idd && !idm) { + idm = idd; + } else if (idm && !idd) { + idd = idm; + } else if (!idd && !idm) { const uuid = utils.generateUUID(); storage.setCookie(COOKIE_KEY_MGUID, uuid); + storage.setCookie(COOKIE_KEY_SSPPID, uuid); return uuid; } - return i; + return idd; }; /* ----- _ss_pp_id:end ------ */ @@ -80,7 +87,6 @@ function getKv(obj, ...keys) { let o = obj; for (let key of keys) { - // console.log(key, o); if (o && o[key]) { o = o[key]; } else { @@ -222,7 +228,7 @@ function getItems(validBidRequests, bidderRequest) { let id = '' + (i + 1); if (mediaTypes.native) { - ret = {...NATIVERET, ...{id, bidFloor}} + ret = { ...NATIVERET, ...{ id, bidFloor } }; } // banner if (mediaTypes.banner) { @@ -249,6 +255,7 @@ function getItems(validBidRequests, bidderRequest) { pos: 1, }, ext: {}, + tagid: globals['tagid'], }; } itemMaps[id] = { @@ -269,18 +276,32 @@ function getItems(validBidRequests, bidderRequest) { */ 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'); + const eids = validBidRequests[0].userIdAsEids || validBidRequests[0].userId; + 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 = getKv(bidderRequest, 'auctionId'); let items = getItems(validBidRequests, bidderRequest); - const location = utils.deepAccess(bidderRequest, 'refererInfo.referer'); - const timeout = bidderRequest.timeout || 2000; + const domain = + utils.deepAccess(bidderRequest, 'refererInfo.domain') || document.domain; + const location = utils.deepAccess(bidderRequest, 'refererInfo.referer'); + const page = utils.deepAccess(bidderRequest, 'refererInfo.page'); + const referer = utils.deepAccess(bidderRequest, 'refererInfo.ref'); + if (items && items.length) { let c = { id: 'pp_hbjs_' + auctionId, + test: +isTest, at: 1, + bcat: globals['bcat'], + badv: globals['adv'], cur: ['USD'], device: { connectiontype: 0, @@ -289,22 +310,26 @@ function getParam(validBidRequests, bidderRequest) { ua: navigator.userAgent, language: /en/.test(navigator.language) ? 'en' : navigator.language, }, + ext: { + eids, + }, user: { buyeruid: getUserID(), - id: pubcid, + id: sharedid || pubcid, }, + eids, tmax: timeout, site: { - name: globals['media'], - domain: globals['media'], - page: location, - ref: location, + name: domain, + domain: domain, + page: page || location, + ref: referer, mobile: isMobile, cat: [], // todo publisher: { + id: globals['publisher'], // todo - id: globals['media'], - name: globals['media'], + // name: xxx }, }, imp: items, @@ -329,10 +354,19 @@ export const spec = { if (bid.params.token) { globals['token'] = bid.params.token; } - if (bid.params.media) { - globals['media'] = bid.params.media; + if (bid.params.publisher) { + globals['publisher'] = bid.params.publisher; + } + if (bid.params.tagid) { + globals['tagid'] = bid.params.tagid; + } + if (bid.params.bcat) { + globals['bcat'] = Array.isArray(bid.params.bcat) ? bid.params.bcat : []; + } + if (bid.params.badv) { + globals['badv'] = Array.isArray(bid.params.badv) ? bid.params.badv : []; } - return !!(bid.params.token && bid.params.media); + return !!(bid.params.token && bid.params.publisher && bid.params.tagid); }, /** @@ -377,8 +411,8 @@ export const spec = { nurl: getKv(bid, 'nurl'), ttl: TIME_TO_LIVE, meta: { - advertiserDomains: getKv(bid, 'adomain') || [] - } + advertiserDomains: getKv(bid, 'adomain') || [], + }, }; if (mediaType === 'native') { const adm = getKv(bid, 'adm'); @@ -424,7 +458,7 @@ export const spec = { native.impressionTrackers.push(tracker.url); break; // case 2: - // native.javascriptTrackers = ``; + // native.javascriptTrackers = ``; // break; } }); @@ -460,8 +494,8 @@ export const spec = { */ onBidWon: function (bid) { if (bid['nurl']) { - utils.triggerPixel(bid['nurl']) + utils.triggerPixel(bid['nurl']); } - } + }, }; registerBidder(spec); diff --git a/modules/discoveryBidAdapter.md b/modules/discoveryBidAdapter.md index 6e7197863a5..e951b0b7448 100644 --- a/modules/discoveryBidAdapter.md +++ b/modules/discoveryBidAdapter.md @@ -1,15 +1,15 @@ # Overview ``` -Module Name: DiscoveryDSP Bid Adapter +Module Name: discovery Bid Adapter Module Type: Bidder Adapter ``` # Description -Module that connects to popIn's demand sources +Module that connects to popIn's demand sources. -The DiscoveryDSP Bidding adapter requires setup before beginning. Please contact us at +The discovery Bidding adapter requires setup before beginning. Please contact us at # Test Parameters ``` @@ -32,7 +32,8 @@ The DiscoveryDSP Bidding adapter requires setup before beginning. Please contact bidder: "discovery", params: { token: "a1b067897e4ae093d1f94261e0ddc6c9", - media: 'test_media' // your media host + tagid: 'test_tagid', + publisher: 'test_publisher' }, }, ], @@ -45,13 +46,13 @@ The DiscoveryDSP Bidding adapter requires setup before beginning. Please contact sizes: [[300, 250]], }, }, - // Replace this object to test a new adapter! bids: [ { bidder: "discovery", params: { token: "d0f4902b616cc5c38cbe0a08676d0ed9", - media: 'test_media' // your media host + tagid: 'test_tagid', + publisher: 'test_publisher' }, }, ], diff --git a/modules/emx_digitalBidAdapter.js b/modules/emx_digitalBidAdapter.js index eb69e76a837..99f313b9484 100644 --- a/modules/emx_digitalBidAdapter.js +++ b/modules/emx_digitalBidAdapter.js @@ -354,16 +354,23 @@ export const spec = { }, getUserSyncs: function (syncOptions, responses, gdprConsent, uspConsent) { const syncs = []; + const consentParams = []; if (syncOptions.iframeEnabled) { let url = 'https://biddr.brealtime.com/check.html'; if (gdprConsent && typeof gdprConsent.consentString === 'string') { // add 'gdpr' only if 'gdprApplies' is defined if (typeof gdprConsent.gdprApplies === 'boolean') { - url += `?gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`; + consentParams.push(`gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`); } else { - url += `?gdpr_consent=${gdprConsent.consentString}`; + consentParams.push(`?gdpr_consent=${gdprConsent.consentString}`); } } + if (uspConsent && typeof uspConsent.consentString === 'string') { + consentParams.push(`usp=${uspConsent.consentString}`); + } + if (consentParams.length > 0) { + url = url + '?' + consentParams.join('&'); + } syncs.push({ type: 'iframe', url: url diff --git a/modules/enrichmentFpdModule.js b/modules/enrichmentFpdModule.js index a4d7c06d0fb..59d5d326109 100644 --- a/modules/enrichmentFpdModule.js +++ b/modules/enrichmentFpdModule.js @@ -1,190 +1,2 @@ - -/** - * This module sets default values and validates ortb2 first part data - * @module modules/firstPartyData - */ -import { timestamp, mergeDeep } from '../src/utils.js'; -import { submodule } from '../src/hook.js'; -import {getRefererInfo, parseDomain} from '../src/refererDetection.js'; -import { getCoreStorageManager } from '../src/storageManager.js'; -import {GreedyPromise} from '../src/utils/promise.js'; -import {getHighEntropySUA, getLowEntropySUA} from '../libraries/fpd/sua.js'; - -let ortb2; -let win = (window === window.top) ? window : window.top; -export const coreStorage = getCoreStorageManager('enrichmentFpd'); - -export const sua = {he: getHighEntropySUA, le: getLowEntropySUA}; - -/** - * Find the root domain - * @param {string|undefined} fullDomain - * @return {string} -*/ -export function findRootDomain(fullDomain = window.location.hostname) { - if (!coreStorage.cookiesAreEnabled()) { - return fullDomain; - } - - const domainParts = fullDomain.split('.'); - if (domainParts.length == 2) { - return fullDomain; - } - let rootDomain; - let continueSearching; - let startIndex = -2; - const TEST_COOKIE_NAME = `_rdc${Date.now()}`; - const TEST_COOKIE_VALUE = 'writeable'; - do { - rootDomain = domainParts.slice(startIndex).join('.'); - let expirationDate = new Date(timestamp() + 10 * 1000).toUTCString(); - - // Write a test cookie - coreStorage.setCookie( - TEST_COOKIE_NAME, - TEST_COOKIE_VALUE, - expirationDate, - 'Lax', - rootDomain, - undefined - ); - - // See if the write was successful - const value = coreStorage.getCookie(TEST_COOKIE_NAME, undefined); - if (value === TEST_COOKIE_VALUE) { - continueSearching = false; - // Delete our test cookie - coreStorage.setCookie( - TEST_COOKIE_NAME, - '', - 'Thu, 01 Jan 1970 00:00:01 GMT', - undefined, - rootDomain, - undefined - ); - } else { - startIndex += -1; - continueSearching = Math.abs(startIndex) <= domainParts.length; - } - } while (continueSearching); - return rootDomain; -} - -/** - * Checks for referer and if exists merges into ortb2 global data - */ -function setReferer() { - if (getRefererInfo().ref) mergeDeep(ortb2, { site: { ref: getRefererInfo().ref } }); -} - -/** - * Checks for canonical url and if exists merges into ortb2 global data - */ -function setPage() { - if (getRefererInfo().page) mergeDeep(ortb2, { site: { page: getRefererInfo().page } }); -} - -/** - * Checks for canonical url and if exists retrieves domain and merges into ortb2 global data - */ -function setDomain() { - const domain = parseDomain(getRefererInfo().page, {noLeadingWww: true}); - if (domain) { - mergeDeep(ortb2, { site: { domain: domain } }); - mergeDeep(ortb2, { site: { publisher: { domain: findRootDomain(domain) } } }); - }; -} - -/** - * Checks for screen/device width and height and sets dimensions - */ -function setDimensions() { - let width; - let height; - - try { - width = win.innerWidth || win.document.documentElement.clientWidth || win.document.body.clientWidth; - height = win.innerHeight || win.document.documentElement.clientHeight || win.document.body.clientHeight; - } catch (e) { - width = window.innerWidth || window.document.documentElement.clientWidth || window.document.body.clientWidth; - height = window.innerHeight || window.document.documentElement.clientHeight || window.document.body.clientHeight; - } - - mergeDeep(ortb2, { device: { w: width, h: height } }); -} - -/** - * Scans page for meta keywords, and if exists, merges into site.keywords - */ -function setKeywords() { - let keywords; - - try { - keywords = win.document.querySelector("meta[name='keywords']"); - } catch (e) { - keywords = window.document.querySelector("meta[name='keywords']"); - } - - if (keywords && keywords.content) mergeDeep(ortb2, { site: { keywords: keywords.content.replace(/\s/g, '') } }); -} - -function setDeviceSua(hints) { - let data = Array.isArray(hints) && hints.length === 0 - ? GreedyPromise.resolve(sua.le()) - : sua.he(hints); - return data.then((sua) => { - if (sua != null) { - mergeDeep(ortb2, {device: {sua}}); - } - }) -} - -/** - * Checks the Global Privacy Control status, and if exists and is true, merges into regs.ext.gpc - */ -function setGpc() { - const gpcValue = navigator.globalPrivacyControl; - if (gpcValue) { - mergeDeep(ortb2, { regs: { ext: { gpc: 1 } } }) - } -} - -/** - * Resets modules global ortb2 data - */ -export const resetEnrichments = () => { ortb2 = null }; - -function runEnrichments(fpdConf) { - setReferer(); - setPage(); - setDomain(); - setDimensions(); - setKeywords(); - setGpc(); - return setDeviceSua(fpdConf.uaHints).then(() => ortb2); -} - -export function processFpd(fpdConf, {global}) { - if (fpdConf.skipEnrichments) { - return {global}; - } else { - let ready; - if (ortb2 == null) { - ortb2 = {}; - ready = runEnrichments(fpdConf); - } else { - ready = GreedyPromise.resolve(); - } - return ready.then(() => ({ - global: mergeDeep({}, ortb2, global) - })) - } -} -/** @type {firstPartyDataSubmodule} */ -export const enrichmentsSubmodule = { - name: 'enrichments', - queue: 2, - processFpd -} - -submodule('firstPartyData', enrichmentsSubmodule) +// Logic from this module was moved into core since approx. 7.27 +// TODO: remove this in v8 diff --git a/modules/eplanningBidAdapter.js b/modules/eplanningBidAdapter.js index b60c3571d47..2216ab329b0 100644 --- a/modules/eplanningBidAdapter.js +++ b/modules/eplanningBidAdapter.js @@ -24,6 +24,7 @@ const VAST_INSTREAM = 1; const VAST_OUTSTREAM = 2; const VAST_VERSION_DEFAULT = 3; const DEFAULT_SIZE_VAST = '640x480'; +const MAX_LEN_URL = 255; export const spec = { code: BIDDER_CODE, @@ -60,7 +61,7 @@ export const spec = { params = { rnd: rnd, e: spaces.str, - ur: pageUrl || FILE, + ur: cutUrl(pageUrl || FILE), pbv: '$prebid.version$', ncb: '1', vs: spaces.vs @@ -70,7 +71,7 @@ export const spec = { } if (referrerUrl) { - params.fr = referrerUrl; + params.fr = cutUrl(referrerUrl); } if (bidderRequest && bidderRequest.gdprConsent) { @@ -128,9 +129,9 @@ export const spec = { advertiserDomains: ad.adom }; } - if (isVastResponse(ad)) { + if (request && request.data && request.data.vv) { bidResponse.vastXml = ad.adm; - bidResponse.mediaTypes = VIDEO; + bidResponse.mediaType = VIDEO; } else { bidResponse.ad = ad.adm; } @@ -491,6 +492,17 @@ function visibilityHandler(obj) { } } +function cutUrl (url) { + if (url.length > MAX_LEN_URL) { + url = url.split('?')[0]; + if (url.length > MAX_LEN_URL) { + url = url.slice(0, MAX_LEN_URL); + } + } + + return url; +} + function registerAuction(storageID) { let value; try { @@ -504,8 +516,4 @@ function registerAuction(storageID) { return true; } -function isVastResponse(bid) { - return bid.adm.match(/^( BID_METADATA[bid.bidId] = { - // TODO: is 'page' the right value here? referer: data.refererInfo.page, transactionId: bid.transactionId }); @@ -227,7 +252,7 @@ function buildRequests(validBidRequests, bidderRequest) { /** * Adapts the FeedAd server response to Prebid format - * @param {ServerResponse} serverResponse - the FeedAd server response + * @param {FeedAdServerResponse} serverResponse - the FeedAd server response * @param {BidRequest} request - the initial bid request * @returns {Bid[]} the FeedAd bids */ @@ -266,7 +291,8 @@ function createTrackingParams(data, klass) { prebid_bid_id: bidId, prebid_transaction_id: transactionId, referer, - sdk_version: VERSION + prebid_adapter_version: VERSION, + prebid_sdk_version: '$prebid.version$', }; } @@ -294,16 +320,20 @@ function trackingHandlerFactory(klass) { /** * Reads the user syncs off the server responses and converts them into Prebid.JS format * @param {SyncOptions} syncOptions - * @param {FeedAdApiBidResponse[]} serverResponses + * @param {FeedAdServerResponse[]} serverResponses * @param gdprConsent * @param uspConsent */ function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent) { - return serverResponses.map(response => response.ext) - .flatMap(extension => { + return serverResponses.flatMap(response => { + // merge all response bodies into one + const body = response.body; + return isArray(body) ? body : []; + }) + .flatMap(/** @param {FeedAdApiBidResponse} bidResponse */ bidResponse => { // extract user syncs from extension - const pixels = syncOptions.pixelEnabled && extension.pixels ? extension.pixels : []; - const iframes = syncOptions.iframeEnabled && extension.iframes ? extension.iframes : []; + const pixels = (syncOptions.pixelEnabled && bidResponse?.ext?.pixels) ? bidResponse.ext.pixels : []; + const iframes = (syncOptions.iframeEnabled && bidResponse?.ext?.iframes) ? bidResponse.ext.iframes : []; return pixels.concat(...iframes); }) .reduce((syncs, sync) => { diff --git a/modules/fluctBidAdapter.js b/modules/fluctBidAdapter.js index ea634027dbe..004d44e6737 100644 --- a/modules/fluctBidAdapter.js +++ b/modules/fluctBidAdapter.js @@ -62,6 +62,11 @@ export const spec = { }); data.params = request.params; + + if (request.schain) { + data.schain = request.schain; + } + const searchParams = new URLSearchParams({ dfpUnitCode: request.params.dfpUnitCode, tagId: request.params.tagId, diff --git a/modules/fpdModule/index.md b/modules/fpdModule/index.md index 638c966883a..238881db96b 100644 --- a/modules/fpdModule/index.md +++ b/modules/fpdModule/index.md @@ -16,9 +16,11 @@ Validation Submodule: - verify that certain OpenRTB attributes are not specified - optionally suppress user FPD based on the existence of _pubcid_optout +Topic Submodule: +- populate first party/third party topics data onto user.data in bid stream. 1. Module initializes on first load and set bidRequestHook -2. When hook runs, corresponding submodule init functions are run to perform enrichments/validations dependant on submodule +2. When hook runs, corresponding submodule init functions are run to perform enrichments/validations/topics dependant on submodule 3. After hook complete, it is disabled - meaning module only runs on first auction 4. To reinitiate the module, run pbjs.refreshFPD(), which allows module to rerun as if initial load @@ -43,4 +45,5 @@ pbjs.setConfig({ At least one of the submodules must be included in order to successfully run the corresponding above operations. enrichmentFpdModule -validationFpdModule \ No newline at end of file +validationFpdModule +topicsFpdModule \ No newline at end of file diff --git a/modules/freewheel-sspBidAdapter.js b/modules/freewheel-sspBidAdapter.js index 764e3d6e6c0..1a962fd4060 100644 --- a/modules/freewheel-sspBidAdapter.js +++ b/modules/freewheel-sspBidAdapter.js @@ -1,6 +1,7 @@ -import { logWarn, isArray } from '../src/utils.js'; +import { logWarn, isArray, isFn, deepAccess } from '../src/utils.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { config } from '../src/config.js'; const BIDDER_CODE = 'freewheel-ssp'; @@ -213,6 +214,27 @@ function getAPIName(componentId) { return componentId.replace('-', ''); } +function getBidFloor(bid, config) { + if (!isFn(bid.getFloor)) { + return deepAccess(bid, 'params.bidfloor', 0); + } + + try { + const bidFloor = bid.getFloor({ + currency: getFloorCurrency(config), + mediaType: typeof bid.mediaTypes['banner'] == 'object' ? 'banner' : 'video', + size: '*', + }); + return bidFloor.floor; + } catch (e) { + return -1; + } +} + +function getFloorCurrency(config) { + return config.getConfig('floors.data.currency') != null ? config.getConfig('floors.data.currency') : 'USD'; +} + function formatAdHTML(bid, size) { var integrationType = bid.params.format; @@ -317,13 +339,17 @@ export const spec = { var zone = currentBidRequest.params.zoneId; var timeInMillis = new Date().getTime(); var keyCode = hashcode(zone + '' + timeInMillis); + var bidfloor = getBidFloor(currentBidRequest, config); + var requestParams = { reqType: 'AdsSetup', - protocolVersion: '2.0', + protocolVersion: '4.2', zoneId: zone, componentId: 'prebid', componentSubId: getComponentId(currentBidRequest.params.format), timestamp: timeInMillis, + _fw_bidfloor: (bidfloor > 0) ? bidfloor : 0, + _fw_bidfloorcur: (bidfloor > 0) ? getFloorCurrency(config) : '', pKey: keyCode }; @@ -348,7 +374,11 @@ export const spec = { // Add schain object var schain = currentBidRequest.schain; if (schain) { - requestParams.schain = schain; + try { + requestParams.schain = JSON.stringify(schain); + } catch (error) { + logWarn('PREBID - ' + BIDDER_CODE + ': Unable to stringify the schain: ' + error); + } } var vastParams = currentBidRequest.params.vastUrlParams; diff --git a/modules/gdprEnforcement.js b/modules/gdprEnforcement.js index b7035c509b6..9553ad0586a 100644 --- a/modules/gdprEnforcement.js +++ b/modules/gdprEnforcement.js @@ -2,7 +2,7 @@ * This module gives publishers extra set of features to enforce individual purposes of TCF v2 */ -import {deepAccess, hasDeviceAccess, isArray, logWarn} from '../src/utils.js'; +import {deepAccess, hasDeviceAccess, isArray, logError, logWarn} from '../src/utils.js'; import {config} from '../src/config.js'; import adapterManager, {gdprDataHandler} from '../src/adapterManager.js'; import {find, includes} from '../src/polyfill.js'; @@ -11,13 +11,7 @@ import {getHook} from '../src/hook.js'; import {validateStorageEnforcement} from '../src/storageManager.js'; import * as events from '../src/events.js'; import CONSTANTS from '../src/constants.json'; - -// modules for which vendor consent is not needed (see https://github.com/prebid/Prebid.js/issues/8161) -const VENDORLESS_MODULES = new Set([ - 'sharedId', - 'pubCommonId', - 'pubProvidedId', -]); +import {VENDORLESS_GVLID} from '../src/consentHandler.js'; export const STRICT_STORAGE_ENFORCEMENT = 'strictStorageEnforcement'; @@ -71,7 +65,7 @@ export const internal = { * @param {{string|Object}} - module * @return {number} - GVL ID */ -export function getGvlid(module) { +export function getGvlid(module, ...args) { let gvlid = null; if (module) { // Check user defined GVL Mapping in pbjs.setConfig() @@ -86,7 +80,7 @@ export function getGvlid(module) { return gvlid; } - gvlid = internal.getGvlidForBidAdapter(moduleCode) || internal.getGvlidForUserIdModule(module) || internal.getGvlidForAnalyticsAdapter(moduleCode); + gvlid = internal.getGvlidForBidAdapter(moduleCode) || internal.getGvlidForUserIdModule(module) || internal.getGvlidForAnalyticsAdapter(moduleCode, ...args); } return gvlid; } @@ -120,10 +114,19 @@ function getGvlidForUserIdModule(userIdModule) { /** * Returns GVL ID for an analytics adapter. If an analytics adapter does not have an associated GVL ID, it returns 'null'. * @param {string} code - 'provider' property on the analytics adapter config + * @param {{}} config - analytics configuration object * @return {number} GVL ID */ -function getGvlidForAnalyticsAdapter(code) { - return adapterManager.getAnalyticsAdapter(code) && (adapterManager.getAnalyticsAdapter(code).gvlid || null); +function getGvlidForAnalyticsAdapter(code, config) { + const adapter = adapterManager.getAnalyticsAdapter(code); + return adapter?.gvlid || ((gvlid) => { + if (typeof gvlid !== 'function') return gvlid; + try { + return gvlid.call(adapter.adapter, config); + } catch (e) { + logError(`Error invoking ${code} adapter.gvlid()`, e) + } + })(adapter?.adapter?.gvlid) } export function shouldEnforce(consentData, purpose, name) { @@ -145,20 +148,20 @@ export function shouldEnforce(consentData, purpose, name) { * @param {Object} consentData - gdpr consent data * @param {string=} currentModule - Bidder code of the current module * @param {number=} gvlId - GVL ID for the module - * @param vendorlessModule a predicate function that takes a module name, and returns true if the module does not need vendor consent * @returns {boolean} */ -export function validateRules(rule, consentData, currentModule, gvlId, vendorlessModule = VENDORLESS_MODULES.has.bind(VENDORLESS_MODULES)) { +export function validateRules(rule, consentData, currentModule, gvlId) { const purposeId = TCF2[Object.keys(TCF2).filter(purposeName => TCF2[purposeName].name === rule.purpose)[0]].id; // return 'true' if vendor present in 'vendorExceptions' - if (includes(rule.vendorExceptions || [], currentModule)) { + if ((rule.vendorExceptions || []).includes(currentModule)) { return true; } + const vendorConsentRequred = !((gvlId === VENDORLESS_GVLID || (rule.softVendorExceptions || []).includes(currentModule))) // get data from the consent string const purposeConsent = deepAccess(consentData, `vendorData.purpose.consents.${purposeId}`); - const vendorConsent = deepAccess(consentData, `vendorData.vendor.consents.${gvlId}`); + const vendorConsent = vendorConsentRequred ? deepAccess(consentData, `vendorData.vendor.consents.${gvlId}`) : true; const liTransparency = deepAccess(consentData, `vendorData.purpose.legitimateInterests.${purposeId}`); /* @@ -166,7 +169,7 @@ export function validateRules(rule, consentData, currentModule, gvlId, vendorles or the user has consented. Similar with vendors. */ const purposeAllowed = rule.enforcePurpose === false || purposeConsent === true; - const vendorAllowed = vendorlessModule(currentModule) || rule.enforceVendor === false || vendorConsent === true; + const vendorAllowed = rule.enforceVendor === false || vendorConsent === true; /* Few if any vendors should be declaring Legitimate Interest for Device Access (Purpose 1), but some are claiming @@ -183,19 +186,18 @@ export function validateRules(rule, consentData, currentModule, gvlId, vendorles /** * This hook checks whether module has permission to access device or not. Device access include cookie and local storage * @param {Function} fn reference to original function (used by hook logic) - * @param isVendorless if true, do not require vendor consent (for e.g. core modules) * @param {Number=} gvlid gvlid of the module * @param {string=} moduleName name of the module * @param result */ -export function deviceAccessHook(fn, isVendorless, gvlid, moduleName, result, {validate = validateRules} = {}) { +export function deviceAccessHook(fn, gvlid, moduleName, result, {validate = validateRules} = {}) { result = Object.assign({}, { hasEnforcementHook: true }); if (!hasDeviceAccess()) { logWarn('Device access is disabled by Publisher'); result.valid = false; - } else if (isVendorless && !strictStorageEnforcement) { + } else if (gvlid === VENDORLESS_GVLID && !strictStorageEnforcement) { // for vendorless (core) storage, do not enforce rules unless strictStorageEnforcement is set result.valid = true; } else { @@ -203,13 +205,13 @@ export function deviceAccessHook(fn, isVendorless, gvlid, moduleName, result, {v if (shouldEnforce(consentData, 1, moduleName)) { const curBidder = config.getCurrentBidder(); // Bidders have a copy of storage object with bidder code binded. Aliases will also pass the same bidder code when invoking storage functions and hence if alias tries to access device we will try to grab the gvl id for alias instead of original bidder - if (curBidder && (curBidder != moduleName) && adapterManager.aliasRegistry[curBidder] === moduleName) { + if (curBidder && (curBidder !== moduleName) && adapterManager.aliasRegistry[curBidder] === moduleName) { gvlid = getGvlid(curBidder); } else { gvlid = getGvlid(moduleName) || gvlid; } const curModule = moduleName || curBidder; - let isAllowed = validate(purpose1Rule, consentData, curModule, gvlid, isVendorless ? () => true : undefined); + let isAllowed = validate(purpose1Rule, consentData, curModule, gvlid,); if (isAllowed) { result.valid = true; } else { @@ -221,7 +223,7 @@ export function deviceAccessHook(fn, isVendorless, gvlid, moduleName, result, {v result.valid = true; } } - fn.call(this, isVendorless, gvlid, moduleName, result); + fn.call(this, gvlid, moduleName, result); } /** @@ -314,7 +316,7 @@ export function enableAnalyticsHook(fn, config) { } config = config.filter(conf => { const analyticsAdapterCode = conf.provider; - const gvlid = getGvlid(analyticsAdapterCode); + const gvlid = getGvlid(analyticsAdapterCode, conf); const isAllowed = !!validateRules(purpose7Rule, consentData, analyticsAdapterCode, gvlid); if (!isAllowed) { analyticsBlocked.push(analyticsAdapterCode); diff --git a/modules/genericAnalyticsAdapter.js b/modules/genericAnalyticsAdapter.js new file mode 100644 index 00000000000..4909745e72b --- /dev/null +++ b/modules/genericAnalyticsAdapter.js @@ -0,0 +1,157 @@ +import AnalyticsAdapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; +import {prefixLog, isPlainObject} from '../src/utils.js'; +import * as CONSTANTS from '../src/constants.json'; +import adapterManager from '../src/adapterManager.js'; +import {ajaxBuilder} from '../src/ajax.js'; + +const DEFAULTS = { + batchSize: 1, + batchDelay: 100, + method: 'POST' +} + +const TYPES = { + handler: 'function', + batchSize: 'number', + batchDelay: 'number', + gvlid: 'number', +} + +const MAX_CALL_DEPTH = 20; + +export function GenericAnalytics() { + const parent = AnalyticsAdapter({analyticsType: 'endpoint'}); + const {logError, logWarn} = prefixLog('Generic analytics:'); + let batch = []; + let callDepth = 0; + let options, handler, timer, translate; + + function optionsAreValid(options) { + if (!options.url && !options.handler) { + logError('options must specify either `url` or `handler`') + return false; + } + if (options.hasOwnProperty('method') && !['GET', 'POST'].includes(options.method)) { + logError('options.method must be GET or POST'); + return false; + } + for (const [field, type] of Object.entries(TYPES)) { + // eslint-disable-next-line valid-typeof + if (options.hasOwnProperty(field) && typeof options[field] !== type) { + logError(`options.${field} must be a ${type}`); + return false; + } + } + if (options.hasOwnProperty('events')) { + if (!isPlainObject(options.events)) { + logError('options.events must be an object'); + return false; + } + for (const [event, handler] of Object.entries(options.events)) { + if (!CONSTANTS.EVENTS.hasOwnProperty(event)) { + logWarn(`options.events.${event} does not match any known Prebid event`); + if (typeof handler !== 'function') { + logError(`options.events.${event} must be a function`); + return false; + } + } + } + } + return true; + } + + function processBatch() { + const currentBatch = batch; + batch = []; + callDepth++; + try { + // the pub-provided handler may inadvertently cause an infinite chain of events; + // even just logging an exception from it may cause an AUCTION_DEBUG event, that + // gets back to the handler, that throws another exception etc. + // to avoid the issue, put a cap on recursion + if (callDepth === MAX_CALL_DEPTH) { + logError('detected probable infinite recursion, discarding events', currentBatch); + } + if (callDepth >= MAX_CALL_DEPTH) { + return; + } + try { + handler(currentBatch); + } catch (e) { + logError('error executing options.handler', e); + } + } finally { + callDepth--; + } + } + + function translator(eventHandlers) { + if (!eventHandlers) { + return (data) => data; + } + return function ({eventType, args}) { + if (eventHandlers.hasOwnProperty(eventType)) { + try { + return eventHandlers[eventType](args); + } catch (e) { + logError(`error executing options.events.${eventType}`, e); + } + } + } + } + + return Object.assign( + Object.create(parent), + { + gvlid(config) { + return config?.options?.gvlid + }, + enableAnalytics(config) { + if (optionsAreValid(config?.options || {})) { + options = Object.assign({}, DEFAULTS, config.options); + handler = options.handler || defaultHandler(options); + translate = translator(options.events); + parent.enableAnalytics.call(this, config); + } + }, + track(event) { + if (event.eventType === CONSTANTS.EVENTS.AUCTION_INIT && event.args.hasOwnProperty('config')) { + // clean up auctionInit event + // TODO: remove this special case in v8 + delete event.args.config; + } + const datum = translate(event); + if (datum != null) { + batch.push(datum); + if (timer != null) { + clearTimeout(timer); + timer = null; + } + if (batch.length >= options.batchSize) { + processBatch(); + } else { + timer = setTimeout(processBatch, options.batchDelay); + } + } + } + } + ) +} + +export function defaultHandler({url, method, batchSize, ajax = ajaxBuilder()}) { + const callbacks = { + success() {}, + error() {} + } + const extract = batchSize > 1 ? (events) => events : (events) => events[0]; + const serialize = method === 'GET' ? (data) => ({data: JSON.stringify(data)}) : (data) => JSON.stringify(data); + + return function (events) { + ajax(url, callbacks, serialize(extract(events)), {method}) + } +} + +adapterManager.registerAnalyticsAdapter({ + adapter: GenericAnalytics(), + code: 'generic', +}); diff --git a/modules/geoedgeRtdProvider.js b/modules/geoedgeRtdProvider.js index 001ef67b66a..6f910632fbc 100644 --- a/modules/geoedgeRtdProvider.js +++ b/modules/geoedgeRtdProvider.js @@ -18,6 +18,8 @@ import { submodule } from '../src/hook.js'; import { ajax } from '../src/ajax.js'; import { generateUUID, insertElement, isEmpty, logError } from '../src/utils.js'; +import * as events from '../src/events.js'; +import CONSTANTS from '../src/constants.json'; /** @type {string} */ const SUBMODULE_NAME = 'geoedge'; @@ -105,6 +107,7 @@ function getMacros(bid, key) { '%%PATTERN:hb_bidder%%': bid.bidderCode, '%_isHb!': true, '%_hbcid!': bid.creativeId || '', + '%_hbadomains': bid.meta && bid.meta.advertiserDomains, '%%PATTERN:hb_pb%%': bid.pbHg, '%%SITE%%': location.hostname, '%_pimp%': PV_ID @@ -184,6 +187,24 @@ function conditionallyWrap(bidResponse, config, userConsent) { } } +/** + * Fire billable events for applicable bids + */ +function fireBillableEventsForApplicableBids(params) { + events.on(CONSTANTS.EVENTS.BID_WON, function (winningBid) { + if (shouldWrap(winningBid, params)) { + events.emit(CONSTANTS.EVENTS.BILLABLE_EVENT, { + vendor: SUBMODULE_NAME, + billingId: generateUUID(), + type: 'impression', + transactionId: winningBid.transactionId, + auctionId: winningBid.auctionId, + bidId: winningBid.requestId + }); + } + }); +} + function init(config, userConsent) { let params = config.params; if (!params || !params.key) { @@ -191,6 +212,7 @@ function init(config, userConsent) { return false; } preloadClient(params.key); + fireBillableEventsForApplicableBids(params); return true; } diff --git a/modules/globalsunBidAdapter.js b/modules/globalsunBidAdapter.js new file mode 100644 index 00000000000..ae3407bbbdd --- /dev/null +++ b/modules/globalsunBidAdapter.js @@ -0,0 +1,212 @@ +import { isFn, deepAccess, logMessage, logError } from '../src/utils.js'; +import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; + +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; +import { config } from '../src/config.js'; + +const BIDDER_CODE = 'globalsun'; +const AD_URL = 'https://endpoint.globalsun.io/pbjs'; +const SYNC_URL = 'https://cs.globalsun.io'; + +function isBidResponseValid(bid) { + if (!bid.requestId || !bid.cpm || !bid.creativeId || !bid.ttl || !bid.currency) { + return false; + } + + switch (bid.mediaType) { + case BANNER: + return Boolean(bid.width && bid.height && bid.ad); + case VIDEO: + return Boolean(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 } = bid; + const schain = bid.schain || {}; + const { placementId, endpointId } = params; + const bidfloor = getBidFloor(bid); + + const placement = { + bidId, + schain, + bidfloor + }; + + if (placementId) { + placement.placementId = placementId; + placement.type = 'publisher'; + } else if (endpointId) { + placement.endpointId = endpointId; + placement.type = 'network'; + } + + if (mediaTypes && mediaTypes[BANNER]) { + placement.adFormat = BANNER; + placement.sizes = mediaTypes[BANNER].sizes; + } else if (mediaTypes && mediaTypes[VIDEO]) { + placement.adFormat = VIDEO; + placement.playerSize = mediaTypes[VIDEO].playerSize; + placement.minduration = mediaTypes[VIDEO].minduration; + placement.maxduration = mediaTypes[VIDEO].maxduration; + placement.mimes = mediaTypes[VIDEO].mimes; + placement.protocols = mediaTypes[VIDEO].protocols; + placement.startdelay = mediaTypes[VIDEO].startdelay; + placement.placement = mediaTypes[VIDEO].placement; + placement.skip = mediaTypes[VIDEO].skip; + placement.skipafter = mediaTypes[VIDEO].skipafter; + placement.minbitrate = mediaTypes[VIDEO].minbitrate; + placement.maxbitrate = mediaTypes[VIDEO].maxbitrate; + placement.delivery = mediaTypes[VIDEO].delivery; + placement.playbackmethod = mediaTypes[VIDEO].playbackmethod; + placement.api = mediaTypes[VIDEO].api; + placement.linearity = mediaTypes[VIDEO].linearity; + } else if (mediaTypes && mediaTypes[NATIVE]) { + placement.native = mediaTypes[NATIVE]; + placement.adFormat = NATIVE; + } + + return placement; +} + +function getBidFloor(bid) { + if (!isFn(bid.getFloor)) { + return deepAccess(bid, 'params.bidfloor', 0); + } + + try { + const bidFloor = bid.getFloor({ + currency: 'USD', + mediaType: '*', + size: '*', + }); + return bidFloor.floor; + } catch (err) { + logError(err); + return 0; + } +} + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER, VIDEO, NATIVE], + + isBidRequestValid: (bid = {}) => { + const { params, bidId, mediaTypes } = bid; + let valid = Boolean(bidId && params && (params.placementId || params.endpointId)); + + 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; + } + return valid; + }, + + buildRequests: (validBidRequests = [], bidderRequest = {}) => { + // convert Native ORTB definition to old-style prebid native definition + validBidRequests = convertOrtbRequestToProprietaryNative(validBidRequests); + + 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); + } + // TODO: does the fallback make sense here? + 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; + const placements = []; + const request = { + deviceWidth, + deviceHeight, + language, + secure, + host, + page, + placements, + coppa: config.getConfig('coppa') === true ? 1 : 0, + ccpa: bidderRequest.uspConsent || undefined, + gdpr: bidderRequest.gdprConsent || undefined, + tmax: config.getConfig('bidderTimeout') + }; + + const len = validBidRequests.length; + for (let i = 0; i < len; i++) { + const bid = validBidRequests[i]; + placements.push(getPlacementReqData(bid)); + } + + return { + method: 'POST', + url: AD_URL, + 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; + }, + + getUserSyncs: (syncOptions, serverResponses, gdprConsent, uspConsent) => { + let syncType = syncOptions.iframeEnabled ? 'iframe' : 'image'; + let syncUrl = SYNC_URL + `/${syncType}?pbjs=1`; + if (gdprConsent && gdprConsent.consentString) { + if (typeof gdprConsent.gdprApplies === 'boolean') { + syncUrl += `&gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`; + } else { + syncUrl += `&gdpr=0&gdpr_consent=${gdprConsent.consentString}`; + } + } + if (uspConsent && uspConsent.consentString) { + syncUrl += `&ccpa_consent=${uspConsent.consentString}`; + } + + const coppa = config.getConfig('coppa') ? 1 : 0; + syncUrl += `&coppa=${coppa}`; + + return [{ + type: syncType, + url: syncUrl + }]; + } +}; + +registerBidder(spec); diff --git a/modules/globalsunBidAdapter.md b/modules/globalsunBidAdapter.md new file mode 100644 index 00000000000..07c3ce32155 --- /dev/null +++ b/modules/globalsunBidAdapter.md @@ -0,0 +1,79 @@ +# Overview + +``` +Module Name: Globalsun Bidder Adapter +Module Type: Globalsun Bidder Adapter +Maintainer: prebid@globalsun.io +``` + +# Description + +Connects to Globalsun exchange for bids. +Globalsun bid adapter supports Banner, Video (instream and outstream) and Native. + +# Test Parameters +``` + var adUnits = [ + // Will return static test banner + { + code: 'adunit1', + mediaTypes: { + banner: { + sizes: [ [300, 250], [320, 50] ], + } + }, + bids: [ + { + bidder: 'globalsun', + params: { + placementId: 'testBanner', + } + } + ] + }, + { + code: 'addunit2', + mediaTypes: { + video: { + playerSize: [ [640, 480] ], + context: 'instream', + minduration: 5, + maxduration: 60, + } + }, + bids: [ + { + bidder: 'globalsun', + params: { + placementId: 'testVideo', + } + } + ] + }, + { + code: 'addunit3', + mediaTypes: { + native: { + title: { + required: true + }, + body: { + required: true + }, + icon: { + required: true, + size: [64, 64] + } + } + }, + bids: [ + { + bidder: 'globalsun', + params: { + placementId: 'testNative', + } + } + ] + } + ]; +``` diff --git a/modules/glomexBidAdapter.js b/modules/glomexBidAdapter.js index 32c2036a748..5c9b3c1fa28 100644 --- a/modules/glomexBidAdapter.js +++ b/modules/glomexBidAdapter.js @@ -4,9 +4,11 @@ import {BANNER} from '../src/mediaTypes.js'; const ENDPOINT = 'https://prebid.mes.glomex.cloud/request-bid' const BIDDER_CODE = 'glomex' +const GVLID = 967 export const spec = { code: BIDDER_CODE, + gvlid: GVLID, supportedMediaTypes: [BANNER], isBidRequestValid: function (bid) { diff --git a/modules/gravitoIdSystem.js b/modules/gravitoIdSystem.js index 30fa3abd6d2..809263a1c68 100644 --- a/modules/gravitoIdSystem.js +++ b/modules/gravitoIdSystem.js @@ -39,19 +39,18 @@ export const gravitoIdSystemSubmodule = { * decode the stored id value for passing to bid requests * @function * @param { {gravitompId: string} } value - * @returns { {gravitompId: {id: string} } | undefined } + * @returns { {gravitompId: {string} } | undefined } */ decode: function(value) { if (value && typeof value === 'object') { - const result = {}; + var result = {}; if (value.gravitompId) { - result.id = value.gravitompId + result = value.gravitompId } return {gravitompId: result}; } return undefined; }, - } submodule('userId', gravitoIdSystemSubmodule); diff --git a/modules/gridBidAdapter.js b/modules/gridBidAdapter.js index 181ce0ebab2..ce7fcc680dd 100644 --- a/modules/gridBidAdapter.js +++ b/modules/gridBidAdapter.js @@ -1,18 +1,38 @@ -import { isEmpty, deepAccess, logError, parseGPTSingleSizeArrayToRtbSize, generateUUID, mergeDeep, logWarn } from '../src/utils.js'; +import { + isEmpty, + deepAccess, + logError, + parseGPTSingleSizeArrayToRtbSize, + generateUUID, + mergeDeep, + logWarn, + parseUrl, isArray, isNumber +} from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; 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 { find } from '../src/polyfill.js'; const BIDDER_CODE = 'grid'; const ENDPOINT_URL = 'https://grid.bidswitch.net/hbjson'; + +const ADAPTER_VERSION_FOR_CRITEO_MODE = 34; +const CDB_ENDPOINT = 'https://bidder.criteo.com/cdb'; +const PROFILE_ID_INLINE = 207; +const SID_COOKIE_NAME = 'cto_sid'; +const IDCPY_COOKIE_NAME = 'cto_idcpy'; +const OPTOUT_COOKIE_NAME = 'cto_optout'; +const BUNDLE_COOKIE_NAME = 'cto_bundle'; + const SYNC_URL = 'https://x.bidswitch.net/sync?ssp=themediagrid'; const TIME_TO_LIVE = 360; const USER_ID_KEY = 'tmguid'; const GVLID = 686; const RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js'; export const storage = getStorageManager({gvlid: GVLID, bidderCode: BIDDER_CODE}); + const LOG_ERROR_MESS = { noAuid: 'Bid from response has no auid parameter - ', noAdm: 'Bid from response has no adm parameter - ', @@ -49,7 +69,7 @@ export const spec = { * @return boolean True if this is a valid bid, and false otherwise. */ isBidRequestValid: function(bid) { - return !!bid.params.uid; + return bid && Boolean(bid.params.uid || bid.params.secid); }, /** * Make a server request from the list of BidRequests. @@ -74,15 +94,24 @@ export const spec = { let {bidderRequestId, auctionId, gdprConsent, uspConsent, timeout, refererInfo} = bidderRequest || {}; const referer = refererInfo ? encodeURIComponent(refererInfo.page) : ''; - const bidderTimeout = config.getConfig('bidderTimeout') || timeout; - const tmax = timeout ? Math.min(bidderTimeout, timeout) : bidderTimeout; + const tmax = timeout || config.getConfig('bidderTimeout'); const imp = []; const bidsMap = {}; const requests = []; + const criteoBidsMap = {}; + const criteoBidRequests = []; const sources = []; const bidsArray = []; validBidRequests.forEach((bid) => { + const bidObject = { bid, savedPrebidBid: null }; + if (bid.params.withCriteo && criteoSpec.isBidRequestValid(bid)) { + criteoBidsMap[bid.bidId] = bidObject; + criteoBidRequests.push(bid); + } + if (!bid.params.uid && !bid.params.secid) { + return; + } if (!bidderRequestId) { bidderRequestId = bid.bidderRequestId; } @@ -100,7 +129,6 @@ export const spec = { } const { params: { uid, keywords, forceBidder, multiRequest }, mediaTypes, bidId, adUnitCode, rtd, ortb2Imp } = bid; const { pubdata, secid, pubid, source, content: bidParamsContent } = bid.params; - bidsMap[bidId] = bid; const bidFloor = _getFloor(mediaTypes || {}, bid); const jwTargeting = rtd && rtd.jwplayer && rtd.jwplayer.targeting; if (jwTargeting) { @@ -201,8 +229,9 @@ export const spec = { requests.push(request); sources.push(source); - bidsArray.push(bid); + bidsArray.push(bidObject); } else { + bidsMap[bidId] = bidObject; imp.push(impObj); } } @@ -259,9 +288,11 @@ export const spec = { return; } + if (request.user) user = request.user; + const ortb2UserData = deepAccess(bidderRequest, 'ortb2.user.data'); if (ortb2UserData && ortb2UserData.length) { - user = request.user || { data: [] }; + if (!user) user = { data: [] }; user = mergeDeep(user, { data: [...ortb2UserData] }); @@ -377,6 +408,11 @@ export const spec = { } }); + const criteoRequest = criteoBidRequests.length && criteoSpec.buildRequests(criteoBidRequests, bidderRequest); + if (criteoRequest) { + criteoRequest.criteoBidsMap = criteoBidsMap; + } + return [...requests.map((req, i) => { let sp; const url = (endpoint || ENDPOINT_URL).replace(/[?&]sp=([^?&=]+)/, (i, found) => { @@ -391,14 +427,14 @@ export const spec = { method: 'POST', url: urlWithParams, data: JSON.stringify(req), - bid: bidsArray[i], + bidObject: bidsArray[i], }; }), ...(mainRequest ? [{ method: 'POST', url: endpoint || ENDPOINT_URL, data: JSON.stringify(mainRequest), bidsMap - }] : [])]; + }] : []), ...(criteoRequest ? [criteoRequest] : [])]; }, /** * Unpack the response from the server into a list of bids. @@ -409,25 +445,33 @@ export const spec = { * @return {Bid[]} An array of bids which were nested inside the server. */ interpretResponse: function(serverResponse, bidRequest, RendererConst = Renderer) { - serverResponse = serverResponse && serverResponse.body; - const bidResponses = []; + if (bidRequest.criteoBidsMap && bidRequest.bidRequests) { + const criteoBids = criteoSpec.interpretResponse(serverResponse, bidRequest); + return criteoBids.filter((bid) => { + const { savedPrebidBid } = bidRequest.criteoBidsMap[bid.requestId] || {}; + return canPublishResponse(bid.cpm, savedPrebidBid && savedPrebidBid.cpm); + }); + } else { + serverResponse = serverResponse && serverResponse.body; + const bidResponses = []; - let errorMessage; + let errorMessage; - if (!serverResponse) errorMessage = LOG_ERROR_MESS.emptyResponse; - else if (serverResponse.seatbid && !serverResponse.seatbid.length) { - errorMessage = LOG_ERROR_MESS.hasEmptySeatbidArray; - } + if (!serverResponse) errorMessage = LOG_ERROR_MESS.emptyResponse; + else if (serverResponse.seatbid && !serverResponse.seatbid.length) { + errorMessage = LOG_ERROR_MESS.hasEmptySeatbidArray; + } - const bidderCode = this.forceBidderName || this.code; + const bidderCode = this.forceBidderName || this.code; - if (!errorMessage && serverResponse.seatbid) { - serverResponse.seatbid.forEach(respItem => { - _addBidResponse(_getBidFromResponse(respItem), bidRequest, bidResponses, RendererConst, bidderCode); - }); + if (!errorMessage && serverResponse.seatbid) { + serverResponse.seatbid.forEach(respItem => { + _addBidResponse(_getBidFromResponse(respItem), bidRequest, bidResponses, RendererConst, bidderCode); + }); + } + if (errorMessage) logError(errorMessage); + return bidResponses; } - if (errorMessage) logError(errorMessage); - return bidResponses; }, getUserSyncs: function (...args) { const [syncOptions,, gdprConsent, uspConsent] = args; @@ -502,8 +546,9 @@ function _addBidResponse(serverBid, bidRequest, bidResponses, RendererConst, bid if (!serverBid.auid) errorMessage = LOG_ERROR_MESS.noAuid + JSON.stringify(serverBid); if (!errorMessage && !serverBid.adm && !serverBid.nurl) errorMessage = LOG_ERROR_MESS.noAdm + JSON.stringify(serverBid); else { - const bid = bidRequest.bidsMap ? bidRequest.bidsMap[serverBid.impid] : bidRequest.bid; - if (bid) { + const bidObject = bidRequest.bidsMap ? bidRequest.bidsMap[serverBid.impid] : bidRequest.bidObject; + const { bid, savedPrebidBid } = bidObject || {}; + if (bid && canPublishResponse(serverBid.price, savedPrebidBid && savedPrebidBid.cpm)) { const bidResponse = { requestId: bid.bidId, // bid.bidderRequestId cpm: serverBid.price, @@ -519,6 +564,8 @@ function _addBidResponse(serverBid, bidRequest, bidResponses, RendererConst, bid dealId: serverBid.dealid }; + bidObject.savedPrebidBid = bidResponse; + if (serverBid.ext && serverBid.ext.bidder && serverBid.ext.bidder.grid && serverBid.ext.bidder.grid.demandSource) { bidResponse.adserverTargeting = { 'hb_ds': serverBid.ext.bidder.grid.demandSource }; bidResponse.meta.demandSource = serverBid.ext.bidder.grid.demandSource; @@ -606,7 +653,7 @@ function getUserIdFromFPDStorage() { function segmentProcessing(segment, forceSegName) { return segment .map((seg) => { - const value = seg && (seg.value || seg.id || seg); + const value = seg && (seg.id || seg); if (typeof value === 'string' || typeof value === 'number') { return { value: value.toString(), @@ -664,6 +711,13 @@ function reformatKeywords(pageKeywords) { return Object.keys(formatedPageKeywords).length && formatedPageKeywords; } +function canPublishResponse(price, savedPrice) { + if (isNumber(savedPrice)) { + return price > savedPrice || (price === savedPrice && Math.random() > 0.5); + } + return true; +} + function outstreamRender (bid) { bid.renderer.push(() => { window.ANOutstreamVideo.renderAd({ @@ -697,4 +751,369 @@ export function getSyncUrl() { return SYNC_URL; } +// ================ Criteo methods ================== + +const criteoSpec = { + /** f + * @param {object} bid + * @return {boolean} + */ + isBidRequestValid: (bid) => { + // either one of zoneId or networkId should be set + if (!(bid && bid.params && (bid.params.zoneId || bid.params.networkId))) { + return false; + } + + // video media types requires some mandatory params + if (hasVideoMediaType(bid)) { + if (!hasValidVideoMediaType(bid)) { + return false; + } + } + + return true; + }, + + /** + * @param {BidRequest[]} bidRequests + * @param {*} bidderRequest + * @return {ServerRequest} + */ + buildRequests: (bidRequests, bidderRequest) => { + let url; + let data; + let fpd = bidderRequest.ortb2 || {}; + + Object.assign(bidderRequest, { + publisherExt: fpd.site?.ext, + userExt: fpd.user?.ext, + ceh: config.getConfig('criteo.ceh'), + coppa: config.getConfig('coppa') + }); + + const context = buildContext(bidRequests, bidderRequest); + url = buildCdbUrl(context); + data = buildCdbRequest(context, bidRequests, bidderRequest); + + if (data) { + return { method: 'POST', url, data, bidRequests }; + } + }, + + /** + * @param {*} response + * @param {ServerRequest} request + * @return {Bid[]} + */ + interpretResponse: (response, request) => { + const body = response.body || response; + const bids = []; + + if (body && body.slots && isArray(body.slots)) { + body.slots.forEach(slot => { + const bidRequest = find(request.bidRequests, b => b.adUnitCode === slot.impid && (!b.params.zoneId || parseInt(b.params.zoneId) === slot.zoneid)); + const bidId = bidRequest.bidId; + const bid = { + requestId: bidId, + cpm: slot.cpm, + currency: slot.currency, + netRevenue: true, + ttl: slot.ttl || 60, + creativeId: slot.creativecode, + width: slot.width, + height: slot.height, + dealId: slot.dealCode, + }; + if (body.ext?.paf?.transmission && slot.ext?.paf?.content_id) { + const pafResponseMeta = { + content_id: slot.ext.paf.content_id, + transmission: response.ext.paf.transmission + }; + bid.meta = Object.assign({}, bid.meta, { paf: pafResponseMeta }); + } + if (slot.adomain) { + bid.meta = Object.assign({}, bid.meta, { advertiserDomains: slot.adomain }); + } + if (slot.video) { + bid.vastUrl = slot.displayurl; + bid.mediaType = VIDEO; + } else { + bid.ad = slot.creative; + } + bids.push(bid); + }); + } + + return bids; + } +}; + +function readFromAllStorages(name) { + const fromCookie = storage.getCookie(name); + const fromLocalStorage = storage.getDataFromLocalStorage(name); + + return fromCookie || fromLocalStorage || undefined; +} + +/** + * @param {BidRequest[]} bidRequests + * @param bidderRequest + */ +function buildContext(bidRequests, bidderRequest) { + let referrer = ''; + if (bidderRequest && bidderRequest.refererInfo) { + referrer = bidderRequest.refererInfo.page; + } + const queryString = parseUrl(bidderRequest?.refererInfo?.topmostLocation).search; + + const context = { + url: referrer, + debug: queryString['pbt_debug'] === '1', + noLog: queryString['pbt_nolog'] === '1', + amp: false, + }; + + bidRequests.forEach(bidRequest => { + if (bidRequest.params.integrationMode === 'amp') { + context.amp = true; + } + }); + + return context; +} + +/** + * @param {CriteoContext} context + * @return {string} + */ +function buildCdbUrl(context) { + let url = CDB_ENDPOINT; + url += '?profileId=' + PROFILE_ID_INLINE; + url += '&av=' + String(ADAPTER_VERSION_FOR_CRITEO_MODE); + url += '&wv=' + encodeURIComponent('$prebid.version$'); + url += '&cb=' + String(Math.floor(Math.random() * 99999999999)); + + if (storage.localStorageIsEnabled()) { + url += '&lsavail=1'; + } else { + url += '&lsavail=0'; + } + + if (context.amp) { + url += '&im=1'; + } + if (context.debug) { + url += '&debug=1'; + } + if (context.noLog) { + url += '&nolog=1'; + } + + const bundle = readFromAllStorages(BUNDLE_COOKIE_NAME); + if (bundle) { + url += `&bundle=${bundle}`; + } + + const optout = readFromAllStorages(OPTOUT_COOKIE_NAME); + if (optout) { + url += `&optout=1`; + } + + const sid = readFromAllStorages(SID_COOKIE_NAME); + if (sid) { + url += `&sid=${sid}`; + } + + const idcpy = readFromAllStorages(IDCPY_COOKIE_NAME); + if (idcpy) { + url += `&idcpy=${idcpy}`; + } + + return url; +} + +/** + * @param {CriteoContext} context + * @param {BidRequest[]} bidRequests + * @param bidderRequest + * @return {*} + */ +function buildCdbRequest(context, bidRequests, bidderRequest) { + let networkId; + let schain; + const request = { + publisher: { + url: context.url, + ext: bidderRequest.publisherExt, + }, + regs: { + coppa: bidderRequest.coppa === true ? 1 : (bidderRequest.coppa === false ? 0 : undefined) + }, + slots: bidRequests.map(bidRequest => { + networkId = bidRequest.params.networkId || networkId; + schain = bidRequest.schain || schain; + const slot = { + impid: bidRequest.adUnitCode, + transactionid: bidRequest.transactionId, + auctionId: bidRequest.auctionId, + }; + if (bidRequest.params.zoneId) { + slot.zoneid = bidRequest.params.zoneId; + } + if (deepAccess(bidRequest, 'ortb2Imp.ext')) { + slot.ext = bidRequest.ortb2Imp.ext; + } + if (bidRequest.params.ext) { + slot.ext = Object.assign({}, slot.ext, bidRequest.params.ext); + } + if (bidRequest.params.publisherSubId) { + slot.publishersubid = bidRequest.params.publisherSubId; + } + + if (hasBannerMediaType(bidRequest)) { + slot.sizes = parseSizes(deepAccess(bidRequest, 'mediaTypes.banner.sizes'), parseSize); + } else { + slot.sizes = []; + } + + if (hasVideoMediaType(bidRequest)) { + const video = { + playersizes: parseSizes(deepAccess(bidRequest, 'mediaTypes.video.playerSize'), parseSize), + mimes: bidRequest.mediaTypes.video.mimes, + protocols: bidRequest.mediaTypes.video.protocols, + maxduration: bidRequest.mediaTypes.video.maxduration, + api: bidRequest.mediaTypes.video.api, + skip: bidRequest.mediaTypes.video.skip, + placement: bidRequest.mediaTypes.video.placement, + minduration: bidRequest.mediaTypes.video.minduration, + playbackmethod: bidRequest.mediaTypes.video.playbackmethod, + startdelay: bidRequest.mediaTypes.video.startdelay + }; + const paramsVideo = bidRequest.params.video; + if (paramsVideo !== undefined) { + video.skip = video.skip || paramsVideo.skip || 0; + video.placement = video.placement || paramsVideo.placement; + video.minduration = video.minduration || paramsVideo.minduration; + video.playbackmethod = video.playbackmethod || paramsVideo.playbackmethod; + video.startdelay = video.startdelay || paramsVideo.startdelay || 0; + } + + slot.video = video; + } + + enrichSlotWithFloors(slot, bidRequest); + + return slot; + }), + }; + if (networkId) { + request.publisher.networkid = networkId; + } + if (schain) { + request.source = { + ext: { + schain: schain + } + }; + } + request.user = { + ext: bidderRequest.userExt + }; + if (bidderRequest && bidderRequest.ceh) { + request.user.ceh = bidderRequest.ceh; + } + if (bidderRequest && bidderRequest.gdprConsent) { + request.gdprConsent = {}; + if (typeof bidderRequest.gdprConsent.gdprApplies !== 'undefined') { + request.gdprConsent.gdprApplies = !!(bidderRequest.gdprConsent.gdprApplies); + } + request.gdprConsent.version = bidderRequest.gdprConsent.apiVersion; + if (typeof bidderRequest.gdprConsent.consentString !== 'undefined') { + request.gdprConsent.consentData = bidderRequest.gdprConsent.consentString; + } + } + if (bidderRequest && bidderRequest.uspConsent) { + request.user.uspIab = bidderRequest.uspConsent; + } + return request; +} + +function parseSizes(sizes, parser = s => s) { + if (sizes === undefined) { + return []; + } + if (Array.isArray(sizes[0])) { // is there several sizes ? (ie. [[728,90],[200,300]]) + return sizes.map(size => parser(size)); + } + return [parser(sizes)]; // or a single one ? (ie. [728,90]) +} + +function parseSize(size) { + return size[0] + 'x' + size[1]; +} + +function hasVideoMediaType(bidRequest) { + return deepAccess(bidRequest, 'mediaTypes.video') !== undefined; +} + +function hasBannerMediaType(bidRequest) { + return deepAccess(bidRequest, 'mediaTypes.banner') !== undefined; +} + +function hasValidVideoMediaType(bidRequest) { + let isValid = true; + + var requiredMediaTypesParams = ['mimes', 'playerSize', 'maxduration', 'protocols', 'api', 'skip', 'placement', 'playbackmethod']; + + requiredMediaTypesParams.forEach(function (param) { + if (deepAccess(bidRequest, 'mediaTypes.video.' + param) === undefined && deepAccess(bidRequest, 'params.video.' + param) === undefined) { + isValid = false; + logError('TheMediaGrid Bid Adapter (withCriteo mode): mediaTypes.video.' + param + ' is required'); + } + }); + + if (isValid) { + const videoPlacement = bidRequest.mediaTypes.video.placement || bidRequest.params.video.placement; + // We do not support long form for now, also we have to check that context & placement are consistent + if (bidRequest.mediaTypes.video.context === 'instream' && videoPlacement === 1) { + return true; + } else if (bidRequest.mediaTypes.video.context === 'outstream' && videoPlacement !== 1) { + return true; + } + } + + return false; +} + +function enrichSlotWithFloors(slot, bidRequest) { + try { + const slotFloors = {}; + + if (bidRequest.getFloor) { + if (bidRequest.mediaTypes?.banner) { + slotFloors.banner = {}; + const bannerSizes = parseSizes(deepAccess(bidRequest, 'mediaTypes.banner.sizes')) + bannerSizes.forEach(bannerSize => slotFloors.banner[parseSize(bannerSize).toString()] = bidRequest.getFloor({ size: bannerSize, mediaType: BANNER })); + } + + if (bidRequest.mediaTypes?.video) { + slotFloors.video = {}; + const videoSizes = parseSizes(deepAccess(bidRequest, 'mediaTypes.video.playerSize')) + videoSizes.forEach(videoSize => slotFloors.video[parseSize(videoSize).toString()] = bidRequest.getFloor({ size: videoSize, mediaType: VIDEO })); + } + + if (Object.keys(slotFloors).length > 0) { + if (!slot.ext) { + slot.ext = {} + } + Object.assign(slot.ext, { + floors: slotFloors + }); + } + } + } catch (e) { + logError('Could not parse floors from Prebid: ' + e); + } +} + registerBidder(spec); diff --git a/modules/gridNMBidAdapter.js b/modules/gridNMBidAdapter.js index 6f8eaba43d3..c49b7619c07 100644 --- a/modules/gridNMBidAdapter.js +++ b/modules/gridNMBidAdapter.js @@ -432,7 +432,7 @@ export function getSyncUrl() { function segmentProcessing(segment, forceSegName) { return segment .map((seg) => { - const value = seg && (seg.value || seg.id || seg); + const value = seg && (seg.id || seg); if (typeof value === 'string' || typeof value === 'number') { return { value: value.toString(), diff --git a/modules/growthCodeAnalyticsAdapter.js b/modules/growthCodeAnalyticsAdapter.js new file mode 100644 index 00000000000..1f11b891139 --- /dev/null +++ b/modules/growthCodeAnalyticsAdapter.js @@ -0,0 +1,176 @@ +/** + * growthCodeAnalyticsAdapter.js - GrowthCode Analytics Adapter + */ +import { ajax } from '../src/ajax.js'; +import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; +import adapterManager from '../src/adapterManager.js'; +import * as utils from '../src/utils.js'; +import CONSTANTS from '../src/constants.json'; +import { getStorageManager } from '../src/storageManager.js'; +import {getRefererInfo} from '../src/refererDetection.js'; +import {logError, logInfo} from '../src/utils.js'; + +const MODULE_NAME = 'growthCodeAnalytics'; +const DEFAULT_PID = 'INVALID_PID' +const ENDPOINT_URL = 'https://p2.gcprivacy.com/v1/pb/analytics' + +export const storage = getStorageManager(); + +let sessionId = utils.generateUUID(); + +let trackEvents = []; +let pid = DEFAULT_PID; +let url = ENDPOINT_URL; + +let eventQueue = []; + +let startAuction = 0; +let bidRequestTimeout = 0; +let analyticsType = 'endpoint'; + +let growthCodeAnalyticsAdapter = Object.assign(adapter({url: url, analyticsType}), { + track({eventType, eventData}) { + eventData = eventData ? JSON.parse(JSON.stringify(eventData)) : {}; + let data = {}; + if (!trackEvents.includes(eventType)) return; + switch (eventType) { + case CONSTANTS.EVENTS.AUCTION_INIT: { + data = eventData; + startAuction = data.timestamp; + bidRequestTimeout = data.timeout; + break; + } + + case CONSTANTS.EVENTS.AUCTION_END: { + data = eventData; + data.start = startAuction; + data.end = Date.now(); + break; + } + + case CONSTANTS.EVENTS.BID_ADJUSTMENT: { + data.bidders = eventData; + break; + } + + case CONSTANTS.EVENTS.BID_TIMEOUT: { + data.bidders = eventData; + data.duration = bidRequestTimeout; + break; + } + + case CONSTANTS.EVENTS.BID_REQUESTED: { + data = eventData; + break; + } + + case CONSTANTS.EVENTS.BID_RESPONSE: { + data = eventData; + delete data.ad; + break; + } + + case CONSTANTS.EVENTS.BID_WON: { + data = eventData; + delete data.ad; + delete data.adUrl; + break; + } + + case CONSTANTS.EVENTS.BIDDER_DONE: { + data = eventData; + break; + } + + case CONSTANTS.EVENTS.SET_TARGETING: { + data.targetings = eventData; + break; + } + + case CONSTANTS.EVENTS.REQUEST_BIDS: { + data = eventData; + break; + } + + case CONSTANTS.EVENTS.ADD_AD_UNITS: { + data = eventData; + break; + } + + default: + return; + } + + data.eventType = eventType; + data.timestamp = data.timestamp || Date.now(); + + sendEvent(data); + } +}); + +growthCodeAnalyticsAdapter.originEnableAnalytics = growthCodeAnalyticsAdapter.enableAnalytics; + +growthCodeAnalyticsAdapter.enableAnalytics = function(conf = {}) { + if (typeof conf.options === 'object') { + if (conf.options.pid) { + pid = conf.options.pid; + url = conf.options.url ? conf.options.url : ENDPOINT_URL; + } else { + logError(MODULE_NAME + ' Not a valid PartnerID') + return + } + if (conf.options.trackEvents) { + trackEvents = conf.options.trackEvents; + } + } else { + logError(MODULE_NAME + ' Invalid configuration'); + return; + } + + growthCodeAnalyticsAdapter.originEnableAnalytics(conf); +}; + +function logToServer() { + if (pid === DEFAULT_PID) return; + if (eventQueue.length > 1) { + let data = { + session: sessionId, + pid: pid, + timestamp: Date.now(), + timezoneoffset: new Date().getTimezoneOffset(), + url: getRefererInfo().page, + referer: document.referrer, + events: eventQueue + }; + + ajax(url, { + success: response => { + logInfo(MODULE_NAME + ' Send Data to Server') + }, + error: error => { + logInfo(MODULE_NAME + ' Problem Send Data to Server: ' + error) + } + }, JSON.stringify(data), {method: 'POST', withCredentials: true}) + + eventQueue = [ + ]; + } +} + +function sendEvent(event) { + eventQueue.push(event); + logInfo(MODULE_NAME + 'Analytics Event: ' + event); + + if (event.eventType === CONSTANTS.EVENTS.AUCTION_END) { + logToServer(); + } +} + +adapterManager.registerAnalyticsAdapter({ + adapter: growthCodeAnalyticsAdapter, + code: 'growthCodeAnalytics' +}); + +growthCodeAnalyticsAdapter.logToServer = logToServer; + +export default growthCodeAnalyticsAdapter; diff --git a/modules/growthCodeAnalyticsAdapter.md b/modules/growthCodeAnalyticsAdapter.md new file mode 100644 index 00000000000..e45cb2e9c62 --- /dev/null +++ b/modules/growthCodeAnalyticsAdapter.md @@ -0,0 +1,41 @@ +## GrowthCode Analytics Adapter + +[GrowthCode](https://growthcode.io) offers scaled infrastructure-as-a-service to +empower independent publishers to harness data and take control of identity and +audience while rapidly aligning to industry changes and margin pressure. + +## Building Prebid with GrowthCode Support + +First, make sure to add the GrowthCode submodule to your Prebid.js package with: + +``` +gulp build --modules=growthCodeIdSystem,growthCodeAnalyticsAdapter,userId +``` + +The following configuration parameters are available: + +```javascript +pbjs.enableAnalytics({ + provider: 'growthCodeAnalytics', + options: { + pid: '', + trackEvents: [ + 'auctionEnd', + 'bidAdjustment', + 'bidTimeout', + 'bidRequested', + 'bidResponse', + 'noBid', + 'bidWon', + 'bidderDone'] + } +}); +``` + +| Param enableAnalytics | Scope | Type | Description | Example | +|-----------------------|----------|--------|-------------------------------------------------------------|--------------------------| +| provider | Required | String | The name of this Adapter. | `"growthCodeAnalytics"` | +| params | Required | Object | Details of module params. | | +| params.pid | Required | String | This is the Customer ID value obtained via Intimate Merger. | `""` | +| params.url | Optional | String | Custom URL for server | | +| params.trackEvents | Required | String | Name if the variable that holds your publisher ID | | diff --git a/modules/growthCodeIdSystem.js b/modules/growthCodeIdSystem.js index 68fe2c7e925..edd7cd33012 100644 --- a/modules/growthCodeIdSystem.js +++ b/modules/growthCodeIdSystem.js @@ -10,7 +10,7 @@ import {ajax} from '../src/ajax.js'; import { submodule } from '../src/hook.js' import { getStorageManager } from '../src/storageManager.js'; -const GCID_EXPIRY = 45; +const GCID_EXPIRY = 7; const MODULE_NAME = 'growthCodeId'; const GC_DATA_KEY = '_gc_data'; const ENDPOINT_URL = 'https://p2.gcprivacy.com/v1/pb?' @@ -24,11 +24,15 @@ export const storage = getStorageManager({ gvlid: undefined, moduleName: MODULE_ */ export function readData(key) { try { + let payload + if (storage.cookiesAreEnabled()) { + payload = tryParse(storage.getCookie(key)) + } if (storage.hasLocalStorage()) { - return storage.getDataFromLocalStorage(key); + payload = tryParse(storage.getDataFromLocalStorage(key)) } - if (storage.cookiesAreEnabled()) { - return storage.getCookie(key); + if ((payload.expire_at !== undefined) && (payload.expire_at > (Date.now() / 1000))) { + return payload } } catch (error) { logError(error); @@ -122,7 +126,7 @@ export const growthCodeIdSubmodule = { } const resp = function(callback) { - let gcData = tryParse(readData(GC_DATA_KEY)); + let gcData = readData(GC_DATA_KEY); if (gcData) { callback(gcData); } else { diff --git a/modules/gumgumBidAdapter.js b/modules/gumgumBidAdapter.js index fe15602c0c0..b12aa3ee861 100644 --- a/modules/gumgumBidAdapter.js +++ b/modules/gumgumBidAdapter.js @@ -293,7 +293,9 @@ function buildRequests(validBidRequests, bidderRequest) { const bids = []; const gdprConsent = bidderRequest && bidderRequest.gdprConsent; const uspConsent = bidderRequest && bidderRequest.uspConsent; + const gppConsent = bidderRequest && bidderRequest.gppConsent; const timeout = config.getConfig('bidderTimeout'); + const coppa = config.getConfig('coppa') === true ? 1 : 0; const topWindowUrl = bidderRequest && bidderRequest.refererInfo && bidderRequest.refererInfo.page; _each(validBidRequests, bidRequest => { const { @@ -386,6 +388,20 @@ function buildRequests(validBidRequests, bidderRequest) { if (uspConsent) { data.uspConsent = uspConsent; } + if (gppConsent) { + data.gppConsent = { + gppString: bidderRequest.gppConsent.gppString, + applicableSections: bidderRequest.gppConsent.applicableSections + } + } else if (!gppConsent && bidderRequest?.ortb2?.regs?.gpp) { + data.gppConsent = { + gppString: bidderRequest.ortb2.regs.gpp, + applicableSections: bidderRequest.ortb2.regs.gpp_sid + }; + } + if (coppa) { + data.coppa = coppa; + } if (schain && schain.nodes) { data.schain = _serializeSupplyChainObj(schain); } diff --git a/modules/hadronIdSystem.js b/modules/hadronIdSystem.js index 2f10245cd59..a75c03ee1c4 100644 --- a/modules/hadronIdSystem.js +++ b/modules/hadronIdSystem.js @@ -8,8 +8,9 @@ import {ajax} from '../src/ajax.js'; import {getStorageManager} from '../src/storageManager.js'; import {submodule} from '../src/hook.js'; -import { isFn, isStr, isPlainObject, logError } from '../src/utils.js'; +import {isFn, isStr, isPlainObject, logError, logInfo} from '../src/utils.js'; +const HADRONID_LOCAL_NAME = 'auHadronId'; const MODULE_NAME = 'hadronId'; const AU_GVLID = 561; const DEFAULT_HADRON_URL_ENDPOINT = 'https://id.hadron.ad.gt/api/v1/pbhid'; @@ -18,8 +19,9 @@ export const storage = getStorageManager({gvlid: AU_GVLID, moduleName: 'hadron'} /** * Param or default. - * @param {String} param + * @param {String|function} param * @param {String} defaultVal + * @param arg */ function paramOrDefault(param, defaultVal, arg) { if (isFn(param)) { @@ -53,11 +55,11 @@ export const hadronIdSubmodule = { * @returns {Object} */ decode(value) { - let hadronId = storage.getDataFromLocalStorage('auHadronId'); + const hadronId = storage.getDataFromLocalStorage(HADRONID_LOCAL_NAME); if (isStr(hadronId)) { return {hadronId: hadronId}; } - return (value && typeof value['hadronId'] === 'string') ? { 'hadronId': value['hadronId'] } : undefined; + return (value && typeof value['hadronId'] === 'string') ? {'hadronId': value['hadronId']} : undefined; }, /** * performs action to obtain id and return a value in the callback's response argument @@ -70,37 +72,40 @@ export const hadronIdSubmodule = { config.params = {}; } const partnerId = config.params.partnerId | 0; - - const url = urlAddParams( - paramOrDefault(config.params.url, DEFAULT_HADRON_URL_ENDPOINT, config.params.urlArg), - `partner_id=${partnerId}&_it=prebid` - ); - + let hadronId = storage.getDataFromLocalStorage(HADRONID_LOCAL_NAME); + if (isStr(hadronId)) { + return {id: {hadronId}}; + } const resp = function (callback) { - let hadronId = storage.getDataFromLocalStorage('auHadronId'); - if (isStr(hadronId)) { - const responseObj = {hadronId: hadronId}; - callback(responseObj); - } else { - const callbacks = { - success: response => { - let responseObj; - if (response) { - try { - responseObj = JSON.parse(response); - } catch (error) { - logError(error); - } + let responseObj = {}; + const callbacks = { + success: response => { + if (response) { + try { + responseObj = JSON.parse(response); + } catch (error) { + logError(error); } - callback(responseObj); - }, - error: error => { - logError(`${MODULE_NAME}: ID fetch encountered an error`, error); - callback(); + logInfo(`Response from backend is ${responseObj}`); + hadronId = responseObj['hadronId']; + storage.setDataInLocalStorage(HADRONID_LOCAL_NAME, hadronId); + responseObj = {id: {hadronId}}; } - }; - ajax(url, callbacks, undefined, {method: 'GET'}); - } + callback(responseObj); + }, + error: error => { + logError(`${MODULE_NAME}: ID fetch encountered an error`, error); + callback(); + } + }; + logInfo('HadronId not found in storage, calling backend...'); + const url = urlAddParams( + // config.params.url and config.params.urlArg are not documented + // since their use is for debugging purposes only + paramOrDefault(config.params.url, DEFAULT_HADRON_URL_ENDPOINT, config.params.urlArg), + `partner_id=${partnerId}&_it=prebid` + ); + ajax(url, callbacks, undefined, {method: 'GET'}); }; return {callback: resp}; } diff --git a/modules/holidBidAdapter.js b/modules/holidBidAdapter.js new file mode 100644 index 00000000000..92b0a1c18db --- /dev/null +++ b/modules/holidBidAdapter.js @@ -0,0 +1,175 @@ +import { + deepAccess, + getBidIdParameter, + isStr, + logMessage, + triggerPixel, +} from '../src/utils.js' +import * as events from '../src/events.js' +import CONSTANTS from '../src/constants.json' +import { BANNER } from '../src/mediaTypes.js' + +import { registerBidder } from '../src/adapters/bidderFactory.js' + +const BIDDER_CODE = 'holid' +const GVLID = 1177 +const ENDPOINT = 'https://helloworld.holid.io/openrtb2/auction' +const COOKIE_SYNC_ENDPOINT = 'https://null.holid.io/sync.html' +const TIME_TO_LIVE = 300 +let wurlMap = {} + +events.on(CONSTANTS.EVENTS.BID_WON, bidWonHandler) + +export const spec = { + code: BIDDER_CODE, + gvlid: GVLID, + supportedMediaTypes: [BANNER], + + isBidRequestValid: function (bid) { + return !!bid.params.adUnitID + }, + + buildRequests: function (validBidRequests, _bidderRequest) { + return validBidRequests.map((bid) => { + const requestData = { + ...bid.ortb2, + id: bid.auctionId, + imp: [getImp(bid)], + } + + return { + method: 'POST', + url: ENDPOINT, + data: JSON.stringify(requestData), + bidId: bid.bidId, + } + }) + }, + + interpretResponse: function (serverResponse, bidRequest) { + const bidResponses = [] + + if (!serverResponse.body.seatbid) { + return [] + } + + serverResponse.body.seatbid.map((response) => { + response.bid.map((bid) => { + const requestId = bidRequest.bidId + const auctionId = bidRequest.auctionId + const wurl = deepAccess(bid, 'ext.prebid.events.win') + const bidResponse = { + requestId, + cpm: bid.price, + width: bid.w, + height: bid.h, + ad: bid.adm, + creativeId: bid.crid, + currency: serverResponse.body.cur, + netRevenue: true, + ttl: TIME_TO_LIVE, + } + + addWurl({ auctionId, requestId, wurl }) + + bidResponses.push(bidResponse) + }) + }) + + return bidResponses + }, + + getUserSyncs(optionsType, serverResponse, gdprConsent, uspConsent) { + if (!serverResponse || serverResponse.length === 0) { + return [] + } + + const syncs = [] + const bidders = getBidders(serverResponse) + + if (optionsType.iframeEnabled && bidders) { + const queryParams = [] + + queryParams.push('bidders=' + bidders) + queryParams.push('gdpr=' + +gdprConsent.gdprApplies) + queryParams.push('gdpr_consent=' + gdprConsent.consentString) + queryParams.push('usp_consent=' + (uspConsent || '')) + + let strQueryParams = queryParams.join('&') + + if (strQueryParams.length > 0) { + strQueryParams = '?' + strQueryParams + } + + syncs.push({ + type: 'iframe', + url: COOKIE_SYNC_ENDPOINT + strQueryParams + '&type=iframe', + }) + + return syncs + } + + return [] + }, +} + +function getImp(bid) { + const imp = { + ext: { + prebid: { + storedrequest: { + id: getBidIdParameter('adUnitID', bid.params), + }, + }, + }, + } + const sizes = + bid.sizes && !Array.isArray(bid.sizes[0]) ? [bid.sizes] : bid.sizes + + if (deepAccess(bid, 'mediaTypes.banner')) { + imp.banner = { + format: sizes.map((size) => { + return { w: size[0], h: size[1] } + }), + } + } + + return imp +} + +function getBidders(serverResponse) { + const bidders = serverResponse + .map((res) => Object.keys(res.body.ext.responsetimemillis || [])) + .flat(1) + + if (bidders.length) { + return encodeURIComponent(JSON.stringify([...new Set(bidders)])) + } +} + +function addWurl(auctionId, adId, wurl) { + if ([auctionId, adId].every(isStr)) { + wurlMap[`${auctionId}${adId}`] = wurl + } +} + +function removeWurl(auctionId, adId) { + delete wurlMap[`${auctionId}${adId}`] +} + +function getWurl(auctionId, adId) { + if ([auctionId, adId].every(isStr)) { + return wurlMap[`${auctionId}${adId}`] + } +} + +function bidWonHandler(bid) { + const wurl = getWurl(bid.auctionId, bid.adId) + if (wurl) { + logMessage(`Invoking image pixel for wurl on BID_WIN: "${wurl}"`) + triggerPixel(wurl) + removeWurl(bid.auctionId, bid.adId) + } +} + +registerBidder(spec) diff --git a/modules/holidBidAdapter.md b/modules/holidBidAdapter.md new file mode 100644 index 00000000000..1d83918c00a --- /dev/null +++ b/modules/holidBidAdapter.md @@ -0,0 +1,36 @@ +# Overview + +``` +Module Name: Holid Bid Adapter +Module Type: Bidder Adapter +Maintainer: richard@holid.se +``` + +# Description + +Currently module supports only banner mediaType. + +# Test Parameters + +## Sample Banner Ad Unit + +```js +var adUnits = [ + { + code: 'bannerAdUnit', + mediaTypes: { + banner: { + sizes: [[300, 250]], + }, + }, + bids: [ + { + bidder: 'holid', + params: { + adUnitID: '12345', + }, + }, + ], + }, +] +``` diff --git a/modules/id5IdSystem.js b/modules/id5IdSystem.js index c2c4a97c62e..488df984913 100644 --- a/modules/id5IdSystem.js +++ b/modules/id5IdSystem.js @@ -113,6 +113,11 @@ export const id5IdSubmodule = { return undefined; } + if (!hasWriteConsentToLocalStorage(consentData)) { + logInfo(LOG_PREFIX + 'Skipping ID5 local storage write because no consent given.') + return undefined; + } + const resp = function (cbFunction) { new IdFetchFlow(submoduleConfig, consentData, cacheIdObj, uspDataHandler.getConsentData()).execute() .then(response => { @@ -140,6 +145,11 @@ export const id5IdSubmodule = { extendId(config, consentData, cacheIdObj) { hasRequiredConfig(config); + if (!hasWriteConsentToLocalStorage(consentData)) { + logInfo(LOG_PREFIX + 'No consent given for ID5 local storage writing, skipping nb increment.') + return cacheIdObj; + } + const partnerId = (config && config.params && config.params.partner) || 0; incrementNb(partnerId); @@ -247,7 +257,9 @@ class IdFetchFlow { 'gdpr': hasGdpr, 'nbPage': nbPage, 'o': 'pbjs', - 'rf': referer.topmostLocation, + 'tml': referer.topmostLocation, + 'ref': referer.ref, + 'cu': referer.canonicalUrl, 'top': referer.reachedTop ? 1 : 0, 'u': referer.stack[0] || window.location.href, 'v': '$prebid.version$', @@ -374,4 +386,19 @@ export function storeInLocalStorage(key, value, expDays) { storage.setDataInLocalStorage(`${key}`, value); } +/** + * Check to see if we can write to local storage based on purpose consent 1, and that we have vendor consent (ID5=131) + * @param {ConsentData} consentData + * @returns {boolean} + */ +function hasWriteConsentToLocalStorage(consentData) { + const hasGdpr = consentData && typeof consentData.gdprApplies === 'boolean' && consentData.gdprApplies; + const localstorageConsent = deepAccess(consentData, `vendorData.purpose.consents.1`) + const id5VendorConsent = deepAccess(consentData, `vendorData.vendor.consents.${GVLID.toString()}`) + if (hasGdpr && (!localstorageConsent || !id5VendorConsent)) { + return false; + } + return true; +} + submodule('userId', id5IdSubmodule); diff --git a/modules/impactifyBidAdapter.js b/modules/impactifyBidAdapter.js index 0717cf43741..04f34bdc7d9 100644 --- a/modules/impactifyBidAdapter.js +++ b/modules/impactifyBidAdapter.js @@ -1,7 +1,7 @@ import { deepAccess, deepSetValue, generateUUID } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { config } from '../src/config.js'; -import {ajax} from '../src/ajax.js'; +import { ajax } from '../src/ajax.js'; import { createEidsArray } from './userId/eids.js'; const BIDDER_CODE = 'impactify'; @@ -27,6 +27,18 @@ const getDeviceType = () => { return 2; }; +const getFloor = (bid) => { + const floorInfo = bid.getFloor({ + currency: DEFAULT_CURRENCY, + mediaType: '*', + size: '*' + }); + if (typeof floorInfo === 'object' && floorInfo.currency === DEFAULT_CURRENCY && !isNaN(parseFloat(floorInfo.floor))) { + return parseFloat(floorInfo.floor); + } + return null; +} + const createOpenRtbRequest = (validBidRequests, bidderRequest) => { // Create request and set imp bids inside let request = { @@ -114,6 +126,12 @@ const createOpenRtbRequest = (validBidRequests, bidderRequest) => { if (bid.params.container) { imp.ext.impactify.container = bid.params.container; } + if (typeof bid.getFloor === 'function') { + const floor = getFloor(bid); + if (floor) { + imp.bidfloor = floor; + } + } request.imp.push(imp); }); diff --git a/modules/improvedigitalBidAdapter.js b/modules/improvedigitalBidAdapter.js index 94f50094a91..437fcf7d5bb 100644 --- a/modules/improvedigitalBidAdapter.js +++ b/modules/improvedigitalBidAdapter.js @@ -378,7 +378,7 @@ const ID_RAZR = { } }; - const cfgStr = JSON.stringify(cfg).replace(/<\/script>/g, '\\x3C/script>'); + const cfgStr = JSON.stringify(cfg).replace(/<\/script>/ig, '\\x3C/script>'); const s = ``; bid.ad = bid.ad.replace(/]*>/, match => match + s); diff --git a/modules/incrxBidAdapter.js b/modules/incrxBidAdapter.js index 914ef0b904e..d054309ee40 100644 --- a/modules/incrxBidAdapter.js +++ b/modules/incrxBidAdapter.js @@ -68,6 +68,8 @@ export const spec = { requestId: response.slotBidId, cpm: response.cpm, currency: response.currency || DEFAULT_CURRENCY, + adType: response.adType || '1', + settings: response.settings, width: response.adWidth, height: response.adHeight, ttl: CREATIVE_TTL, diff --git a/modules/ixBidAdapter.js b/modules/ixBidAdapter.js index fc387fac76a..360a373ba9a 100644 --- a/modules/ixBidAdapter.js +++ b/modules/ixBidAdapter.js @@ -16,15 +16,15 @@ import { parseQueryStringParameters, safeJSONParse } from '../src/utils.js'; -import {BANNER, VIDEO, NATIVE} from '../src/mediaTypes.js'; -import {config} from '../src/config.js'; +import { BANNER, VIDEO, NATIVE } from '../src/mediaTypes.js'; +import { config } from '../src/config.js'; import CONSTANTS from '../src/constants.json'; -import {getStorageManager} from '../src/storageManager.js'; +import { getStorageManager } from '../src/storageManager.js'; import * as events from '../src/events.js'; -import {find} from '../src/polyfill.js'; -import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {INSTREAM, OUTSTREAM} from '../src/video.js'; -import {Renderer} from '../src/Renderer.js'; +import { find } from '../src/polyfill.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { INSTREAM, OUTSTREAM } from '../src/video.js'; +import { Renderer } from '../src/Renderer.js'; const BIDDER_CODE = 'ix'; const ALIAS_BIDDER_CODE = 'roundel'; @@ -38,7 +38,6 @@ const BANNER_TIME_TO_LIVE = 300; const VIDEO_TIME_TO_LIVE = 3600; // 1hr const NATIVE_TIME_TO_LIVE = 3600; // Since native can have video, use ttl same as video const NET_REVENUE = true; -const MAX_REQUEST_SIZE = 8000; const MAX_REQUEST_LIMIT = 4; const OUTSTREAM_MINIMUM_PLAYER_SIZE = [144, 144]; const PRICE_TO_DOLLAR_FACTOR = { @@ -77,7 +76,8 @@ const SOURCE_RTI_MAPPING = { 'epsilon.com': '', // Publisher Link, publinkId 'audigent.com': '', // Hadron ID from Audigent, hadronId 'pubcid.org': '', // SharedID, pubcid - 'trustpid.com': '' // Trustpid + 'trustpid.com': '', // Trustpid + 'intimatemerger.com': '' }; const PROVIDERS = [ 'britepoolid', @@ -102,13 +102,13 @@ const VIDEO_PARAMS_ALLOW_LIST = [ const LOCAL_STORAGE_KEY = 'ixdiag'; export const LOCAL_STORAGE_FEATURE_TOGGLES_KEY = `${BIDDER_CODE}_features`; let hasRegisteredHandler = false; -export const storage = getStorageManager({gvlid: GLOBAL_VENDOR_ID, bidderCode: BIDDER_CODE}); +export const storage = getStorageManager({ gvlid: GLOBAL_VENDOR_ID, bidderCode: BIDDER_CODE }); export const FEATURE_TOGGLES = { featureToggles: {}, - isFeatureEnabled: function(ft) { + isFeatureEnabled: function (ft) { return deepAccess(this.featureToggles, `features.${ft}.activated`) }, - getFeatureToggles: function() { + getFeatureToggles: function () { if (storage.localStorageIsEnabled()) { const parsedToggles = safeJSONParse(storage.getDataFromLocalStorage(LOCAL_STORAGE_FEATURE_TOGGLES_KEY)); if (deepAccess(parsedToggles, 'expiry') && parsedToggles.expiry >= new Date().getTime()) { @@ -118,7 +118,7 @@ export const FEATURE_TOGGLES = { } } }, - setFeatureToggles: function(serverResponse) { + setFeatureToggles: function (serverResponse) { const responseBody = serverResponse.body; const expiryTime = new Date(); const toggles = deepAccess(responseBody, 'ext.features'); @@ -133,7 +133,7 @@ export const FEATURE_TOGGLES = { } } }, - clearFeatureToggles: function() { + clearFeatureToggles: function () { this.featureToggles = {}; if (storage.localStorageIsEnabled()) { storage.removeDataFromLocalStorage(LOCAL_STORAGE_FEATURE_TOGGLES_KEY); @@ -152,6 +152,11 @@ const MEDIA_TYPES = { Native: 4 }; +let baseRequestSize = 0; +let currentRequestSize = 0; +let wasAdUnitImpressionsTrimmed = false; +let currentImpressionSize = 0; + /** * Transform valid bid request config object to banner impression object that will be sent to ad server. * @@ -159,7 +164,7 @@ const MEDIA_TYPES = { * @return {object} A impression object that will be sent to ad server. */ function bidToBannerImp(bid) { - const imp = bidToImp(bid); + const imp = bidToImp(bid, BANNER); imp.banner = {}; const impSize = deepAccess(bid, 'params.size'); if (impSize) { @@ -181,7 +186,7 @@ function bidToBannerImp(bid) { * @return {object} A impression object that will be sent to ad server. */ function bidToVideoImp(bid) { - const imp = bidToImp(bid); + const imp = bidToImp(bid, VIDEO); const videoAdUnitRef = deepAccess(bid, 'mediaTypes.video'); const videoParamRef = deepAccess(bid, 'params.video'); const videoParamErrors = checkVideoParams(videoAdUnitRef, videoParamRef); @@ -249,7 +254,7 @@ function bidToVideoImp(bid) { * @return {object} A impression object that will be sent to ad server. */ function bidToNativeImp(bid) { - const imp = bidToImp(bid); + const imp = bidToImp(bid, NATIVE); const request = bid.nativeOrtbRequest request.eventtrackers = [{ @@ -276,13 +281,28 @@ function bidToNativeImp(bid) { * @param {object} bid PBJS bid object * @returns {object} IX impression object */ -function bidToImp(bid) { +function bidToImp(bid, mediaType) { const imp = {}; imp.id = bid.bidId; imp.ext = {}; - imp.ext.siteID = bid.params.siteId.toString(); + + if (deepAccess(bid, `params.${mediaType}.siteId`) && !isNaN(Number(bid.params[mediaType].siteId))) { + switch (mediaType) { + case BANNER: + imp.ext.siteID = bid.params.banner.siteId.toString(); + break; + case VIDEO: + imp.ext.siteID = bid.params.video.siteId.toString(); + break; + case NATIVE: + imp.ext.siteID = bid.params.native.siteId.toString(); + break; + } + } else { + imp.ext.siteID = bid.params.siteId.toString(); + } // populate imp level sid if (bid.params.hasOwnProperty('id') && (typeof bid.params.id === 'string' || typeof bid.params.id === 'number')) { @@ -366,8 +386,8 @@ function parseBid(rawBid, currency, bidRequest) { bid.netRevenue = NET_REVENUE; bid.currency = currency; bid.creativeId = rawBid.hasOwnProperty('crid') ? rawBid.crid : '-'; - - if (rawBid.mtype == MEDIA_TYPES.Video) { + // If mtype = video is passed and vastURl is not set, set vastxml + if (rawBid.mtype == MEDIA_TYPES.Video && ((rawBid.ext && !rawBid.ext.vasturl) || !rawBid.ext)) { bid.vastXml = rawBid.adm; } else if (rawBid.ext && rawBid.ext.vasturl) { bid.vastUrl = rawBid.ext.vasturl; @@ -391,7 +411,7 @@ function parseBid(rawBid, currency, bidRequest) { bid.mediaTypes = bidRequest.mediaTypes; bid.ttl = isValidExpiry ? rawBid.exp : VIDEO_TIME_TO_LIVE; } else if (parsedAdm && parsedAdm.native) { - bid.native = {ortb: parsedAdm.native}; + bid.native = { ortb: parsedAdm.native }; bid.width = rawBid.w ? rawBid.w : 1; bid.height = rawBid.h ? rawBid.h : 1; bid.mediaType = NATIVE; @@ -411,7 +431,6 @@ function parseBid(rawBid, currency, bidRequest) { if (rawBid.adomain && rawBid.adomain.length > 0) { bid.meta.advertiserDomains = rawBid.adomain; } - return bid; } @@ -579,28 +598,23 @@ function getEidInfo(allEids) { * */ function buildRequest(validBidRequests, bidderRequest, impressions, version) { + baseRequestSize = 0; + currentRequestSize = 0; + wasAdUnitImpressionsTrimmed = false; + currentImpressionSize = 0; + // Always use secure HTTPS protocol. let baseUrl = SECURE_BID_URL; // Get ids from Prebid User ID Modules let eidInfo = getEidInfo(deepAccess(validBidRequests, '0.userIdAsEids')); let userEids = eidInfo.toSend; - const pageUrl = deepAccess(bidderRequest, 'refererInfo.page'); + + let MAX_REQUEST_SIZE = 8000; // RTI ids will be included in the bid request if the function getIdentityInfo() is loaded // and if the data for the partner exist if (window.headertag && typeof window.headertag.getIdentityInfo === 'function') { - let identityInfo = window.headertag.getIdentityInfo(); - if (identityInfo && typeof identityInfo === 'object') { - for (const partnerName in identityInfo) { - if (identityInfo.hasOwnProperty(partnerName)) { - let response = identityInfo[partnerName]; - if (!response.responsePending && response.data && typeof response.data === 'object' && - Object.keys(response.data).length && !eidInfo.seenSources[response.data.source]) { - userEids.push(response.data); - } - } - } - } + addRTI(userEids, eidInfo); } // If `roundel` alias bidder, only send requests if liveramp ids exist. @@ -608,9 +622,123 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { return []; } - const r = {}; - const tmax = config.getConfig('bidderTimeout'); + const requests = []; + let r = createRequest(validBidRequests); + + // getting ixdiags for adunits of the video, outstream & multi format (MF) style + let ixdiag = buildIXDiag(validBidRequests); + for (var key in ixdiag) { + r.ext.ixdiag[key] = ixdiag[key]; + } + + r = enrichRequest(r, bidderRequest, impressions, validBidRequests, userEids); + + r = applyRegulations(r, bidderRequest); + + let payload = {}; + createPayload(validBidRequests, bidderRequest, r, baseUrl, requests, payload, MAX_REQUEST_SIZE); + + let requestSequenceNumber = 0; + const transactionIds = Object.keys(impressions); + let isFpdAdded = false; + + for (let adUnitIndex = 0; adUnitIndex < transactionIds.length; adUnitIndex++) { + // buildRequestV2 does not have request spliting logic. + if (!FEATURE_TOGGLES.isFeatureEnabled('pbjs_use_buildRequestV2')) { + if (currentRequestSize >= MAX_REQUEST_SIZE) { + break; + } + } + if (requests.length >= MAX_REQUEST_LIMIT) { + break; + } + + r = addImpressions(impressions, transactionIds, r, adUnitIndex, MAX_REQUEST_SIZE); + currentRequestSize += currentImpressionSize; + + const fpd = deepAccess(bidderRequest, 'ortb2') || {}; + const site = { ...(fpd.site || fpd.context) }; + const user = { ...fpd.user }; + if (!isEmpty(fpd) && !isFpdAdded) { + r = addFPD(bidderRequest, r, fpd, site, user); + + const clonedRObject = deepClone(r); + + clonedRObject.site = mergeDeep({}, clonedRObject.site, site); + clonedRObject.user = mergeDeep({}, clonedRObject.user, user); + + const requestSize = `${baseUrl}${parseQueryStringParameters({ ...payload, r: JSON.stringify(clonedRObject) })}`.length; + + if (requestSize < MAX_REQUEST_SIZE) { + r.site = mergeDeep({}, r.site, site); + r.user = mergeDeep({}, r.user, user); + isFpdAdded = true; + const fpdRequestSize = encodeURIComponent(JSON.stringify({ ...site, ...user })).length; + currentRequestSize += fpdRequestSize; + } else { + logError('IX Bid Adapter: FPD request size has exceeded maximum request size.', { bidder: BIDDER_CODE, code: ERROR_CODES.PB_FPD_EXCEEDS_MAX_SIZE }); + } + } + // add identifiers info to ixDiag + r = addIdentifiersInfo(impressions, r, transactionIds, adUnitIndex, payload, baseUrl, MAX_REQUEST_SIZE); + + const isLastAdUnit = adUnitIndex === transactionIds.length - 1; + + if (wasAdUnitImpressionsTrimmed || isLastAdUnit) { + if (!isLastAdUnit || requestSequenceNumber) { + r.ext.ixdiag.sn = requestSequenceNumber; + } + + requestSequenceNumber++; + + requests.push({ + method: 'POST', + url: baseUrl + '?s=' + siteID, + data: deepClone(r), + option: { + contentType: 'text/plain', + }, + validBidRequests + }); + + currentRequestSize = baseRequestSize; + r.imp = []; + isFpdAdded = false; + } + } + + return requests; +} + +/** + * addRTI adds RTI info of the partner to retrieved user IDs from prebid ID module. + * + * @param {array} userEids userEids info retrieved from prebid + * @param {array} eidInfo eidInfo info from prebid + */ +function addRTI(userEids, eidInfo) { + let identityInfo = window.headertag.getIdentityInfo(); + if (identityInfo && typeof identityInfo === 'object') { + for (const partnerName in identityInfo) { + if (identityInfo.hasOwnProperty(partnerName)) { + let response = identityInfo[partnerName]; + if (!response.responsePending && response.data && typeof response.data === 'object' && + Object.keys(response.data).length && !eidInfo.seenSources[response.data.source]) { + userEids.push(response.data); + } + } + } + } +} + +/** + * createRequest creates the base request object + * @param {array} validBidRequests A list of valid bid request config objects. + * @return {object} Object describing the request to the server. + */ +function createRequest(validBidRequests) { + const r = {}; // Since bidderRequestId are the same for different bid request, just use the first one. r.id = validBidRequests[0].bidderRequestId.toString(); r.site = {}; @@ -620,13 +748,21 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { r.ext.ixdiag.ls = storage.localStorageIsEnabled(); r.imp = []; r.at = 1; + return r +} - // getting ixdiags for adunits of the video, outstream & multi format (MF) style - let ixdiag = buildIXDiag(validBidRequests); - for (var key in ixdiag) { - r.ext.ixdiag[key] = ixdiag[key]; - } - +/** + * enrichRequest adds userSync configs, source, and referer info to request and ixDiag objects. + * + * @param {object} r Base reuqest object. + * @param {object} bidderRequest An object containing other info like gdprConsent. + * @param {array} impressions A list of impressions to be added to the request. + * @param {array} validBidRequests A list of valid bid request config objects. + * @param {array} userEids User ID info retrieved from Prebid ID module. + * @return {object} Enriched object describing the request to the server. + */ +function enrichRequest(r, bidderRequest, impressions, validBidRequests, userEids) { + const tmax = deepAccess(bidderRequest, 'timeout'); if (tmax) { r.ext.ixdiag.tmax = tmax; } @@ -642,6 +778,9 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { r.ext.ixdiag.err = cachedErrors; } + // Add number of available imps to ixDiag. + r.ext.ixdiag.imps = Object.keys(impressions).length; + // set source.tid to auctionId for outgoing request to Exchange. r.source = { tid: validBidRequests[0].auctionId, @@ -662,6 +801,17 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { r.site.ref = document.referrer; } + return r +} + +/** + * applyRegulations applies regulation info such as GDPR and GPP to the reqeust obejct. + * + * @param {object} r Base reuqest object. + * @param {object} bidderRequest An object containing other info like gdprConsent. + * @return {object} Object enriched with regulation info describing the request to the server. + */ +function applyRegulations(r, bidderRequest) { // Apply GDPR information to the request if GDPR is enabled. if (bidderRequest) { if (bidderRequest.gdprConsent) { @@ -694,48 +844,53 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { usPrivacy = bidderRequest.uspConsent; } + const pageUrl = deepAccess(bidderRequest, 'refererInfo.page'); if (pageUrl) { r.site.page = pageUrl; } + + if (bidderRequest.gppConsent) { + deepSetValue(r, 'regs.gpp', bidderRequest.gppConsent.gppString); + deepSetValue(r, 'regs.gpp_sid', bidderRequest.gppConsent.applicableSections); + } } if (config.getConfig('coppa')) { deepSetValue(r, 'regs.coppa', 1); } - const payload = {}; + return r +} + +/** + * createPayload creates the payload to be sent with the request. + * + * @param {array} validBidRequests A list of valid bid request config objects. + * @param {object} bidderRequest An object containing other info like gdprConsent. + * @param {object} r Reuqest object. + * @param {string} baseUrl Base exchagne URL. + * @param {array} requests List of request obejcts. + * @param {object} payload Request payload object. + * @param {int} MAX_REQUEST_SIZE Maximum request size limit (buildrequest V1). + */ +function createPayload(validBidRequests, bidderRequest, r, baseUrl, requests, payload, MAX_REQUEST_SIZE) { // Use the siteId in the first bid request as the main siteId. siteID = validBidRequests[0].params.siteId; payload.s = siteID; - if (!FEATURE_TOGGLES.isFeatureEnabled('pbjs_enable_post')) { - if (version) { - payload.v = version; - } - payload.ac = 'j'; - payload.sd = 1; - - if (version === VIDEO_ENDPOINT_VERSION) { - payload.nf = 1; - } - } - // Parse additional runtime configs. const bidderCode = (bidderRequest && bidderRequest.bidderCode) || 'ix'; const otherIxConfig = config.getConfig(bidderCode); - const requests = []; - let requestSequenceNumber = 0; - const transactionIds = Object.keys(impressions); - const baseRequestSize = `${baseUrl}${parseQueryStringParameters({ ...payload, r: JSON.stringify(r) })}`.length; + + baseRequestSize = `${baseUrl}${parseQueryStringParameters({ ...payload, r: JSON.stringify(r) })}`.length; if (baseRequestSize > MAX_REQUEST_SIZE) { logError('IX Bid Adapter: Base request size has exceeded maximum request size.', { bidder: BIDDER_CODE, code: ERROR_CODES.EXCEEDS_MAX_SIZE }); return requests; } - let currentRequestSize = baseRequestSize; + currentRequestSize = baseRequestSize; let fpdRequestSize = 0; - let isFpdAdded = false; if (otherIxConfig) { // Append firstPartyData to r.site.page if firstPartyData exists. @@ -751,202 +906,198 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { fpdRequestSize = encodeURIComponent(firstPartyString).length; - if (fpdRequestSize < MAX_REQUEST_SIZE) { + if (!FEATURE_TOGGLES.isFeatureEnabled('pbjs_use_buildRequestV2')) { + if (fpdRequestSize < MAX_REQUEST_SIZE) { + if ('page' in r.site) { + r.site.page += firstPartyString; + } else { + r.site.page = firstPartyString; + } + currentRequestSize += fpdRequestSize; + } else { + logError('IX Bid Adapter: IX config FPD request size has exceeded maximum request size.', { bidder: BIDDER_CODE, code: ERROR_CODES.IX_FPD_EXCEEDS_MAX_SIZE }); + } + } else { if ('page' in r.site) { r.site.page += firstPartyString; } else { r.site.page = firstPartyString; } - currentRequestSize += fpdRequestSize; - } else { - logError('IX Bid Adapter: IX config FPD request size has exceeded maximum request size.', { bidder: BIDDER_CODE, code: ERROR_CODES.IX_FPD_EXCEEDS_MAX_SIZE }); - } - } - - if (!FEATURE_TOGGLES.isFeatureEnabled('pbjs_enable_post')) { - // Create t in payload if timeout is configured. - if (typeof otherIxConfig.timeout === 'number') { - payload.t = otherIxConfig.timeout; } } } +} - for (let adUnitIndex = 0; adUnitIndex < transactionIds.length; adUnitIndex++) { - if (currentRequestSize >= MAX_REQUEST_SIZE || requests.length >= MAX_REQUEST_LIMIT) { - break; - } +/** + * addImpressions adds impressions to request object + * + * @param {array} impressions List of impressions to be added to the request. + * @param {array} transactionIds List of transaction Ids. + * @param {object} r Reuqest object. + * @param {int} adUnitIndex Index of the current add unit + * @param {int} MAX_REQUEST_SIZE Maximum request size limit (buildrequest V1). + * @return {object} Reqyest object with added impressions describing the request to the server. + */ +function addImpressions(impressions, transactionIds, r, adUnitIndex, MAX_REQUEST_SIZE) { + const adUnitImpressions = impressions[transactionIds[adUnitIndex]]; + const { missingImps: missingBannerImpressions = [], ixImps = [] } = adUnitImpressions; - const adUnitImpressions = impressions[transactionIds[adUnitIndex]]; - const { missingImps: missingBannerImpressions = [], ixImps = [] } = adUnitImpressions; - let wasAdUnitImpressionsTrimmed = false; - let remainingRequestSize = MAX_REQUEST_SIZE - currentRequestSize; - const sourceImpressions = { ixImps, missingBannerImpressions }; - const impressionObjects = Object.keys(sourceImpressions) - .map((key) => sourceImpressions[key]) - .filter(item => Array.isArray(item)) - .reduce((acc, curr) => acc.concat(...curr), []); + let remainingRequestSize = MAX_REQUEST_SIZE - currentRequestSize; + const sourceImpressions = { ixImps, missingBannerImpressions }; + const impressionObjects = Object.keys(sourceImpressions) + .map((key) => sourceImpressions[key]) + .filter(item => Array.isArray(item)) + .reduce((acc, curr) => acc.concat(...curr), []); - let currentImpressionSize = encodeURIComponent(JSON.stringify({ impressionObjects })).length; + currentImpressionSize = encodeURIComponent(JSON.stringify({ impressionObjects })).length; + if (!FEATURE_TOGGLES.isFeatureEnabled('pbjs_use_buildRequestV2')) { while (impressionObjects.length && currentImpressionSize > remainingRequestSize) { wasAdUnitImpressionsTrimmed = true; impressionObjects.pop(); currentImpressionSize = encodeURIComponent(JSON.stringify({ impressionObjects })).length; } + } - const gpid = impressions[transactionIds[adUnitIndex]].gpid; - const dfpAdUnitCode = impressions[transactionIds[adUnitIndex]].dfp_ad_unit_code; - const tid = impressions[transactionIds[adUnitIndex]].tid; - const sid = impressions[transactionIds[adUnitIndex]].sid - - if (impressionObjects.length && BANNER in impressionObjects[0]) { - const { id, banner: { topframe } } = impressionObjects[0]; - const _bannerImpression = { - id, - banner: { - topframe, - format: impressionObjects.map(({ banner: { w, h }, ext }) => ({ w, h, ext })) - }, - }; - - for (let i = 0; i < _bannerImpression.banner.format.length; i++) { - // We add sid in imp.ext.sid therefore, remove from banner.format[].ext - if (_bannerImpression.banner.format[i].ext != null && _bannerImpression.banner.format[i].ext.sid != null) { - delete _bannerImpression.banner.format[i].ext.sid; - } - - // add floor per size - if ('bidfloor' in impressionObjects[i]) { - _bannerImpression.banner.format[i].ext.bidfloor = impressionObjects[i].bidfloor - } - } + const gpid = impressions[transactionIds[adUnitIndex]].gpid; + const dfpAdUnitCode = impressions[transactionIds[adUnitIndex]].dfp_ad_unit_code; + const tid = impressions[transactionIds[adUnitIndex]].tid; + const sid = impressions[transactionIds[adUnitIndex]].sid - const position = impressions[transactionIds[adUnitIndex]].pos; - if (isInteger(position)) { - _bannerImpression.banner.pos = position; - } - - if (dfpAdUnitCode || gpid || tid || sid) { - _bannerImpression.ext = {}; - _bannerImpression.ext.dfp_ad_unit_code = dfpAdUnitCode; - _bannerImpression.ext.gpid = gpid; - _bannerImpression.ext.tid = tid; - _bannerImpression.ext.sid = sid; - } + if (impressionObjects.length && BANNER in impressionObjects[0]) { + const { id, banner: { topframe } } = impressionObjects[0]; + const _bannerImpression = { + id, + banner: { + topframe, + format: impressionObjects.map(({ banner: { w, h }, ext }) => ({ w, h, ext })) + }, + }; - if ('bidfloor' in impressionObjects[0]) { - _bannerImpression.bidfloor = impressionObjects[0].bidfloor; + for (let i = 0; i < _bannerImpression.banner.format.length; i++) { + // We add sid in imp.ext.sid therefore, remove from banner.format[].ext + if (_bannerImpression.banner.format[i].ext != null && _bannerImpression.banner.format[i].ext.sid != null) { + delete _bannerImpression.banner.format[i].ext.sid; } - if ('bidfloorcur' in impressionObjects[0]) { - _bannerImpression.bidfloorcur = impressionObjects[0].bidfloorcur; + // add floor per size + if ('bidfloor' in impressionObjects[i]) { + _bannerImpression.banner.format[i].ext.bidfloor = impressionObjects[i].bidfloor; } + } - r.imp.push(_bannerImpression); - } else { - // set imp.ext.gpid to resolved gpid for each imp - impressionObjects.forEach(imp => deepSetValue(imp, 'ext.gpid', gpid)); - r.imp.push(...impressionObjects); + const position = impressions[transactionIds[adUnitIndex]].pos; + if (isInteger(position)) { + _bannerImpression.banner.pos = position; } - currentRequestSize += currentImpressionSize; + if (dfpAdUnitCode || gpid || tid || sid) { + _bannerImpression.ext = {}; + _bannerImpression.ext.dfp_ad_unit_code = dfpAdUnitCode; + _bannerImpression.ext.gpid = gpid; + _bannerImpression.ext.tid = tid; + _bannerImpression.ext.sid = sid; + } - const fpd = deepAccess(bidderRequest, 'ortb2') || {}; + if ('bidfloor' in impressionObjects[0]) { + _bannerImpression.bidfloor = impressionObjects[0].bidfloor; + } - if (!isEmpty(fpd) && !isFpdAdded) { - r.ext.ixdiag.fpd = true; + if ('bidfloorcur' in impressionObjects[0]) { + _bannerImpression.bidfloorcur = impressionObjects[0].bidfloorcur; + } - const site = { ...(fpd.site || fpd.context) }; + r.imp.push(_bannerImpression); + } else { + // set imp.ext.gpid to resolved gpid for each imp + impressionObjects.forEach(imp => deepSetValue(imp, 'ext.gpid', gpid)); + r.imp.push(...impressionObjects); + } - Object.keys(site).forEach(key => { - if (FIRST_PARTY_DATA.SITE.indexOf(key) === -1) { - delete site[key]; - } - }); + return r; +} - const user = { ...fpd.user }; +/** + * addFPD adds ortb2 first party data to request object. + * + * @param {object} bidderRequest An object containing other info like gdprConsent. + * @param {object} r Reuqest object. + * @param {object} fpd ortb2 first party data. + * @param {object} site First party site data. + * @param {object} user First party user data. + * @return {object} Reqyest object with added FPD describing the request to the server. + */ +function addFPD(bidderRequest, r, fpd, site, user) { + r.ext.ixdiag.fpd = true; - Object.keys(user).forEach(key => { - if (FIRST_PARTY_DATA.USER.indexOf(key) === -1) { - delete user[key]; - } - }); + Object.keys(site).forEach(key => { + if (FIRST_PARTY_DATA.SITE.indexOf(key) === -1) { + delete site[key]; + } + }); - const clonedRObject = deepClone(r); + Object.keys(user).forEach(key => { + if (FIRST_PARTY_DATA.USER.indexOf(key) === -1) { + delete user[key]; + } + }); - clonedRObject.site = mergeDeep({}, clonedRObject.site, site); - clonedRObject.user = mergeDeep({}, clonedRObject.user, user); + if (fpd.device) { + const sua = {...fpd.device.sua}; + if (!isEmpty(sua)) { + deepSetValue(r, 'device.sua', sua); + } + } - const requestSize = `${baseUrl}${parseQueryStringParameters({ ...payload, r: JSON.stringify(clonedRObject) })}`.length; + if (fpd.hasOwnProperty('regs') && !bidderRequest.gppConsent) { + if (fpd.regs.hasOwnProperty('gpp') && typeof fpd.regs.gpp == 'string') { + deepSetValue(r, 'regs.gpp', fpd.regs.gpp) + } - if (requestSize < MAX_REQUEST_SIZE) { - r.site = mergeDeep({}, r.site, site); - r.user = mergeDeep({}, r.user, user); - isFpdAdded = true; - const fpdRequestSize = encodeURIComponent(JSON.stringify({ ...site, ...user })).length; - currentRequestSize += fpdRequestSize; - } else { - logError('IX Bid Adapter: FPD request size has exceeded maximum request size.', { bidder: BIDDER_CODE, code: ERROR_CODES.PB_FPD_EXCEEDS_MAX_SIZE }); - } + if (fpd.regs.hasOwnProperty('gpp_sid') && Array.isArray(fpd.regs.gpp_sid)) { + deepSetValue(r, 'regs.gpp_sid', fpd.regs.gpp_sid) } + } - // add identifiers info to ixDiag - const pbaAdSlot = impressions[transactionIds[adUnitIndex]].pbadslot; - const tagId = impressions[transactionIds[adUnitIndex]].tagId; - const adUnitCode = impressions[transactionIds[adUnitIndex]].adUnitCode; - const divId = impressions[transactionIds[adUnitIndex]].divId; - if (pbaAdSlot || tagId || adUnitCode || divId) { - const clonedRObject = deepClone(r); - const requestSize = `${baseUrl}${parseQueryStringParameters({ ...payload, r: JSON.stringify(clonedRObject) })}`.length; + return r; +} + +/** + * addIdentifiersInfo adds indentifier info to ixDaig. + * + * @param {array} impressions List of impressions to be added to the request. + * @param {object} r Reuqest object. + * @param {array} transactionIds List of transaction Ids. + * @param {int} adUnitIndex Index of the current add unit + * @param {object} payload Request payload object. + * @param {string} baseUrl Base exchagne URL. + * @param {int} MAX_REQUEST_SIZE Maximum request size limit (buildrequest V1). + * @return {object} Reqyest object with added indentigfier info to ixDiag. + */ +function addIdentifiersInfo(impressions, r, transactionIds, adUnitIndex, payload, baseUrl, MAX_REQUEST_SIZE) { + const pbaAdSlot = impressions[transactionIds[adUnitIndex]].pbadslot; + const tagId = impressions[transactionIds[adUnitIndex]].tagId; + const adUnitCode = impressions[transactionIds[adUnitIndex]].adUnitCode; + const divId = impressions[transactionIds[adUnitIndex]].divId; + if (pbaAdSlot || tagId || adUnitCode || divId) { + const clonedRObject = deepClone(r); + const requestSize = `${baseUrl}${parseQueryStringParameters({ ...payload, r: JSON.stringify(clonedRObject) })}`.length; + if (!FEATURE_TOGGLES.isFeatureEnabled('pbjs_use_buildRequestV2')) { if (requestSize < MAX_REQUEST_SIZE) { r.ext.ixdiag.pbadslot = pbaAdSlot; r.ext.ixdiag.tagid = tagId; r.ext.ixdiag.adunitcode = adUnitCode; r.ext.ixdiag.divId = divId; } - } - - const isLastAdUnit = adUnitIndex === transactionIds.length - 1; - - if (wasAdUnitImpressionsTrimmed || isLastAdUnit) { - const clonedPayload = deepClone(payload); - if (!isLastAdUnit || requestSequenceNumber) { - r.ext.ixdiag.sn = requestSequenceNumber; - clonedPayload.sn = requestSequenceNumber; - } - - requestSequenceNumber++; - clonedPayload.r = JSON.stringify(r); - - let requestData; - - if (FEATURE_TOGGLES.isFeatureEnabled('pbjs_enable_post')) { - requestData = { - method: 'POST', - url: baseUrl + '?s=' + payload.s, - data: deepClone(r), - option: { - contentType: 'text/plain', - }, - validBidRequests - } - } else { - requestData = { - method: 'GET', - url: baseUrl, - data: clonedPayload, - validBidRequests - } - } - requests.push(requestData); - - currentRequestSize = baseRequestSize; - r.imp = []; - isFpdAdded = false; + } else { + r.ext.ixdiag.pbadslot = pbaAdSlot; + r.ext.ixdiag.tagid = tagId; + r.ext.ixdiag.adunitcode = adUnitCode; + r.ext.ixdiag.divId = divId; } } - return requests; + return r; } /** @@ -1452,7 +1603,7 @@ export const spec = { // Step 1: Create impresssions from IX params validBidRequests.forEach((validBidRequest) => { - const adUnitMediaTypes = Object.keys(deepAccess(validBidRequest, 'mediaTypes', {})) + const adUnitMediaTypes = Object.keys(deepAccess(validBidRequest, 'mediaTypes', {})); for (const type in adUnitMediaTypes) { switch (adUnitMediaTypes[type]) { @@ -1532,13 +1683,7 @@ export const spec = { // Transform rawBid in bid response to the format that will be accepted by prebid. const innerBids = seatbid[i].bid; - let requestBid; - - if (FEATURE_TOGGLES.isFeatureEnabled('pbjs_enable_post')) { - requestBid = bidderRequest.data; - } else { - requestBid = safeJSONParse(bidderRequest.data.r); - } + const requestBid = bidderRequest.data; for (let j = 0; j < innerBids.length; j++) { const bidRequest = getBidRequest(innerBids[j].impid, requestBid.imp, bidderRequest.validBidRequests); diff --git a/modules/jixieBidAdapter.js b/modules/jixieBidAdapter.js index f6f58883990..5eeab197f3a 100644 --- a/modules/jixieBidAdapter.js +++ b/modules/jixieBidAdapter.js @@ -56,6 +56,8 @@ function fetchIds_() { if (tmp) ret.client_id_ls = tmp; tmp = storage.getDataFromLocalStorage('_jxxs'); if (tmp) ret.session_id_ls = tmp; + tmp = storage.getCookie('_jxtoko'); + if (tmp) ret.jxtoko_id = tmp; } catch (error) {} return ret; } diff --git a/modules/jwplayerRtdProvider.js b/modules/jwplayerRtdProvider.js index 342531ba26e..b79843dccfd 100644 --- a/modules/jwplayerRtdProvider.js +++ b/modules/jwplayerRtdProvider.js @@ -274,8 +274,7 @@ export function getContentSegments(segments) { const formattedSegments = segments.reduce((convertedSegments, rawSegment) => { convertedSegments.push({ - id: rawSegment, - value: rawSegment + id: rawSegment }); return convertedSegments; }, []); diff --git a/modules/jwplayerVideoProvider.js b/modules/jwplayerVideoProvider.js index d606e8121a7..6264522ad83 100644 --- a/modules/jwplayerVideoProvider.js +++ b/modules/jwplayerVideoProvider.js @@ -7,7 +7,7 @@ import { AUTOSTART_BLOCKED, PLAY_ATTEMPT_FAILED, CONTENT_LOADED, PLAY, PAUSE, BUFFER, TIME, SEEK_START, SEEK_END, MUTE, VOLUME, RENDITION_UPDATE, ERROR, COMPLETE, PLAYLIST_COMPLETE, FULLSCREEN, PLAYER_RESIZE, VIEWABLE, CAST } from '../libraries/video/constants/events.js'; -import { PLAYBACK_MODE } from '../libraries/video/constants/enums.js'; +import { PLAYBACK_MODE } from '../libraries/video/constants/constants.js'; 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'; @@ -47,19 +47,26 @@ export function JWPlayerProvider(config, jwplayer_, adState_, timeState_, callba function init() { if (!jwplayer) { - triggerSetupFailure(-1); // TODO: come up with code for player absent + triggerSetupFailure(-1); // TODO: come up with error code schema- player is absent return; } playerVersion = jwplayer.version; if (playerVersion < minimumSupportedPlayerVersion) { - triggerSetupFailure(-2); // TODO: come up with code for version not supported + triggerSetupFailure(-2); // TODO: come up with error code schema - version not supported + return; + } + + if (!document.getElementById(divId)) { + triggerSetupFailure(-3); // TODO: come up with error code schema - missing div id return; } player = jwplayer(divId); - if (player.getState() === undefined) { + if (!player || !player.getState) { + triggerSetupFailure(-4); // TODO: come up with error code schema - factory function failure + } else if (player.getState() === undefined) { setupPlayer(playerConfig); } else { const payload = getSetupCompletePayload(); diff --git a/modules/kargoBidAdapter.js b/modules/kargoBidAdapter.js index f4563081aa7..6a1c1cf94b0 100644 --- a/modules/kargoBidAdapter.js +++ b/modules/kargoBidAdapter.js @@ -1,4 +1,4 @@ -import { _each, buildUrl, triggerPixel } from '../src/utils.js'; +import { _each, buildUrl, deepAccess, pick, triggerPixel } from '../src/utils.js'; import { config } from '../src/config.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { getStorageManager } from '../src/storageManager.js'; @@ -37,10 +37,9 @@ export const spec = { bidSizes[bid.bidId] = bid.sizes; }); - let tdid; - if (validBidRequests.length > 0 && validBidRequests[0].userId && validBidRequests[0].userId.tdid) { - tdid = validBidRequests[0].userId.tdid; - } + const firstBidRequest = validBidRequests[0]; + + const tdid = deepAccess(firstBidRequest, 'userId.tdid') const transformedParams = Object.assign({}, { sessionId: spec._getSessionId(), @@ -62,10 +61,17 @@ export const spec = { prebidRawBidRequests: validBidRequests }, spec._getAllMetadata(bidderRequest, tdid)); + // User Agent Client Hints / SUA + const uaClientHints = deepAccess(firstBidRequest, 'ortb2.device.sua'); + if (uaClientHints) { + transformedParams.device.sua = pick(uaClientHints, ['browsers', 'platform', 'mobile', 'model']); + } + // Pull Social Canvas segments and embed URL - if (validBidRequests.length > 0 && validBidRequests[0].params.socialCanvas) { - transformedParams.socialCanvasSegments = validBidRequests[0].params.socialCanvas.segments; - transformedParams.socialEmbedURL = validBidRequests[0].params.socialCanvas.embedURL; + const socialCanvas = deepAccess(firstBidRequest, 'params.socialCanvas'); + if (socialCanvas) { + transformedParams.socialCanvasSegments = socialCanvas.segments; + transformedParams.socialEmbedURL = socialCanvas.embedURL; } const encodedParams = encodeURIComponent(JSON.stringify(transformedParams)); @@ -110,7 +116,11 @@ export const spec = { }; if (meta.mediaType == VIDEO) { - bidResponse.vastXml = adUnit.adm; + if (adUnit.admUrl) { + bidResponse.vastUrl = adUnit.admUrl; + } else { + bidResponse.vastXml = adUnit.adm; + } } bidResponses.push(bidResponse); @@ -225,7 +235,7 @@ export const spec = { _getAllMetadata(bidderRequest, tdid) { return { userIDs: spec._getUserIds(tdid, bidderRequest.uspConsent, bidderRequest.gdprConsent), - pageURL: bidderRequest.refererInfo && bidderRequest.refererInfo.page, + pageURL: bidderRequest?.refererInfo?.page, rawCRB: storage.getCookie('krg_crb'), rawCRBLocalStorage: spec._getLocalStorageSafely('krg_crb') }; diff --git a/modules/kueezRtbBidAdapter.js b/modules/kueezRtbBidAdapter.js new file mode 100644 index 00000000000..821b3263597 --- /dev/null +++ b/modules/kueezRtbBidAdapter.js @@ -0,0 +1,325 @@ +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'; + +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; +export const SUPPORTED_ID_SYSTEMS = { + 'britepoolid': 1, + 'criteoId': 1, + 'id5id': 1, + 'idl_env': 1, + 'lipb': 1, + 'netId': 1, + 'parrableId': 1, + 'pubcid': 1, + 'tdid': 1, + 'pubProvidedId': 1 +}; +const storage = getStorageManager({gvlid: GVLID, bidderCode: BIDDER_CODE}); + +function getTopWindowQueryParams() { + try { + const parsedUrl = parseUrl(window.top.document.URL, {decodeSearchAsString: true}); + return parsedUrl.search; + } catch (e) { + return ''; + } +} + +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) { + 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); + + 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, + auctionId: auctionId, + transactionId: transactionId, + bidderRequestId: bidderRequestId, + bidRequestsCount: bidRequestsCount, + bidderRequestsCount: bidderRequestsCount, + bidderWinsCount: bidderWinsCount, + bidderTimeout: bidderTimeout + }; + + appendUserIdsToRequestPayload(data, userId); + + 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) => { + if (SUPPORTED_ID_SYSTEMS[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 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, 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, + 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.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; + } +} + +export const spec = { + code: BIDDER_CODE, + version: BIDDER_VERSION, + gvlid: GVLID, + supportedMediaTypes: [BANNER, VIDEO], + isBidRequestValid, + buildRequests, + interpretResponse, + getUserSyncs +}; + +registerBidder(spec); diff --git a/modules/kueezRtbBidAdapter.md b/modules/kueezRtbBidAdapter.md new file mode 100644 index 00000000000..52d11aa362a --- /dev/null +++ b/modules/kueezRtbBidAdapter.md @@ -0,0 +1,35 @@ +# Overview + +**Module Name:** Kueez RTB Bidder Adapter + +**Module Type:** Bidder Adapter + +**Maintainer:** rtb@kueez.com + +# Description + +Module that connects to Kueez's demand sources. + +# Test Parameters +```js +var adUnits = [ + { + code: 'test-ad', + sizes: [[300, 250]], + bids: [ + { + bidder: 'kueezrtb', + params: { + cId: '562524b21b1c1f08117fc7f9', + pId: '59ac17c192832d0011283fe3', + bidFloor: 0.0001, + ext: { + param1: 'loremipsum', + param2: 'dolorsitamet' + } + } + } + ] + } +]; +``` diff --git a/modules/lassoBidAdapter.js b/modules/lassoBidAdapter.js index da48bc460c7..ad25cbe1e85 100644 --- a/modules/lassoBidAdapter.js +++ b/modules/lassoBidAdapter.js @@ -40,21 +40,21 @@ export const spec = { auctionId: bidRequest.auctionId, bidId: bidRequest.bidId, transactionId: bidRequest.transactionId, - device: JSON.stringify(getDeviceData()), + device: encodeURIComponent(JSON.stringify(getDeviceData())), sizes, aimXR, uid: '$UID', params: JSON.stringify(bidRequest.params), crumbs: JSON.stringify(bidRequest.crumbs), prebidVersion: '$prebid.version$', - version: 2, + version: 3, coppa: config.getConfig('coppa') == true ? 1 : 0, ccpa: bidderRequest.uspConsent || undefined } return { method: 'GET', - url: getBidRequestUrl(aimXR), + url: getBidRequestUrl(aimXR, bidRequest.params), data: payload, options: { withCredentials: true @@ -113,11 +113,15 @@ export const spec = { supportedMediaTypes: [BANNER] } -function getBidRequestUrl(aimXR) { +function getBidRequestUrl(aimXR, params) { + let path = '/request'; + if (params && params.dtc) { + path = '/dtc-request'; + } if (!aimXR) { - return GET_IUD_URL + ENDPOINT_URL + '/request'; + return GET_IUD_URL + ENDPOINT_URL + path; } - return ENDPOINT_URL + '/request' + return ENDPOINT_URL + path; } function getDeviceData() { diff --git a/modules/limelightDigitalBidAdapter.js b/modules/limelightDigitalBidAdapter.js index c39fd36e597..601d78578b3 100644 --- a/modules/limelightDigitalBidAdapter.js +++ b/modules/limelightDigitalBidAdapter.js @@ -26,7 +26,7 @@ function isBidResponseValid(bid) { export const spec = { code: BIDDER_CODE, - aliases: ['pll'], + aliases: ['pll', 'iionads'], supportedMediaTypes: [BANNER, VIDEO], /** @@ -158,7 +158,12 @@ function buildPlacement(bidRequest) { type: bidRequest.params.adUnitType.toUpperCase(), publisherId: bidRequest.params.publisherId, userIdAsEids: bidRequest.userIdAsEids, - supplyChain: bidRequest.schain + supplyChain: bidRequest.schain, + custom1: bidRequest.params.custom1, + custom2: bidRequest.params.custom2, + custom3: bidRequest.params.custom3, + custom4: bidRequest.params.custom4, + custom5: bidRequest.params.custom5 } } } diff --git a/modules/limelightDigitalBidAdapter.md b/modules/limelightDigitalBidAdapter.md index a4abb6f1411..2c773859a7f 100644 --- a/modules/limelightDigitalBidAdapter.md +++ b/modules/limelightDigitalBidAdapter.md @@ -24,7 +24,12 @@ var adUnits = [{ params: { host: 'exchange-9qao.ortb.net', adUnitId: 0, - adUnitType: 'banner' + adUnitType: 'banner', + custom1: 'custom1', + custom2: 'custom2', + custom3: 'custom3', + custom4: 'custom4', + custom5: 'custom5' } }] }]; @@ -40,7 +45,12 @@ var videoAdUnit = [{ params: { host: 'exchange-9qao.ortb.net', adUnitId: 0, - adUnitType: 'video' + adUnitType: 'video', + custom1: 'custom1', + custom2: 'custom2', + custom3: 'custom3', + custom4: 'custom4', + custom5: 'custom5' } }] }]; diff --git a/modules/liveIntentIdSystem.js b/modules/liveIntentIdSystem.js index 724bf5ece6a..9f45daeea29 100644 --- a/modules/liveIntentIdSystem.js +++ b/modules/liveIntentIdSystem.js @@ -7,10 +7,9 @@ import { triggerPixel, logError } from '../src/utils.js'; import { ajaxBuilder } from '../src/ajax.js'; import { submodule } from '../src/hook.js'; -import { LiveConnect } from 'live-connect-js/esm/initializer.js'; +import { LiveConnect } from 'live-connect-js'; // eslint-disable-line prebid/validate-imports import { gdprDataHandler, uspDataHandler } from '../src/adapterManager.js'; import { getStorageManager } from '../src/storageManager.js'; -import { MinimalLiveConnect } from 'live-connect-js/esm/minimal-live-connect.js'; const MODULE_NAME = 'liveIntentId'; export const storage = getStorageManager({gvlid: null, moduleName: MODULE_NAME}); @@ -140,7 +139,7 @@ export const liveIntentIdSubmodule = { this.moduleMode = mode }, getInitializer() { - return this.moduleMode === 'minimal' ? MinimalLiveConnect : LiveConnect + return (liveConnectConfig, storage, calls) => LiveConnect(liveConnectConfig, storage, calls, this.moduleMode) }, /** diff --git a/modules/livewrappedBidAdapter.js b/modules/livewrappedBidAdapter.js index 3839eb80b91..af754ae3ff0 100644 --- a/modules/livewrappedBidAdapter.js +++ b/modules/livewrappedBidAdapter.js @@ -1,4 +1,4 @@ -import {deepAccess, getWindowTop, isSafariBrowser, mergeDeep} from '../src/utils.js'; +import {deepAccess, getWindowTop, isSafariBrowser, mergeDeep, isFn, isPlainObject} from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {config} from '../src/config.js'; import {find} from '../src/polyfill.js'; @@ -68,7 +68,9 @@ export const spec = { bidUrl = bidUrl ? bidUrl.params.bidUrl : URL; url = url ? url.params.url : (getAppDomain() || getTopWindowLocation(bidderRequest)); test = test ? test.params.test : undefined; - var adRequests = bidRequests.map(bidToAdRequest); + const currency = config.getConfig('currency.adServerCurrency') || 'USD'; + var adRequests = bidRequests.map(b => bidToAdRequest(b, currency)); + const adRequestsContainFloors = adRequests.some(r => r.flr !== undefined); if (eids) { ortb2 = mergeDeep(mergeDeep({}, ortb2 || {}), eids); @@ -96,7 +98,8 @@ export const spec = { rcv: getAdblockerRecovered(), adRequests: [...adRequests], rtbData: ortb2, - schain: schain + schain: schain, + flrCur: adRequestsContainFloors ? currency : undefined }; if (config.getConfig().debug) { @@ -223,13 +226,14 @@ function hasPubcid(bid) { return !!bid.crumbs && !!bid.crumbs.pubcid; } -function bidToAdRequest(bid) { +function bidToAdRequest(bid, currency) { var adRequest = { adUnitId: bid.params.adUnitId, callerAdUnitId: bid.params.adUnitName || bid.adUnitCode || bid.placementCode, bidId: bid.bidId, transactionId: bid.transactionId, formats: getSizes(bid).map(sizeToFormat), + flr: getBidFloor(bid, currency), options: bid.params.options }; @@ -264,6 +268,22 @@ function sizeToFormat(size) { } } +function getBidFloor(bid, currency) { + if (!isFn(bid.getFloor)) { + return undefined; + } + + const floor = bid.getFloor({ + currency: currency, + mediaType: '*', + size: '*' + }); + + return isPlainObject(floor) && !isNaN(floor.floor) && floor.currency == currency + ? floor.floor + : undefined; +} + function getAdblockerRecovered() { try { return getWindowTop().I12C && getWindowTop().I12C.Morph === 1; @@ -302,21 +322,13 @@ function getDeviceIfa() { } function getDeviceWidth() { - let device = config.getConfig('device'); - if (typeof device === 'object' && device.width) { - return device.width; - } - - return window.innerWidth; + const device = config.getConfig('device') || {}; + return device.w || window.innerWidth; } function getDeviceHeight() { - let device = config.getConfig('device'); - if (typeof device === 'object' && device.height) { - return device.height; - } - - return window.innerHeight; + const device = config.getConfig('device') || {}; + return device.h || window.innerHeight; } function getCoppa() { diff --git a/modules/lotamePanoramaIdSystem.js b/modules/lotamePanoramaIdSystem.js index 832d98e4f83..883c931824b 100644 --- a/modules/lotamePanoramaIdSystem.js +++ b/modules/lotamePanoramaIdSystem.js @@ -29,6 +29,7 @@ const DAY_MS = 60 * 60 * 24 * 1000; const MISSING_CORE_CONSENT = 111; const GVLID = 95; const ID_HOST = 'id.crwdcntrl.net'; +const ID_HOST_COOKIELESS = 'c.ltmsphrcl.net'; export const storage = getStorageManager({gvlid: GVLID, moduleName: MODULE_NAME}); let cookieDomain; @@ -252,6 +253,13 @@ export const lotamePanoramaIdSubmodule = { usPrivacy = getFromStorage('us_privacy'); } + const getRequestHost = function() { + if (navigator.userAgent && navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) { + return ID_HOST_COOKIELESS; + } + return ID_HOST; + } + const resolveIdFunction = function (callback) { let queryParams = {}; if (storedUserId) { @@ -288,7 +296,7 @@ export const lotamePanoramaIdSubmodule = { const url = buildUrl({ protocol: 'https', - host: ID_HOST, + host: getRequestHost(), pathname: '/id', search: isEmpty(queryParams) ? undefined : queryParams, }); diff --git a/modules/magniteAnalyticsAdapter.js b/modules/magniteAnalyticsAdapter.js index dba847e1b07..9d437c0b246 100644 --- a/modules/magniteAnalyticsAdapter.js +++ b/modules/magniteAnalyticsAdapter.js @@ -254,9 +254,14 @@ export const parseBidResponse = (bid, previousBidResponse) => { const validAdomains = Array.isArray(adomains) && adomains.filter(domain => typeof domain === 'string'); return validAdomains && validAdomains.length > 0 ? validAdomains.slice(0, 10) : undefined }, + 'networkId', () => { + const networkId = deepAccess(bid, 'meta.networkId'); + // if not a valid after this, set to undefined so it gets filtered out + return (networkId && networkId.toString()) || undefined; + }, 'conversionError', conversionError => conversionError === true || undefined, // only pass if exactly true 'ogCurrency', - 'ogPrice' + 'ogPrice', ]); } @@ -300,6 +305,10 @@ const getTopLevelDetails = () => { } } + if (browser) { + deepSetValue(payload, rubiConf.pbaBrowserLocation || 'client.browser', browser); + } + // Add DM wrapper details if (rubiConf.wrapperName) { payload.wrapper = { @@ -590,6 +599,28 @@ const subscribeToGamSlots = () => { }); } +/** + * Lazy parsing of UA to determine browser + * @param {string} userAgent string from prebid ortb ua or navigator + * @returns {string} lazily guessed browser name + */ +export const detectBrowserFromUa = userAgent => { + let normalizedUa = userAgent.toLowerCase(); + + if (normalizedUa.includes('edg')) { + return 'Edge'; + } else if ((/opr|opera|opt/i).test(normalizedUa)) { + return 'Opera'; + } else if ((/chrome|crios/i).test(normalizedUa)) { + return 'Chrome'; + } else if ((/fxios|firefox/i).test(normalizedUa)) { + return 'Firefox'; + } else if (normalizedUa.includes('safari') && !(/chromium|ucbrowser/i).test(normalizedUa)) { + return 'Safari'; + } + return 'OTHER'; +} + let accountId; let endpoint; @@ -638,11 +669,20 @@ magniteAdapter.disableAnalytics = function () { accountId = undefined; resetConfs(); magniteAdapter.originDisableAnalytics(); -} +}; + +magniteAdapter.onDataDeletionRequest = function () { + if (storage.localStorageIsEnabled()) { + storage.removeDataFromLocalStorage(COOKIE_NAME); + } else { + throw Error('Unable to access local storage, no data deleted'); + } +}; magniteAdapter.MODULE_INITIALIZED_TIME = Date.now(); magniteAdapter.referrerHostname = ''; +let browser; magniteAdapter.track = ({ eventType, args }) => { switch (eventType) { case AUCTION_INIT: @@ -662,6 +702,12 @@ magniteAdapter.track = ({ eventType, args }) => { ]); auctionData.accountId = accountId; + // get browser + if (!browser) { + const userAgent = deepAccess(args, 'bidderRequests.0.ortb2.device.ua', navigator.userAgent) || ''; + browser = detectBrowserFromUa(userAgent); + } + // Order bidders were called auctionData.bidderOrder = args.bidderRequests.map(bidderRequest => bidderRequest.bidderCode); @@ -701,7 +747,7 @@ magniteAdapter.track = ({ eventType, args }) => { 'code as adUnitCode', 'transactionId', 'mediaTypes', mediaTypes => Object.keys(mediaTypes), - 'sizes as dimensions', sizes => sizes.map(sizeToDimensions), + 'sizes as dimensions', sizes => (sizes || [[1, 1]]).map(sizeToDimensions), ]); ad.pbAdSlot = deepAccess(adUnit, 'ortb2Imp.ext.data.pbadslot'); ad.pattern = deepAccess(adUnit, 'ortb2Imp.ext.data.aupname'); diff --git a/modules/mediagoBidAdapter.js b/modules/mediagoBidAdapter.js index 514c56061df..9b1b02e00a2 100644 --- a/modules/mediagoBidAdapter.js +++ b/modules/mediagoBidAdapter.js @@ -148,12 +148,12 @@ function isMobileAndTablet() { */ // 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 }); +// 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" && +// typeof floorInfo === 'object' && +// floorInfo.currency === 'USD' && // !isNaN(parseFloat(floorInfo.floor)) // ) { // floor = parseFloat(floorInfo.floor); @@ -255,7 +255,6 @@ function getItems(validBidRequests, bidderRequest) { // utils.deepAccess(req, 'ortb2Imp.ext.gpid') || // utils.deepAccess(req, 'ortb2Imp.ext.data.pbadslot') || // utils.deepAccess(req, 'params.placementId', 0); - // console.log("wjh getItems:", req, bidFloor, gpid); // if (mediaTypes.native) {} // banner广告类型 @@ -270,7 +269,7 @@ function getItems(validBidRequests, bidderRequest) { pos: 1, }, ext: { - // gpid: gpid, // 加入后无法返回广告 + // gpid: gpid, // 加入后无法返回广告 }, }; itemMaps[id] = { @@ -296,8 +295,11 @@ function getParam(validBidRequests, bidderRequest) { const sharedid = utils.deepAccess(validBidRequests[0], 'userId.sharedid.id') || utils.deepAccess(validBidRequests[0], 'userId.pubcid'); + const eids = validBidRequests[0].userIdAsEids || validBidRequests[0].userId; + let isMobile = isMobileAndTablet() ? 1 : 0; - let isTest = 0; + // input test status by Publisher. more frequently for test true req + let isTest = validBidRequests[0].params.test || 0; let auctionId = getProperty(bidderRequest, 'auctionId'); let items = getItems(validBidRequests, bidderRequest); @@ -317,19 +319,23 @@ function getParam(validBidRequests, bidderRequest) { cur: ['USD'], device: { connectiontype: 0, - // ip: '64.188.178.115', + // ip: '98.61.5.0', js: 1, - // language: "en", - // os: "Microsoft Windows", - // ua: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.19043", + // language: 'en', + // os: 'Microsoft Windows', + // ua: 'Mozilla/5.0 (Linux; Android 12; SM-G970U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Mobile Safari/537.36', os: navigator.platform || '', ua: navigator.userAgent, language: /en/.test(navigator.language) ? 'en' : navigator.language, }, - ext: {}, + ext: { + eids, + }, user: { - id: sharedid || pubcid || getUserID(), + buyeruid: getUserID(), + id: sharedid || pubcid, }, + eids, site: { name: domain, domain: domain, @@ -419,12 +425,12 @@ export const spec = { nurl: getProperty(bid, 'nurl'), // adserverTargeting: { // granularityMultiplier: 0.1, - // priceGranularity: "pbHg", - // pbMg: "0.01", + // priceGranularity: 'pbHg', + // pbMg: '0.01', // }, - // pbMg: "0.01", + // pbMg: '0.01', // granularityMultiplier: 0.1, - // priceGranularity: "pbHg", + // priceGranularity: 'pbHg', }; bidResponses.push(bidResponse); } diff --git a/modules/medianetRtdProvider.js b/modules/medianetRtdProvider.js index 3e01d0e5631..5a159b39081 100644 --- a/modules/medianetRtdProvider.js +++ b/modules/medianetRtdProvider.js @@ -59,14 +59,14 @@ function onAuctionInitEvent(auctionInit) { }, SOURCE)); } -function getTargetingData(adUnitCode) { - const adUnits = getAdUnits(undefined, adUnitCode); +function getTargetingData(adUnitCodes, config, consent, auction) { + const adUnits = getAdUnits(auction.adUnits, adUnitCodes); let targetingData = {}; if (window.mnjs.loaded && isFn(window.mnjs.getTargetingData)) { - targetingData = window.mnjs.getTargetingData(adUnitCode, adUnits, SOURCE) || {}; + targetingData = window.mnjs.getTargetingData(adUnitCodes, adUnits, SOURCE) || {}; } const targeting = {}; - adUnitCode.forEach(adUnitCode => { + adUnitCodes.forEach(adUnitCode => { targeting[adUnitCode] = targeting[adUnitCode] || {}; targetingData[adUnitCode] = targetingData[adUnitCode] || {}; targeting[adUnitCode] = { diff --git a/modules/mgidRtdProvider.js b/modules/mgidRtdProvider.js new file mode 100644 index 00000000000..f30f14ea528 --- /dev/null +++ b/modules/mgidRtdProvider.js @@ -0,0 +1,190 @@ +import { submodule } from '../src/hook.js'; +import {ajax} from '../src/ajax.js'; +import {deepAccess, logError, logInfo, mergeDeep} from '../src/utils.js'; +import {getStorageManager} from '../src/storageManager.js'; +import {getRefererInfo} from '../src/refererDetection.js'; + +const MODULE_NAME = 'realTimeData'; +const SUBMODULE_NAME = 'mgid'; +const MGID_RTD_API_URL = 'https://servicer.mgid.com/sda'; +const MGUID_LOCAL_STORAGE_KEY = 'mguid'; +const ORTB2_NAME = 'www.mgid.com' + +const GVLID = 358; +/** @type {?Object} */ +export const storage = getStorageManager({ + gvlid: GVLID, + moduleName: SUBMODULE_NAME +}); + +function init(moduleConfig) { + if (!moduleConfig?.params?.clientSiteId) { + logError('Mgid clientSiteId is not set!'); + return false; + } + return true; +} + +function getBidRequestData(reqBidsConfigObj, onDone, moduleConfig, userConsent) { + let mguid; + try { + mguid = storage.getDataFromLocalStorage(MGUID_LOCAL_STORAGE_KEY); + } catch (e) { + logInfo(`Can't get mguid from localstorage`); + } + + const params = [ + { + name: 'gdprApplies', + data: typeof userConsent?.gdpr?.gdprApplies !== 'undefined' ? userConsent?.gdpr?.gdprApplies + '' : undefined, + }, + { + name: 'consentData', + data: userConsent?.gdpr?.consentString, + }, + { + name: 'uspString', + data: userConsent?.usp, + }, + { + name: 'cxurl', + data: encodeURIComponent(getContextUrl()), + }, + { + name: 'muid', + data: mguid, + }, + { + name: 'clientSiteId', + data: moduleConfig?.params?.clientSiteId, + }, + { + name: 'cxlang', + data: deepAccess(reqBidsConfigObj.ortb2Fragments.global, 'site.content.language'), + }, + ]; + + const url = MGID_RTD_API_URL + '?' + params.filter((p) => p.data).map((p) => p.name + '=' + p.data).join('&'); + + let isDone = false; + + ajax(url, { + success: (response, req) => { + if (req.status === 200) { + try { + const data = JSON.parse(response); + const ortb2 = reqBidsConfigObj?.ortb2Fragments?.global || {}; + + mergeDeep(ortb2, getDataForMerge(data)); + + if (data?.muid) { + try { + mguid = storage.setDataInLocalStorage(MGUID_LOCAL_STORAGE_KEY, data.muid); + } catch (e) { + logInfo(`Can't set mguid to localstorage`); + } + } + + onDone(); + isDone = true; + } catch (e) { + onDone(); + isDone = true; + + logError('Unable to parse Mgid RTD data', e); + } + } else { + onDone(); + isDone = true; + + logError('Mgid RTD wrong response status'); + } + }, + error: () => { + onDone(); + isDone = true; + + logError('Unable to get Mgid RTD data'); + } + }, + null, { + method: 'GET', + withCredentials: false, + }); + + setTimeout(function () { + if (!isDone) { + onDone(); + logInfo('Mgid RTD timeout'); + isDone = true; + } + }, moduleConfig.params.timeout || 1000); +} + +function getContextUrl() { + const refererInfo = getRefererInfo(); + + let resultUrl = refererInfo.canonicalUrl || refererInfo.topmostLocation; + + const metaElements = document.getElementsByTagName('meta'); + for (let i = 0; i < metaElements.length; i++) { + if (metaElements[i].getAttribute('property') === 'og:url') { + resultUrl = metaElements[i].content; + } + } + + return resultUrl; +} + +function getDataForMerge(responseData) { + let siteData = { + name: ORTB2_NAME + }; + let userData = { + name: ORTB2_NAME + }; + + if (responseData.siteSegments) { + siteData.segment = responseData.siteSegments.map((segmentId) => ({ id: segmentId })); + } + if (responseData.siteSegtax) { + siteData.ext = { + segtax: responseData.siteSegtax + } + } + + if (responseData.userSegments) { + userData.segment = responseData.userSegments.map((segmentId) => ({ id: segmentId })); + } + if (responseData.userSegtax) { + userData.ext = { + segtax: responseData.userSegtax + } + } + + let result = {}; + if (siteData.segment || siteData.ext) { + result.site = { + content: { + data: [siteData], + } + } + } + + if (userData.segment || userData.ext) { + result.user = { + data: [userData], + } + } + + return result; +} + +/** @type {RtdSubmodule} */ +export const mgidSubmodule = { + name: SUBMODULE_NAME, + init: init, + getBidRequestData: getBidRequestData, +}; + +submodule(MODULE_NAME, mgidSubmodule); diff --git a/modules/mgidRtdProvider.md b/modules/mgidRtdProvider.md new file mode 100644 index 00000000000..58d4564e14e --- /dev/null +++ b/modules/mgidRtdProvider.md @@ -0,0 +1,51 @@ +# Overview + +``` +Module Name: Mgid RTD Provider +Module Type: RTD Provider +Maintainer: prebid@mgid.com +``` + +# Description + +Mgid RTD module allows you to enrich bid data with contextual and audience signals, based on IAB taxonomies. + +## Configuration + +This module is configured as part of the `realTimeData.dataProviders` object. + +{: .table .table-bordered .table-striped } +| Name | Scope | Description | Example | Type | +|------------|----------|----------------------------------------|---------------|----------| +| `name ` | required | Real time data module name | `'mgid'` | `string` | +| `params` | required | | | `Object` | +| `params.clientSiteId` | required | The client site id provided by Mgid. | `'123456'` | `string` | +| `params.timeout` | optional | Maximum amount of milliseconds allowed for module to finish working | `1000` | `number` | + +#### Example + +```javascript +pbjs.setConfig({ + realTimeData: { + dataProviders: [{ + name: 'mgid', + params: { + clientSiteId: '123456' + } + }] + } +}); +``` + +## Integration +To install the module, follow these instructions: + +#### Step 1: Prepare the base Prebid file + +- Option 1: Use Prebid [Download](/download.html) page to build the prebid package. Ensure that you do check *Mgid Realtime Module* module + +- Option 2: From the command line, run `gulp build --modules=mgidRtdProvider,...` + +#### Step 2: Set configuration + +Enable Mgid Real Time Module using `pbjs.setConfig`. Example is provided in Configuration section. diff --git a/modules/microadBidAdapter.js b/modules/microadBidAdapter.js index 1b31000df43..13aea0f3f77 100644 --- a/modules/microadBidAdapter.js +++ b/modules/microadBidAdapter.js @@ -1,4 +1,5 @@ -import { deepAccess, isEmpty, isStr } from '../src/utils.js'; +import { deepAccess, isArray, isEmpty, isStr } from '../src/utils.js'; +import { find } from '../src/polyfill.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER } from '../src/mediaTypes.js'; import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; @@ -24,15 +25,16 @@ const NATIVE_CODE = 2; const VIDEO_CODE = 4; const AUDIENCE_IDS = [ - {type: 6, bidKey: 'userId.imuid'}, - {type: 8, bidKey: 'userId.id5id.uid'}, - {type: 9, bidKey: 'userId.tdid'}, - {type: 10, bidKey: 'userId.novatiq.snowflake'}, - {type: 11, bidKey: 'userId.parrableId.eid'}, - {type: 12, bidKey: 'userId.dacId.id'}, - {type: 13, bidKey: 'userId.idl_env'}, - {type: 14, bidKey: 'userId.criteoId'}, - {type: 15, bidKey: 'userId.pubcid'} + {type: 6, bidKey: 'userId.imuid', source: 'intimatemerger.com'}, + {type: 8, bidKey: 'userId.id5id.uid', source: 'id5-sync.com'}, + {type: 9, bidKey: 'userId.tdid', source: 'adserver.org'}, + {type: 10, bidKey: 'userId.novatiq.snowflake', source: 'novatiq.com'}, + {type: 11, bidKey: 'userId.parrableId.eid', source: 'parrable.com'}, + {type: 12, bidKey: 'userId.dacId.id', source: 'dac.co.jp'}, + {type: 13, bidKey: 'userId.idl_env', source: 'liveramp.com'}, + {type: 14, bidKey: 'userId.criteoId', source: 'criteo.com'}, + {type: 15, bidKey: 'userId.pubcid', source: 'pubcid.org'}, + {type: 17, bidKey: 'userId.uid2.id', source: 'uidapi.com'} ]; function createCBT() { @@ -100,10 +102,19 @@ export const spec = { } const aidsParams = [] + const userIdAsEids = bid.userIdAsEids; AUDIENCE_IDS.forEach((audienceId) => { const bidAudienceId = deepAccess(bid, audienceId.bidKey); if (!isEmpty(bidAudienceId) && isStr(bidAudienceId)) { - aidsParams.push({ type: audienceId.type, id: bidAudienceId }); + const aidParam = { type: audienceId.type, id: bidAudienceId }; + // Set ext + if (isArray(userIdAsEids)) { + const targetEid = find(userIdAsEids, (eid) => eid.source === audienceId.source) || {}; + if (!isEmpty(deepAccess(targetEid, 'uids.0.ext'))) { + aidParam.ext = targetEid.uids[0].ext; + } + } + aidsParams.push(aidParam); // Set Ramp ID if (audienceId.type === 13) params['idl_env'] = bidAudienceId; } diff --git a/modules/minutemediaBidAdapter.md b/modules/minutemediaBidAdapter.md index 70f106a745f..66b54adaf0e 100644 --- a/modules/minutemediaBidAdapter.md +++ b/modules/minutemediaBidAdapter.md @@ -20,7 +20,7 @@ The adapter supports Video(instream) & Banner. | Name | Scope | Type | Description | Example | ---- | ----- | ---- | ----------- | ------- -| `org` | required | String | MinuteMedia publisher Id provided by your MinuteMedia representative | "56f91cd4d3e3660002000033" +| `org` | required | String | MinuteMedia publisher Id provided by your MinuteMedia representative | "1234567890abcdef12345678" | `floorPrice` | optional | Number | Minimum price in USD. Misuse of this parameter can impact revenue | 2.00 | `placementId` | optional | String | A unique placement identifier | "12345678" | `testMode` | optional | Boolean | This activates the test mode | false @@ -43,7 +43,7 @@ var adUnits = [{ bids: [{ bidder: 'minutemedia', params: { - org: '56f91cd4d3e3660002000033', // Required + org: '1234567890abcdef12345678', // Required floorPrice: 2.00, // Optional placementId: 'video-test', // Optional testMode: false // Optional @@ -65,7 +65,7 @@ var adUnits = [{ bids: [{ bidder: 'minutemedia', params: { - org: '56f91cd4d3e3660002000033', // Required + org: '1234567890abcdef12345678', // Required floorPrice: 2.00, // Optional placementId: 'banner-test', // Optional testMode: false // Optional diff --git a/modules/minutemediaplusBidAdapter.js b/modules/minutemediaplusBidAdapter.js new file mode 100644 index 00000000000..578db846289 --- /dev/null +++ b/modules/minutemediaplusBidAdapter.js @@ -0,0 +1,291 @@ +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'; + +const GVLID = 918; +const DEFAULT_SUB_DOMAIN = 'exchange'; +const BIDDER_CODE = 'mmplus'; +const BIDDER_VERSION = '1.0.0'; +const CURRENCY = 'USD'; +const TTL_SECONDS = 60 * 5; +const UNIQUE_DEAL_ID_EXPIRY = 1000 * 60 * 15; +export const SUPPORTED_ID_SYSTEMS = { + 'britepoolid': 1, + 'criteoId': 1, + 'id5id': 1, + 'idl_env': 1, + 'lipb': 1, + 'netId': 1, + 'parrableId': 1, + 'pubcid': 1, + 'tdid': 1, + 'pubProvidedId': 1 +}; +const storage = getStorageManager({ gvlid: GVLID, bidderCode: BIDDER_CODE }); + +function getTopWindowQueryParams() { + try { + const parsedUrl = parseUrl(window.top.document.URL, { decodeSearchAsString: true }); + return parsedUrl.search; + } catch (e) { + return ''; + } +} + +export function createDomain(subDomain = DEFAULT_SUB_DOMAIN) { + return `https://${subDomain}.minutemedia-prebid.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) { + const { params, bidId, userId, adUnitCode, schain, mediaTypes } = 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); + + 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 + }; + + appendUserIdsToRequestPayload(data, userId); + + 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; + } + + 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) => { + if (SUPPORTED_ID_SYSTEMS[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 requests = []; + validBidRequests.forEach(validBidRequest => { + const sizes = parseSizesInput(validBidRequest.sizes); + const request = buildRequest(validBidRequest, topWindowUrl, sizes, bidderRequest); + 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, 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, + 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.minutemedia-prebid.com/api/sync/iframe/${params}` + }); + } + if (pixelEnabled) { + syncs.push({ + type: 'image', + url: `https://sync.minutemedia-prebid.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; + } +} + +export const spec = { + code: BIDDER_CODE, + version: BIDDER_VERSION, + gvlid: GVLID, + supportedMediaTypes: [BANNER, VIDEO], + isBidRequestValid, + buildRequests, + interpretResponse, + getUserSyncs +}; + +registerBidder(spec); diff --git a/modules/minutemediaplusBidAdapter.md b/modules/minutemediaplusBidAdapter.md new file mode 100644 index 00000000000..410c00e7017 --- /dev/null +++ b/modules/minutemediaplusBidAdapter.md @@ -0,0 +1,35 @@ +# Overview + +**Module Name:** MinuteMediaPlus Bidder Adapter + +**Module Type:** Bidder Adapter + +**Maintainer:** hb@minutemedia.com + +# Description + +Module that connects to MinuteMediaPlus's demand sources. + +# Test Parameters +```js +var adUnits = [ + { + code: 'test-ad', + sizes: [[300, 250]], + bids: [ + { + bidder: 'mmplus', + params: { + cId: '562524b21b1c1f08117fc7f9', + pId: '59ac17c192832d0011283fe3', + bidFloor: 0.0001, + ext: { + param1: 'loremipsum', + param2: 'dolorsitamet' + } + } + } + ] + } +]; +``` diff --git a/modules/missenaBidAdapter.js b/modules/missenaBidAdapter.js index 2ec9d39fc5d..02fd454c780 100644 --- a/modules/missenaBidAdapter.js +++ b/modules/missenaBidAdapter.js @@ -1,9 +1,11 @@ -import { formatQS, logInfo } from '../src/utils.js'; +import { buildUrl, formatQS, logInfo, triggerPixel } from '../src/utils.js'; import { BANNER } from '../src/mediaTypes.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'missena'; const ENDPOINT_URL = 'https://bid.missena.io/'; +const EVENTS_DOMAIN = 'events.missena.io'; +const EVENTS_DOMAIN_DEV = 'events.staging.missena.xyz'; export const spec = { aliases: [BIDDER_CODE], @@ -30,6 +32,7 @@ export const spec = { buildRequests: function (validBidRequests, bidderRequest) { return validBidRequests.map((bidRequest) => { const payload = { + adunit: bidRequest.adUnitCode, request_id: bidRequest.bidId, timeout: bidderRequest.timeout, }; @@ -48,6 +51,15 @@ export const spec = { if (bidRequest.params.test) { payload.test = bidRequest.params.test; } + if (bidRequest.params.placement) { + payload.placement = bidRequest.params.placement; + } + if (bidRequest.params.formats) { + payload.formats = bidRequest.params.formats; + } + if (bidRequest.params.isInternal) { + payload.is_internal = bidRequest.params.isInternal; + } return { method: 'POST', url: baseUrl + '?' + formatQS({ t: bidRequest.params.apiKey }), @@ -109,6 +121,15 @@ export const spec = { * @param {Bid} The bid that won the auction */ onBidWon: function (bid) { + const hostname = bid.params[0].baseUrl ? EVENTS_DOMAIN_DEV : EVENTS_DOMAIN; + triggerPixel( + buildUrl({ + protocol: 'https', + hostname, + pathname: '/v1/bidsuccess', + search: { t: bid.params[0].apiKey }, + }) + ); logInfo('Missena - Bid won', bid); }, }; diff --git a/modules/nativoBidAdapter.js b/modules/nativoBidAdapter.js index 7eb37ea8b82..a92168492d0 100644 --- a/modules/nativoBidAdapter.js +++ b/modules/nativoBidAdapter.js @@ -140,13 +140,9 @@ export const spec = { const floorPriceData = {} let placementId, pageUrl validBidRequests.forEach((bidRequest) => { - pageUrl = deepAccess( - bidRequest, - 'params.url', - ) - if (pageUrl == undefined || pageUrl === '') { - pageUrl = bidderRequest.refererInfo.location - } + pageUrl = + getPageUrlFromBidRequest(bidRequest) || + bidderRequest.refererInfo.location placementId = deepAccess(bidRequest, 'params.placementId') @@ -380,10 +376,12 @@ export const spec = { return syncs } - body = - typeof response.body === 'string' - ? JSON.parse(response.body) - : response.body + try { + body = + typeof response.body === 'string' + ? JSON.parse(response.body) + : response.body + } catch (err) { return } // Make sure we have valid content if (!body || !body.seatbid || body.seatbid.length === 0) return @@ -465,7 +463,7 @@ export function parseFloorPriceData(bidRequest) { // Setup price floor data per media type let mediaTypeData = bidMediaTypes[mediaType] let mediaTypeFloorPriceData = {} - let mediaTypeSizes = mediaTypeData.sizes || mediaTypeData.playerSize || []; + let mediaTypeSizes = mediaTypeData.sizes || mediaTypeData.playerSize || [] // Step through each size of the media type so we can get floor data for each size per media type mediaTypeSizes.forEach((size) => { // Get floor price data per the getFloor method and respective media type / size combination @@ -634,3 +632,37 @@ function appendFilterData(filter, filterData) { filterData.forEach((ad) => filter.add(ad)) } } + +export function getPageUrlFromBidRequest(bidRequest) { + let paramPageUrl = deepAccess(bidRequest, 'params.url') + + if (paramPageUrl == undefined) return + + if (hasProtocol(paramPageUrl)) return paramPageUrl + + paramPageUrl = addProtocol(paramPageUrl) + + try { + const url = new URL(paramPageUrl) + return url.href + } catch (err) {} +} + +export function hasProtocol(url) { + const protocolRegexp = /^http[s]?\:/ + return protocolRegexp.test(url) +} + +export function addProtocol(url) { + if (hasProtocol(url)) { + return url + } + + let protocolPrefix = 'https:' + + if (url.indexOf('//') !== 0) { + protocolPrefix += '//' + } + + return `${protocolPrefix}${url}` +} diff --git a/modules/neuwoRtdProvider.js b/modules/neuwoRtdProvider.js new file mode 100644 index 00000000000..e13c6151e5d --- /dev/null +++ b/modules/neuwoRtdProvider.js @@ -0,0 +1,175 @@ +import { deepAccess, deepSetValue, generateUUID, logError, logInfo, mergeDeep } from '../src/utils.js'; +import { getRefererInfo } from '../src/refererDetection.js'; +import { ajax } from '../src/ajax.js'; +import { submodule } from '../src/hook.js'; +import * as events from '../src/events.js'; +import CONSTANTS from '../src/constants.json'; + +export const DATA_PROVIDER = 'neuwo.ai'; +const SEGTAX_IAB = 6 // IAB - Content Taxonomy version 2 +const CATTAX_IAB = 6 // IAB Tech Lab Content Taxonomy 2.2 +const RESPONSE_IAB_TIER_1 = 'marketing_categories.iab_tier_1' +const RESPONSE_IAB_TIER_2 = 'marketing_categories.iab_tier_2' + +function init(config = {}, userConsent = '') { + config.params = config.params || {} + // ignore module if publicToken is missing (module setup failure) + if (!config.params.publicToken) { + logError('publicToken missing', 'NeuwoRTDModule', 'config.params.publicToken') + return false; + } + if (!config.params.apiUrl) { + logError('apiUrl missing', 'NeuwoRTDModule', 'config.params.apiUrl') + return false; + } + return true; +} + +export function getBidRequestData(reqBidsConfigObj, callback, config, userConsent) { + config.params = config.params || {}; + logInfo('NeuwoRTDModule', 'starting getBidRequestData') + + const wrappedArgUrl = encodeURIComponent(config.params.argUrl || getRefererInfo().page); + const url = config.params.apiUrl + [ + 'token=' + config.params.publicToken, + 'lang=en', + 'url=' + wrappedArgUrl + ].join('&') + const billingId = generateUUID(); + + const success = (responseContent) => { + logInfo('NeuwoRTDModule', 'GetAiTopics: response', responseContent) + try { + const jsonContent = JSON.parse(responseContent); + if (jsonContent.marketing_categories) { + events.emit(CONSTANTS.EVENTS.BILLABLE_EVENT, { type: 'request', billingId, vendor: neuwoRtdModule.name }) + } + injectTopics(jsonContent, reqBidsConfigObj, billingId) + } catch (ex) { + logError('NeuwoRTDModule', 'Response to JSON parse error', ex) + } + callback() + } + + const error = (err) => { + logError('xhr error', null, err); + callback() + } + + ajax(url, {success, error}, null, { + // could assume Origin header is set, or + // customHeaders: { 'Origin': 'Origin' } + }) +} + +export function addFragment(base, path, addition) { + const container = {} + deepSetValue(container, path, addition) + mergeDeep(base, container) +} + +/** + * Concatenate a base array and an array within an object + * non-array bases will be arrays, non-arrays at object key will be discarded + * @param {array} base base array to add to + * @param {object} source object to get an array from + * @param {string} key dot-notated path to array within object + * @returns base + source[key] if that's an array + */ +function combineArray(base, source, key) { + if (Array.isArray(base) === false) base = [] + const addition = deepAccess(source, key, []) + if (Array.isArray(addition)) return base.concat(addition) + else return base +} + +export function injectTopics(topics, bidsConfig) { + topics = topics || {} + + // join arrays of IAB category details to single array + const combinedTiers = combineArray( + combineArray([], topics, RESPONSE_IAB_TIER_1), + topics, RESPONSE_IAB_TIER_2) + + const segment = pickSegments(combinedTiers) + // effectively gets topics.marketing_categories.iab_tier_1, topics.marketing_categories.iab_tier_2 + // used as FPD segments content + + const IABSegments = { + name: DATA_PROVIDER, + ext: { segtax: SEGTAX_IAB }, + segment + } + + addFragment(bidsConfig.ortb2Fragments.global, 'site.content.data', [IABSegments]) + + // upgrade category taxonomy to IAB 2.2, inject result to page categories + if (segment.length > 0) { + addFragment(bidsConfig.ortb2Fragments.global, 'site.cattax', CATTAX_IAB) + addFragment(bidsConfig.ortb2Fragments.global, 'site.pagecat', segment.map(s => s.id)) + } + + logInfo('NeuwoRTDModule', 'injectTopics: post-injection bidsConfig', bidsConfig) +} + +/* eslint-disable object-property-newline */ +const D_IAB_ID = { // Content Taxonomy version 2.0 final release November 2017 [sic] (Taxonomy ID Mapping, IAB versions 2.0 - 2.2) + 'IAB19-1': '603', 'IAB6-1': '193', 'IAB5-2': '133', 'IAB20-1': '665', 'IAB20-2': '656', 'IAB23-2': '454', 'IAB3-2': '102', 'IAB20-3': '672', 'IAB8-5': '211', + 'IAB8-18': '211', 'IAB7-4': '288', 'IAB7-5': '233', 'IAB17-12': '484', 'IAB19-3': '608', 'IAB21-1': '442', 'IAB9-2': '248', 'IAB15-1': '456', 'IAB9-17': '265', 'IAB20-4': '658', + 'IAB2-3': '30', 'IAB2-1': '32', 'IAB17-1': '518', 'IAB2-2': '34', 'IAB2': '1', 'IAB8-2': '215', 'IAB17-2': '545', 'IAB17-26': '547', 'IAB9-3': '249', 'IAB18-1': '553', 'IAB20-5': '674', + 'IAB15-2': '465', 'IAB3-3': '119', 'IAB16-2': '423', 'IAB9-4': '259', 'IAB9-5': '270', 'IAB18-2': '574', 'IAB17-4': '549', 'IAB7-33': '312', 'IAB1-1': '42', 'IAB17-5': '485', 'IAB23-3': '458', + 'IAB20-6': '675', 'IAB3': '53', 'IAB20-7': '676', 'IAB19-5': '633', 'IAB20-9': '677', 'IAB9-6': '250', 'IAB17-6': '499', 'IAB2-4': '25', 'IAB9-7': '271', 'IAB4-11': '125', 'IAB4-1': '126', + 'IAB4': '123', 'IAB16-3': '424', 'IAB2-5': '18', 'IAB17-7': '486', 'IAB15-3': '466', 'IAB23-5': '459', 'IAB9-9': '260', 'IAB2-22': '19', 'IAB17-8': '500', 'IAB9-10': '261', 'IAB5-5': '137', + 'IAB9-11': '262', 'IAB2-21': '3', 'IAB19-2': '610', 'IAB19-8': '600', 'IAB19-9': '601', 'IAB3-5': '121', 'IAB9-15': '264', 'IAB2-6': '8', 'IAB2-7': '9', 'IAB22-2': '474', 'IAB17-9': '491', + 'IAB2-8': '10', 'IAB20-12': '678', 'IAB17-3': '492', 'IAB19-12': '611', 'IAB14-1': '188', 'IAB6-3': '194', 'IAB7-17': '316', 'IAB19-13': '612', 'IAB8-8': '217', 'IAB9-1': '205', 'IAB19-22': '613', + 'IAB8-9': '218', 'IAB14-2': '189', 'IAB16-4': '425', 'IAB9-12': '251', 'IAB5': '132', 'IAB6-9': '190', 'IAB19-15': '623', 'IAB17-17': '496', 'IAB20-14': '659', 'IAB6': '186', 'IAB20-26': '666', + 'IAB17-10': '510', 'IAB13-4': '396', 'IAB1-3': '201', 'IAB16-1': '426', 'IAB17-11': '511', 'IAB17-13': '511', 'IAB17-32': '511', 'IAB7-1': '225', 'IAB8': '210', 'IAB8-10': '219', 'IAB9-13': '266', + 'IAB10-4': '275', 'IAB9-14': '273', 'IAB15-8': '469', 'IAB15-4': '470', 'IAB17-15': '512', 'IAB3-7': '77', 'IAB19-16': '614', 'IAB3-8': '78', 'IAB2-10': '22', 'IAB2-12': '22', 'IAB2-11': '11', + 'IAB8-12': '221', 'IAB7-35': '223', 'IAB7-38': '223', 'IAB7-24': '296', 'IAB13-5': '411', 'IAB7-25': '234', 'IAB23-6': '460', 'IAB9': '239', 'IAB7-26': '235', 'IAB10': '274', 'IAB10-1': '278', + 'IAB10-2': '279', 'IAB19-17': '634', 'IAB10-5': '280', 'IAB5-10': '145', 'IAB5-11': '146', 'IAB20-17': '667', 'IAB17-16': '497', 'IAB20-18': '668', 'IAB3-9': '55', 'IAB1-4': '440', 'IAB17-18': '514', + 'IAB17-27': '515', 'IAB10-3': '282', 'IAB19-25': '618', 'IAB17-19': '516', 'IAB13-6': '398', 'IAB10-7': '283', 'IAB12-1': '382', 'IAB19-24': '624', 'IAB6-4': '195', 'IAB23-7': '461', 'IAB9-19': '252', + 'IAB4-4': '128', 'IAB4-5': '127', 'IAB23-8': '462', 'IAB10-8': '284', 'IAB5-8': '147', 'IAB16-5': '427', 'IAB11-2': '383', 'IAB12-3': '384', 'IAB3-10': '57', 'IAB2-13': '23', 'IAB9-20': '241', + 'IAB3-1': '58', 'IAB3-11': '58', 'IAB14-4': '191', 'IAB17-20': '520', 'IAB7-31': '228', 'IAB7-37': '301', 'IAB3-12': '107', 'IAB2-14': '13', 'IAB17-25': '519', 'IAB2-15': '27', 'IAB1-5': '324', + 'IAB1-6': '338', 'IAB9-16': '243', 'IAB13-8': '412', 'IAB12-2': '385', 'IAB9-21': '253', 'IAB8-6': '222', 'IAB7-32': '229', 'IAB2-16': '14', 'IAB17-23': '521', 'IAB13-9': '413', 'IAB17-24': '501', + 'IAB9-22': '254', 'IAB15-5': '244', 'IAB6-2': '196', 'IAB6-5': '197', 'IAB6-6': '198', 'IAB2-17': '24', 'IAB13-2': '405', 'IAB13': '391', 'IAB13-7': '410', 'IAB13-12': '415', 'IAB16': '422', + 'IAB9-23': '255', 'IAB7-36': '236', 'IAB15-6': '471', 'IAB2-18': '15', 'IAB11-4': '386', 'IAB1-2': '432', 'IAB5-9': '139', 'IAB6-7': '305', 'IAB5-12': '149', 'IAB5-13': '134', 'IAB19-4': '631', + 'IAB19-19': '631', 'IAB19-20': '631', 'IAB19-32': '631', 'IAB9-24': '245', 'IAB21': '441', 'IAB21-3': '451', 'IAB23': '453', 'IAB10-9': '276', 'IAB4-9': '130', 'IAB16-6': '429', 'IAB4-6': '129', + 'IAB13-10': '416', 'IAB2-19': '28', 'IAB17-28': '525', 'IAB9-25': '272', 'IAB17-29': '527', 'IAB17-30': '227', 'IAB17-31': '530', 'IAB22-1': '481', 'IAB15': '464', 'IAB9-26': '246', 'IAB9-27': '256', + 'IAB9-28': '267', 'IAB17-33': '502', 'IAB19-35': '627', 'IAB2-20': '4', 'IAB7-39': '307', 'IAB19-30': '605', 'IAB22': '473', 'IAB17-34': '503', 'IAB17-35': '531', 'IAB7-19': '309', 'IAB7-40': '310', + 'IAB19-6': '635', 'IAB7-41': '237', 'IAB17-36': '504', 'IAB17-44': '533', 'IAB20-23': '662', 'IAB15-7': '472', 'IAB20-24': '671', 'IAB5-14': '136', 'IAB6-8': '199', 'IAB17': '483', 'IAB9-29': '263', + 'IAB2-23': '5', 'IAB13-11': '414', 'IAB4-3': '395', 'IAB18': '552', 'IAB7-42': '311', 'IAB17-37': '505', 'IAB17-38': '537', 'IAB17-39': '538', 'IAB19-26': '636', 'IAB19': '596', 'IAB1-7': '640', + 'IAB17-40': '539', 'IAB7-43': '293', 'IAB20': '653', 'IAB8-16': '212', 'IAB8-17': '213', 'IAB16-7': '430', 'IAB9-30': '680', 'IAB17-41': '541', 'IAB17-42': '542', 'IAB17-43': '506', 'IAB15-10': '390', + 'IAB19-23': '607', 'IAB19-34': '629', 'IAB14-7': '165', 'IAB7-44': '231', 'IAB7-45': '238', 'IAB9-31': '257', 'IAB5-1': '135', 'IAB7-2': '301', 'IAB18-6': '580', 'IAB7-3': '297', 'IAB23-1': '453', + 'IAB8-1': '214', 'IAB7-6': '312', 'IAB7-7': '300', 'IAB7-8': '301', 'IAB13-1': '410', 'IAB7-9': '301', 'IAB15-9': '465', 'IAB7-10': '313', 'IAB3-4': '602', 'IAB20-8': '660', 'IAB8-3': '214', + 'IAB20-10': '660', 'IAB7-11': '314', 'IAB20-11': '660', 'IAB23-4': '459', 'IAB9-8': '270', 'IAB8-4': '214', 'IAB7-12': '306', 'IAB7-13': '313', 'IAB7-14': '287', 'IAB18-5': '575', 'IAB7-15': '315', + 'IAB8-7': '214', 'IAB19-11': '616', 'IAB7-16': '289', 'IAB7-18': '301', 'IAB7-20': '290', 'IAB20-13': '659', 'IAB7-21': '313', 'IAB18-3': '579', 'IAB13-3': '52', 'IAB20-15': '659', 'IAB8-11': '214', + 'IAB7-22': '318', 'IAB20-16': '659', 'IAB7-23': '313', 'IAB7': '223', 'IAB10-6': '634', 'IAB7-27': '318', 'IAB11-1': '388', 'IAB7-29': '318', 'IAB7-30': '304', 'IAB19-18': '619', 'IAB8-13': '214', + 'IAB20-19': '659', 'IAB20-20': '657', 'IAB8-14': '214', 'IAB18-4': '565', 'IAB23-9': '459', 'IAB11': '379', 'IAB8-15': '214', 'IAB20-21': '662', 'IAB17-21': '492', 'IAB17-22': '518', 'IAB12': '379', + 'IAB23-10': '453', 'IAB7-34': '301', 'IAB4-8': '395', 'IAB26-3': '608', 'IAB20-25': '151', 'IAB20-27': '659' +} + +export function convertSegment(segment) { + if (!segment) return {} + return { + id: D_IAB_ID[segment.id || segment.ID] + } +} + +/** + * map array of objects to segments + * @param {Array[{ID: string}]} normalizable + * @returns array of IAB "segments" + */ +export function pickSegments(normalizable) { + if (Array.isArray(normalizable) === false) return [] + return normalizable.map(convertSegment) + .filter(t => t.id) +} + +export const neuwoRtdModule = { + name: 'NeuwoRTDModule', + init, + getBidRequestData +} + +submodule('realTimeData', neuwoRtdModule) diff --git a/modules/neuwoRtdProvider.md b/modules/neuwoRtdProvider.md new file mode 100644 index 00000000000..2adead66d4e --- /dev/null +++ b/modules/neuwoRtdProvider.md @@ -0,0 +1,49 @@ +# Overview + +Module Name: Neuwo Rtd Provider +Module Type: Rtd Provider +Maintainer: neuwo.ai + +# Description + +The Neuwo AI RTD module is an advanced AI solution for real-time data processing in the field of contextual targeting and advertising. With its cutting-edge algorithms, it allows advertisers to target their audiences with the highest level of precision based on context, while also delivering a seamless user experience. + +The module provides advertiser with valuable insights and real-time contextual bidding capabilities. Whether you're a seasoned advertising professional or just starting out, Neuwo AI RTD module is the ultimate tool for contextual targeting and advertising. + +The benefit of Neuwo AI RTD module is that it provides an alternative solution for advertisers to target their audiences and deliver relevant advertisements, as the widespread use of cookies for tracking and targeting is becoming increasingly limited. + +The RTD module uses cutting-edge algorithms to process real-time data, allowing advertisers to target their audiences based on contextual information, such as segments, IAB Tiers and brand safety. The RTD module is designed to be flexible and scalable, making it an ideal solution for advertisers looking to stay ahead of the curve in the post-cookie era. + +Generate your token at: [https://neuwo.ai/generatetoken/] + +# Configuration + +```javascript + +const neuwoDataProvider = { + name: 'NeuwoRTDModule', + params: { + publicToken: '', + apiUrl: '' + } +} +pbjs.setConfig({realTimeData: { dataProviders: [ neuwoDataProvider ]}}) + +``` + +# Testing + +## Add development tools if necessary + +- Install node for npm +- run in prebid.js source folder: +`npm ci` +`npm i -g gulp-cli` + +## Serve + +`gulp serve --modules=rtdModule,neuwoRtdProvider,appnexusBidAdapter` + +- in your browser, navigate to: + +`http://localhost:9999/integrationExamples/gpt/neuwoRtdProvider_example.html` diff --git a/modules/nextMillenniumBidAdapter.js b/modules/nextMillenniumBidAdapter.js index 25ad1f43e82..6abb369522b 100644 --- a/modules/nextMillenniumBidAdapter.js +++ b/modules/nextMillenniumBidAdapter.js @@ -1,4 +1,5 @@ import { + isArray, _each, createTrackPixelHtml, deepAccess, @@ -14,6 +15,7 @@ import { import CONSTANTS from '../src/constants.json'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import {config} from '../src/config.js'; import * as events from '../src/events.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; @@ -22,18 +24,22 @@ import { getRefererInfo } from '../src/refererDetection.js'; const BIDDER_CODE = 'nextMillennium'; const ENDPOINT = 'https://pbs.nextmillmedia.com/openrtb2/auction'; const TEST_ENDPOINT = 'https://test.pbs.nextmillmedia.com/openrtb2/auction'; -const SYNC_ENDPOINT = 'https://statics.nextmillmedia.com/load-cookie.html?v=4'; +const SYNC_ENDPOINT = 'https://cookies.nextmillmedia.com/sync?'; +const REPORT_ENDPOINT = 'https://report2.hb.brainlyads.com/statistics/metric'; const TIME_TO_LIVE = 360; const VIDEO_PARAMS = [ 'api', 'linearity', 'maxduration', 'mimes', 'minduration', 'placement', 'playbackmethod', 'protocols', 'startdelay' ]; +const sendingDataStatistic = initSendingDataStatistic(); +events.on(CONSTANTS.EVENTS.AUCTION_INIT, auctionInitHandler); + const EXPIRENCE_WURL = 20 * 60000; const wurlMap = {}; +cleanWurl(); events.on(CONSTANTS.EVENTS.BID_WON, bidWonHandler); -cleanWurl(); export const spec = { code: BIDDER_CODE, @@ -135,17 +141,19 @@ export const spec = { const urlParameters = parseUrl(getWindowTop().location.href).search; const isTest = urlParameters['pbs'] && urlParameters['pbs'] === 'test'; + const params = bid.params; requests.push({ method: 'POST', url: isTest ? TEST_ENDPOINT : ENDPOINT, data: JSON.stringify(postBody), options: { - contentType: 'application/json', + contentType: 'text/plain', withCredentials: true }, bidId, + params, auctionId, }); }); @@ -160,6 +168,7 @@ export const spec = { _each(response.seatbid, (resp) => { _each(resp.bid, (bid) => { const requestId = bidRequest.bidId; + const params = bidRequest.params; const auctionId = bidRequest.auctionId; const wurl = deepAccess(bid, 'ext.prebid.events.win'); addWurl({auctionId, requestId, wurl}); @@ -168,12 +177,13 @@ export const spec = { const bidResponse = { requestId, + params, cpm: bid.price, width: bid.w, height: bid.h, creativeId: bid.adid, currency: response.cur, - netRevenue: false, + netRevenue: true, ttl: TIME_TO_LIVE, meta: { advertiserDomains: bid.adomain || [] @@ -198,31 +208,98 @@ export const spec = { }, getUserSyncs: function (syncOptions, responses, gdprConsent, uspConsent) { - if (!syncOptions.iframeEnabled) { - return; - }; + const pixels = []; + + if (isArray(responses)) { + responses.forEach(response => { + if (syncOptions.pixelEnabled) { + deepAccess(response, 'body.ext.sync.image', []).forEach(imgUrl => { + pixels.push({ + type: 'image', + url: replaceUsersyncMacros(imgUrl, gdprConsent, uspConsent) + }); + }) + } - let syncurl = gdprConsent && gdprConsent.gdprApplies ? `${SYNC_ENDPOINT}&gdpr=1&gdpr_consent=${gdprConsent.consentString}` : SYNC_ENDPOINT; + if (syncOptions.iframeEnabled) { + deepAccess(response, 'body.ext.sync.iframe', []).forEach(iframeUrl => { + pixels.push({ + type: 'iframe', + url: replaceUsersyncMacros(iframeUrl, gdprConsent, uspConsent) + }); + }) + } + }) + } + + if (!pixels.length) { + let syncUrl = SYNC_ENDPOINT; + if (gdprConsent && gdprConsent.gdprApplies) syncUrl += 'gdpr=1&gdpr_consent=' + gdprConsent.consentString + '&'; + if (uspConsent) syncUrl += 'us_privacy=' + uspConsent + '&'; + if (syncOptions.iframeEnabled) pixels.push({type: 'iframe', url: syncUrl + 'type=iframe'}); + if (syncOptions.pixelEnabled) pixels.push({type: 'image', url: syncUrl + 'type=image'}); + } + return pixels; + }, - let bidders = []; - if (responses) { - _each(responses, (response) => { - if (!(response && response.body && response.body.ext && response.body.ext.responsetimemillis)) return; - _each(Object.keys(response.body.ext.responsetimemillis), b => bidders.push(b)); - }); + getUrlPixelMetric(eventName, bid) { + const bidder = bid.bidder || bid.bidderCode; + if (bidder != BIDDER_CODE) return; + + let params; + if (bid.params) { + params = Array.isArray(bid.params) ? bid.params : [bid.params]; + } else { + if (Array.isArray(bid.bids)) params = bid.bids.map(bidI => bidI.params); }; - if (bidders.length) { - syncurl += `&bidders=${bidders.join(',')}`; + if (!params.length) return; + + const placementIdsArray = []; + const groupIdsArray = []; + params.forEach(paramsI => { + if (paramsI.group_id) { + groupIdsArray.push(paramsI.group_id); + } else { + if (paramsI.placement_id) placementIdsArray.push(paramsI.placement_id); + }; + }); + + const placementIds = (placementIdsArray.length && `&placements=${placementIdsArray.join(';')}`) || ''; + const groupIds = (groupIdsArray.length && `&groups=${groupIdsArray.join(';')}`) || ''; + + if (!(groupIds || placementIds)) { + return; }; - return [{ - type: 'iframe', - url: syncurl - }]; + const url = `${REPORT_ENDPOINT}?event=${eventName}&bidder=${bidder}&source=pbjs${groupIds}${placementIds}`; + + return url; }, }; +function replaceUsersyncMacros(url, gdprConsent, uspConsent) { + const { consentString, gdprApplies } = gdprConsent || {}; + + if (gdprApplies) { + const gdpr = Number(gdprApplies); + url = url.replace('{{.GDPR}}', gdpr); + + if (gdpr == 1 && consentString && consentString.length > 0) { + url = url.replace('{{.GDPRConsent}}', consentString); + } + } else { + url = url.replace('{{.GDPR}}', 0); + url = url.replace('{{.GDPRConsent}}', ''); + } + + if (uspConsent) { + url = url.replace('{{.USPrivacy}}', uspConsent); + } + + return url; +}; + function getAdEl(bid) { // best way I could think of to get El, is by matching adUnitCode to google slots... const slot = window.googletag && window.googletag.pubads && window.googletag.pubads().getSlots().find(slot => slot.getAdUnitPath() === bid.adUnitCode); @@ -342,6 +419,10 @@ function bidWonHandler(bid) { }; } +function auctionInitHandler() { + sendingDataStatistic.initEvents(); +} + function cleanWurl() { const dateNow = Date.now(); Object.keys(wurlMap).forEach(key => { @@ -353,4 +434,79 @@ function cleanWurl() { setTimeout(cleanWurl, 60000); } +function initSendingDataStatistic() { + class SendingDataStatistic { + eventNames = [ + CONSTANTS.EVENTS.BID_TIMEOUT, + CONSTANTS.EVENTS.BID_RESPONSE, + CONSTANTS.EVENTS.BID_REQUESTED, + CONSTANTS.EVENTS.NO_BID, + ]; + + disabledSending = false; + enabledSending = false; + eventHendlers = {}; + + initEvents() { + this.disabledSending = !!config.getBidderConfig()?.nextMillennium?.disabledSendingStatisticData; + if (this.disabledSending) { + this.removeEvents(); + } else { + this.createEvents(); + }; + } + + createEvents() { + if (this.enabledSending) return; + + this.enabledSending = true; + for (let eventName of this.eventNames) { + if (!this.eventHendlers[eventName]) { + this.eventHendlers[eventName] = this.eventHandler(eventName); + }; + + events.on(eventName, this.eventHendlers[eventName]); + }; + } + + removeEvents() { + if (!this.enabledSending) return; + + this.enabledSending = false; + for (let eventName of this.eventNames) { + if (!this.eventHendlers[eventName]) continue; + + events.off(eventName, this.eventHendlers[eventName]); + }; + } + + eventHandler(eventName) { + const eventHandlerFunc = this.getEventHandler(eventName); + if (eventName == CONSTANTS.EVENTS.BID_TIMEOUT) { + return bids => { + if (this.disabledSending || !Array.isArray(bids)) return; + + for (let bid of bids) { + eventHandlerFunc(bid); + }; + } + }; + + return eventHandlerFunc; + } + + getEventHandler(eventName) { + return bid => { + if (this.disabledSending) return; + + const url = spec.getUrlPixelMetric(eventName, bid); + if (!url) return; + triggerPixel(url); + }; + } + }; + + return new SendingDataStatistic(); +} + registerBidder(spec); diff --git a/modules/nexx360BidAdapter.js b/modules/nexx360BidAdapter.js index ed0c0c66a7a..397196ee7a9 100644 --- a/modules/nexx360BidAdapter.js +++ b/modules/nexx360BidAdapter.js @@ -1,176 +1,300 @@ -import {ajax} from '../src/ajax.js'; import {config} from '../src/config.js'; -import { transformBidderParamKeywords } from '../src/utils.js'; +import * as utils from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; +import {getGlobal} from '../src/prebidGlobal.js'; +const VIDEO_TARGETING = ['startdelay', 'mimes', 'minduration', 'maxduration', 'delivery', + 'startdelay', 'skip', 'playbackmethod', 'api', 'protocol', 'boxingallowed', 'maxextended', + 'linearity', 'delivery', 'protocols', 'placement', 'minbitrate', 'maxbitrate', 'battr', 'ext']; const BIDDER_CODE = 'nexx360'; -const BIDDER_URL = 'https://fast.nexx360.io/prebid'; -const CACHE_URL = 'https://fast.nexx360.io/cache'; -const METRICS_TRACKER_URL = 'https://fast.nexx360.io/track-imp'; +const REQUEST_URL = 'https://fast.nexx360.io/booster'; + +const PAGE_VIEW_ID = utils.generateUUID(); + +const BIDDER_VERSION = '1.0'; const GVLID = 965; export const spec = { code: BIDDER_CODE, gvlid: GVLID, - aliases: ['revenuemaker'], // short code + aliases: [ + { code: 'revenuemaker' }, + { code: 'first-id', gvlid: 1178 }, + { code: 'adwebone' }, + { code: 'league-m', gvlid: 965 } + ], supportedMediaTypes: [BANNER, VIDEO], - /** + isBidRequestValid, + buildRequests, + interpretResponse, + getUserSyncs, +}; + +registerBidder(spec); + +/** * 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) { - if (!!bid.params.bidfloorCurrency && !['EUR', 'USD'].includes(bid.params.bidfloorCurrency)) return false; - if (!!bid.params.bidfloor && typeof bid.params.bidfloor !== 'number') return false; - if (!!bid.params.keywords && typeof bid.params.keywords !== 'object') return false; - return !!(bid.params.account && bid.params.tagId); - }, - /** +function isBidRequestValid(bid) { + return !!bid.params.tagId || !!bid.params.videoTagId; +}; + +/** * Make a server request from the list of BidRequests. * * @param {validBidRequests[]} - an array of bids * @return ServerRequest Info describing the request to the server. */ - buildRequests: function(validBidRequests, bidderRequest) { - const adUnits = []; - const test = config.getConfig('debug') ? 1 : 0; - let adunitValue = null; - let userEids = null; - Object.keys(validBidRequests).forEach(key => { - adunitValue = validBidRequests[key]; - const foo = { - account: adunitValue.params.account, - tagId: adunitValue.params.tagId, - videoExt: adunitValue.params.videoExt, - label: adunitValue.adUnitCode, - bidId: adunitValue.bidId, - auctionId: adunitValue.auctionId, - transactionId: adunitValue.transactionId, - mediatypes: adunitValue.mediaTypes, - bidfloor: adunitValue.params.bidfloor || 0, - bidfloorCurrency: adunitValue.params.bidfloorCurrency || 'USD', - keywords: adunitValue.params.keywords ? transformBidderParamKeywords(adunitValue.params.keywords) : [], + +function buildRequests(bids, bidderRequest) { + const data = getBaseRequest(bids[0], bidderRequest); + bids.forEach((bid) => { + const impObject = createImpObject(bid); + if (isBannerBid(bid)) impObject.banner = getBannerObject(bid); + if (isVideoBid(bid)) impObject.video = getVideoObject(bid); + data.imp.push(impObject); + }); + return { + method: 'POST', + url: REQUEST_URL, + data, + } +} + +function createImpObject(bid) { + const floor = getFloor(bid, BANNER); + const imp = { + id: bid.bidId, + tagid: bid.adUnitCode, + ext: { + divId: bid.adUnitCode, + nexx360: { + videoTagId: bid.params.videoTagId, + tagId: bid.params.tagId, + allBids: bid.params.allBids === true, } - adUnits.push(foo); - if (adunitValue.userIdAsEids) userEids = adunitValue.userIdAsEids; + } + }; + enrichImp(imp, bid, floor); + return imp; +} + +function getBannerObject(bid) { + return { + format: toFormat(bid.mediaTypes.banner.sizes), + topframe: utils.inIframe() ? 0 : 1 + }; +} + +function getVideoObject(bid) { + let width, height; + const videoParams = utils.deepAccess(bid, `mediaTypes.video`); + const playerSize = utils.deepAccess(bid, 'mediaTypes.video.playerSize'); + const context = utils.deepAccess(bid, 'mediaTypes.video.context'); + // normalize config for video size + if (utils.isArray(bid.sizes) && bid.sizes.length === 2 && !utils.isArray(bid.sizes[0])) { + width = parseInt(bid.sizes[0], 10); + height = parseInt(bid.sizes[1], 10); + } else if (utils.isArray(bid.sizes) && utils.isArray(bid.sizes[0]) && bid.sizes[0].length === 2) { + width = parseInt(bid.sizes[0][0], 10); + height = parseInt(bid.sizes[0][1], 10); + } else if (utils.isArray(playerSize) && playerSize.length === 2) { + width = parseInt(playerSize[0], 10); + height = parseInt(playerSize[1], 10); + } + const video = { + playerSize: [height, width], + context, + }; + + Object.keys(videoParams) + .filter(param => VIDEO_TARGETING.includes(param)) + .forEach(param => video[param] = videoParams[param]); + return video; +} + +function isVideoBid(bid) { + return utils.deepAccess(bid, 'mediaTypes.video'); +} + +function isBannerBid(bid) { + return utils.deepAccess(bid, 'mediaTypes.banner') || !isVideoBid(bid); +} + +function toFormat(sizes) { + return sizes.map((s) => { + return { w: s[0], h: s[1] }; + }); +} + +function getFloor(bid, mediaType) { + let floor = 0; + if (typeof bid.getFloor === 'function') { + const floorInfo = bid.getFloor({ + currency: 'USD', + mediaType: mediaType, + size: '*' }); - const payload = { - adUnits, - // TODO: does the fallback make sense here? - href: encodeURIComponent(bidderRequest.refererInfo.page || bidderRequest.refererInfo.topmostLocation) - }; - if (bidderRequest) { // modules informations (gdpr, ccpa, schain, userId) - if (bidderRequest.gdprConsent) { - payload.gdpr = bidderRequest.gdprConsent.gdprApplies ? 1 : 0; - payload.gdprConsent = bidderRequest.gdprConsent.consentString; - } else { - payload.gdpr = 0; - payload.gdprConsent = ''; - } - if (bidderRequest.uspConsent) { payload.uspConsent = bidderRequest.uspConsent; } - if (bidderRequest.schain) { payload.schain = bidderRequest.schain; } - if (userEids !== null) payload.userEids = userEids; - }; - if (test) payload.test = 1; - const payloadString = JSON.stringify(payload); - return { - method: 'POST', - url: BIDDER_URL, - data: payloadString, - }; - }, - /** + + if (typeof floorInfo === 'object' && + floorInfo.currency === 'USD' && + !isNaN(parseFloat(floorInfo.floor))) { + floor = Math.max(floor, parseFloat(floorInfo.floor)); + } + } + + return floor; +} + +function enrichImp(imp, bid, floor) { + if (floor > 0) { + imp.bidfloor = floor; + imp.bidfloorcur = 'USD'; + } else if (bid.params.customFloor) { + imp.bidfloor = bid.params.customFloor; + } + if (bid.ortb2Imp && bid.ortb2Imp.ext && bid.ortb2Imp.ext.data) { + imp.ext.data = bid.ortb2Imp.ext.data; + } +} + +function getBaseRequest(bid, bidderRequest) { + let req = { + id: bidderRequest.auctionId, + imp: [], + cur: [config.getConfig('currency.adServerCurrency') || 'USD'], + at: 1, + tmax: config.getConfig('bidderTimeout'), + site: { + page: bidderRequest.refererInfo.topmostLocation || bidderRequest.refererInfo.page, + domain: bidderRequest.refererInfo.domain, + }, + regs: { + coppa: (config.getConfig('coppa') === true || bid.params.coppa) ? 1 : 0, + }, + device: { + dnt: (utils.getDNT() || bid.params.doNotTrack) ? 1 : 0, + h: screen.height, + w: screen.width, + ua: window.navigator.userAgent, + language: window.navigator.language.split('-').shift() + }, + user: {}, + ext: { + source: 'prebid.js', + version: '$prebid.version$', + pageViewId: PAGE_VIEW_ID, + bidderVersion: BIDDER_VERSION, + } + }; + + if (bid.params.platform) { + utils.deepSetValue(req, 'ext.platform', bid.params.platform); + } + if (bid.params.response_template_name) { + utils.deepSetValue(req, 'ext.response_template_name', bid.params.response_template_name); + } + req.test = config.getConfig('debug') ? 1 : 0; + if (bidderRequest.gdprConsent) { + if (bidderRequest.gdprConsent.gdprApplies !== undefined) { + utils.deepSetValue(req, 'regs.ext.gdpr', bidderRequest.gdprConsent.gdprApplies === true ? 1 : 0); + } + if (bidderRequest.gdprConsent.consentString !== undefined) { + utils.deepSetValue(req, 'user.ext.consent', bidderRequest.gdprConsent.consentString); + } + if (bidderRequest.gdprConsent.addtlConsent !== undefined) { + utils.deepSetValue(req, 'user.ext.ConsentedProvidersSettings.consented_providers', bidderRequest.gdprConsent.addtlConsent); + } + } + if (bidderRequest.uspConsent) { + utils.deepSetValue(req, 'regs.ext.us_privacy', bidderRequest.uspConsent); + } + if (bid.schain) { + utils.deepSetValue(req, 'source.ext.schain', bid.schain); + } + if (bid.userIdAsEids) { + utils.deepSetValue(req, 'user.ext.eids', bid.userIdAsEids); + } + const commonFpd = bidderRequest.ortb2 || {}; + if (commonFpd.site) { + utils.mergeDeep(req, {site: commonFpd.site}); + } + if (commonFpd.user) { + utils.mergeDeep(req, {user: commonFpd.user}); + } + return req; +} + +/** * 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, bidRequest) { - const serverBody = serverResponse.body; - const bidResponses = []; - let bidResponse = null; - let value = null; - if (serverBody.hasOwnProperty('responses')) { - Object.keys(serverBody['responses']).forEach(key => { - value = serverBody['responses'][key]; - const url = `${CACHE_URL}?uuid=${value['uuid']}`; - bidResponse = { - requestId: value['bidId'], - cpm: value['cpm'], - currency: value['currency'], - width: value['width'], - height: value['height'], - ttl: value['ttl'], - creativeId: value['creativeId'], - netRevenue: true, - nexx360: { - 'ssp': value['bidder'], - 'consent': value['consent'], - 'tagId': value['tagId'] - }, - /* - meta: { - 'advertiserDomains': value['adomain'] - } - */ - }; - if (value.type === 'banner') bidResponse.adUrl = url; - if (value.type === 'video') { - const params = { - type: 'prebid', - mediatype: 'video', - ssp: value.bidder, - tag_id: value.tagId, - consent: value.consent, - price: value.cpm, - }; - bidResponse.cpm = value.cpm; - bidResponse.mediaType = 'video'; - bidResponse.vastUrl = url; - bidResponse.vastImpUrl = `${METRICS_TRACKER_URL}?${new URLSearchParams(params).toString()}`; - } - bidResponses.push(bidResponse); - }); - } - return bidResponses; - }, +function interpretResponse(response, req) { + const { bidderSettings } = getGlobal(); + const allowAlternateBidderCodes = bidderSettings && bidderSettings.standard ? bidderSettings.standard.allowAlternateBidderCodes : false; + const respBody = response.body; + if (!respBody || !Array.isArray(respBody.seatbid)) { + return []; + } + + let bids = []; + respBody.seatbid.forEach(seatbid => { + const ssp = seatbid.seat; + bids = [...bids, ...seatbid.bid.map(bid => { + const response = { + requestId: bid.impid, + cpm: bid.price, + width: bid.w, + height: bid.h, + creativeId: bid.crid, + dealId: bid.dealid, + currency: respBody.cur || 'USD', + netRevenue: true, + ttl: 120, + mediaType: bid.type === 'banner' ? 'banner' : 'video', + meta: { + advertiserDomains: bid.adomain, + demandSource: ssp, + }, + }; + if (allowAlternateBidderCodes) response.bidderCode = `n360-${bid.ssp}`; + + if (response.mediaType === 'banner') { + response.adUrl = bid.adUrl; + } + + if (['instream', 'outstream'].includes(bid.type)) response.vastXml = bid.vastXml; + + if (bid.ext) { + response.meta.networkId = bid.ext.dsp_id; + response.meta.advertiserId = bid.ext.buyer_id; + response.meta.brandId = bid.ext.brand_id; + } + return response; + })]; + }); + return bids; +} - /** +/** * Register the user sync pixels which should be dropped after the auction. * * @param {SyncOptions} syncOptions Which user syncs are allowed? * @param {ServerResponse[]} serverResponses List of server's responses. * @return {UserSync[]} The user syncs which should be dropped. */ - getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) { - if (typeof serverResponses === 'object' && serverResponses != null && serverResponses.length > 0 && serverResponses[0].hasOwnProperty('body') && +function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent) { + if (typeof serverResponses === 'object' && serverResponses != null && serverResponses.length > 0 && serverResponses[0].hasOwnProperty('body') && serverResponses[0].body.hasOwnProperty('cookies') && typeof serverResponses[0].body.cookies === 'object') { - return serverResponses[0].body.cookies.slice(0, 5); - } else { - return []; - } - }, - - /** - * Register bidder specific code, which will execute if a bid from this bidder won the auction - * @param {Bid} The bid that won the auction - */ - onBidWon: function(bid) { - // fires a pixel to confirm a winning bid - const params = { type: 'prebid', mediatype: 'banner' }; - if (bid.hasOwnProperty('nexx360')) { - if (bid.nexx360.hasOwnProperty('ssp')) params.ssp = bid.nexx360.ssp; - if (bid.nexx360.hasOwnProperty('tagId')) params.tag_id = bid.nexx360.tagId; - if (bid.nexx360.hasOwnProperty('consent')) params.consent = bid.nexx360.consent; - }; - params.price = bid.cpm; - const url = `${METRICS_TRACKER_URL}?${new URLSearchParams(params).toString()}`; - ajax(url, null, undefined, {method: 'GET', withCredentials: true}); - return true; + return serverResponses[0].body.cookies.slice(0, 5); + } else { + return []; } - -} -registerBidder(spec); +}; diff --git a/modules/novatiqIdSystem.js b/modules/novatiqIdSystem.js index 7bd1ee8acd9..1d1ad6f054d 100644 --- a/modules/novatiqIdSystem.js +++ b/modules/novatiqIdSystem.js @@ -35,6 +35,16 @@ export const novatiqIdSubmodule = { snowflake: novatiqId } }; + + if (novatiqId.syncResponse !== undefined) { + responseObj.novatiq.ext = {}; + responseObj.novatiq.ext.syncResponse = novatiqId.syncResponse; + } + + if (typeof config != 'undefined' && typeof config.params !== 'undefined' && typeof config.params.removeAdditionalInfo !== 'undefined' && config.params.removeAdditionalInfo === true) { + delete responseObj.novatiq.snowflake.syncResponse; + } + return responseObj; }, @@ -120,7 +130,7 @@ export const novatiqIdSubmodule = { getNovatiqId(urlParams) { // standard uuid format let uuidFormat = [1e7] + -1e3 + -4e3 + -8e3 + -1e11; - if (urlParams.useStandardUuid == false) { + if (urlParams.useStandardUuid === false) { // novatiq standard uuid(like) format uuidFormat = uuidFormat + 1e3; } diff --git a/modules/oguryBidAdapter.js b/modules/oguryBidAdapter.js index cb082f2d9a9..da62ce5c0a1 100644 --- a/modules/oguryBidAdapter.js +++ b/modules/oguryBidAdapter.js @@ -11,7 +11,7 @@ const DEFAULT_TIMEOUT = 1000; const BID_HOST = 'https://mweb-hb.presage.io/api/header-bidding-request'; const TIMEOUT_MONITORING_HOST = 'https://ms-ads-monitoring-events.presage.io'; const MS_COOKIE_SYNC_DOMAIN = 'https://ms-cookie-sync.presage.io'; -const ADAPTER_VERSION = '1.3.0'; +const ADAPTER_VERSION = '1.4.0'; function getClientWidth() { const documentElementClientWidth = window.top.document.documentElement.clientWidth @@ -114,7 +114,10 @@ function buildRequests(validBidRequests, bidderRequest) { banner: { format: sizes }, - ext: bidRequest.params + ext: { + ...bidRequest.params, + timeSpentOnPage: document.timeline && document.timeline.currentTime ? document.timeline.currentTime : 0 + } }); } }); diff --git a/modules/onetagBidAdapter.js b/modules/onetagBidAdapter.js index 40ef6d596be..70238294c38 100644 --- a/modules/onetagBidAdapter.js +++ b/modules/onetagBidAdapter.js @@ -3,7 +3,7 @@ import { BANNER, VIDEO } from '../src/mediaTypes.js'; import { INSTREAM, OUTSTREAM } from '../src/video.js'; import { Renderer } from '../src/Renderer.js'; -import {find} from '../src/polyfill.js'; +import { find } from '../src/polyfill.js'; import { getStorageManager } from '../src/storageManager.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { deepClone, logError, deepAccess } from '../src/utils.js'; @@ -13,7 +13,7 @@ const USER_SYNC_ENDPOINT = 'https://onetag-sys.com/usync/'; const BIDDER_CODE = 'onetag'; const GVLID = 241; -const storage = getStorageManager({gvlid: GVLID, bidderCode: BIDDER_CODE}); +const storage = getStorageManager({ gvlid: GVLID, bidderCode: BIDDER_CODE }); /** * Determines whether or not the given bid request is valid. @@ -53,7 +53,7 @@ export function isValid(type, bid) { function buildRequests(validBidRequests, bidderRequest) { const payload = { bids: requestsToBids(validBidRequests), - ...getPageInfo() + ...getPageInfo(bidderRequest) }; if (bidderRequest && bidderRequest.gdprConsent) { payload.gdprConsent = { @@ -61,6 +61,12 @@ function buildRequests(validBidRequests, bidderRequest) { consentRequired: bidderRequest.gdprConsent.gdprApplies }; } + if (bidderRequest && bidderRequest.gppConsent) { + payload.gppConsent = { + consentString: bidderRequest.gppConsent.gppString, + applicableSections: bidderRequest.gppConsent.applicableSections + } + } if (bidderRequest && bidderRequest.uspConsent) { payload.usPrivacy = bidderRequest.uspConsent; } @@ -74,7 +80,10 @@ function buildRequests(validBidRequests, bidderRequest) { if (storage.hasLocalStorage()) { payload.onetagSid = storage.getDataFromLocalStorage('onetag_sid'); } - } catch (e) {} + } catch (e) { } + const connection = navigator.connection || navigator.webkitConnection; + payload.networkConnectionType = (connection && connection.type) ? connection.type : null; + payload.networkEffectiveConnectionType = (connection && connection.effectiveType) ? connection.effectiveType : null; return { method: 'POST', url: ENDPOINT, @@ -112,7 +121,7 @@ function interpretResponse(serverResponse, bidderRequest) { if (bid.mediaType === BANNER) { responseBid.ad = bid.ad; } else if (bid.mediaType === VIDEO) { - const {context, adUnitCode} = find(requestData.bids, (item) => + const { context, adUnitCode } = find(requestData.bids, (item) => item.bidId === bid.requestId && item.type === VIDEO ); @@ -141,7 +150,7 @@ function createRenderer(bid, rendererOptions = {}) { loaded: false }); try { - renderer.setRender(({renderer, width, height, vastXml, adUnitCode}) => { + renderer.setRender(({ renderer, width, height, vastXml, adUnitCode }) => { renderer.push(() => { window.onetag.Player.init({ ...bid, @@ -162,7 +171,6 @@ function createRenderer(bid, rendererOptions = {}) { function getFrameNesting() { let topmostFrame = window; let parent = window.parent; - let currentFrameNesting = 0; try { while (topmostFrame !== topmostFrame.parent) { parent = topmostFrame.parent; @@ -170,13 +178,8 @@ function getFrameNesting() { parent.location.href; topmostFrame = topmostFrame.parent; } - } catch (e) { - currentFrameNesting = parent === topmostFrame.top ? 1 : 2; - } - return { - topmostFrame, - currentFrameNesting - } + } catch (e) { } + return topmostFrame; } function getDocumentVisibility(window) { @@ -197,21 +200,15 @@ function getDocumentVisibility(window) { /** * Returns information about the page needed by the server in an object to be converted in JSON - * @returns {{location: *, referrer: (*|string), masked: *, wWidth: (*|Number), wHeight: (*|Number), sWidth, sHeight, date: string, timeOffset: number}} + * @returns {{location: *, referrer: (*|string), stack: (*|Array.), numIframes: (*|Number), wWidth: (*|Number), wHeight: (*|Number), sWidth, sHeight, date: string, timeOffset: number}} */ -function getPageInfo() { - const { topmostFrame, currentFrameNesting } = getFrameNesting(); +function getPageInfo(bidderRequest) { + const topmostFrame = getFrameNesting(); return { - location: topmostFrame.location.href, - referrer: - topmostFrame.document.referrer !== '' - ? topmostFrame.document.referrer - : null, - ancestorOrigin: - window.location.ancestorOrigins && window.location.ancestorOrigins.length > 0 - ? window.location.ancestorOrigins[window.location.ancestorOrigins.length - 1] - : null, - masked: currentFrameNesting, + location: deepAccess(bidderRequest, 'refererInfo.page', null), + referrer: deepAccess(bidderRequest, 'refererInfo.ref', null), + stack: deepAccess(bidderRequest, 'refererInfo.stack', []), + numIframes: deepAccess(bidderRequest, 'refererInfo.numIframes', 0), wWidth: topmostFrame.innerWidth, wHeight: topmostFrame.innerHeight, oWidth: topmostFrame.outerWidth, @@ -230,7 +227,7 @@ function getPageInfo() { timing: getTiming(), version: { prebid: '$prebid.version$', - adapter: '1.1.0' + adapter: '1.1.1' } }; } @@ -344,12 +341,12 @@ function getSizes(sizes) { const ret = []; for (let i = 0; i < sizes.length; i++) { const size = sizes[i]; - ret.push({width: size[0], height: size[1]}) + ret.push({ width: size[0], height: size[1] }) } return ret; } -function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent) { +function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent, gppConsent) { let syncs = []; let params = ''; if (gdprConsent) { @@ -360,6 +357,11 @@ function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent) { params += '&gdpr_consent=' + gdprConsent.consentString; } } + if (gppConsent) { + if (typeof gppConsent.gppString === 'string') { + params += '&gpp_consent=' + gppConsent.gppString; + } + } if (uspConsent && typeof uspConsent === 'string') { params += '&us_privacy=' + uspConsent; } diff --git a/modules/openxBidAdapter.js b/modules/openxBidAdapter.js index 14525cd0cfc..b6f4523bb50 100644 --- a/modules/openxBidAdapter.js +++ b/modules/openxBidAdapter.js @@ -268,6 +268,11 @@ function buildCommonQueryParamsFromBids(bids, bidderRequest) { nocache: new Date().getTime() }; + const userAgentClientHints = deepAccess(bidderRequest, 'ortb2.device.sua'); + if (userAgentClientHints) { + defaultParams.sua = JSON.stringify(userAgentClientHints); + } + const userDataSegments = buildFpdQueryParams('user.data', bidderRequest.ortb2); if (userDataSegments.length > 0) { defaultParams.sm = userDataSegments; diff --git a/modules/openxBidAdapter.md b/modules/openxBidAdapter.md index 28dba424fb2..0690bf6b4fc 100644 --- a/modules/openxBidAdapter.md +++ b/modules/openxBidAdapter.md @@ -15,23 +15,24 @@ Publishers are welcome to test the other adapter and give feedback. Please note # Bid Parameters ## Banner -| Name | Scope | Type | Description | Example -| ---- | ----- | ---- | ----------- | ------- -| `delDomain` or `platform` | required | String | OpenX delivery domain or platform id provided by your OpenX representative. | "PUBLISHER-d.openx.net" or "555not5a-real-plat-form-id0123456789" -| `unit` | required | String | OpenX ad unit ID provided by your OpenX representative. | "1611023122" -| `customParams` | optional | Object | User-defined targeting key-value pairs. customParams applies to a specific unit. | `{key1: "v1", key2: ["v2","v3"]}` -| `customFloor` | optional | Number | Minimum price in USD. customFloor applies to a specific unit. For example, use the following value to set a $1.50 floor: 1.50

**WARNING:**
Misuse of this parameter can impact revenue | 1.50 -| `doNotTrack` | optional | Boolean | Prevents advertiser from using data for this user.

**WARNING:**
Request-level setting. May impact revenue. | true -| `coppa` | optional | Boolean | Enables Child's Online Privacy Protection Act (COPPA) regulations. | true +| Name | Scope | Type | Description | Example | +|---------------------------------|----------|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------| +| `delDomain` ~~or `platform`~~** | required | String | OpenX delivery domain provided by your OpenX representative. | "PUBLISHER-d.openx.net" | +| `unit` | required | String | OpenX ad unit ID provided by your OpenX representative. | "1611023122" | +| `customParams` | optional | Object | User-defined targeting key-value pairs. customParams applies to a specific unit. | `{key1: "v1", key2: ["v2","v3"]}` | +| `customFloor` | optional | Number | Minimum price in USD. customFloor applies to a specific unit. For example, use the following value to set a $1.50 floor: 1.50

**WARNING:**
Misuse of this parameter can impact revenue

Note: OpenX suggests using the [Price Floor Module](https://docs.prebid.org/dev-docs/modules/floors.html) instead of customFloor. The Price Floor Module is prioritized over customFloor if both are present. | 1.50 | +| `doNotTrack` | optional | Boolean | Prevents advertiser from using data for this user.

**WARNING:**
Request-level setting. May impact revenue. | true | +| `coppa` | optional | Boolean | Enables Child's Online Privacy Protection Act (COPPA) regulations. | true | -## Video +** platform is deprecated. Please use delDomain instead. If you have any questions please contact your representative. -| Name | Scope | Type | Description | Example -| ---- | ----- | ---- | ----------- | ------- -| `unit` | required | String | OpenX ad unit ID provided by your OpenX representative. | "1611023122" -| `delDomain` | required | String | OpenX delivery domain provided by your OpenX representative. | "PUBLISHER-d.openx.net" -| `openrtb` | optional | OpenRTB Impression | An OpenRtb Impression with Video subtype properties | `{ imp: [{ video: {mimes: ['video/x-ms-wmv, video/mp4']} }] }` +## Video +| Name | Scope | Type | Description | Example | +|-------------|----------|--------------------|--------------------------------------------------------------|----------------------------------------------------------------| +| `unit` | required | String | OpenX ad unit ID provided by your OpenX representative. | "1611023122" | +| `delDomain` | required | String | OpenX delivery domain provided by your OpenX representative. | "PUBLISHER-d.openx.net" | +| `openrtb` | optional | OpenRTB Impression | An OpenRtb Impression with Video subtype properties | `{ imp: [{ video: {mimes: ['video/x-ms-wmv, video/mp4']} }] }` | # Example ```javascript diff --git a/modules/optidigitalBidAdapter.js b/modules/optidigitalBidAdapter.js new file mode 100755 index 00000000000..4372aa830e6 --- /dev/null +++ b/modules/optidigitalBidAdapter.js @@ -0,0 +1,221 @@ +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER } from '../src/mediaTypes.js'; +import { deepAccess, parseSizesInput, getAdUnitSizes } from '../src/utils.js'; + +const BIDDER_CODE = 'optidigital'; +const GVL_ID = 915; +const ENDPOINT_URL = 'https://pbs.optidigital.com/bidder'; +const USER_SYNC_URL_IFRAME = 'https://scripts.opti-digital.com/js/presync.html?endpoint=optidigital'; +let CUR = 'USD'; + +export const spec = { + code: BIDDER_CODE, + gvlid: GVL_ID, + 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) { + let isValid = false; + if (typeof bid.params !== 'undefined' && bid.params.placementId && bid.params.publisherId) { + isValid = true; + } + + return isValid; + }, + /** + * Make a server request from the list of BidRequests. + * + * @param {validBidRequests[]} - an array of bids + * @return ServerRequest Info describing the request to the server. + */ + buildRequests: function(validBidRequests, bidderRequest) { + if (!validBidRequests || validBidRequests.length === 0 || !bidderRequest || !bidderRequest.bids) { + return []; + } + + const ortb2 = bidderRequest.ortb2 || { + bcat: [], + badv: [] + }; + + const payload = { + referrer: (bidderRequest.refererInfo && bidderRequest.refererInfo.page) ? bidderRequest.refererInfo.page : '', + hb_version: '$prebid.version$', + deviceWidth: document.documentElement.clientWidth, + auctionId: deepAccess(validBidRequests[0], 'auctionId'), + bidderRequestId: deepAccess(validBidRequests[0], 'bidderRequestId'), + publisherId: deepAccess(validBidRequests[0], 'params.publisherId'), + imp: validBidRequests.map(bidRequest => buildImp(bidRequest, ortb2)), + badv: ortb2.badv || deepAccess(validBidRequests[0], 'params.badv') || [], + bcat: ortb2.bcat || deepAccess(validBidRequests[0], 'params.bcat') || [], + bapp: deepAccess(validBidRequests[0], 'params.bapp') || [] + } + + if (validBidRequests[0].params.pageTemplate && validBidRequests[0].params.pageTemplate !== '') { + payload.pageTemplate = validBidRequests[0].params.pageTemplate; + } + + if (validBidRequests[0].schain) { + payload.schain = validBidRequests[0].schain; + } + + const gdpr = deepAccess(bidderRequest, 'gdprConsent'); + if (bidderRequest && gdpr) { + const isConsentString = typeof gdpr.consentString === 'string'; + payload.gdpr = { + consent: isConsentString ? gdpr.consentString : '', + required: true + }; + } + if (bidderRequest && !gdpr) { + payload.gdpr = { + consent: '', + required: false + } + } + + if (window.location.href.indexOf('optidigitalTestMode=true') !== -1) { + payload.testMode = true; + } + + if (bidderRequest && bidderRequest.uspConsent) { + payload.uspConsent = bidderRequest.uspConsent; + } + + const payloadObject = JSON.stringify(payload); + return { + method: 'POST', + url: ENDPOINT_URL, + data: payloadObject + }; + }, + /** + * 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, bidRequest) { + const bidResponses = []; + serverResponse = serverResponse.body; + + if (serverResponse.bids) { + serverResponse.bids.forEach((bid) => { + const bidResponse = { + placementId: bid.placementId, + transactionId: bid.transactionId, + requestId: bid.bidId, + ttl: bid.ttl, + creativeId: bid.creativeId, + currency: bid.cur, + cpm: bid.cpm, + width: bid.w, + height: bid.h, + ad: bid.adm, + netRevenue: true, + meta: { + advertiserDomains: bid.adomain && bid.adomain.length > 0 ? bid.adomain : [] + } + }; + bidResponses.push(bidResponse); + }); + } + return bidResponses; + }, + + /** + * Register the user sync pixels which should be dropped after the auction. + * + * @param {SyncOptions} syncOptions Which user syncs are allowed? + * @param {ServerResponse[]} serverResponses List of server's responses. + * @return {UserSync[]} The user syncs which should be dropped. + */ + getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) { + let syncurl = ''; + + // Attaching GDPR Consent Params in UserSync url + if (gdprConsent) { + syncurl += '&gdpr=' + (gdprConsent.gdprApplies ? 1 : 0); + syncurl += '&gdpr_consent=' + encodeURIComponent(gdprConsent.consentString || ''); + } + if (uspConsent && uspConsent.consentString) { + syncurl += `&ccpa_consent=${uspConsent.consentString}`; + } + + if (syncOptions.iframeEnabled) { + return [{ + type: 'iframe', + url: USER_SYNC_URL_IFRAME + syncurl + }]; + } + }, +}; + +function buildImp(bidRequest, ortb2) { + let imp = {}; + imp = { + sizes: parseSizesInput(deepAccess(bidRequest, 'mediaTypes.banner.sizes')), + bidId: deepAccess(bidRequest, 'bidId'), + adUnitCode: deepAccess(bidRequest, 'adUnitCode'), + transactionId: deepAccess(bidRequest, 'transactionId'), + placementId: deepAccess(bidRequest, 'params.placementId') + }; + + if (bidRequest.params.divId && bidRequest.params.divId !== '') { + if (getAdContainer(bidRequest.params.divId)) { + imp.adContainerWidth = getAdContainer(bidRequest.params.divId).offsetWidth; + imp.adContainerHeight = getAdContainer(bidRequest.params.divId).offsetHeight; + } + } + + let floorSizes = []; + if (deepAccess(bidRequest, 'mediaTypes.banner')) { + floorSizes = getAdUnitSizes(bidRequest); + } + + if (bidRequest.params.currency && bidRequest.params.currency !== '') { + CUR = bidRequest.params.currency; + } + + let bidFloor = _getFloor(bidRequest, floorSizes, CUR); + if (bidFloor) { + imp.bidFloor = bidFloor; + } + + let battr = ortb2.battr || deepAccess(bidRequest, 'params.battr'); + if (battr && Array.isArray(battr) && battr.length) { + imp.battr = battr; + } + + return imp; +} + +function getAdContainer(container) { + if (document.getElementById(container)) { + return document.getElementById(container); + } +} + +function _getFloor (bid, sizes, currency) { + let floor = null; + let size = sizes.length === 1 ? sizes[0] : '*'; + if (typeof bid.getFloor === 'function') { + try { + const floorInfo = bid.getFloor({ + currency: currency, + mediaType: 'banner', + size: size + }); + if (typeof floorInfo === 'object' && floorInfo.currency === CUR && !isNaN(parseFloat(floorInfo.floor))) { + floor = parseFloat(floorInfo.floor); + } + } catch (err) {} + } + return floor !== null ? floor : bid.params.floor; +} + +registerBidder(spec); diff --git a/modules/optidigitalBidAdapter.md b/modules/optidigitalBidAdapter.md new file mode 100755 index 00000000000..466dfb3bef2 --- /dev/null +++ b/modules/optidigitalBidAdapter.md @@ -0,0 +1,46 @@ +# Overview + +**Module Name**: OptiDigital Bidder Adapter +**Module Type**: Bidder Adapter +**Maintainer**: prebid@optidigital.com + +# Description + +Bidder Adapter for Prebid.js. + +## AdUnits configuration example +``` + var adUnits = [{ + code: 'your-slot_1-div', //use exactly the same code as your slot div id. + mediaTypes: { + banner: { + sizes: [[300,600]] + } + }, + bids: [{ + bidder: 'optidigital', + params: { + publisherId: 'test', + placementId: 'Billboard_Top', + divId: 'Billboard_Top_3c5425', // optional parameter + pageTemplate: 'home', // optional parameter + badv: ['example.com'], // optional parameter + bcat: ['IAB1-1'], // optional parameter + bapp: ['com.blocked'], // optional parameter + battr: [1, 2] // optional parameter + } + }] + }]; +``` + +## UserSync example + +``` +pbjs.setConfig({ + userSync: { + iframeEnabled: true, + syncEnabled: true, + syncDelay: 3000 + } +}); +``` diff --git a/modules/orbitsoftBidAdapter.js b/modules/orbitsoftBidAdapter.js new file mode 100644 index 00000000000..d72a8719bd8 --- /dev/null +++ b/modules/orbitsoftBidAdapter.js @@ -0,0 +1,150 @@ +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {config} from '../src/config.js'; + +const BIDDER_CODE = 'orbitsoft'; +let styleParamsMap = { + 'title.family': 'f1', // headerFont + 'title.size': 'fs1', // headerFontSize + 'title.weight': 'w1', // headerWeight + 'title.style': 's1', // headerStyle + 'title.color': 'c3', // headerColor + 'description.family': 'f2', // descriptionFont + 'description.size': 'fs2', // descriptionFontSize + 'description.weight': 'w2', // descriptionWeight + 'description.style': 's2', // descriptionStyle + 'description.color': 'c4', // descriptionColor + 'url.family': 'f3', // urlFont + 'url.size': 'fs3', // urlFontSize + 'url.weight': 'w3', // urlWeight + 'url.style': 's3', // urlStyle + 'url.color': 'c5', // urlColor + 'colors.background': 'c2', // borderColor + 'colors.border': 'c1', // borderColor + 'colors.link': 'c6', // lnkColor +}; +export const spec = { + code: BIDDER_CODE, + aliases: ['oas', '152media'], // short code and customer aliases + isBidRequestValid: function (bid) { + switch (true) { + case !('params' in bid): + utils.logError(bid.bidder + ': No required params'); + return false; + case !(bid.params.placementId): + utils.logError(bid.bidder + ': No required param placementId'); + return false; + case !(bid.params.requestUrl): + utils.logError(bid.bidder + ': No required param requestUrl'); + return false; + } + return true; + }, + buildRequests: function (validBidRequests) { + let bidRequest; + let serverRequests = []; + for (let i = 0; i < validBidRequests.length; i++) { + bidRequest = validBidRequests[i]; + let bidRequestParams = bidRequest.params; + let placementId = utils.getBidIdParameter('placementId', bidRequestParams); + let requestUrl = utils.getBidIdParameter('requestUrl', bidRequestParams); + let referrer = utils.getBidIdParameter('ref', bidRequestParams); + let location = utils.getBidIdParameter('loc', bidRequestParams); + // Append location & referrer + if (location === '') { + location = utils.getWindowLocation(); + } + if (referrer === '' && bidRequest && bidRequest.refererInfo) { + referrer = bidRequest.refererInfo.referer; + } + + // Styles params + let stylesParams = utils.getBidIdParameter('style', bidRequestParams); + let stylesParamsArray = {}; + for (let currentValue in stylesParams) { + if (stylesParams.hasOwnProperty(currentValue)) { + let currentStyle = stylesParams[currentValue]; + for (let field in currentStyle) { + if (currentStyle.hasOwnProperty(field)) { + let styleField = styleParamsMap[currentValue + '.' + field]; + if (typeof styleField !== 'undefined') { + stylesParamsArray[styleField] = currentStyle[field]; + } + } + } + } + } + // Custom params + let customParams = utils.getBidIdParameter('customParams', bidRequestParams); + let customParamsArray = {}; + for (let customField in customParams) { + if (customParams.hasOwnProperty(customField)) { + customParamsArray['c.' + customField] = customParams[customField]; + } + } + + // Sizes params (not supports by server, for future features) + let sizesParams = bidRequest.sizes; + let parsedSizes = utils.parseSizesInput(sizesParams); + let requestData = Object.assign({ + 'scid': placementId, + 'callback_uid': utils.generateUUID(), + 'loc': location, + 'ref': referrer, + 'size': parsedSizes + }, stylesParamsArray, customParamsArray); + + serverRequests.push({ + method: 'POST', + url: requestUrl, + data: requestData, + options: {withCredentials: false}, + bidRequest: bidRequest + }); + } + return serverRequests; + }, + interpretResponse: function (serverResponse, request) { + let bidResponses = []; + if (!serverResponse || serverResponse.error) { + utils.logError(BIDDER_CODE + ': Server response error'); + return bidResponses; + } + + const serverBody = serverResponse.body; + if (!serverBody) { + utils.logError(BIDDER_CODE + ': Empty bid response'); + return bidResponses; + } + + const CPM = serverBody.cpm; + const WIDTH = serverBody.width; + const HEIGHT = serverBody.height; + const CREATIVE = serverBody.content_url; + const CALLBACK_UID = serverBody.callback_uid; + const TIME_TO_LIVE = config.getConfig('_bidderTimeout'); + const REFERER = utils.getWindowTop(); + let bidRequest = request.bidRequest; + if (CPM > 0 && WIDTH > 0 && HEIGHT > 0) { + let bidResponse = { + requestId: bidRequest.bidId, + cpm: CPM, + width: WIDTH, + height: HEIGHT, + creativeId: CALLBACK_UID, + ttl: TIME_TO_LIVE, + referrer: REFERER, + currency: 'USD', + netRevenue: true, + adUrl: CREATIVE, + meta: { + advertiserDomains: serverBody.adomain ? serverBody.adomain : [] + } + }; + bidResponses.push(bidResponse); + } + + return bidResponses; + } +}; +registerBidder(spec); diff --git a/modules/outbrainBidAdapter.js b/modules/outbrainBidAdapter.js index 3db1da0d689..6bcbc6a1cba 100644 --- a/modules/outbrainBidAdapter.js +++ b/modules/outbrainBidAdapter.js @@ -4,11 +4,13 @@ import { registerBidder } from '../src/adapters/bidderFactory.js'; -import { NATIVE, BANNER } from '../src/mediaTypes.js'; -import { deepAccess, deepSetValue, replaceAuctionPrice, _map, isArray } from '../src/utils.js'; +import { NATIVE, BANNER, VIDEO } from '../src/mediaTypes.js'; +import { OUTSTREAM } from '../src/video.js'; +import { deepAccess, deepSetValue, replaceAuctionPrice, _map, isArray, logWarn } from '../src/utils.js'; import { ajax } from '../src/ajax.js'; import { config } from '../src/config.js'; import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; +import { Renderer } from '../src/Renderer.js'; const BIDDER_CODE = 'outbrain'; const GVLID = 164; @@ -22,11 +24,12 @@ const NATIVE_PARAMS = { body: { id: 4, name: 'data', type: 2 }, cta: { id: 1, type: 12, name: 'data' } }; +const OUTSTREAM_RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js'; export const spec = { code: BIDDER_CODE, gvlid: GVLID, - supportedMediaTypes: [ NATIVE, BANNER ], + supportedMediaTypes: [ NATIVE, BANNER, VIDEO ], isBidRequestValid: (bid) => { if (typeof bid.params !== 'object') { return false; @@ -50,7 +53,7 @@ export const spec = { return ( !!config.getConfig('outbrain.bidderUrl') && - !!(bid.nativeParams || bid.sizes) + (!!(bid.nativeParams || bid.sizes) || isValidVideoRequest(bid)) ); }, buildRequests: (validBidRequests, bidderRequest) => { @@ -85,6 +88,8 @@ export const spec = { assets: getNativeAssets(bid) }) } + } else if (isVideoRequest(bid)) { + imp.video = getVideoAsset(bid); } else { imp.banner = { format: transformSizes(bid.sizes) @@ -163,7 +168,12 @@ export const spec = { return bids.map((bid, id) => { const bidResponse = bidResponses[id]; if (bidResponse) { - const type = bid.nativeParams ? NATIVE : BANNER; + let type = BANNER; + if (bid.nativeParams) { + type = NATIVE; + } else if (isVideoRequest(bid)) { + type = VIDEO; + } const bidObject = { requestId: bid.bidId, cpm: bidResponse.price, @@ -176,10 +186,16 @@ export const spec = { }; if (type === NATIVE) { bidObject.native = parseNative(bidResponse); - } else { + } else if (type === BANNER) { bidObject.ad = bidResponse.adm; bidObject.width = bidResponse.w; bidObject.height = bidResponse.h; + } else if (type === VIDEO) { + bidObject.vastXml = bidResponse.adm; + const videoContext = deepAccess(bid, 'mediaTypes.video.context'); + if (videoContext === OUTSTREAM) { + bidObject.renderer = createRenderer(bid); + } } bidObject.meta = {}; if (bidResponse.adomain && bidResponse.adomain.length > 0) { @@ -304,6 +320,27 @@ function getNativeAssets(bid) { }).filter(Boolean); } +function getVideoAsset(bid) { + const sizes = flatten(bid.mediaTypes.video.playerSize); + return { + w: parseInt(sizes[0], 10), + h: parseInt(sizes[1], 10), + protocols: bid.mediaTypes.video.protocols, + playbackmethod: bid.mediaTypes.video.playbackmethod, + mimes: bid.mediaTypes.video.mimes, + skip: bid.mediaTypes.video.skip, + delivery: bid.mediaTypes.video.delivery, + api: bid.mediaTypes.video.api, + minbitrate: bid.mediaTypes.video.minbitrate, + maxbitrate: bid.mediaTypes.video.maxbitrate, + minduration: bid.mediaTypes.video.minduration, + maxduration: bid.mediaTypes.video.maxduration, + startdelay: bid.mediaTypes.video.startdelay, + placement: bid.mediaTypes.video.placement, + linearity: bid.mediaTypes.video.linearity + }; +} + /* Turn bid request sizes into ut-compatible format */ function transformSizes(requestSizes) { if (!isArray(requestSizes)) { @@ -338,3 +375,63 @@ function _getFloor(bid, type) { } return null; } + +function isVideoRequest(bid) { + return bid.mediaType === 'video' || !!deepAccess(bid, 'mediaTypes.video'); +} + +function createRenderer(bid) { + let config = {}; + let playerUrl = OUTSTREAM_RENDERER_URL; + let render = function (bid) { + bid.renderer.push(() => { + window.ANOutstreamVideo.renderAd({ + sizes: bid.sizes, + targetId: bid.adUnitCode, + adResponse: { content: bid.vastXml } + }); + }); + }; + + let externalRenderer = deepAccess(bid, 'mediaTypes.video.renderer'); + if (!externalRenderer) { + externalRenderer = deepAccess(bid, 'renderer'); + } + + if (externalRenderer) { + config = externalRenderer.options; + playerUrl = externalRenderer.url; + render = externalRenderer.render; + } + + const renderer = Renderer.install({ + id: bid.adUnitCode, + url: playerUrl, + config: config, + adUnitCode: bid.adUnitCode, + loaded: false + }); + try { + renderer.setRender(render); + } catch (err) { + logWarn('Prebid Error calling setRender on renderer', err); + } + return renderer; +} + +function isValidVideoRequest(bid) { + const videoAdUnit = deepAccess(bid, 'mediaTypes.video') + if (!videoAdUnit) { + return false; + } + + if (!Array.isArray(videoAdUnit.playerSize)) { + return false; + } + + if (videoAdUnit.context == '') { + return false; + } + + return true; +} diff --git a/modules/permutiveRtdProvider.js b/modules/permutiveRtdProvider.js index a2cd7847564..305e175bf2c 100644 --- a/modules/permutiveRtdProvider.js +++ b/modules/permutiveRtdProvider.js @@ -14,6 +14,7 @@ import {includes} from '../src/polyfill.js'; const MODULE_NAME = 'permutive' export const PERMUTIVE_SUBMODULE_CONFIG_KEY = 'permutive-prebid-rtd' +export const PERMUTIVE_STANDARD_AUD_KEYWORD = 'p_standard_aud' export const storage = getStorageManager({gvlid: null, moduleName: MODULE_NAME}) @@ -118,9 +119,21 @@ export function setBidderRtb (bidderOrtb2, customModuleConfig) { const transformationConfigs = deepAccess(moduleConfig, 'params.transformations') || [] const segmentData = getSegments(maxSegs) - acBidders.forEach(function (bidder) { + const ssps = segmentData?.ssp?.ssps ?? [] + const sspCohorts = segmentData?.ssp?.cohorts ?? [] + + const bidders = new Set([...acBidders, ...ssps]) + bidders.forEach(function (bidder) { const currConfig = { ortb2: bidderOrtb2[bidder] || {} } - const nextConfig = updateOrtbConfig(currConfig, segmentData.ac, transformationConfigs) // ORTB2 uses the `ac` segment IDs + + const isAcBidder = acBidders.indexOf(bidder) > -1 + const isSspBidder = ssps.indexOf(bidder) > -1 + + let cohorts = [] + if (isAcBidder) cohorts = segmentData.ac + if (isSspBidder) cohorts = [...new Set([...cohorts, ...sspCohorts])].slice(0, maxSegs) + + const nextConfig = updateOrtbConfig(currConfig, cohorts, sspCohorts, transformationConfigs) bidderOrtb2[bidder] = nextConfig.ortb2; }) } @@ -131,9 +144,10 @@ export function setBidderRtb (bidderOrtb2, customModuleConfig) { * @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 * @return {Object} Merged ortb2 object */ -function updateOrtbConfig (currConfig, segmentIDs, transformationConfigs) { +function updateOrtbConfig (currConfig, segmentIDs, sspSegmentIDs, transformationConfigs) { const name = 'permutive.com' const permutiveUserData = { @@ -154,6 +168,12 @@ function updateOrtbConfig (currConfig, segmentIDs, transformationConfigs) { deepSetValue(ortbConfig, 'ortb2.user.data', updatedUserData) + // As of writing this, only used for AppNexus/Xandr in place of appnexusAuctionKeywords in config + const currentUserKeywords = deepAccess(ortbConfig, 'ortb2.user.keywords') || '' + const keywords = sspSegmentIDs.map(segment => `${PERMUTIVE_STANDARD_AUD_KEYWORD}=${segment}`).join(',') + const updatedUserKeywords = (currentUserKeywords === '') ? keywords : `${currentUserKeywords},${keywords}` + deepSetValue(ortbConfig, 'ortb2.user.keywords', updatedUserKeywords) + return ortbConfig } @@ -222,10 +242,19 @@ function getCustomBidderFn (moduleConfig, bidder) { * @return {Object} Bidder function */ function getDefaultBidderFn (bidder) { + const isPStandardTargetingEnabled = (data, acEnabled) => { + return (acEnabled && data.ac && data.ac.length) || (data.ssp && data.ssp.cohorts && data.ssp.cohorts.length) + } + const pStandardTargeting = (data, acEnabled) => { + const ac = (acEnabled) ? (data.ac ?? []) : [] + const ssp = data?.ssp?.cohorts ?? [] + return [...new Set([...ac, ...ssp])] + } const bidderMap = { appnexus: function (bid, data, acEnabled) { - if (acEnabled && data.ac && data.ac.length) { - deepSetValue(bid, 'params.keywords.p_standard', data.ac) + if (isPStandardTargetingEnabled(data, acEnabled)) { + const segments = pStandardTargeting(data, acEnabled) + deepSetValue(bid, 'params.keywords.p_standard', segments) } if (data.appnexus && data.appnexus.length) { deepSetValue(bid, 'params.keywords.permutive', data.appnexus) @@ -234,18 +263,20 @@ function getDefaultBidderFn (bidder) { return bid }, rubicon: function (bid, data, acEnabled) { - if (acEnabled && data.ac && data.ac.length) { - deepSetValue(bid, 'params.visitor.p_standard', data.ac) + if (isPStandardTargetingEnabled(data, acEnabled)) { + const segments = pStandardTargeting(data, acEnabled) + deepSetValue(bid, 'params.visitor.p_standard', segments) } if (data.rubicon && data.rubicon.length) { - deepSetValue(bid, 'params.visitor.permutive', data.rubicon) + deepSetValue(bid, 'params.visitor.permutive', data.rubicon.map(String)) } return bid }, ozone: function (bid, data, acEnabled) { - if (acEnabled && data.ac && data.ac.length) { - deepSetValue(bid, 'params.customData.0.targeting.p_standard', data.ac) + if (isPStandardTargetingEnabled(data, acEnabled)) { + const segments = pStandardTargeting(data, acEnabled) + deepSetValue(bid, 'params.customData.0.targeting.p_standard', segments) } return bid @@ -280,19 +311,29 @@ export function isPermutiveOnPage () { * @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') + const legacySegs = readSegments('_psegs', []).map(Number).filter(seg => seg >= 1000000).map(String) + const _ppam = readSegments('_ppam', []) + const _pcrprs = readSegments('_pcrprs', []) const segments = { ac: [..._pcrprs, ..._ppam, ...legacySegs], - rubicon: readSegments('_prubicons'), - appnexus: readSegments('_papns'), - gam: readSegments('_pdfps'), + rubicon: readSegments('_prubicons', []), + appnexus: readSegments('_papns', []), + gam: readSegments('_pdfps', []), + ssp: readSegments('_pssps', { + cohorts: [], + ssps: [] + }), } for (const bidder in segments) { - segments[bidder] = segments[bidder].slice(0, maxSegs) + if (bidder === 'ssp') { + if (segments[bidder].cohorts && Array.isArray(segments[bidder].cohorts)) { + segments[bidder].cohorts = segments[bidder].cohorts.slice(0, maxSegs) + } + } else { + segments[bidder] = segments[bidder].slice(0, maxSegs) + } } return segments @@ -300,15 +341,17 @@ export function getSegments (maxSegs) { /** * Gets an array of segment IDs from LocalStorage - * or returns an empty array + * or return the default value provided. + * @template A * @param {string} key - * @return {string[]|number[]} + * @param {A} defaultValue + * @return {A} */ -function readSegments (key) { +function readSegments (key, defaultValue) { try { - return JSON.parse(storage.getDataFromLocalStorage(key) || '[]') + return JSON.parse(storage.getDataFromLocalStorage(key)) || defaultValue } catch (e) { - return [] + return defaultValue } } diff --git a/modules/permutiveRtdProvider.md b/modules/permutiveRtdProvider.md index f99389f82cc..7d8f073357c 100644 --- a/modules/permutiveRtdProvider.md +++ b/modules/permutiveRtdProvider.md @@ -45,17 +45,52 @@ as well as enabling settings for specific use cases mentioned above (e.g. acbidd | params.acBidders | String[] | An array of bidders which should receive AC cohorts. | `[]` | | params.maxSegs | Integer | Maximum number of cohorts to be included in either the `permutive` or `p_standard` key-value. | `500` | | params.transformations | Object[] | An array of configurations for ORTB2 user data transformations | | +| params.overwrites | Object | An object specifying functions for custom targeting logic for bidders. | - | ##### The `transformations` parameter This array contains configurations for transformations we'll apply to the Permutive object in the ORTB2 `user.data` array. The results of these transformations will be appended to the `user.data` array that's attached to ORTB2 bid requests. -##### Supported transformations +###### Supported transformations | Name | ID | Config structure | Description | |----------------|-----|---------------------------------------------------|--------------------------------------------------------------------------------------| | IAB taxonomies | iab | { segtax: number, iabIds: Object} | Transform segment IDs from Permutive to IAB (note: alpha version, subject to change) | +##### The `overwrites` parameter + +The keys for this object should match a bidder (e.g. `rubicon`), which then can define a function to overwrite the customer targeting logic. + +```javascript +{ + params: { + overwrites: { + rubicon: function customTargeting(bid, data, acEnabled, utils, defaultFn) { + if (defaultFn) { + bid = defaultFn(bid, data, acEnabled) + } + if (data.gam && data.gam.length) { + utils.deepSetValue(bid, 'params.visitor.permutive', data.gam) + } + } + } + } +} +``` + +###### `customTargeting` function parameters + +| Name | Description | +|--------------|--------------------------------------------------------------------------------| +| `bid` | The bid request object. | +| `data` | Permutive's targeting data read from localStorage. | +| `acEnabled` | Boolean stating whether Audience Connect is enabled via `acBidders`. | +| `utils` | An object of helpful utilities. `(deepSetValue, deepAccess, isFn, mergeDeep)`. | +| `defaultFn` | The default targeting function. | + + + + #### Context Permutive is not listed as a TCF vendor as all data collection is on behalf of the publisher and based on consent the publisher has received from the user. diff --git a/modules/prebidServerBidAdapter/index.js b/modules/prebidServerBidAdapter/index.js index 072c280aecf..c5f082f5355 100644 --- a/modules/prebidServerBidAdapter/index.js +++ b/modules/prebidServerBidAdapter/index.js @@ -216,16 +216,29 @@ export function resetSyncedStatus() { /** * @param {Array} bidderCodes list of bidders to request user syncs for. */ -function queueSync(bidderCodes, gdprConsent, uspConsent, s2sConfig) { +function queueSync(bidderCodes, gdprConsent, uspConsent, gppConsent, s2sConfig) { if (_s2sConfigs.length === _syncCount) { return; } _syncCount++; + let filterSettings = {}; + const userSyncFilterSettings = getConfig('userSync.filterSettings'); + + if (userSyncFilterSettings) { + const { all, iframe, image } = userSyncFilterSettings; + const ifrm = iframe || all; + const img = image || all; + + if (ifrm) filterSettings = Object.assign({ iframe: ifrm }, filterSettings); + if (img) filterSettings = Object.assign({ image: img }, filterSettings); + } + const payload = { uuid: generateUUID(), bidders: bidderCodes, - account: s2sConfig.accountId + account: s2sConfig.accountId, + filterSettings }; let userSyncLimit = s2sConfig.userSyncLimit; @@ -246,6 +259,15 @@ function queueSync(bidderCodes, gdprConsent, uspConsent, s2sConfig) { payload.us_privacy = uspConsent; } + if (gppConsent) { + // proposing the following formatting, can adjust if needed... + // update - leaving this param as an array, since it's part of a POST payload where the [] characters shouldn't matter too much + payload.gpp_sid = gppConsent.applicableSections + // should we add check if applicableSections was not equal to -1 (where user was out of scope)? + // this would be similar to what was done above for TCF + payload.gpp = gppConsent.gppString; + } + if (typeof s2sConfig.coopSync === 'boolean') { payload.coopSync = s2sConfig.coopSync; } @@ -330,7 +352,7 @@ function doBidderSync(type, url, bidder, done, timeout) { * * @param {Array} bidders a list of bidder names */ -function doClientSideSyncs(bidders, gdprConsent, uspConsent) { +function doClientSideSyncs(bidders, gdprConsent, uspConsent, gppConsent) { bidders.forEach(bidder => { let clientAdapter = adapterManager.getBidAdapter(bidder); if (clientAdapter && clientAdapter.registerSyncs) { @@ -341,7 +363,8 @@ function doClientSideSyncs(bidders, gdprConsent, uspConsent) { clientAdapter, [], gdprConsent, - uspConsent + uspConsent, + gppConsent ) ); } @@ -411,12 +434,13 @@ function getMatchingConsentUrl(urlProp, gdprConsent) { } function getConsentData(bidRequests) { - let gdprConsent, uspConsent; + let gdprConsent, uspConsent, gppConsent; if (Array.isArray(bidRequests) && bidRequests.length > 0) { gdprConsent = bidRequests[0].gdprConsent; uspConsent = bidRequests[0].uspConsent; + gppConsent = bidRequests[0].gppConsent; } - return { gdprConsent, uspConsent }; + return { gdprConsent, uspConsent, gppConsent }; } /** @@ -433,7 +457,7 @@ export function PrebidServer() { done = adapterMetrics.startTiming('total').stopBefore(done); bidRequests.forEach(req => useMetrics(req.metrics).join(adapterMetrics, {continuePropagation: false})); - let { gdprConsent, uspConsent } = getConsentData(bidRequests); + let { gdprConsent, uspConsent, gppConsent } = getConsentData(bidRequests); if (Array.isArray(_s2sConfigs)) { if (s2sBidRequest.s2sConfig && s2sBidRequest.s2sConfig.syncEndpoint && getMatchingConsentUrl(s2sBidRequest.s2sConfig.syncEndpoint, gdprConsent)) { @@ -441,16 +465,19 @@ export function PrebidServer() { .map(bidder => adapterManager.aliasRegistry[bidder] || bidder) .filter((bidder, index, array) => (array.indexOf(bidder) === index)); - queueSync(syncBidders, gdprConsent, uspConsent, s2sBidRequest.s2sConfig); + queueSync(syncBidders, gdprConsent, uspConsent, gppConsent, s2sBidRequest.s2sConfig); } processPBSRequest(s2sBidRequest, bidRequests, ajax, { - onResponse: function (isValid, requestedBidders) { + onResponse: function (isValid, requestedBidders, response) { if (isValid) { bidRequests.forEach(bidderRequest => events.emit(CONSTANTS.EVENTS.BIDDER_DONE, bidderRequest)); } + if (shouldEmitNonbids(s2sBidRequest.s2sConfig, response)) { + emitNonBids(response.ext.seatnonbid, bidRequests[0].auctionId); + } done(); - doClientSideSyncs(requestedBidders, gdprConsent, uspConsent); + doClientSideSyncs(requestedBidders, gdprConsent, uspConsent, gppConsent); }, onError: done, onBid: function ({adUnit, bid}) { @@ -527,7 +554,7 @@ export const processPBSRequest = hook('sync', function (s2sBidRequest, bidReques logError('error parsing response: ', result ? result.status : 'not valid JSON'); onResponse(false, requestedBidders); } else { - onResponse(true, requestedBidders); + onResponse(true, requestedBidders, result); } }, error: function () { @@ -543,6 +570,17 @@ export const processPBSRequest = hook('sync', function (s2sBidRequest, bidReques } }, 'processPBSRequest'); +function shouldEmitNonbids(s2sConfig, response) { + return s2sConfig?.extPrebid?.returnallbidstatus && response?.ext?.seatnonbid; +} + +function emitNonBids(seatnonbid, auctionId) { + events.emit(CONSTANTS.EVENTS.SEAT_NON_BID, { + seatnonbid, + auctionId + }); +} + /** * Global setter that sets eids permissions for bidders * This setter is to be used by userId module when included diff --git a/modules/prebidServerBidAdapter/ortbConverter.js b/modules/prebidServerBidAdapter/ortbConverter.js index 0aee261c25d..be034b3cfbe 100644 --- a/modules/prebidServerBidAdapter/ortbConverter.js +++ b/modules/prebidServerBidAdapter/ortbConverter.js @@ -32,6 +32,12 @@ const PBS_CONVERTER = ortbConverter({ imp(buildImp, proxyBidRequest, context) { Object.assign(context, proxyBidRequest.pbsData); const imp = buildImp(proxyBidRequest, context); + (proxyBidRequest.bids || []).forEach(bid => { + if (bid.ortb2Imp && Object.keys(bid.ortb2Imp).length > 0) { + // set bidder-level imp attributes; see https://github.com/prebid/prebid-server/issues/2335 + deepSetValue(imp, `ext.prebid.imp.${bid.bidder}`, bid.ortb2Imp); + } + }); if (Object.values(SUPPORTED_MEDIA_TYPES).some(mtype => imp[mtype])) { imp.secure = context.s2sBidRequest.s2sConfig.secure; return imp; @@ -47,7 +53,7 @@ const PBS_CONVERTER = ortbConverter({ request.tmax = s2sBidRequest.s2sConfig.timeout; deepSetValue(request, 'source.tid', proxyBidderRequest.auctionId); - [request.app, request.site].forEach(section => { + [request.app, request.dooh, request.site].forEach(section => { if (section && !section.publisher?.id) { deepSetValue(section, 'publisher.id', s2sBidRequest.s2sConfig.accountId); } @@ -246,6 +252,7 @@ export function buildPBSRequest(s2sBidRequest, bidderRequests, adUnits, requeste impIds.add(impId) proxyBidRequests.push({ ...adUnit, + adUnitCode: adUnit.code, ...getDefinedParams(actualBidRequests.values().next().value || {}, ['userId', 'userIdAsEids', 'schain']), pbsData: {impId, actualBidRequests, adUnit} }); diff --git a/modules/prebidmanagerAnalyticsAdapter.js b/modules/prebidmanagerAnalyticsAdapter.js index 1180a74db30..908be5400e4 100644 --- a/modules/prebidmanagerAnalyticsAdapter.js +++ b/modules/prebidmanagerAnalyticsAdapter.js @@ -9,9 +9,9 @@ import CONSTANTS from '../src/constants.json'; * prebidmanagerAnalyticsAdapter.js - analytics adapter for prebidmanager */ export const storage = getStorageManager({gvlid: undefined, moduleName: 'prebidmanager'}); -const DEFAULT_EVENT_URL = 'https://endpoint.prebidmanager.com/endpoint'; +const DEFAULT_EVENT_URL = 'https://endpt.prebidmanager.com/endpoint'; const analyticsType = 'endpoint'; -const analyticsName = 'Prebid Manager Analytics: '; +const analyticsName = 'Prebid Manager Analytics'; let ajax = ajaxBuilder(0); @@ -28,8 +28,8 @@ var w = window; var d = document; var e = d.documentElement; var g = d.getElementsByTagName('body')[0]; -var x = w.innerWidth || e.clientWidth || g.clientWidth; -var y = w.innerHeight || e.clientHeight || g.clientHeight; +var x = (w && w.innerWidth) || (e && e.clientWidth) || (g && g.clientWidth); +var y = (w && w.innerHeight) || (e && e.clientHeight) || (g && g.clientHeight); var _pageView = { eventType: 'pageView', @@ -56,13 +56,20 @@ prebidmanagerAnalytics.originEnableAnalytics = prebidmanagerAnalytics.enableAnal prebidmanagerAnalytics.enableAnalytics = function (config) { initOptions = config.options || {}; initOptions.url = initOptions.url || DEFAULT_EVENT_URL; - pmAnalyticsEnabled = true; + initOptions.sampling = initOptions.sampling || 1; + + if (Math.floor(Math.random() * initOptions.sampling) === 0) { + pmAnalyticsEnabled = true; + flushInterval = setInterval(flush, 1000); + } else { + logInfo(`${analyticsName} isn't enabled because of sampling`); + } + prebidmanagerAnalytics.originEnableAnalytics(config); - flushInterval = setInterval(flush, 1000); }; prebidmanagerAnalytics.originDisableAnalytics = prebidmanagerAnalytics.disableAnalytics; -prebidmanagerAnalytics.disableAnalytics = function() { +prebidmanagerAnalytics.disableAnalytics = function () { if (!pmAnalyticsEnabled) { return; } @@ -95,7 +102,7 @@ function collectUtmTagData() { }); } } catch (e) { - logError(`${analyticsName}Error`, e); + logError(`${analyticsName} Error`, e); pmUtmTags['error_utm'] = 1; } return pmUtmTags; @@ -126,6 +133,16 @@ function flush() { pageInfo: collectPageInfo(), }; + if ('version' in initOptions) { + data.version = initOptions.version; + } + if ('tcf_compliant' in initOptions) { + data.tcf_compliant = initOptions.tcf_compliant; + } + if ('sampling' in initOptions) { + data.sampling = initOptions.sampling; + } + ajax( initOptions.url, () => logInfo(`${analyticsName} sent events batch`), @@ -142,65 +159,156 @@ function flush() { } } +function trimAdUnit(adUnit) { + if (!adUnit) return adUnit; + const res = {}; + res.code = adUnit.code; + res.sizes = adUnit.sizes; + return res; +} + +function trimBid(bid) { + if (!bid) return bid; + const res = {}; + res.auctionId = bid.auctionId; + res.bidder = bid.bidder; + res.bidderRequestId = bid.bidderRequestId; + res.bidId = bid.bidId; + res.crumbs = bid.crumbs; + res.cpm = bid.cpm; + res.currency = bid.currency; + res.mediaTypes = bid.mediaTypes; + res.sizes = bid.sizes; + res.transactionId = bid.transactionId; + res.adUnitCode = bid.adUnitCode; + res.bidRequestsCount = bid.bidRequestsCount; + res.serverResponseTimeMs = bid.serverResponseTimeMs; + return res; +} + +function trimBidderRequest(bidderRequest) { + if (!bidderRequest) return bidderRequest; + const res = {}; + res.auctionId = bidderRequest.auctionId; + res.auctionStart = bidderRequest.auctionStart; + res.bidderRequestId = bidderRequest.bidderRequestId; + res.bidderCode = bidderRequest.bidderCode; + res.bids = bidderRequest.bids && bidderRequest.bids.map(trimBid); + return res; +} + function handleEvent(eventType, eventArgs) { - eventArgs = eventArgs ? JSON.parse(JSON.stringify(eventArgs)) : {}; - var pmEvent = {}; + try { + eventArgs = eventArgs ? JSON.parse(JSON.stringify(eventArgs)) : {}; + } catch (e) { + // keep eventArgs as is + } + + const pmEvent = {}; switch (eventType) { case CONSTANTS.EVENTS.AUCTION_INIT: { - pmEvent = eventArgs; + pmEvent.auctionId = eventArgs.auctionId; + pmEvent.timeout = eventArgs.timeout; + pmEvent.eventType = eventArgs.eventType; + pmEvent.adUnits = eventArgs.adUnits && eventArgs.adUnits.map(trimAdUnit) + pmEvent.bidderRequests = eventArgs.bidderRequests && eventArgs.bidderRequests.map(trimBidderRequest) _startAuction = pmEvent.timestamp; _bidRequestTimeout = pmEvent.timeout; break; } case CONSTANTS.EVENTS.AUCTION_END: { - pmEvent = eventArgs; + pmEvent.auctionId = eventArgs.auctionId; + pmEvent.end = eventArgs.end; + pmEvent.start = eventArgs.start; + pmEvent.adUnitCodes = eventArgs.adUnitCodes; + pmEvent.bidsReceived = eventArgs.bidsReceived && eventArgs.bidsReceived.map(trimBid); pmEvent.start = _startAuction; pmEvent.end = Date.now(); break; } case CONSTANTS.EVENTS.BID_ADJUSTMENT: { - pmEvent.bidders = eventArgs; break; } case CONSTANTS.EVENTS.BID_TIMEOUT: { - pmEvent.bidders = eventArgs; + pmEvent.bidders = eventArgs && eventArgs.map ? eventArgs.map(trimBid) : eventArgs; pmEvent.duration = _bidRequestTimeout; break; } case CONSTANTS.EVENTS.BID_REQUESTED: { - pmEvent = eventArgs; + pmEvent.auctionId = eventArgs.auctionId; + pmEvent.bidderCode = eventArgs.bidderCode; + pmEvent.doneCbCallCount = eventArgs.doneCbCallCount; + pmEvent.start = eventArgs.start; + pmEvent.bidderRequestId = eventArgs.bidderRequestId; + pmEvent.bids = eventArgs.bids && eventArgs.bids.map(trimBid); + pmEvent.auctionStart = eventArgs.auctionStart; + pmEvent.timeout = eventArgs.timeout; break; } case CONSTANTS.EVENTS.BID_RESPONSE: { - pmEvent = eventArgs; - delete pmEvent.ad; + pmEvent.bidderCode = eventArgs.bidderCode; + pmEvent.width = eventArgs.width; + pmEvent.height = eventArgs.height; + pmEvent.adId = eventArgs.adId; + pmEvent.mediaType = eventArgs.mediaType; + pmEvent.cpm = eventArgs.cpm; + pmEvent.currency = eventArgs.currency; + pmEvent.requestId = eventArgs.requestId; + pmEvent.adUnitCode = eventArgs.adUnitCode; + pmEvent.auctionId = eventArgs.auctionId; + pmEvent.timeToRespond = eventArgs.timeToRespond; + pmEvent.responseTimestamp = eventArgs.responseTimestamp; + pmEvent.requestTimestamp = eventArgs.requestTimestamp; + pmEvent.netRevenue = eventArgs.netRevenue; + pmEvent.size = eventArgs.size; + pmEvent.adserverTargeting = eventArgs.adserverTargeting; break; } case CONSTANTS.EVENTS.BID_WON: { - pmEvent = eventArgs; - delete pmEvent.ad; - delete pmEvent.adUrl; + pmEvent.auctionId = eventArgs.auctionId; + pmEvent.adId = eventArgs.adId; + pmEvent.adserverTargeting = eventArgs.adserverTargeting; + pmEvent.adUnitCode = eventArgs.adUnitCode; + pmEvent.bidderCode = eventArgs.bidderCode; + pmEvent.height = eventArgs.height; + pmEvent.mediaType = eventArgs.mediaType; + pmEvent.netRevenue = eventArgs.netRevenue; + pmEvent.cpm = eventArgs.cpm; + pmEvent.requestTimestamp = eventArgs.requestTimestamp; + pmEvent.responseTimestamp = eventArgs.responseTimestamp; + pmEvent.size = eventArgs.size; + pmEvent.width = eventArgs.width; + pmEvent.currency = eventArgs.currency; + pmEvent.bidder = eventArgs.bidder; break; } case CONSTANTS.EVENTS.BIDDER_DONE: { - pmEvent = eventArgs; + pmEvent.auctionId = eventArgs.auctionId; + pmEvent.auctionStart = eventArgs.auctionStart; + pmEvent.bidderCode = eventArgs.bidderCode; + pmEvent.bidderRequestId = eventArgs.bidderRequestId; + pmEvent.bids = eventArgs.bids && eventArgs.bids.map(trimBid); + pmEvent.doneCbCallCount = eventArgs.doneCbCallCount; + pmEvent.start = eventArgs.start; + pmEvent.timeout = eventArgs.timeout; + pmEvent.tid = eventArgs.tid; + pmEvent.src = eventArgs.src; break; } case CONSTANTS.EVENTS.SET_TARGETING: { - pmEvent.targetings = eventArgs; break; } case CONSTANTS.EVENTS.REQUEST_BIDS: { - pmEvent = eventArgs; break; } case CONSTANTS.EVENTS.ADD_AD_UNITS: { - pmEvent = eventArgs; break; } case CONSTANTS.EVENTS.AD_RENDER_FAILED: { - pmEvent = eventArgs; + pmEvent.bid = eventArgs.bid; + pmEvent.message = eventArgs.message; + pmEvent.reason = eventArgs.reason; break; } default: @@ -215,7 +323,7 @@ function handleEvent(eventType, eventArgs) { function sendEvent(event) { _eventQueue.push(event); - logInfo(`${analyticsName}Event ${event.eventType}:`, event); + logInfo(`${analyticsName} Event ${event.eventType}:`, event); if (event.eventType === CONSTANTS.EVENTS.AUCTION_END) { flush(); diff --git a/modules/priceFloors.js b/modules/priceFloors.js index d7ab811d673..92aecb0ca50 100644 --- a/modules/priceFloors.js +++ b/modules/priceFloors.js @@ -28,6 +28,7 @@ import {auctionManager} from '../src/auctionManager.js'; import {IMP, PBS, registerOrtbProcessor, REQUEST} from '../src/pbjsORTB.js'; import {timedAuctionHook, timedBidResponseHook} from '../src/utils/perfMetrics.js'; import {beConvertCurrency} from '../src/utils/currency.js'; +import {adjustCpm} from '../src/utils/cpm.js'; /** * @summary This Module is intended to provide users with the ability to dynamically set and enforce price floors on a per auction basis. @@ -82,7 +83,7 @@ const getHostname = (() => { let domain; return function() { if (domain == null) { - domain = parseUrl(getRefererInfo().topmostLocation, {noDecodeWholeUrl: true}).hostname; + domain = parseUrl(getRefererInfo().topmostLocation, {noDecodeWholeURL: true}).hostname; } return domain; } @@ -179,12 +180,8 @@ function generatePossibleEnumerations(arrayOfFields, delimiter) { /** * @summary If a the input bidder has a registered cpmadjustment it returns the input CPM after being adjusted */ -export function getBiddersCpmAdjustment(bidderName, inputCpm, bid = {}) { - const adjustmentFunction = bidderSettings.get(bidderName, 'bidCpmAdjustment'); - if (adjustmentFunction) { - return parseFloat(adjustmentFunction(inputCpm, {...bid, cpm: inputCpm})); - } - return parseFloat(inputCpm); +export function getBiddersCpmAdjustment(inputCpm, bid, bidRequest) { + return parseFloat(adjustCpm(inputCpm, {...bid, cpm: inputCpm}, bidRequest)); } /** @@ -249,8 +246,14 @@ export function getFloor(requestParams = {currency: 'USD', mediaType: '*', size: // if cpmAdjustment flag is true and we have a valid floor then run the adjustment on it if (floorData.enforcement.bidAdjustment && floorInfo.matchingFloor) { - let cpmAdjustment = getBiddersCpmAdjustment(bidRequest.bidder, floorInfo.matchingFloor); - floorInfo.matchingFloor = cpmAdjustment ? calculateAdjustedFloor(floorInfo.matchingFloor, cpmAdjustment) : floorInfo.matchingFloor; + // pub provided inverse function takes precedence, otherwise do old adjustment stuff + const inverseFunction = bidderSettings.get(bidRequest.bidder, 'inverseBidAdjustment'); + if (inverseFunction) { + floorInfo.matchingFloor = inverseFunction(floorInfo.matchingFloor, bidRequest); + } else { + let cpmAdjustment = getBiddersCpmAdjustment(floorInfo.matchingFloor, null, bidRequest); + floorInfo.matchingFloor = cpmAdjustment ? calculateAdjustedFloor(floorInfo.matchingFloor, cpmAdjustment) : floorInfo.matchingFloor; + } } if (floorInfo.matchingFloor) { @@ -307,6 +310,8 @@ export function getFloorDataFromAdUnits(adUnits) { // copy over the new rules into our values object Object.assign(accum.values, newRules); } + } else if (adUnit.floors != null) { + logWarn(`adUnit '${adUnit.code}' provides an invalid \`floor\` definition, it will be ignored for floor calculations`, adUnit); } return accum; }, {}); @@ -731,7 +736,7 @@ export const addBidResponseHook = timedBidResponseHook('priceFloors', function a } // ok we got the bid response cpm in our desired currency. Now we need to run the bidders CPMAdjustment function if it exists - adjustedCpm = getBiddersCpmAdjustment(bid.bidderCode, adjustedCpm, bid); + adjustedCpm = getBiddersCpmAdjustment(adjustedCpm, bid, matchingBidRequest); // add necessary data information for analytics adapters / floor providers would possibly need addFloorDataToBid(floorData, floorInfo, bid, adjustedCpm); diff --git a/modules/proxistoreBidAdapter.js b/modules/proxistoreBidAdapter.js index 04d363be7fb..1f113f9c432 100644 --- a/modules/proxistoreBidAdapter.js +++ b/modules/proxistoreBidAdapter.js @@ -3,9 +3,9 @@ import { registerBidder } from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'proxistore'; const PROXISTORE_VENDOR_ID = 418; -const COOKIE_BASE_URL = 'https://abs.proxistore.com/v3/rtb/prebid/multi'; +const COOKIE_BASE_URL = 'https://api.proxistore.com/v3/rtb/prebid/multi'; const COOKIE_LESS_URL = - 'https://abs.cookieless-proxistore.com/v3/rtb/prebid/multi'; + 'https://api.cookieless-proxistore.com/v3/rtb/prebid/multi'; function _createServerRequest(bidRequests, bidderRequest) { var sizeIds = []; diff --git a/modules/pubCommonId.js b/modules/pubCommonId.js index 5cadd522af2..1fde8f8db5b 100644 --- a/modules/pubCommonId.js +++ b/modules/pubCommonId.js @@ -9,8 +9,9 @@ import * as events from '../src/events.js'; import CONSTANTS from '../src/constants.json'; import { getStorageManager } from '../src/storageManager.js'; import {timedAuctionHook} from '../src/utils/perfMetrics.js'; +import {VENDORLESS_GVLID} from '../src/consentHandler.js'; -const storage = getStorageManager({moduleName: 'pubCommonId'}); +const storage = getStorageManager({moduleName: 'pubCommonId', gvlid: VENDORLESS_GVLID}); const ID_NAME = '_pubcid'; const OPTOUT_NAME = '_pubcid_optout'; diff --git a/modules/pubProvidedIdSystem.js b/modules/pubProvidedIdSystem.js index 669d223c57f..baffd997443 100644 --- a/modules/pubProvidedIdSystem.js +++ b/modules/pubProvidedIdSystem.js @@ -7,6 +7,7 @@ import {submodule} from '../src/hook.js'; import { logInfo, isArray } from '../src/utils.js'; +import {VENDORLESS_GVLID} from '../src/consentHandler.js'; const MODULE_NAME = 'pubProvidedId'; @@ -18,6 +19,7 @@ export const pubProvidedIdSubmodule = { * @type {string} */ name: MODULE_NAME, + gvlid: VENDORLESS_GVLID, /** * decode the stored id value for passing to bid request diff --git a/modules/pubmaticAnalyticsAdapter.js b/modules/pubmaticAnalyticsAdapter.js index c8dc7cef15d..a4a13c56a68 100755 --- a/modules/pubmaticAnalyticsAdapter.js +++ b/modules/pubmaticAnalyticsAdapter.js @@ -30,6 +30,11 @@ const DEFAULT_PUBLISHER_ID = 0; const DEFAULT_PROFILE_ID = 0; const DEFAULT_PROFILE_VERSION_ID = 0; const enc = window.encodeURIComponent; +const MEDIATYPE = { + BANNER: 0, + VIDEO: 1, + NATIVE: 2 +} /// /////////// VARIABLES ////////////// let publisherId = DEFAULT_PUBLISHER_ID; // int: mandatory @@ -89,6 +94,7 @@ function copyRequiredBidDetails(bid) { 'status', () => NO_BID, // default a bid to NO_BID until response is recieved or bid is timed out 'finalSource as source', 'params', + 'floorData', 'adUnit', () => pick(bid, [ 'adUnitCode', 'transactionId', @@ -153,6 +159,7 @@ function parseBidResponse(bid) { 'bidId', 'mediaType', 'params', + 'floorData', 'mi', 'regexPattern', () => bid.regexPattern || undefined, 'partnerImpId', // partner impression ID @@ -217,6 +224,38 @@ function getAdDomain(bidResponse) { } } +function isObject(object) { + return typeof object === 'object' && object !== null; +}; + +function isEmptyObject(object) { + return isObject(object) && Object.keys(object).length === 0; +}; + +/** + * Prepare meta object to pass in logger call + * @param {*} meta + */ +export function getMetadata(meta) { + if (!meta || isEmptyObject(meta)) return; + const metaObj = {}; + if (meta.networkId) metaObj.nwid = meta.networkId; + if (meta.advertiserId) metaObj.adid = meta.advertiserId; + if (meta.networkName) metaObj.nwnm = meta.networkName; + if (meta.primaryCatId) metaObj.pcid = meta.primaryCatId; + if (meta.advertiserName) metaObj.adnm = meta.advertiserName; + if (meta.agencyId) metaObj.agid = meta.agencyId; + if (meta.agencyName) metaObj.agnm = meta.agencyName; + if (meta.brandId) metaObj.brid = meta.brandId; + if (meta.brandName) metaObj.brnm = meta.brandName; + if (meta.dchain) metaObj.dc = meta.dchain; + if (meta.demandSource) metaObj.ds = meta.demandSource; + if (meta.secondaryCatIds) metaObj.scids = meta.secondaryCatIds; + + if (isEmptyObject(metaObj)) return; + return metaObj; +} + function gatherPartnerBidsForAdUnitForLogger(adUnit, adUnitId, highestBid) { highestBid = (highestBid && highestBid.length > 0) ? highestBid[0] : null; return Object.keys(adUnit.bids).reduce(function(partnerBids, bidId) { @@ -243,17 +282,29 @@ function gatherPartnerBidsForAdUnitForLogger(adUnit, adUnitId, highestBid) { 'af': bid.bidResponse ? (bid.bidResponse.mediaType || undefined) : undefined, 'ocpm': bid.bidResponse ? (bid.bidResponse.originalCpm || 0) : 0, 'ocry': bid.bidResponse ? (bid.bidResponse.originalCurrency || CURRENCY_USD) : CURRENCY_USD, - 'piid': bid.bidResponse ? (bid.bidResponse.partnerImpId || EMPTY_STRING) : EMPTY_STRING + 'piid': bid.bidResponse ? (bid.bidResponse.partnerImpId || EMPTY_STRING) : EMPTY_STRING, + 'frv': (s2sBidders.indexOf(bid.bidder) > -1) ? undefined : (bid.bidResponse ? (bid.bidResponse.floorData ? bid.bidResponse.floorData.floorRuleValue : undefined) : undefined), + 'md': bid.bidResponse ? getMetadata(bid.bidResponse.meta) : undefined }); }); return partnerBids; }, []) } +function getAdUnitAdFormats(adUnit) { + var af = adUnit ? Object.keys(adUnit.mediaTypes || {}).map(format => MEDIATYPE[format.toUpperCase()]) : []; + return af; +} + +function getAdUnit(adUnits, adUnitId) { + return adUnits.filter(adUnit => (adUnit.divID && adUnit.divID == adUnitId) || (adUnit.code == adUnitId))[0]; +} + function executeBidsLoggerCall(e, highestCpmBids) { let auctionId = e.auctionId; let referrer = config.getConfig('pageUrl') || cache.auctions[auctionId].referer || ''; let auctionCache = cache.auctions[auctionId]; + let floorData = auctionCache.floorData; let outputObj = { s: [] }; let pixelURL = END_POINT_BID_LOGGER; @@ -283,12 +334,21 @@ function executeBidsLoggerCall(e, highestCpmBids) { return 0; })(); + if (floorData) { + outputObj['fmv'] = floorData.floorRequestData ? floorData.floorRequestData.modelVersion || undefined : undefined; + outputObj['ft'] = floorData.floorResponseData ? (floorData.floorResponseData.enforcements.enforceJS == false ? 0 : 1) : undefined; + } + outputObj.s = Object.keys(auctionCache.adUnitCodes).reduce(function(slotsArray, adUnitId) { let adUnit = auctionCache.adUnitCodes[adUnitId]; + let origAdUnit = getAdUnit(auctionCache.origAdUnits, adUnitId) || {}; let slotObject = { 'sn': adUnitId, + 'au': origAdUnit.adUnitId || adUnitId, + 'mt': getAdUnitAdFormats(origAdUnit), 'sz': adUnit.dimensions.map(e => e[0] + 'x' + e[1]), - 'ps': gatherPartnerBidsForAdUnitForLogger(adUnit, adUnitId, highestCpmBids.filter(bid => bid.adUnitCode === adUnitId)) + 'ps': gatherPartnerBidsForAdUnitForLogger(adUnit, adUnitId, highestCpmBids.filter(bid => bid.adUnitCode === adUnitId)), + 'fskp': floorData ? (floorData.floorRequestData ? (floorData.floorRequestData.skipped == false ? 0 : 1) : undefined) : undefined, }; slotsArray.push(slotObject); return slotsArray; @@ -318,6 +378,7 @@ function executeBidWonLoggerCall(auctionId, adUnitId) { } const adapterName = getAdapterNameForAlias(winningBid.adapterCode || winningBid.bidder); + let origAdUnit = getAdUnit(cache.auctions[auctionId].origAdUnits, adUnitId) || {}; let pixelURL = END_POINT_WIN_BID_LOGGER; pixelURL += 'pubid=' + publisherId; pixelURL += '&purl=' + enc(config.getConfig('pageUrl') || cache.auctions[auctionId].referer || ''); @@ -327,6 +388,7 @@ function executeBidWonLoggerCall(auctionId, adUnitId) { pixelURL += '&pid=' + enc(profileId); pixelURL += '&pdvid=' + enc(profileVersionId); pixelURL += '&slot=' + enc(adUnitId); + pixelURL += '&au=' + enc(origAdUnit.adUnitId || adUnitId); pixelURL += '&pn=' + enc(adapterName); pixelURL += '&bc=' + enc(winningBid.bidderCode || winningBid.bidder); pixelURL += '&en=' + enc(winningBid.bidResponse.bidPriceUSD); @@ -358,6 +420,8 @@ function auctionInitHandler(args) { 'bidderDonePendingCount', () => args.bidderRequests.length, ]); cacheEntry.adUnitCodes = {}; + cacheEntry.floorData = {}; + cacheEntry.origAdUnits = args.adUnits; cacheEntry.referer = args.bidderRequests[0].refererInfo.topmostLocation; cache.auctions[args.auctionId] = cacheEntry; } @@ -372,6 +436,9 @@ function bidRequestedHandler(args) { }; } cache.auctions[args.auctionId].adUnitCodes[bid.adUnitCode].bids[bid.bidId] = [copyRequiredBidDetails(bid)]; + if (bid.floorData) { + cache.auctions[args.auctionId].floorData['floorRequestData'] = bid.floorData; + } }) } @@ -386,6 +453,11 @@ function bidResponseHandler(args) { bid = copyRequiredBidDetails(args); cache.auctions[args.auctionId].adUnitCodes[args.adUnitCode].bids[args.requestId].push(bid); } + + if (args.floorData) { + cache.auctions[args.auctionId].floorData['floorResponseData'] = args.floorData; + } + bid.adId = args.adId; bid.source = formatSource(bid.source || args.source); setBidStatus(bid, args); diff --git a/modules/pubmaticBidAdapter.js b/modules/pubmaticBidAdapter.js index 02198042474..5ca8a2c04b3 100644 --- a/modules/pubmaticBidAdapter.js +++ b/modules/pubmaticBidAdapter.js @@ -378,51 +378,39 @@ function _createNativeRequest(params) { if (!(nativeRequestObject.assets && nativeRequestObject.assets.length > 0 && nativeRequestObject.assets.hasOwnProperty(key))) { switch (key) { case NATIVE_ASSETS.TITLE.KEY: - if (params[key].len || params[key].length) { - assetObj = { - id: NATIVE_ASSETS.TITLE.ID, - required: params[key].required ? 1 : 0, - title: { - len: params[key].len || params[key].length, - ext: params[key].ext - } - }; - } else { - logWarn(LOG_WARN_PREFIX + 'Error: Title Length is required for native ad: ' + JSON.stringify(params)); - } + assetObj = { + id: NATIVE_ASSETS.TITLE.ID, + required: params[key].required ? 1 : 0, + title: { + len: params[key].len || params[key].length, + ext: params[key].ext + } + }; break; case NATIVE_ASSETS.IMAGE.KEY: - if (params[key].sizes && params[key].sizes.length > 0) { - assetObj = { - id: NATIVE_ASSETS.IMAGE.ID, - required: params[key].required ? 1 : 0, - img: { - type: NATIVE_ASSET_IMAGE_TYPE.IMAGE, - w: params[key].w || params[key].width || (params[key].sizes ? params[key].sizes[0] : UNDEFINED), - h: params[key].h || params[key].height || (params[key].sizes ? params[key].sizes[1] : UNDEFINED), - wmin: params[key].wmin || params[key].minimumWidth || (params[key].minsizes ? params[key].minsizes[0] : UNDEFINED), - hmin: params[key].hmin || params[key].minimumHeight || (params[key].minsizes ? params[key].minsizes[1] : UNDEFINED), - mimes: params[key].mimes, - ext: params[key].ext, - } - }; - } else { - logWarn(LOG_WARN_PREFIX + 'Error: Image sizes is required for native ad: ' + JSON.stringify(params)); - } + assetObj = { + id: NATIVE_ASSETS.IMAGE.ID, + required: params[key].required ? 1 : 0, + img: { + type: NATIVE_ASSET_IMAGE_TYPE.IMAGE, + w: params[key].w || params[key].width || (params[key].sizes ? params[key].sizes[0] : UNDEFINED), + h: params[key].h || params[key].height || (params[key].sizes ? params[key].sizes[1] : UNDEFINED), + wmin: params[key].wmin || params[key].minimumWidth || (params[key].minsizes ? params[key].minsizes[0] : UNDEFINED), + hmin: params[key].hmin || params[key].minimumHeight || (params[key].minsizes ? params[key].minsizes[1] : UNDEFINED), + mimes: params[key].mimes, + ext: params[key].ext, + } + }; break; case NATIVE_ASSETS.ICON.KEY: - if (params[key].sizes && params[key].sizes.length > 0) { - assetObj = { - id: NATIVE_ASSETS.ICON.ID, - required: params[key].required ? 1 : 0, - img: { - type: NATIVE_ASSET_IMAGE_TYPE.ICON, - w: params[key].w || params[key].width || (params[key].sizes ? params[key].sizes[0] : UNDEFINED), - h: params[key].h || params[key].height || (params[key].sizes ? params[key].sizes[1] : UNDEFINED), - } - }; - } else { - logWarn(LOG_WARN_PREFIX + 'Error: Icon sizes is required for native ad: ' + JSON.stringify(params)); + assetObj = { + id: NATIVE_ASSETS.ICON.ID, + required: params[key].required ? 1 : 0, + img: { + type: NATIVE_ASSET_IMAGE_TYPE.ICON, + w: params[key].w || params[key].width || (params[key].sizes ? params[key].sizes[0] : UNDEFINED), + h: params[key].h || params[key].height || (params[key].sizes ? params[key].sizes[1] : UNDEFINED), + } }; break; case NATIVE_ASSETS.VIDEO.KEY: @@ -615,7 +603,7 @@ function _addDealCustomTargetings(imp, bid) { } } -function _addJWPlayerSegmentData(imp, bid, isS2S) { +function _addJWPlayerSegmentData(imp, bid) { var jwSegData = (bid.rtd && bid.rtd.jwplayer && bid.rtd.jwplayer.targeting) || undefined; var jwPlayerData = ''; const jwMark = 'jw-'; @@ -632,12 +620,8 @@ function _addJWPlayerSegmentData(imp, bid, isS2S) { var ext; - if (isS2S) { - (imp.dctr === undefined || imp.dctr.length == 0) ? imp.dctr = jwPlayerData : imp.dctr += '|' + jwPlayerData; - } else { - ext = imp.ext; - ext && ext.key_val === undefined ? ext.key_val = jwPlayerData : ext.key_val += '|' + jwPlayerData; - } + ext = imp.ext; + ext && ext.key_val === undefined ? ext.key_val = jwPlayerData : ext.key_val += '|' + jwPlayerData; } function _createImpressionObject(bid, conf) { @@ -985,6 +969,49 @@ function isNonEmptyArray(test) { return false; } +/** + * Prepare meta object to pass as params + * @param {*} br : bidResponse + * @param {*} bid : bids + */ +export function prepareMetaObject(br, bid, seat) { + br.meta = {}; + + if (bid.ext && bid.ext.dspid) { + br.meta.networkId = bid.ext.dspid; + br.meta.demandSource = bid.ext.dspid; + } + + // NOTE: We will not recieve below fields from the translator response also not sure on what will be the key names for these in the response, + // when we needed we can add it back. + // New fields added, assignee fields name may change + // if (bid.ext.networkName) br.meta.networkName = bid.ext.networkName; + // if (bid.ext.advertiserName) br.meta.advertiserName = bid.ext.advertiserName; + // if (bid.ext.agencyName) br.meta.agencyName = bid.ext.agencyName; + // if (bid.ext.brandName) br.meta.brandName = bid.ext.brandName; + if (bid.ext && bid.ext.dchain) { + br.meta.dchain = bid.ext.dchain; + } + + const advid = seat || (bid.ext && bid.ext.advid); + if (advid) { + br.meta.advertiserId = advid; + br.meta.agencyId = advid; + br.meta.buyerId = advid; + } + + if (bid.adomain && isNonEmptyArray(bid.adomain)) { + br.meta.advertiserDomains = bid.adomain; + br.meta.clickUrl = bid.adomain[0]; + br.meta.brandId = bid.adomain[0]; + } + + if (bid.cat && isNonEmptyArray(bid.cat)) { + br.meta.secondaryCatIds = bid.cat; + br.meta.primaryCatId = bid.cat[0]; + } +} + export const spec = { code: BIDDER_CODE, gvlid: 76, @@ -1197,6 +1224,10 @@ export const spec = { if (commonFpd.bcat) { blockedIabCategories = blockedIabCategories.concat(commonFpd.bcat); } + // check if fpd ortb2 contains device property with sua object + if (commonFpd.device?.sua) { + payload.device.sua = commonFpd.device?.sua; + } if (commonFpd.ext?.prebid?.bidderparams?.[bidderRequest.bidderCode]?.acat) { const acatParams = commonFpd.ext.prebid.bidderparams[bidderRequest.bidderCode].acat; @@ -1262,7 +1293,7 @@ export const spec = { seatbidder.bid.forEach(bid => { let newBid = { requestId: bid.impid, - cpm: (parseFloat(bid.price) || 0).toFixed(2), + cpm: parseFloat((bid.price || 0).toFixed(2)), width: bid.w, height: bid.h, creativeId: bid.crid || bid.id, @@ -1301,17 +1332,7 @@ export const spec = { newBid['dealChannel'] = dealChannelValues[bid.ext.deal_channel] || null; } - newBid.meta = {}; - if (bid.ext && bid.ext.dspid) { - newBid.meta.networkId = bid.ext.dspid; - } - if (bid.ext && bid.ext.advid) { - newBid.meta.buyerId = bid.ext.advid; - } - if (bid.adomain && bid.adomain.length > 0) { - newBid.meta.advertiserDomains = bid.adomain; - newBid.meta.clickUrl = bid.adomain[0]; - } + prepareMetaObject(newBid, bid, seatbidder.seat); // adserverTargeting if (seatbidder.ext && seatbidder.ext.buyid) { @@ -1379,7 +1400,6 @@ export const spec = { */ transformBidParams: function (params, isOpenRtb, adUnit, bidRequests) { - _addJWPlayerSegmentData(params, adUnit.bids[0], true); return convertTypes({ 'publisherId': 'string', 'adSlot': 'string' diff --git a/modules/pubwiseAnalyticsAdapter.js b/modules/pubwiseAnalyticsAdapter.js index 19a74c7c245..0a775b07b7f 100644 --- a/modules/pubwiseAnalyticsAdapter.js +++ b/modules/pubwiseAnalyticsAdapter.js @@ -304,11 +304,14 @@ pubwiseAnalytics.storeSessionID = function (userSessID) { // ensure a session exists, if not make one, always store it pubwiseAnalytics.ensureSession = function () { - if (sessionExpired() === true || userSessionID() === null || userSessionID() === '') { + let sessionId = userSessionID(); + if (sessionExpired() === true || sessionId === null || sessionId === '') { let generatedId = generateUUID(); expireUtmData(); this.storeSessionID(generatedId); sessionData.sessionId = generatedId; + } else if (sessionId != null) { + sessionData.sessionId = sessionId; } // eslint-disable-next-line // console.log('ensured session'); diff --git a/modules/pubxaiAnalyticsAdapter.js b/modules/pubxaiAnalyticsAdapter.js index f7e73dd5fdd..96665c786bf 100644 --- a/modules/pubxaiAnalyticsAdapter.js +++ b/modules/pubxaiAnalyticsAdapter.js @@ -6,7 +6,7 @@ import CONSTANTS from '../src/constants.json'; const emptyUrl = ''; const analyticsType = 'endpoint'; -const pubxaiAnalyticsVersion = 'v1.1.0'; +const pubxaiAnalyticsVersion = 'v1.2.0'; const defaultHost = 'api.pbxai.com'; const auctionPath = '/analytics/auction'; const winningBidPath = '/analytics/bidwon'; @@ -154,7 +154,7 @@ function send(data, status) { search: location.search }); if (typeof data !== 'undefined' && typeof data.auctionInit !== 'undefined') { - data.pageDetail.adUnitCount = data.auctionInit.adUnitCodes ? data.auctionInit.adUnitCodes.length : null; + data.pageDetail.adUnits = data.auctionInit.adUnitCodes; data.initOptions.auctionId = data.auctionInit.auctionId; delete data.auctionInit; diff --git a/modules/pulsepointBidAdapter.js b/modules/pulsepointBidAdapter.js index 25f82fb60d9..015e80d5692 100644 --- a/modules/pulsepointBidAdapter.js +++ b/modules/pulsepointBidAdapter.js @@ -16,6 +16,7 @@ const DEFAULT_BID_TTL = 20; const DEFAULT_CURRENCY = 'USD'; const DEFAULT_NET_REVENUE = true; const KNOWN_PARAMS = ['cp', 'ct', 'cf', 'video', 'battr', 'bcat', 'badv', 'bidfloor']; +const DEFAULT_TMAX = 500; /** * PulsePoint Bid Adapter. @@ -54,6 +55,7 @@ export const spec = { user: user(bidRequests[0], bidderRequest), regs: regs(bidderRequest), source: source(bidRequests[0].schain), + tmax: bidderRequest.timeout || DEFAULT_TMAX, }; return { method: 'POST', diff --git a/modules/rasBidAdapter.js b/modules/rasBidAdapter.js index 7bc3cf66b0d..f8ca260d490 100644 --- a/modules/rasBidAdapter.js +++ b/modules/rasBidAdapter.js @@ -1,4 +1,3 @@ -import * as utils from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER } from '../src/mediaTypes.js'; import { isEmpty, getAdUnitSizes, parseSizesInput, deepAccess } from '../src/utils.js'; @@ -12,9 +11,15 @@ const getEndpoint = (network) => { function parseParams(params, bidderRequest) { const newParams = {}; + if (params.customParams && typeof params.customParams === 'object') { + for (const param in params.customParams) { + if (params.customParams.hasOwnProperty(param)) { + newParams[param] = params.customParams[param]; + } + } + } const du = deepAccess(bidderRequest, 'refererInfo.page'); const dr = deepAccess(bidderRequest, 'refererInfo.ref'); - if (du) { newParams.du = du; } @@ -93,7 +98,7 @@ const getSlots = (bidRequests) => { const batchSize = bidRequests.length; for (let i = 0; i < batchSize; i++) { const adunit = bidRequests[i]; - const slotSequence = utils.deepAccess(adunit, 'params.slotSequence'); + const slotSequence = deepAccess(adunit, 'params.slotSequence'); const sizes = parseSizesInput(getAdUnitSizes(adunit)).join(','); diff --git a/modules/rasBidAdapter.md b/modules/rasBidAdapter.md index 384ba0b611f..e8a61974130 100644 --- a/modules/rasBidAdapter.md +++ b/modules/rasBidAdapter.md @@ -34,18 +34,19 @@ var adUnits = [{ # Parameters -| Name | Scope | Type | Description | Example -| --- | --- | --- |---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| --- -| network | required | String | Specific identifier provided by RAS | `"4178463"` -| site | required | String | Specific identifier name (case-insensitive) that is associated with this ad unit and provided by RAS | `"example_com"` -| area | required | String | Ad unit category name; only case-insensitive alphanumeric with underscores and hyphens are allowed | `"sport"` -| slot | required | String | Ad unit placement name (case-insensitive) provided by RAS | `"slot"` -| slotSequence | optional | Number | Ad unit sequence position provided by RAS | `1` -| pageContext | optional | Object | Web page context data | `{}` -| pageContext.dr | optional | String | Document referrer URL address | `"https://example.com/"` -| pageContext.du | optional | String | Document URL address | `"https://example.com/sport/football/article.html?id=932016a5-02fc-4d5c-b643-fafc2f270f06"` -| pageContext.dv | optional | String | Document virtual address as slash-separated path that may consist of any number of parts (case-insensitive alphanumeric with underscores and hyphens); first part should be the same as `site` value and second as `area` value; next parts may reflect website navigation | `"example_com/sport/football"` -| pageContext.keyWords | optional | String[] | List of keywords associated with this ad unit; only case-insensitive alphanumeric with underscores and hyphens are allowed | `["euro", "lewandowski"]` -| pageContext.keyValues | optional | Object | Key-values associated with this ad unit (case-insensitive); following characters are not allowed in the values: `" ' = ! + # * ~ ; ^ ( ) < > [ ] & @` | `{}` -| pageContext.keyValues.ci | optional | String | Content unique identifier | `"932016a5-02fc-4d5c-b643-fafc2f270f06"` -| pageContext.keyValues.adunit | optional | String | Ad unit name | `"example_com/sport"` +| Name | Scope | Type | Description | Example | +|------------------------------|----------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------| +| network | required | String | Specific identifier provided by RAS | `"4178463"` | +| site | required | String | Specific identifier name (case-insensitive) that is associated with this ad unit and provided by RAS | `"example_com"` | +| area | required | String | Ad unit category name; only case-insensitive alphanumeric with underscores and hyphens are allowed | `"sport"` | +| slot | required | String | Ad unit placement name (case-insensitive) provided by RAS | `"slot"` | +| slotSequence | optional | Number | Ad unit sequence position provided by RAS | `1` | +| pageContext | optional | Object | Web page context data | `{}` | +| pageContext.dr | optional | String | Document referrer URL address | `"https://example.com/"` | +| pageContext.du | optional | String | Document URL address | `"https://example.com/sport/football/article.html?id=932016a5-02fc-4d5c-b643-fafc2f270f06"` | +| pageContext.dv | optional | String | Document virtual address as slash-separated path that may consist of any number of parts (case-insensitive alphanumeric with underscores and hyphens); first part should be the same as `site` value and second as `area` value; next parts may reflect website navigation | `"example_com/sport/football"` | +| pageContext.keyWords | optional | String[] | List of keywords associated with this ad unit; only case-insensitive alphanumeric with underscores and hyphens are allowed | `["euro", "lewandowski"]` | +| pageContext.keyValues | optional | Object | Key-values associated with this ad unit (case-insensitive); following characters are not allowed in the values: `" ' = ! + # * ~ ; ^ ( ) < > [ ] & @` | `{}` | +| pageContext.keyValues.ci | optional | String | Content unique identifier | `"932016a5-02fc-4d5c-b643-fafc2f270f06"` | +| pageContext.keyValues.adunit | optional | String | Ad unit name | `"example_com/sport"` | +| customParams | optional | Object | Custom request params | `{}` | \ No newline at end of file diff --git a/modules/redtramBidAdapter.js b/modules/redtramBidAdapter.js new file mode 100644 index 00000000000..e1dc0e2a148 --- /dev/null +++ b/modules/redtramBidAdapter.js @@ -0,0 +1,155 @@ +import { + isFn, + isStr, + deepAccess, + getWindowTop, + triggerPixel +} from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER } from '../src/mediaTypes.js'; +import { config } from '../src/config.js'; + +const BIDDER_CODE = 'redtram'; +const AD_URL = 'https://prebid.redtram.com/pbjs'; +const SYNC_URL = 'https://prebid.redtram.com/sync'; + +function isBidResponseValid(bid) { + if (!bid.requestId || !bid.cpm || !bid.creativeId || + !bid.ttl || !bid.currency || !bid.meta) { + return false; + } + + switch (bid.mediaType) { + case BANNER: + return Boolean(bid.width && bid.height && bid.ad); + default: + return false; + } +} + +function getBidFloor(bid) { + if (!isFn(bid.getFloor)) { + return deepAccess(bid, 'params.bidFloor', 0); + } + + try { + const bidFloor = bid.getFloor({ + currency: 'USD', + mediaType: '*', + size: '*', + }); + return bidFloor.floor; + } catch (_) { + return 0 + } +} + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER], + + isBidRequestValid: (bid) => { + return Boolean(bid.bidId && bid.params && bid.params.placementId); + }, + + buildRequests: (validBidRequests = [], bidderRequest) => { + const winTop = getWindowTop(); + const location = winTop.location; + const placements = []; + + const request = { + deviceWidth: winTop.screen.width, + deviceHeight: winTop.screen.height, + language: (navigator && navigator.language) ? navigator.language.split('-')[0] : '', + host: location.host, + page: location.pathname, + placements: placements + }; + + if (bidderRequest) { + if (bidderRequest.uspConsent) { + request.ccpa = bidderRequest.uspConsent; + } + if (bidderRequest.gdprConsent) { + request.gdpr = bidderRequest.gdprConsent; + } + } + + const len = validBidRequests.length; + for (let i = 0; i < len; i++) { + const bid = validBidRequests[i]; + const placement = { + placementId: bid.params.placementId, + bidId: bid.bidId, + schain: bid.schain || {}, + bidfloor: getBidFloor(bid) + }; + + if (typeof bid.userId !== 'undefined') { + placement.userId = bid.userId; + } + + const mediaType = bid.mediaTypes; + + if (mediaType && mediaType[BANNER] && mediaType[BANNER].sizes) { + placement.sizes = mediaType[BANNER].sizes; + placement.adFormat = BANNER; + } + + placements.push(placement); + } + + return { + method: 'POST', + url: AD_URL, + 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; + }, + + getUserSyncs: (syncOptions, serverResponses, gdprConsent, uspConsent) => { + let syncType = syncOptions.iframeEnabled ? 'iframe' : 'image'; + let syncUrl = SYNC_URL + `/${syncType}?pbjs=1`; + if (gdprConsent && gdprConsent.consentString) { + if (typeof gdprConsent.gdprApplies === 'boolean') { + syncUrl += `&gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`; + } else { + syncUrl += `&gdpr=0&gdpr_consent=${gdprConsent.consentString}`; + } + } + if (uspConsent && uspConsent.consentString) { + syncUrl += `&ccpa_consent=${uspConsent.consentString}`; + } + + const coppa = config.getConfig('coppa') ? 1 : 0; + syncUrl += `&coppa=${coppa}`; + + return [{ + type: syncType, + url: syncUrl + }]; + }, + + onBidWon: (bid) => { + const cpm = deepAccess(bid, 'adserverTargeting.hb_pb') || ''; + if (isStr(bid.nurl) && bid.nurl !== '') { + bid.nurl = bid.nurl.replace(/\${AUCTION_PRICE}/, cpm); + triggerPixel(bid.nurl); + } + } +}; + +registerBidder(spec); diff --git a/modules/redtramBidAdapter.md b/modules/redtramBidAdapter.md new file mode 100644 index 00000000000..39115502aa7 --- /dev/null +++ b/modules/redtramBidAdapter.md @@ -0,0 +1,33 @@ +# Overview + +``` +Module Name: redtram Bidder Adapter +Module Type: redtram Bidder Adapter +Maintainer: support@redtram.com +``` + +# Description + +Module that connects to redtram demand sources + +# Test Parameters +``` + var adUnits = [ + { + code: 'div-prebid', + mediaTypes:{ + banner: { + sizes: [[300, 250]], + } + }, + bids:[ + { + bidder: 'redtram', + params: { + placementId: '23611' //test, please replace after test + } + } + ] + }, + ]; +``` \ No newline at end of file diff --git a/modules/resetdigitalBidAdapter.js b/modules/resetdigitalBidAdapter.js index a606f0c0b7d..93846e402e9 100644 --- a/modules/resetdigitalBidAdapter.js +++ b/modules/resetdigitalBidAdapter.js @@ -1,9 +1,11 @@ - -import { timestamp, deepAccess } from '../src/utils.js'; +import { timestamp, deepAccess, isStr, deepClone } from '../src/utils.js'; import { getOrigin } from '../libraries/getOrigin/index.js'; import { config } from '../src/config.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {BANNER} from '../src/mediaTypes.js'; + const BIDDER_CODE = 'resetdigital'; +const CURRENCY = 'USD'; export const spec = { code: BIDDER_CODE, @@ -43,16 +45,70 @@ export const spec = { }; } + if (bidderRequest && bidderRequest.uspConsent) { + payload.ccpa = bidderRequest.uspConsent; + } + + function getOrtb2Keywords(ortb2Obj) { + const fields = ['site.keywords', 'site.content.keywords', 'user.keywords', 'app.keywords', 'app.content.keywords']; + let result = []; + + fields.forEach(path => { + let keyStr = deepAccess(ortb2Obj, path); + if (isStr(keyStr)) result.push(keyStr); + }); + return result; + } + + // get the ortb2 keywords data (if it exists) + let ortb2 = deepClone(bidderRequest && bidderRequest.ortb2); + let ortb2KeywordsList = getOrtb2Keywords(ortb2); + // get meta keywords data (if it exists) + let metaKeywords = document.getElementsByTagName('meta')['keywords']; + if (metaKeywords && metaKeywords.content) { + metaKeywords = metaKeywords.content.split(','); + } + for (let x = 0; x < validBidRequests.length; x++) { - let req = validBidRequests[x] + let req = validBidRequests[x]; + + let bidFloor = req.params.bidFloor ? req.params.bidFloor : null; + let bidFloorCur = req.params.bidFloor ? req.params.bidFloorCur : null; + + if (typeof req.getFloor === 'function') { + const floorInfo = req.getFloor({ + currency: CURRENCY, + mediaType: BANNER, + size: '*' + }); + if (typeof floorInfo === 'object' && floorInfo.currency === CURRENCY && !isNaN(parseFloat(floorInfo.floor))) { + bidFloor = parseFloat(floorInfo.floor); + bidFloorCur = CURRENCY; + } + } + + // get param kewords (if it exists) + let paramsKeywords = req.params.keywords ? req.params.keywords.split(',') : []; + // merge all keywords + let keywords = ortb2KeywordsList.concat(paramsKeywords).concat(metaKeywords); payload.imps.push({ pub_id: req.params.pubId, + site_id: req.params.siteID ? req.params.siteID : null, + placement_id: req.params.placement ? req.params.placement : null, + position: req.params.position ? req.params.position : null, + bid_floor: bidFloor, + bid_floor_cur: bidFloorCur, + lat_long: req.params.latLong ? req.params.latLong : null, + inventory: req.params.inventory ? req.params.inventory : null, + visitor: req.params.visitor ? req.params.visitor : null, + keywords: keywords.join(','), zone_id: req.params.zoneId, bid_id: req.bidId, imp_id: req.transactionId, sizes: req.sizes, force_bid: req.params.forceBid, + coppa: config.getConfig('coppa') === true ? 1 : 0, media_types: deepAccess(req, 'mediaTypes') }); } @@ -62,7 +118,8 @@ export const spec = { return { method: 'POST', url: url, - data: JSON.stringify(payload) + data: JSON.stringify(payload), + bids: validBidRequests }; }, interpretResponse: function(serverResponse, bidRequest) { diff --git a/modules/resetdigitalBidAdapter.md b/modules/resetdigitalBidAdapter.md index 2f9f69b5e84..a368c7f5633 100644 --- a/modules/resetdigitalBidAdapter.md +++ b/modules/resetdigitalBidAdapter.md @@ -21,17 +21,43 @@ Video is supported but requires a publisher supplied renderer at this time. 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", - forceBid: true + site_id: "your-site-id", + forceBid: true, } } ] } ]; + ``` diff --git a/modules/riseBidAdapter.js b/modules/riseBidAdapter.js index c1360b79066..0c4d6148f2b 100644 --- a/modules/riseBidAdapter.js +++ b/modules/riseBidAdapter.js @@ -309,6 +309,16 @@ function generateBidParameters(bid, bidderRequest) { 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; + } + if (mediaType === VIDEO) { const playbackMethod = deepAccess(bid, `mediaTypes.video.playbackmethod`); let playbackMethodValue; @@ -349,6 +359,11 @@ function generateBidParameters(bid, bidderRequest) { if (linearity) { bidObject.linearity = linearity; } + + const protocols = deepAccess(bid, `mediaTypes.video.protocols`); + if (protocols) { + bidObject.protocols = protocols; + } } return bidObject; @@ -385,7 +400,8 @@ function generateGeneralParams(generalObject, bidderRequest) { 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), + is_wrapper: !!generalBidParams.isWrapper, + session_id: generalBidParams.sessionId || getBidIdParameter('auctionId', generalObject), tmax: timeout }; diff --git a/modules/riseBidAdapter.md b/modules/riseBidAdapter.md index 2920fd28528..f0837cb5508 100644 --- a/modules/riseBidAdapter.md +++ b/modules/riseBidAdapter.md @@ -20,11 +20,13 @@ The adapter supports Video(instream). | Name | Scope | Type | Description | Example | ---- | ----- | ---- | ----------- | ------- -| `org` | required | String | Rise publisher Id provided by your Rise representative | "56f91cd4d3e3660002000033" +| `org` | required | String | Rise publisher Id provided by your Rise representative | "1234567890abcdef12345678" | `floorPrice` | optional | Number | Minimum price in USD. Misuse of this parameter can impact revenue | 2.00 | `placementId` | optional | String | A unique placement identifier | "12345678" | `testMode` | optional | Boolean | This activates the test mode | false | `rtbDomain` | optional | String | Sets the seller end point | "www.test.com" +| `is_wrapper` | private | Boolean | Please don't use unless your account manager asked you to | false + # Test Parameters ```javascript @@ -41,10 +43,10 @@ var adUnits = [ bids: [{ bidder: 'rise', params: { - org: '56f91cd4d3e3660002000033', // Required + org: '1234567890abcdef12345678', // Required floorPrice: 2.00, // Optional placementId: '12345678', // Optional - testMode: false // Optional, + testMode: false, // Optional, rtbDomain: "www.test.com" //Optional } }] diff --git a/modules/rtbhouseBidAdapter.js b/modules/rtbhouseBidAdapter.js index fdf64483da7..9f498014a8e 100644 --- a/modules/rtbhouseBidAdapter.js +++ b/modules/rtbhouseBidAdapter.js @@ -1,13 +1,15 @@ -import {deepAccess, isArray, logError} from '../src/utils.js'; +import {deepAccess, mergeDeep, isArray, logError, logInfo} from '../src/utils.js'; import { getOrigin } from '../libraries/getOrigin/index.js'; import {BANNER, NATIVE} from '../src/mediaTypes.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {includes} from '../src/polyfill.js'; import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; +import { config } from '../src/config.js'; const BIDDER_CODE = 'rtbhouse'; const REGIONS = ['prebid-eu', 'prebid-us', 'prebid-asia']; const ENDPOINT_URL = 'creativecdn.com/bidder/prebid/bids'; +const FLEDGE_ENDPOINT_URL = 'creativecdn.com/bidder/prebidfledge/bids'; const DEFAULT_CURRENCY_ARR = ['USD']; // NOTE - USD is the only supported currency right now; Hardcoded for bids const SUPPORTED_MEDIA_TYPES = [BANNER, NATIVE]; const TTL = 55; @@ -50,12 +52,13 @@ export const spec = { const request = { id: validBidRequests[0].auctionId, - imp: validBidRequests.map(slot => mapImpression(slot)), + imp: validBidRequests.map(slot => mapImpression(slot, bidderRequest)), site: mapSite(validBidRequests, bidderRequest), cur: DEFAULT_CURRENCY_ARR, test: validBidRequests[0].params.test || 0, source: mapSource(validBidRequests[0]), }; + if (bidderRequest && bidderRequest.gdprConsent && bidderRequest.gdprConsent.gdprApplies) { const consentStr = (bidderRequest.gdprConsent.consentString) ? bidderRequest.gdprConsent.consentString.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '') : ''; @@ -81,37 +84,32 @@ export const spec = { } } - const ortb2Params = bidderRequest && bidderRequest.ortb2; - if (ortb2Params?.user) { - request.user = { - ...request.user, - ...(ortb2Params.user.data && { - data: { ...request.user?.data, ...ortb2Params.user.data }, - }), - ...(ortb2Params.user.ext && { - ext: { ...request.user?.ext, ...ortb2Params.user.ext }, - }), - }; + const ortb2Params = bidderRequest?.ortb2 || {}; + if (ortb2Params.site) { + mergeDeep(request, { site: ortb2Params.site }); + } + if (ortb2Params.user) { + mergeDeep(request, { user: ortb2Params.user }); + } + if (ortb2Params.device) { + mergeDeep(request, { device: ortb2Params.device }); } - if (ortb2Params?.site) { - request.site = { - ...request.site, - ...(ortb2Params.site.content && { - content: { ...request.site?.content, ...ortb2Params.site.content }, - }), - ...(ortb2Params.site.ext && { - ext: { ...request.site?.ext, ...ortb2Params.site.ext }, - }), - }; + + let computedEndpointUrl = ENDPOINT_URL; + + const fledgeConfig = config.getConfig('fledgeConfig'); + if (bidderRequest.fledgeEnabled && fledgeConfig) { + mergeDeep(request, { ext: { fledge_config: fledgeConfig } }); + computedEndpointUrl = FLEDGE_ENDPOINT_URL; } return { method: 'POST', - url: 'https://' + validBidRequests[0].params.region + '.' + ENDPOINT_URL, + url: 'https://' + validBidRequests[0].params.region + '.' + computedEndpointUrl, data: JSON.stringify(request) }; }, - interpretResponse: function (serverResponse, originalRequest) { + interpretOrtbResponse: function (serverResponse, originalRequest) { const responseBody = serverResponse.body; if (!isArray(responseBody)) { return []; @@ -119,17 +117,72 @@ export const spec = { const bids = []; responseBody.forEach(serverBid => { - if (serverBid.price === 0) { + if (!serverBid.price) { // price may exist and is === 0 or there's no price prop at all (fledge req case) return; } + + let interpretedBid; + // try...catch would be risky cause JSON.parse throws SyntaxError if (serverBid.adm.indexOf('{') === 0) { - bids.push(interpretNativeBid(serverBid)); + interpretedBid = interpretNativeBid(serverBid); } else { - bids.push(interpretBannerBid(serverBid)); + interpretedBid = interpretBannerBid(serverBid); } + if (serverBid.ext) interpretedBid.ext = serverBid.ext; + + bids.push(interpretedBid); }); return bids; + }, + interpretResponse: function (serverResponse, originalRequest) { + let bids; + + const responseBody = serverResponse.body; + let fledgeAuctionConfigs = null; + + if (responseBody.bidid && isArray(responseBody?.ext?.igbid)) { + // we have fledge response + // mimic the original response ([{},...]) + bids = this.interpretOrtbResponse({ body: responseBody.seatbid[0]?.bid }, originalRequest); + + const seller = responseBody.ext.seller; + const decisionLogicUrl = responseBody.ext.decisionLogicUrl; + const sellerTimeout = 'sellerTimeout' in responseBody.ext ? { sellerTimeout: responseBody.ext.sellerTimeout } : {}; + responseBody.ext.igbid.forEach((igbid) => { + const perBuyerSignals = {}; + igbid.igbuyer.forEach(buyerItem => { + perBuyerSignals[buyerItem.igdomain] = buyerItem.buyersignal + }); + fledgeAuctionConfigs = fledgeAuctionConfigs || {}; + fledgeAuctionConfigs[igbid.impid] = mergeDeep( + { + seller, + decisionLogicUrl, + interestGroupBuyers: Object.keys(perBuyerSignals), + perBuyerSignals, + }, + sellerTimeout + ); + }); + } else { + bids = this.interpretOrtbResponse(serverResponse, originalRequest); + } + + if (fledgeAuctionConfigs) { + fledgeAuctionConfigs = Object.entries(fledgeAuctionConfigs).map(([bidId, cfg]) => { + return Object.assign({ + bidId, + auctionSignals: {} + }, cfg); + }); + logInfo('Response with FLEDGE:', { bids, fledgeAuctionConfigs }); + return { + bids, + fledgeAuctionConfigs, + } + } + return bids; } }; registerBidder(spec); @@ -154,7 +207,7 @@ function applyFloor(slot) { * @param {object} slot Ad Unit Params by Prebid * @returns {object} Imp by OpenRTB 2.5 §3.2.4 */ -function mapImpression(slot) { +function mapImpression(slot, bidderRequest) { const imp = { id: slot.bidId, banner: mapBanner(slot), @@ -167,6 +220,14 @@ function mapImpression(slot) { imp.bidfloor = bidfloor; } + if (bidderRequest.fledgeEnabled) { + imp.ext = imp.ext || {}; + imp.ext.ae = slot?.ortb2Imp?.ext?.ae + } else { + if (imp.ext?.ae) { + delete imp.ext.ae; + } + } return imp; } diff --git a/modules/rtdModule/index.js b/modules/rtdModule/index.js index e32d2169c5c..05594c63132 100644 --- a/modules/rtdModule/index.js +++ b/modules/rtdModule/index.js @@ -108,6 +108,13 @@ * @param {UserConsentData} userConsent */ +/** + * @function? + * @summary on data deletion request + * @name RtdSubmodule#onDataDeletionRequest + * @param {SubmoduleConfig} config + */ + /** * @interface ModuleConfig */ @@ -156,7 +163,7 @@ import {getHook, module} from '../../src/hook.js'; import {logError, logInfo, logWarn} from '../../src/utils.js'; import * as events from '../../src/events.js'; import CONSTANTS from '../../src/constants.json'; -import {gdprDataHandler, uspDataHandler} from '../../src/adapterManager.js'; +import adapterManager, {gdprDataHandler, uspDataHandler, gppDataHandler} from '../../src/adapterManager.js'; import {find} from '../../src/polyfill.js'; import {timedAuctionHook} from '../../src/utils/perfMetrics.js'; @@ -230,6 +237,7 @@ export function init(config) { _dataProviders = realTimeData.dataProviders; setEventsListeners(); getHook('startAuction').before(setBidRequestsData, 20); // RTD should run before FPD + adapterManager.callDataDeletionRequest.before(onDataDeletionRequest); initSubModules(); }); } @@ -238,6 +246,7 @@ function getConsentData() { return { gdpr: gdprDataHandler.getConsentData(), usp: uspDataHandler.getConsentData(), + gpp: gppDataHandler.getConsentData(), coppa: !!(config.getConfig('coppa')) } } @@ -386,5 +395,18 @@ export function deepMerge(arr) { }, {}); } +export function onDataDeletionRequest(next, ...args) { + subModules.forEach((sm) => { + if (typeof sm.onDataDeletionRequest === 'function') { + try { + sm.onDataDeletionRequest(sm.config); + } catch (e) { + logError(`Error executing ${sm.name}.onDataDeletionRequest`, e) + } + } + }); + next.apply(this, args); +} + module('realTimeData', attachRealTimeDataProvider); init(config); diff --git a/modules/rubiconBidAdapter.js b/modules/rubiconBidAdapter.js index 254799b995d..d4875345043 100644 --- a/modules/rubiconBidAdapter.js +++ b/modules/rubiconBidAdapter.js @@ -115,6 +115,7 @@ var sizeMap = { 257: '400x600', 258: '500x200', 259: '998x200', + 261: '480x480', 264: '970x1000', 265: '1920x1080', 274: '1800x200', @@ -134,7 +135,8 @@ var sizeMap = { 574: '620x891', 576: '610x877', 578: '980x552', - 580: '505x656' + 580: '505x656', + 622: '192x160' }; _each(sizeMap, (item, key) => sizeMap[item] = key); diff --git a/modules/scatteredBidAdapter.js b/modules/scatteredBidAdapter.js new file mode 100644 index 00000000000..47dc09cd1b2 --- /dev/null +++ b/modules/scatteredBidAdapter.js @@ -0,0 +1,72 @@ +// jshint esversion: 6, es3: false, node: true +'use strict'; + +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER } from '../src/mediaTypes.js'; +import { deepAccess, logInfo } from '../src/utils.js'; +import { ortbConverter } from '../libraries/ortbConverter/converter.js'; + +const BIDDER_CODE = 'scattered'; +const GVLID = 1179; +export const converter = ortbConverter({ + context: { + mediaType: BANNER, + ttl: 360, + netRevenue: true + } +}) + +export const spec = { + code: BIDDER_CODE, + gvlid: GVLID, + supportedMediaTypes: [BANNER], + + // 1. + isBidRequestValid: function (bid) { + const bidderDomain = deepAccess(bid, 'params.bidderDomain') + if (bidderDomain === undefined || bidderDomain === '') { + return false + } + + const sizes = deepAccess(bid, 'mediaTypes.banner.sizes') + if (sizes === undefined || sizes.length < 1) { + return false + } + + return true + }, + + // 2. + buildRequests: function (bidRequests, bidderRequest) { + return { + method: 'POST', + url: 'https://' + getKeyOnAny(bidRequests, 'params.bidderDomain'), + data: converter.toORTB({ bidderRequest, bidRequests }), + options: { + contentType: 'application/json' + }, + }; + }, + + // 3. + interpretResponse: function (response, request) { + if (!response.body) return; + return converter.fromORTB({ response: response.body, request: request.data }).bids; + }, + + // 4 + onBidWon: function (bid) { + logInfo('onBidWon', bid) + } +} + +function getKeyOnAny(collection, key) { + for (let i = 0; i < collection.length; i++) { + const result = deepAccess(collection[i], key); + if (result) { + return result; + } + } +} + +registerBidder(spec); diff --git a/modules/scatteredBidAdapter.md b/modules/scatteredBidAdapter.md new file mode 100644 index 00000000000..031d953e32b --- /dev/null +++ b/modules/scatteredBidAdapter.md @@ -0,0 +1,36 @@ +# Overview + +``` +Module Name: Scattered Adapter +Module Type: Bidder Adapter +Maintainer: office@scattered.pl +``` + +# Description + +Module that connects to Scattered's demand sources. +It uses OpenRTB standard to communicate between the adapter and bidding servers. + +# Test Parameters + +```javascript + var adUnits = [ + { + code: 'test-div', + mediaTypes: { + banner: { + sizes: [[300, 250]], // a display size + } + }, + bids: [ + { + bidder: "scattered", + params: { + bidderDomain: "prebid-test.scattered.eu/bid", + test: 0 + } + } + ] + } + ]; +``` \ No newline at end of file diff --git a/modules/seedingAllianceBidAdapter.js b/modules/seedingAllianceBidAdapter.js index 64b9cd5d4aa..29953da7ffa 100755 --- a/modules/seedingAllianceBidAdapter.js +++ b/modules/seedingAllianceBidAdapter.js @@ -2,120 +2,111 @@ 'use strict'; import { registerBidder } from '../src/adapters/bidderFactory.js'; -import { NATIVE } from '../src/mediaTypes.js'; -import { _map, deepSetValue, isEmpty, deepAccess } from '../src/utils.js'; +import { NATIVE, BANNER } from '../src/mediaTypes.js'; +import { _map, isArray, isEmpty, deepSetValue, replaceAuctionPrice } from '../src/utils.js'; import { config } from '../src/config.js'; import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; -const BIDDER_CODE = 'seedingAlliance'; const GVL_ID = 371; +const BIDDER_CODE = 'seedingAlliance'; const DEFAULT_CUR = 'EUR'; const ENDPOINT_URL = 'https://b.nativendo.de/cds/rtb/bid?format=openrtb2.5&ssp=pb'; -const NATIVE_ASSET_IDS = {0: 'title', 1: 'body', 2: 'sponsoredBy', 3: 'image', 4: 'cta', 5: 'icon'}; +const NATIVE_ASSET_IDS = { 0: 'title', 1: 'body', 2: 'sponsoredBy', 3: 'image', 4: 'cta', 5: 'icon' }; const NATIVE_PARAMS = { - title: { - id: 0, - name: 'title' - }, - - body: { - id: 1, - name: 'data', - type: 2 - }, - - sponsoredBy: { - id: 2, - name: 'data', - type: 1 - }, - - image: { - id: 3, - type: 3, - name: 'img' - }, - - cta: { - id: 4, - type: 12, - name: 'data' - }, - - icon: { - id: 5, - type: 1, - name: 'img' - } + title: { id: 0, name: 'title' }, + body: { id: 1, name: 'data', type: 2 }, + sponsoredBy: { id: 2, name: 'data', type: 1 }, + image: { id: 3, type: 3, name: 'img' }, + cta: { id: 4, type: 12, name: 'data' }, + icon: { id: 5, type: 1, name: 'img' } }; export const spec = { code: BIDDER_CODE, - gvlid: GVL_ID, + supportedMediaTypes: [NATIVE, BANNER], - supportedMediaTypes: [NATIVE], - - isBidRequestValid: function(bid) { + isBidRequestValid: function (bid) { return !!bid.params.adUnitId; }, - buildRequests: (validBidRequests, bidderRequest) => { + buildRequests: (validBidRequests = [], bidderRequest) => { // convert Native ORTB definition to old-style prebid native definition validBidRequests = convertOrtbRequestToProprietaryNative(validBidRequests); - const pt = setOnAny(validBidRequests, 'params.pt') || setOnAny(validBidRequests, 'params.priceType') || 'net'; - const tid = bidderRequest.auctionId; - const cur = [config.getConfig('currency.adServerCurrency') || DEFAULT_CUR]; let url = bidderRequest.refererInfo.page; - const imp = validBidRequests.map((bid, id) => { - const assets = _map(bid.nativeParams, (bidParams, key) => { - const props = NATIVE_PARAMS[key]; - - const asset = { - required: bidParams.required & 1 - }; + const imps = validBidRequests.map((bidRequest, id) => { + const imp = { + id: String(id + 1), + tagid: bidRequest.params.adUnitId + }; - if (props) { - asset.id = props.id; + /** + * Native Ad + */ + if (bidRequest.nativeParams) { + const assets = _map(bidRequest.nativeParams, (nativeAsset, key) => { + const props = NATIVE_PARAMS[key]; + + if (props) { + let wmin, hmin, w, h; + let aRatios = nativeAsset.aspect_ratios; + + if (aRatios && aRatios[0]) { + aRatios = aRatios[0]; + wmin = aRatios.min_width || 0; + hmin = aRatios.ratio_height * wmin / aRatios.ratio_width | 0; + } - let w, h; + if (nativeAsset.sizes) { + const sizes = flatten(nativeAsset.sizes); + w = parseInt(sizes[0], 10); + h = parseInt(sizes[1], 10); + } - if (bidParams.sizes) { - w = bidParams.sizes[0]; - h = bidParams.sizes[1]; + const asset = { + id: props.id, + required: nativeAsset.required & 1 + }; + + asset[props.name] = { + len: nativeAsset.len, + type: props.type, + wmin, + hmin, + w, + h + }; + + return asset; + } else { + // TODO Filter impressions with required assets we don't support } + }).filter(Boolean); - asset[props.name] = { - len: bidParams.len, - type: props.type, - w, - h - }; + imp.native = { + request: { + assets + } + }; + } else { + let sizes = transformSizes(bidRequest.sizes); - return asset; + imp.banner = { + format: sizes, + w: sizes[0] ? sizes[0].w : 0, + h: sizes[0] ? sizes[0].h : 0 } - }) - .filter(Boolean); + } - if (bid.params.url) { - url = bid.params.url; + if (bidRequest.params.url) { + url = bidRequest.params.url; } - return { - id: String(id + 1), - tagid: bid.params.adUnitId, - tid: tid, - pt: pt, - native: { - request: { - assets - } - } - }; + return imp; }); const request = { @@ -123,12 +114,9 @@ export const spec = { site: { page: url }, - device: { - ua: navigator.userAgent - }, - cur, - imp, - user: {}, + cur: [config.getConfig('currency.adServerCurrency') || DEFAULT_CUR], + imp: imps, + tmax: bidderRequest.timeout, regs: { ext: { gdpr: 0, @@ -137,23 +125,22 @@ export const spec = { } }; - if (bidderRequest && bidderRequest.gdprConsent) { + if (bidderRequest.gdprConsent) { + request.user = {}; + deepSetValue(request, 'user.ext.consent', bidderRequest.gdprConsent.consentString); deepSetValue(request, 'regs.ext.gdpr', (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean' && bidderRequest.gdprConsent.gdprApplies) ? 1 : 0); } return { method: 'POST', - url: ENDPOINT_URL, + url: config.getConfig('seedingAlliance.endpoint') || ENDPOINT_URL, data: JSON.stringify(request), - options: { - contentType: 'application/json' - }, - bids: validBidRequests + bidRequests: validBidRequests }; }, - interpretResponse: function(serverResponse, { bids }) { + interpretResponse: function (serverResponse, { bidRequests }) { if (isEmpty(serverResponse.body)) { return []; } @@ -165,35 +152,72 @@ export const spec = { return result; }, []) : []; - return bids - .map((bid, id) => { + return bidRequests + .map((bidRequest, id) => { const bidResponse = bidResponses[id]; + const type = bidRequest.nativeParams ? NATIVE : BANNER; + if (bidResponse) { - return { - requestId: bid.bidId, + const bidObject = { + requestId: bidRequest.bidId, // TODO get this value from response? cpm: bidResponse.price, creativeId: bidResponse.crid, - ttl: 1000, - netRevenue: (!bid.netRevenue || bid.netRevenue === 'net'), + ttl: 600, + netRevenue: true, currency: cur, - mediaType: NATIVE, + mediaType: type, bidderCode: BIDDER_CODE, - native: parseNative(bidResponse), meta: { advertiserDomains: bidResponse.adomain && bidResponse.adomain.length > 0 ? bidResponse.adomain : [] } }; + + if (type === NATIVE) { + bidObject.native = parseNative(bidResponse); + bidObject.mediaType = NATIVE; + } + + if (type === BANNER) { + bidObject.ad = replaceAuctionPrice(bidResponse.adm, bidResponse.price); + bidObject.width = bidResponse.w; + bidObject.height = bidResponse.h; + bidObject.mediaType = BANNER; + } + + return bidObject; } }) .filter(Boolean); } }; -registerBidder(spec); +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 flatten(arr) { + return [].concat(...arr); +} function parseNative(bid) { - const {assets, link, imptrackers} = bid.adm.native; + const { assets, link, imptrackers } = bid.adm.native; let clickUrl = link.url.replace(/\$\{AUCTION_PRICE\}/g, bid.price); @@ -228,15 +252,4 @@ 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); -} +registerBidder(spec); diff --git a/modules/seedtagBidAdapter.js b/modules/seedtagBidAdapter.js index 5c4a3af866c..f54245a41ab 100644 --- a/modules/seedtagBidAdapter.js +++ b/modules/seedtagBidAdapter.js @@ -1,18 +1,18 @@ import { isArray, _map, triggerPixel } from '../src/utils.js'; -import { registerBidder } from '../src/adapters/bidderFactory.js' -import { VIDEO, BANNER } from '../src/mediaTypes.js' +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { VIDEO, BANNER } from '../src/mediaTypes.js'; +import { config } from '../src/config.js'; const BIDDER_CODE = 'seedtag'; const SEEDTAG_ALIAS = 'st'; const SEEDTAG_SSP_ENDPOINT = 'https://s.seedtag.com/c/hb/bid'; const SEEDTAG_SSP_ONTIMEOUT_ENDPOINT = 'https://s.seedtag.com/se/hb/timeout'; -const ALLOWED_PLACEMENTS = { - inImage: true, - inScreen: true, - inArticle: true, - banner: true, - video: true -} +const ALLOWED_DISPLAY_PLACEMENTS = [ + 'inScreen', + 'inImage', + 'inArticle', + 'inBanner', +]; // Global Vendor List Id // https://iabeurope.eu/vendor-list-tcf-v2-0/ @@ -20,27 +20,33 @@ const GVLID = 157; const mediaTypesMap = { [BANNER]: 'display', - [VIDEO]: 'video' + [VIDEO]: 'video', }; const deviceConnection = { FIXED: 'fixed', MOBILE: 'mobile', - UNKNOWN: 'unknown' + UNKNOWN: 'unknown', }; const getConnectionType = () => { - const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection || {} + const connection = + navigator.connection || + navigator.mozConnection || + navigator.webkitConnection || + {}; switch (connection.type || connection.effectiveType) { case 'wifi': case 'ethernet': - return deviceConnection.FIXED + return deviceConnection.FIXED; case 'cellular': case 'wimax': - return deviceConnection.MOBILE + return deviceConnection.MOBILE; default: - const isMobile = /iPad|iPhone|iPod/.test(navigator.userAgent) || /android/i.test(navigator.userAgent) - return isMobile ? deviceConnection.UNKNOWN : deviceConnection.FIXED + const isMobile = + /iPad|iPhone|iPod/.test(navigator.userAgent) || + /android/i.test(navigator.userAgent); + return isMobile ? deviceConnection.UNKNOWN : deviceConnection.FIXED; } }; @@ -51,24 +57,46 @@ function mapMediaType(seedtagMediaType) { } function hasVideoMediaType(bid) { - return (!!bid.mediaTypes && !!bid.mediaTypes.video) || (!!bid.params && !!bid.params.video) + return !!bid.mediaTypes && !!bid.mediaTypes.video; +} + +function hasBannerMediaType(bid) { + return !!bid.mediaTypes && !!bid.mediaTypes.banner; } -function hasMandatoryParams(params) { +function hasMandatoryDisplayParams(bid) { + const p = bid.params; return ( - !!params.publisherId && - !!params.adUnitId && - !!params.placement && - !!ALLOWED_PLACEMENTS[params.placement] + !!p.publisherId && + !!p.adUnitId && + ALLOWED_DISPLAY_PLACEMENTS.indexOf(p.placement) > -1 ); } function hasMandatoryVideoParams(bid) { - const videoParams = getVideoParams(bid) + const videoParams = getVideoParams(bid); - return hasVideoMediaType(bid) && !!videoParams.playerSize && + let isValid = + !!bid.params.publisherId && + !!bid.params.adUnitId && + hasVideoMediaType(bid) && + !!videoParams.playerSize && isArray(videoParams.playerSize) && videoParams.playerSize.length > 0; + + switch (bid.params.placement) { + // instream accept only video format + case 'inStream': + return isValid && videoParams.context === 'instream'; + // outstream accept banner/native/video format + default: + return ( + isValid && + videoParams.context === 'outstream' && + hasBannerMediaType(bid) && + hasMandatoryDisplayParams(bid) + ); + } } function buildBidRequest(validBidRequest) { @@ -88,15 +116,11 @@ function buildBidRequest(validBidRequest) { adUnitId: params.adUnitId, adUnitCode: validBidRequest.adUnitCode, placement: params.placement, - requestCount: validBidRequest.bidderRequestsCount || 1 // FIXME : in unit test the parameter bidderRequestsCount is undefined + requestCount: validBidRequest.bidderRequestsCount || 1, // FIXME : in unit test the parameter bidderRequestsCount is undefined }; - if (params.adPosition) { - bidRequest.adPosition = params.adPosition; - } - if (hasVideoMediaType(validBidRequest)) { - bidRequest.videoParams = getVideoParams(validBidRequest) + bidRequest.videoParams = getVideoParams(validBidRequest); } return bidRequest; @@ -112,13 +136,7 @@ function getVideoParams(validBidRequest) { videoParams.h = videoParams.playerSize[0][1]; } - const bidderVideoParams = (validBidRequest.params && validBidRequest.params.video) || {} - // override video params from seedtag bidder params - Object.keys(bidderVideoParams).forEach(key => { - videoParams[key] = validBidRequest.params.video[key] - }) - - return videoParams + return videoParams; } function buildBidResponse(seedtagBid) { @@ -135,8 +153,11 @@ function buildBidResponse(seedtagBid) { ttl: seedtagBid.ttl, nurl: seedtagBid.nurl, meta: { - advertiserDomains: seedtagBid && seedtagBid.adomain && seedtagBid.adomain.length > 0 ? seedtagBid.adomain : [] - } + advertiserDomains: + seedtagBid && seedtagBid.adomain && seedtagBid.adomain.length > 0 + ? seedtagBid.adomain + : [], + }, }; if (mediaType === VIDEO) { @@ -177,19 +198,24 @@ function ttfb() { return ttfb >= 0 && ttfb <= performance.now() ? ttfb : 0; } -export function getTimeoutUrl (data) { +export function getTimeoutUrl(data) { let queryParams = ''; if ( - isArray(data) && data[0] && - isArray(data[0].params) && data[0].params[0] + isArray(data) && + data[0] && + isArray(data[0].params) && + data[0].params[0] ) { const params = data[0].params[0]; - const timeout = data[0].timeout + const timeout = data[0].timeout; queryParams = - '?publisherToken=' + params.publisherId + - '&adUnitId=' + params.adUnitId + - '&timeout=' + timeout; + '?publisherToken=' + + params.publisherId + + '&adUnitId=' + + params.adUnitId + + '&timeout=' + + timeout; } return SEEDTAG_SSP_ONTIMEOUT_ENDPOINT + queryParams; } @@ -207,8 +233,8 @@ export const spec = { */ isBidRequestValid(bid) { return hasVideoMediaType(bid) - ? hasMandatoryParams(bid.params) && hasMandatoryVideoParams(bid) - : hasMandatoryParams(bid.params); + ? hasMandatoryVideoParams(bid) + : hasMandatoryDisplayParams(bid); }, /** @@ -235,21 +261,37 @@ export const spec = { if (gdprApplies !== undefined) payload['ga'] = gdprApplies; payload['cd'] = bidderRequest.gdprConsent.consentString; } - if (bidderRequest.uspConsent) { - payload['uspConsent'] = bidderRequest.uspConsent + payload['uspConsent'] = bidderRequest.uspConsent; } if (validBidRequests[0].schain) { payload.schain = validBidRequests[0].schain; } - const payloadString = JSON.stringify(payload) + let coppa = config.getConfig('coppa'); + if (coppa) { + payload.coppa = coppa; + } + + if (bidderRequest.gppConsent) { + payload.gppConsent = { + gppString: bidderRequest.gppConsent.gppString, + applicableSections: bidderRequest.gppConsent.applicableSections + } + } else if (bidderRequest.ortb2?.regs?.gpp) { + payload.gppConsent = { + gppString: bidderRequest.ortb2.regs.gpp, + applicableSections: bidderRequest.ortb2.regs.gpp_sid + } + } + + const payloadString = JSON.stringify(payload); return { method: 'POST', url: SEEDTAG_SSP_ENDPOINT, - data: payloadString - } + data: payloadString, + }; }, /** @@ -258,10 +300,10 @@ export const spec = { * @param {ServerResponse} serverResponse A successful response from the server. * @return {Bid[]} An array of bids which were nested inside the server. */ - interpretResponse: function(serverResponse) { + interpretResponse: function (serverResponse) { const serverBody = serverResponse.body; if (serverBody && serverBody.bids && isArray(serverBody.bids)) { - return _map(serverBody.bids, function(bid) { + return _map(serverBody.bids, function (bid) { return buildBidResponse(bid); }); } else { @@ -303,6 +345,6 @@ export const spec = { if (bid && bid.nurl) { triggerPixel(bid.nurl); } - } -} + }, +}; registerBidder(spec); diff --git a/modules/seedtagBidAdapter.md b/modules/seedtagBidAdapter.md index 061a254c5fa..8ccfcfb701e 100644 --- a/modules/seedtagBidAdapter.md +++ b/modules/seedtagBidAdapter.md @@ -59,3 +59,63 @@ const adUnits = [ } ] ``` + +## InBanner +```js +const adUnits = [ + { + code: '/21804003197/prebid_test_300x250', + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + bids: [ + { + bidder: 'seedtag', + params: { + publisherId: '0000-0000-01', // required + adUnitId: '0000', // required + placement: 'inBanner', // required + } + } + ] + } +] +``` + +## inStream Video +```js +var adUnits = [{ + code: 'video', + mediaTypes: { + video: { + context: 'instream', // required + playerSize: [640, 360], // required + // Video object as specified in OpenRTB 2.5 + mimes: ['video/mp4'], // recommended + minduration: 5, // optional + maxduration: 60, // optional + boxingallowed: 1, // optional + skip: 1, // optional + startdelay: 1, // optional + linearity: 1, // optional + battr: [1, 2], // optional + maxbitrate: 10, // optional + playbackmethod: [1], // optional + delivery: [1], // optional + placement: 1, // optional + } + }, + bids: [ + { + bidder: 'seedtag', + params: { + publisherId: '0000-0000-01', // required + adUnitId: '0000', // required + placement: 'inStream', // required + } + } + ] +}]; +``` diff --git a/modules/sharedIdSystem.js b/modules/sharedIdSystem.js index 99a34ae17f4..7562b472047 100644 --- a/modules/sharedIdSystem.js +++ b/modules/sharedIdSystem.js @@ -9,8 +9,9 @@ import { parseUrl, buildUrl, triggerPixel, logInfo, hasDeviceAccess, generateUUI import {submodule} from '../src/hook.js'; import { coppaDataHandler } from '../src/adapterManager.js'; import {getStorageManager} from '../src/storageManager.js'; +import {VENDORLESS_GVLID} from '../src/consentHandler.js'; -export const storage = getStorageManager({moduleName: 'pubCommonId'}); +export const storage = getStorageManager({moduleName: 'pubCommonId', gvlid: VENDORLESS_GVLID}); const COOKIE = 'cookie'; const LOCAL_STORAGE = 'html5'; const OPTOUT_NAME = '_pubcid_optout'; @@ -73,6 +74,7 @@ export const sharedIdSystemSubmodule = { */ name: 'sharedId', aliasName: 'pubCommonId', + gvlid: VENDORLESS_GVLID, /** * decode the stored id value for passing to bid requests diff --git a/modules/sirdataRtdProvider.js b/modules/sirdataRtdProvider.js index 369276e7638..40ee3d8b973 100644 --- a/modules/sirdataRtdProvider.js +++ b/modules/sirdataRtdProvider.js @@ -1,12 +1,13 @@ /** * This module adds Sirdata provider to the real time data module + * and now supports Seller Defined Audience * The {@link module:modules/realTimeData} module is required * The module will fetch segments (user-centric) and categories (page-centric) from Sirdata server * The module will automatically handle user's privacy and choice in California (IAB TL CCPA Framework) and in Europe (IAB EU TCF FOR GDPR) * @module modules/sirdataRtdProvider * @requires module:modules/realTimeData */ -import {deepAccess, deepEqual, deepSetValue, isEmpty, logError, mergeDeep} from '../src/utils.js'; +import {deepAccess, deepSetValue, isEmpty, logError, mergeDeep} from '../src/utils.js'; import {submodule} from '../src/hook.js'; import {ajax} from '../src/ajax.js'; import {findIndex} from '../src/polyfill.js'; @@ -16,6 +17,52 @@ import {config} from '../src/config.js'; /** @type {string} */ const MODULE_NAME = 'realTimeData'; const SUBMODULE_NAME = 'SirdataRTDModule'; +const ORTB2_NAME = 'sirdata.com'; + +const partnerIds = { + 'criteo': 27443, + 'openx': 30342, + 'pubmatic': 30345, + 'smaato': 27520, + 'triplelift': 27518, + 'yahoossp': 30339, + 'rubicon': 27452, + 'appnexus': 27446, + 'appnexusAst': 27446, + 'brealtime': 27446, + 'emxdigital': 27446, + 'pagescience': 27446, + 'gourmetads': 33394, + 'matomy': 27446, + 'featureforward': 27446, + 'oftmedia': 27446, + 'districtm': 27446, + 'adasta': 27446, + 'beintoo': 27446, + 'gravity': 27446, + 'msq_classic': 27878, + 'msq_max': 27878, + '366_apx': 27878, + 'mediasquare': 27878, + 'smartadserver': 27440, + 'smart': 27440, + 'proxistore': 27484, + 'ix': 27248, + 'sdRtdForGpt': 27449, + 'smilewanted': 28690, + 'taboola': 33379, + 'ttd': 33382, + 'zeta_global': 33385, + 'teads': 33388, + 'conversant': 33391, + 'improvedigital': 33397, + 'invibes': 33400, + 'sublime': 33403, + 'rtbhouse': 33406, + 'zeta_global_ssp': 33385, +}; + +let CONTEXT_ONLY = true; export function getSegmentsAndCategories(reqBidsConfigObj, onDone, moduleConfig, userConsent) { moduleConfig.params = moduleConfig.params || {}; @@ -46,9 +93,10 @@ export function getSegmentsAndCategories(reqBidsConfigObj, onDone, moduleConfig, if (!sirdataDomain || !gdprApplies || (deepAccess(userConsent, 'gdpr.vendorData.vendor.consents') && userConsent.gdpr.vendorData.vendor.consents[53] && userConsent.gdpr.vendorData.purpose.consents[1] && userConsent.gdpr.vendorData.purpose.consents[4])) { sirdataDomain = 'sddan.com'; sendWithCredentials = true; + CONTEXT_ONLY = false; } - // TODO: is 'page' the right value here? - var actualUrl = moduleConfig.params.actualUrl || getRefererInfo().page; + + var actualUrl = moduleConfig.params.actualUrl || getRefererInfo().stack.pop() || getRefererInfo().page; const url = 'https://kvt.' + sirdataDomain + '/api/v1/public/p/' + moduleConfig.params.partnerId + '/d/' + moduleConfig.params.key + '/s?callback=&gdpr=' + gdprApplies + '&gdpr_consent=' + tcString + (actualUrl ? '&url=' + encodeURIComponent(actualUrl) : ''); @@ -86,39 +134,74 @@ export function getSegmentsAndCategories(reqBidsConfigObj, onDone, moduleConfig, }); } -export function setGlobalOrtb2(ortb2, segments, categories) { +export function setGlobalOrtb2Sda(ortb2Fragments, data, segtaxid, cattaxid) { try { - let addOrtb2 = {}; - let testGlobal = ortb2 || {} - if (!deepAccess(testGlobal, 'user.ext.data.sd_rtd') || !deepEqual(testGlobal.user.ext.data.sd_rtd, segments)) { - deepSetValue(addOrtb2, 'user.ext.data.sd_rtd', segments || {}); + if (!isEmpty(data.segments)) { + applyGlobalOrtb2Sda(ortb2Fragments, 'user', data.segments, segtaxid); } - if (!deepAccess(testGlobal, 'site.ext.data.sd_rtd') || !deepEqual(testGlobal.site.ext.data.sd_rtd, categories)) { - deepSetValue(addOrtb2, 'site.ext.data.sd_rtd', categories || {}); - } - if (!isEmpty(addOrtb2)) { - mergeDeep(ortb2, addOrtb2); + if (!isEmpty(data.categories)) { + applyGlobalOrtb2Sda(ortb2Fragments, 'site', data.categories, cattaxid); } } catch (e) { logError(e) } + return true; +} +export function applyGlobalOrtb2Sda(ortb2Fragments, type, segments, segtaxValue) { + try { + let ortb2Data = [{ + name: ORTB2_NAME, + segment: segments.map((segmentId) => ({ id: segmentId })), + }]; + if (segtaxValue) { + ortb2Data[0].ext = { segtax: segtaxValue }; + } + let ortb2Conf = (type == 'site' ? {site: {content: {data: ortb2Data}}} : {user: {data: ortb2Data}}); + mergeDeep(ortb2Fragments, ortb2Conf); + } catch (e) { + logError(e) + } return true; } -export function setBidderOrtb2(bidderOrtb2, bidder, segments, categories) { +export function setBidderOrtb2Sda(ortb2Fragments, bidder, data, segtaxid, cattaxid) { try { - let addOrtb2 = {}; - let testBidder = bidderOrtb2[bidder]; - if (!deepAccess(testBidder, 'user.ext.data.sd_rtd') || !deepEqual(testBidder.user.ext.data.sd_rtd, segments)) { - deepSetValue(addOrtb2, 'user.ext.data.sd_rtd', segments || {}); + if (!isEmpty(data.segments)) { + applyBidderOrtb2Sda(ortb2Fragments, bidder, 'user', data.segments, segtaxid); } - if (!deepAccess(testBidder, 'site.ext.data.sd_rtd') || !deepEqual(testBidder.site.ext.data.sd_rtd, categories)) { - deepSetValue(addOrtb2, 'site.ext.data.sd_rtd', categories || {}); + if (!isEmpty(data.categories)) { + applyBidderOrtb2Sda(ortb2Fragments, bidder, 'site', data.categories, cattaxid); } - if (!isEmpty(addOrtb2)) { - mergeDeep(bidderOrtb2[bidder], addOrtb2) + } catch (e) { + logError(e) + } + return true; +} + +export function applyBidderOrtb2Sda(ortb2Fragments, bidder, type, segments, segtaxValue) { + try { + let ortb2Data = [{ + name: ORTB2_NAME, + segment: segments.map((segmentId) => ({ id: segmentId })), + }]; + if (segtaxValue) { + ortb2Data[0].ext = { segtax: segtaxValue }; } + let ortb2Conf = (type == 'site' ? {site: {content: {data: ortb2Data}}} : {user: {data: ortb2Data}}); + mergeDeep(ortb2Fragments, {[bidder]: ortb2Conf}); + } catch (e) { + logError(e) + } + return true; +} + +export function setBidderOrtb2(bidderOrtb2Fragments, bidder, path, segments) { + try { + if (isEmpty(segments)) { return; } + let ortb2Conf = {}; + deepSetValue(ortb2Conf, path, segments || {}); + mergeDeep(bidderOrtb2Fragments, {[bidder]: ortb2Conf}); } catch (e) { logError(e) } @@ -137,16 +220,16 @@ export function loadCustomFunction(todo, adUnit, list, data, bid) { return true; } -export function getSegAndCatsArray(data, minScore) { - var sirdataData = {'segments': [], 'categories': []}; +export function getSegAndCatsArray(data, minScore, pid) { + let sirdataData = {'segments': [], 'categories': []}; minScore = minScore && typeof minScore == 'number' ? minScore : 30; try { if (data && data.contextual_categories) { for (let catId in data.contextual_categories) { - if (data.contextual_categories.hasOwnProperty(catId)) { + if (data.contextual_categories.hasOwnProperty(catId) && data.contextual_categories[catId]) { let value = data.contextual_categories[catId]; if (value >= minScore && sirdataData.categories.indexOf(catId) === -1) { - sirdataData.categories.push(catId.toString()); + sirdataData.categories.push((pid ? pid.toString() + 'cc' : '') + catId.toString()); } } } @@ -157,8 +240,11 @@ export function getSegAndCatsArray(data, minScore) { try { if (data && data.segments) { for (let segId in data.segments) { - if (data.segments.hasOwnProperty(segId)) { - sirdataData.segments.push(data.segments[segId].toString()); + if (data.segments.hasOwnProperty(segId) && data.segments[segId]) { + sirdataData.segments.push((pid ? pid.toString() + 'us' : '') + data.segments[segId].toString()); + if (pid && CONTEXT_ONLY) { + sirdataData.categories.push(pid.toString() + 'uc' + data.segments[segId].toString()); + } } } } @@ -168,34 +254,77 @@ export function getSegAndCatsArray(data, minScore) { return sirdataData; } +export function applySdaGetSpecificData(data, sirdataList, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit) { + // only share SDA data if whitelisted + if (!biddersParamsExist || indexFound) { + // SDA Publisher + let sirdataDataForSDA = getSegAndCatsArray(data, minScore, moduleConfig.params.partnerId); + setBidderOrtb2Sda(reqBids.ortb2Fragments?.bidder, bid.bidder, sirdataDataForSDA, data.segtaxid, data.cattaxid); + } + + // always share SDA for curation + let curationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : (partnerIds[bid.bidder] ? partnerIds[bid.bidder] : null)); + if (curationId) { + // seller defined audience & bidder specific data + if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { + // Get Bidder Specific Data + let curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore, null); + sirdataList = sirdataList.concat(curationData.segments).concat(curationData.categories); + + // SDA Partners + let curationDataForSDA = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore, curationId); + setBidderOrtb2Sda(reqBids.ortb2Fragments?.bidder, bid.bidder, curationDataForSDA, data.shared_taxonomy[curationId].segtaxid, data.shared_taxonomy[curationId].cattaxid); + } + } + + // Apply custom function or return Bidder Specific Data if publisher is ok + if (sirdataList && sirdataList.length > 0 && (!biddersParamsExist || indexFound)) { + if (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('customFunction')) { + return loadCustomFunction(moduleConfig.params.bidders[bidderIndex].customFunction, adUnit, sirdataList, data, bid); + } else { + return sirdataList; + } + } +} + +export function applySdaAndDefaultSpecificData(data, sirdataList, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit) { + let specificData = applySdaGetSpecificData(data, sirdataList, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit); + if (specificData && specificData.length > 0) { + setBidderOrtb2(reqBids.ortb2Fragments?.bidder, bid.bidder, 'user.ext.data', {sd_rtd: specificData}); + } +} + export function addSegmentData(reqBids, data, moduleConfig, onDone) { const adUnits = reqBids.adUnits; moduleConfig = moduleConfig || {}; moduleConfig.params = moduleConfig.params || {}; const globalMinScore = moduleConfig.params.hasOwnProperty('contextualMinRelevancyScore') ? moduleConfig.params.contextualMinRelevancyScore : 30; - var sirdataData = getSegAndCatsArray(data, globalMinScore); + var sirdataData = getSegAndCatsArray(data, globalMinScore, null); const sirdataList = sirdataData.segments.concat(sirdataData.categories); - var sirdataMergedList = []; - var curationData = {'segments': [], 'categories': []}; - var curationId = '1'; const biddersParamsExist = (!!(moduleConfig.params && moduleConfig.params.bidders)); - // Global ortb2 - if (!biddersParamsExist) { - setGlobalOrtb2(reqBids.ortb2Fragments?.global, sirdataData.segments, sirdataData.categories); + // Global ortb2 SDA + if (data.global_taxonomy && !isEmpty(data.global_taxonomy)) { + let globalData = {'segments': [], 'categories': []}; + for (let i in data.global_taxonomy) { + if (!isEmpty(data.global_taxonomy[i])) { + globalData = getSegAndCatsArray(data.global_taxonomy[i], globalMinScore, null); + setGlobalOrtb2Sda(reqBids.ortb2Fragments?.global, globalData, data.global_taxonomy[i].segtaxid, data.global_taxonomy[i].cattaxid); + } + } } // Google targeting if (typeof window.googletag !== 'undefined' && (moduleConfig.params.setGptKeyValues || !moduleConfig.params.hasOwnProperty('setGptKeyValues'))) { try { - // For curation Google is pid 27449 - curationId = (moduleConfig.params.gptCurationId ? moduleConfig.params.gptCurationId : '27449'); - if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { - curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], globalMinScore); + let gptCurationId = (moduleConfig.params.gptCurationId ? moduleConfig.params.gptCurationId : (partnerIds['sdRtdForGpt'] ? partnerIds['sdRtdForGpt'] : null)); + let sirdataMergedList = sirdataList; + if (gptCurationId && data.shared_taxonomy && data.shared_taxonomy[gptCurationId]) { + let gamCurationData = getSegAndCatsArray(data.shared_taxonomy[gptCurationId], globalMinScore, null); + sirdataMergedList = sirdataMergedList.concat(gamCurationData.segments).concat(gamCurationData.categories); } - sirdataMergedList = sirdataList.concat(curationData.segments).concat(curationData.categories); window.googletag.pubads().getSlots().forEach(function (n) { if (typeof n.setTargeting !== 'undefined' && sirdataMergedList && sirdataMergedList.length > 0) { n.setTargeting('sd_rtd', sirdataMergedList); @@ -221,259 +350,108 @@ export function addSegmentData(reqBids, data, moduleConfig, onDone) { }) : false); indexFound = (!!(typeof bidderIndex == 'number' && bidderIndex >= 0)); try { - curationData = {'segments': [], 'categories': []}; - sirdataMergedList = []; - let minScore = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('contextualMinRelevancyScore') ? moduleConfig.params.bidders[bidderIndex].contextualMinRelevancyScore : globalMinScore); + let specificData = null; + + switch (bid.bidder) { + case 'appnexus': + case 'appnexusAst': + case 'brealtime': + case 'emxdigital': + case 'pagescience': + case 'gourmetads': + case 'matomy': + case 'featureforward': + case 'oftmedia': + case 'districtm': + case 'adasta': + case 'beintoo': + case 'gravity': + case 'msq_classic': + case 'msq_max': + case '366_apx': + specificData = applySdaGetSpecificData(data, sirdataList, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit); + if (specificData && specificData.length > 0) { + deepSetValue(bid, 'params.keywords.sd_rtd', specificData); + } + break; - if (!biddersParamsExist || (indexFound && (!moduleConfig.params.bidders[bidderIndex].hasOwnProperty('adUnitCodes') || moduleConfig.params.bidders[bidderIndex].adUnitCodes.indexOf(adUnit.code) !== -1))) { - switch (bid.bidder) { - case 'appnexus': - case 'appnexusAst': - case 'brealtime': - case 'emxdigital': - case 'pagescience': - case 'gourmetads': - case 'matomy': - case 'featureforward': - case 'oftmedia': - case 'districtm': - case 'adasta': - case 'beintoo': - case 'gravity': - case 'msq_classic': - case 'msq_max': - case '366_apx': - // For curation Xandr is pid 27446 - curationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : '27446'); - if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { - curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore); - } - sirdataMergedList = sirdataList.concat(curationData.segments).concat(curationData.categories); - if (sirdataMergedList && sirdataMergedList.length > 0) { - if (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('customFunction')) { - loadCustomFunction(moduleConfig.params.bidders[bidderIndex].customFunction, adUnit, sirdataMergedList, data, bid); - } else { - deepSetValue(bid, 'params.keywords.sd_rtd', sirdataMergedList); - } - } - break; - - case 'smartadserver': - case 'smart': + case 'smartadserver': + case 'smart': + specificData = applySdaGetSpecificData(data, sirdataList, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit); + if (specificData && specificData.length > 0) { var target = []; if (bid.hasOwnProperty('params') && bid.params.hasOwnProperty('target')) { target.push(bid.params.target); } - // For curation Smart is pid 27440 - curationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : '27440'); - if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { - curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore); - } - sirdataMergedList = sirdataList.concat(curationData.segments).concat(curationData.categories); - if (sirdataMergedList && sirdataMergedList.length > 0) { - if (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('customFunction')) { - loadCustomFunction(moduleConfig.params.bidders[bidderIndex].customFunction, adUnit, sirdataMergedList, data, bid); - } else { - sirdataMergedList.forEach(function (entry) { - if (target.indexOf('sd_rtd=' + entry) === -1) { - target.push('sd_rtd=' + entry); - } - }); - deepSetValue(bid, 'params.target', target.join(';')); - } - } - break; - - case 'rubicon': - // For curation Magnite is pid 27518 - curationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : '27452'); - if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { - curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore); - } - sirdataMergedList = sirdataList.concat(curationData.segments).concat(curationData.categories); - if (sirdataMergedList && sirdataMergedList.length > 0) { - if (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('customFunction')) { - loadCustomFunction(moduleConfig.params.bidders[bidderIndex].customFunction, adUnit, sirdataMergedList, data, bid); - } else { - setBidderOrtb2(reqBids.ortb2Fragments?.bidder, bid.bidder, data.segments.concat(curationData.segments), sirdataMergedList); - } - } - break; - - case 'ix': - var ixConfig = config.getConfig('ix.firstPartyData.sd_rtd'); - if (!ixConfig) { - // For curation index is pid 27248 - curationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : '27248'); - if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { - curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore); - } - sirdataMergedList = sirdataList.concat(curationData.segments).concat(curationData.categories); - if (sirdataMergedList && sirdataMergedList.length > 0) { - if (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('customFunction')) { - loadCustomFunction(moduleConfig.params.bidders[bidderIndex].customFunction, adUnit, sirdataMergedList, data, bid); - } else { - var cappIxCategories = []; - var ixLength = 0; - var ixLimit = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('sizeLimit') ? moduleConfig.params.bidders[bidderIndex].sizeLimit : 1000); - // Push ids For publisher use and for curation if exists but limit size because the bidder uses GET parameters - sirdataMergedList.forEach(function (entry) { - if (ixLength < ixLimit) { - cappIxCategories.push(entry); - ixLength += entry.toString().length; - } - }); - config.setConfig({ix: {firstPartyData: {sd_rtd: cappIxCategories}}}); - } - } - } - break; - - case 'proxistore': - // For curation Proxistore is pid 27484 - curationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : '27484'); - if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { - curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore); - } else { - data.shared_taxonomy[curationId] = {contextual_categories: {}}; - } - sirdataMergedList = sirdataList.concat(curationData.segments).concat(curationData.categories); - if (sirdataMergedList && sirdataMergedList.length > 0) { - if (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('customFunction')) { - loadCustomFunction(moduleConfig.params.bidders[bidderIndex].customFunction, adUnit, sirdataMergedList, data, bid); - } else { - deepSetValue(bid, 'ortb2.user.ext.data', { - segments: sirdataData.segments.concat(curationData.segments), - contextual_categories: {...data.contextual_categories, ...data.shared_taxonomy[curationId].contextual_categories} - }); - } - } - break; - - case 'criteo': - // For curation Smart is pid 27443 - curationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : '27443'); - if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { - curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore); - } - sirdataMergedList = sirdataList.concat(curationData.segments).concat(curationData.categories); - if (sirdataMergedList && sirdataMergedList.length > 0) { - if (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('customFunction')) { - loadCustomFunction(moduleConfig.params.bidders[bidderIndex].customFunction, adUnit, sirdataMergedList, data, bid); - } else { - setBidderOrtb2(reqBids.ortb2Fragments?.bidder, bid.bidder, data.segments.concat(curationData.segments), sirdataMergedList); - } - } - break; - - case 'triplelift': - // For curation Triplelift is pid 27518 - curationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : '27518'); - if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { - curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore); - } - sirdataMergedList = sirdataList.concat(curationData.segments).concat(curationData.categories); - if (sirdataMergedList && sirdataMergedList.length > 0) { - if (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('customFunction')) { - loadCustomFunction(moduleConfig.params.bidders[bidderIndex].customFunction, adUnit, sirdataMergedList, data, bid); - } else { - setBidderOrtb2(reqBids.ortb2Fragments?.bidder, bid.bidder, data.segments.concat(curationData.segments), sirdataMergedList); - } - } - break; - - case 'avct': - case 'avocet': - // For curation Avocet is pid 27522 - curationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : '27522'); - if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { - curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore); - } - sirdataMergedList = sirdataList.concat(curationData.segments).concat(curationData.categories); - if (sirdataMergedList && sirdataMergedList.length > 0) { - if (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('customFunction')) { - loadCustomFunction(moduleConfig.params.bidders[bidderIndex].customFunction, adUnit, sirdataMergedList, data, bid); - } else { - setBidderOrtb2(reqBids.ortb2Fragments?.bidder, bid.bidder, data.segments.concat(curationData.segments), sirdataMergedList); - } - } - break; - - case 'smaato': - // For curation Smaato is pid 27520 - curationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : '27520'); - if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { - curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore); - } - sirdataMergedList = sirdataList.concat(curationData.segments).concat(curationData.categories); - if (sirdataMergedList && sirdataMergedList.length > 0) { - if (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('customFunction')) { - loadCustomFunction(moduleConfig.params.bidders[bidderIndex].customFunction, adUnit, sirdataMergedList, data, bid); - } else { - setBidderOrtb2(reqBids.ortb2Fragments?.bidder, bid.bidder, data.segments.concat(curationData.segments), sirdataMergedList); - } - } - break; - - case 'yahoossp': - // For curation Yahoo is pid 30339 - curationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : '30339'); - if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { - curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore); - } - sirdataMergedList = sirdataList.concat(curationData.segments).concat(curationData.categories); - if (sirdataMergedList && sirdataMergedList.length > 0) { - if (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('customFunction')) { - loadCustomFunction(moduleConfig.params.bidders[bidderIndex].customFunction, adUnit, sirdataMergedList, data, bid); - } else { - setBidderOrtb2(reqBids.ortb2Fragments?.bidder, bid.bidder, data.segments.concat(curationData.segments), sirdataMergedList); - } - } - break; - - case 'openx': - // For curation OpenX is pid 30342 - curationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : '30342'); - if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { - curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore); - } - sirdataMergedList = sirdataList.concat(curationData.segments).concat(curationData.categories); - if (sirdataMergedList && sirdataMergedList.length > 0) { - if (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('customFunction')) { - loadCustomFunction(moduleConfig.params.bidders[bidderIndex].customFunction, adUnit, sirdataMergedList, data, bid); - } else { - setBidderOrtb2(reqBids.ortb2Fragments?.bidder, bid.bidder, data.segments.concat(curationData.segments), sirdataMergedList); + specificData.forEach(function (entry) { + if (target.indexOf('sd_rtd=' + entry) === -1) { + target.push('sd_rtd=' + entry); } - } - break; - - case 'pubmatic': - // For curation Pubmatic is pid 30345 - curationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : '30345'); - if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { - curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore); - } - sirdataMergedList = sirdataList.concat(curationData.segments).concat(curationData.categories); - if (sirdataMergedList && sirdataMergedList.length > 0) { - if (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('customFunction')) { - loadCustomFunction(moduleConfig.params.bidders[bidderIndex].customFunction, adUnit, sirdataMergedList, data, bid); - } else { - setBidderOrtb2(reqBids.ortb2Fragments?.bidder, bid.bidder, data.segments.concat(curationData.segments), sirdataMergedList); - } - } - break; - - default: - if (!biddersParamsExist || indexFound) { - if (!deepAccess(bid, 'ortb2.site.ext.data.sd_rtd')) { - deepSetValue(bid, 'ortb2.site.ext.data.sd_rtd', sirdataData.categories); - } - if (!deepAccess(bid, 'ortb2.user.ext.data.sd_rtd')) { - deepSetValue(bid, 'ortb2.user.ext.data.sd_rtd', sirdataData.segments); + }); + deepSetValue(bid, 'params.target', target.join(';')); + } + break; + + case 'ix': + specificData = applySdaGetSpecificData(data, sirdataList, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit); + let ixConfig = config.getConfig('ix.firstPartyData.sd_rtd'); + if (!ixConfig && specificData && specificData.length > 0) { + let cappIxCategories = []; + let ixLength = 0; + let ixLimit = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('sizeLimit') ? moduleConfig.params.bidders[bidderIndex].sizeLimit : 1000); + // Push ids For publisher use and for curation if exists but limit size because the bidder uses GET parameters + specificData.forEach(function (entry) { + if (ixLength < ixLimit) { + cappIxCategories.push(entry); + ixLength += entry.toString().length; } + }); + config.setConfig({ix: {firstPartyData: {sd_rtd: cappIxCategories}}}); + } + break; + + case 'proxistore': + specificData = applySdaGetSpecificData(data, sirdataList, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit); + if (specificData && specificData.length > 0) { + let psCurationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : (partnerIds[bid.bidder] ? partnerIds[bid.bidder] : null)); + if (!data.shared_taxonomy || !data.shared_taxonomy[psCurationId]) { + data.shared_taxonomy[psCurationId] = {segments: [], contextual_categories: {}, segtaxid: null, cattaxid: null}; } - } + let psCurationData = getSegAndCatsArray(data.shared_taxonomy[psCurationId], minScore, null); + setBidderOrtb2(reqBids.ortb2Fragments?.bidder, bid.bidder, 'user.ext.data', { + segments: sirdataData.segments.concat(psCurationData.segments), + contextual_categories: {...data.contextual_categories, ...data.shared_taxonomy[psCurationId].contextual_categories} + }); + } + break; + + case 'rubicon': + case 'criteo': + case 'triplelift': + case 'smaato': + case 'yahoossp': + case 'openx': + case 'pubmatic': + case 'smilewanted': + case 'taboola': + case 'ttd': + case 'zeta_global': + case 'zeta_global_ssp': + case 'teads': + case 'conversant': + case 'improvedigital': + case 'invibes': + case 'sublime': + case 'rtbhouse': + case 'mediasquare': + applySdaAndDefaultSpecificData(data, sirdataList, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit); + break; + + default: + if (!biddersParamsExist || (indexFound && (!moduleConfig.params.bidders[bidderIndex].hasOwnProperty('adUnitCodes') || moduleConfig.params.bidders[bidderIndex].adUnitCodes.indexOf(adUnit.code) !== -1))) { + applySdaAndDefaultSpecificData(data, sirdataList, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit); + } } } catch (e) { logError(e); diff --git a/modules/smaatoBidAdapter.js b/modules/smaatoBidAdapter.js index 18ce56c7a80..8c2d9d4ff17 100644 --- a/modules/smaatoBidAdapter.js +++ b/modules/smaatoBidAdapter.js @@ -8,7 +8,7 @@ import CONSTANTS from '../src/constants.json'; const { NATIVE_IMAGE_TYPES } = CONSTANTS; const BIDDER_CODE = 'smaato'; const SMAATO_ENDPOINT = 'https://prebid.ad.smaato.net/oapi/prebid'; -const SMAATO_CLIENT = 'prebid_js_$prebid.version$_1.7' +const SMAATO_CLIENT = 'prebid_js_$prebid.version$_1.8' const CURRENCY = 'USD'; const buildOpenRtbBidRequest = (bidRequest, bidderRequest) => { @@ -63,6 +63,11 @@ const buildOpenRtbBidRequest = (bidRequest, bidderRequest) => { deepSetValue(requestTemplate, 'regs.ext.us_privacy', bidderRequest.uspConsent); } + if (ortb2.regs?.gpp !== undefined) { + deepSetValue(requestTemplate, 'regs.ext.gpp', ortb2.regs.gpp); + deepSetValue(requestTemplate, 'regs.ext.gpp_sid', ortb2.regs.gpp_sid); + } + if (deepAccess(bidRequest, 'params.app')) { const geo = deepAccess(bidRequest, 'params.app.geo'); deepSetValue(requestTemplate, 'device.geo', geo); diff --git a/modules/smartadserverBidAdapter.js b/modules/smartadserverBidAdapter.js index 5d64cad27b5..c07b2abe933 100644 --- a/modules/smartadserverBidAdapter.js +++ b/modules/smartadserverBidAdapter.js @@ -13,6 +13,7 @@ export const spec = { gvlid: GVL_ID, aliases: ['smart'], // short code supportedMediaTypes: [BANNER, VIDEO], + /** * Determines whether or not the given bid request is valid. * @@ -131,8 +132,9 @@ export const spec = { */ buildRequests: function (validBidRequests, bidderRequest) { // use bidderRequest.bids[] to get bidder-dependent request info - const adServerCurrency = config.getConfig('currency.adServerCurrency'); + const sellerDefinedAudience = deepAccess(bidderRequest, 'ortb2.user.data', config.getAnyConfig('ortb2.user.data')); + const sellerDefinedContext = deepAccess(bidderRequest, 'ortb2.site.content.data', config.getAnyConfig('ortb2.site.content.data')); // pull requested transaction ID from bidderRequest.bids[].transactionId return validBidRequests.reduce((bidRequests, bid) => { @@ -142,7 +144,6 @@ export const spec = { pageid: bid.params.pageId, formatid: bid.params.formatId, currencyCode: adServerCurrency, - bidfloor: bid.params.bidfloor || spec.getBidFloor(bid, adServerCurrency), targeting: bid.params.target && bid.params.target !== '' ? bid.params.target : undefined, buid: bid.params.buId && bid.params.buId !== '' ? bid.params.buId : undefined, appname: bid.params.appName && bid.params.appName !== '' ? bid.params.appName : undefined, @@ -154,13 +155,26 @@ export const spec = { timeout: config.getConfig('bidderTimeout'), bidId: bid.bidId, prebidVersion: '$prebid.version$', - schain: spec.serializeSupplyChain(bid.schain) + schain: spec.serializeSupplyChain(bid.schain), + sda: sellerDefinedAudience, + sdc: sellerDefinedContext }; - if (bidderRequest && bidderRequest.gdprConsent) { - payload.addtl_consent = bidderRequest.gdprConsent.addtlConsent; - payload.gdpr_consent = bidderRequest.gdprConsent.consentString; - payload.gdpr = bidderRequest.gdprConsent.gdprApplies; // we're handling the undefined case server side + if (bidderRequest) { + if (bidderRequest.gdprConsent) { + payload.addtl_consent = bidderRequest.gdprConsent.addtlConsent; + payload.gdpr_consent = bidderRequest.gdprConsent.consentString; + payload.gdpr = bidderRequest.gdprConsent.gdprApplies; // we're handling the undefined case server side + } + + if (bidderRequest.gppConsent) { + payload.gpp = bidderRequest.gppConsent.gppString; + payload.gpp_sid = bidderRequest.gppConsent.applicableSections; + } + + if (bidderRequest.uspConsent) { + payload.us_privacy = bidderRequest.uspConsent; + } } if (bid && bid.userId) { @@ -171,24 +185,28 @@ export const spec = { payload.us_privacy = bidderRequest.uspConsent; } - const videoMediaType = deepAccess(bid, 'mediaTypes.video'); const bannerMediaType = deepAccess(bid, 'mediaTypes.banner'); - const isAdUnitContainingVideo = videoMediaType && (videoMediaType.context === 'instream' || videoMediaType.context === 'outstream'); - if (!isAdUnitContainingVideo && bannerMediaType) { - payload.sizes = spec.adaptBannerSizes(bannerMediaType.sizes); - bidRequests.push(spec.createServerRequest(payload, bid.params.domain)); - } else if (isAdUnitContainingVideo && !bannerMediaType) { - spec.fillPayloadForVideoBidRequest(payload, videoMediaType, bid.params.video); - bidRequests.push(spec.createServerRequest(payload, bid.params.domain)); - } else if (isAdUnitContainingVideo && bannerMediaType) { - // If there are video and banner media types in the ad unit, we clone the payload - // to create a specific one for video. - let videoPayload = deepClone(payload); + const videoMediaType = deepAccess(bid, 'mediaTypes.video'); + const isSupportedVideoContext = videoMediaType && (videoMediaType.context === 'instream' || videoMediaType.context === 'outstream'); + + if (bannerMediaType || isSupportedVideoContext) { + let type; + if (bannerMediaType) { + type = BANNER; + payload.sizes = spec.adaptBannerSizes(bannerMediaType.sizes); - spec.fillPayloadForVideoBidRequest(videoPayload, videoMediaType, bid.params.video); - bidRequests.push(spec.createServerRequest(videoPayload, bid.params.domain)); + if (isSupportedVideoContext) { + let videoPayload = deepClone(payload); + spec.fillPayloadForVideoBidRequest(videoPayload, videoMediaType, bid.params.video); + videoPayload.bidfloor = bid.params.bidfloor || spec.getBidFloor(bid, adServerCurrency, VIDEO); + bidRequests.push(spec.createServerRequest(videoPayload, bid.params.domain)); + } + } else { + type = VIDEO; + spec.fillPayloadForVideoBidRequest(payload, videoMediaType, bid.params.video); + } - payload.sizes = spec.adaptBannerSizes(bannerMediaType.sizes); + payload.bidfloor = bid.params.bidfloor || spec.getBidFloor(bid, adServerCurrency, type); bidRequests.push(spec.createServerRequest(payload, bid.params.domain)); } else { bidRequests.push({}); @@ -209,7 +227,7 @@ export const spec = { const bidResponses = []; let response = serverResponse.body; try { - if (response && !response.isNoAd) { + if (response && !response.isNoAd && (response.ad || response.adUrl)) { const bidRequest = JSON.parse(bidRequestString.data); let bidResponse = { @@ -249,24 +267,21 @@ export const spec = { * * @param {object} bid Bid request object * @param {string} currency Ad server currency + * @param {string} mediaType Bid media type * @return {number} Floor price */ - getBidFloor: function (bid, currency) { + getBidFloor: function (bid, currency, mediaType) { if (!isFn(bid.getFloor)) { return DEFAULT_FLOOR; } const floor = bid.getFloor({ currency: currency || 'USD', - mediaType: '*', + mediaType, size: '*' }); - if (isPlainObject(floor) && !isNaN(floor.floor)) { - return floor.floor; - } - - return DEFAULT_FLOOR; + return isPlainObject(floor) && !isNaN(floor.floor) ? floor.floor : DEFAULT_FLOOR; }, /** diff --git a/modules/smartxBidAdapter.js b/modules/smartxBidAdapter.js index e5f71265e34..d91b62729bc 100644 --- a/modules/smartxBidAdapter.js +++ b/modules/smartxBidAdapter.js @@ -10,8 +10,10 @@ import { } from '../src/mediaTypes.js'; const BIDDER_CODE = 'smartx'; const URL = 'https://bid.sxp.smartclip.net/bid/1000'; +const GVLID = 115; export const spec = { code: BIDDER_CODE, + gvlid: GVLID, supportedMediaTypes: [VIDEO], /** * Determines whether or not the given bid request is valid. @@ -67,7 +69,6 @@ export const spec = { * @return ServerRequest Info describing the request to the server. */ buildRequests: function (bidRequests, bidderRequest) { - // TODO: does the fallback make sense here? const page = bidderRequest.refererInfo.page || bidderRequest.refererInfo.topmostLocation; const isPageSecure = !!page.match(/^https:/) @@ -77,6 +78,7 @@ export const spec = { const bidfloor = getBidFloor(bid) || 0; const bidfloorcur = getBidIdParameter('bidfloorcur', bid.params) || 'EUR'; const siteId = getBidIdParameter('siteId', bid.params); + const sitekey = getBidIdParameter('sitekey', bid.params); const domain = getBidIdParameter('domain', bid.params); const cat = getBidIdParameter('cat', bid.params) || ['']; let pubcid = null; @@ -192,11 +194,25 @@ export const spec = { } } + // Add sitekey if available + if (sitekey) { + requestPayload.site.content.ext.sitekey = sitekey; + } + // Add common id if available if (pubcid) { userExt.fpc = pubcid; } + // Add schain object if available + if (bid && bid.schain) { + requestPayload['source'] = { + ext: { + schain: bid.schain + } + }; + } + // Only add the user object if it's not empty if (!isEmpty(userExt)) { requestPayload.user = { @@ -204,9 +220,7 @@ export const spec = { }; } - // requestPayload.user.ext.ver = pbjs.version; - - // Targeting + // Add targeting if (getBidIdParameter('data', bid.params.user)) { var targetingarr = []; for (var i = 0; i < bid.params.user.data.length; i++) { @@ -225,8 +239,6 @@ export const spec = { } } - // Todo: USER ID MODULE - requestPayload.user = { ext: userExt, data: targetingarr @@ -241,7 +253,7 @@ export const spec = { options: { contentType: 'application/json', customHeaders: { - 'x-openrtb-version': '2.3' + 'x-openrtb-version': '2.5' } } }; @@ -269,7 +281,6 @@ export const spec = { } /** * Make sure currency and price are the right ones - * TODO: what about the pre_market_bid partners sizes? */ _each(currentBidRequest.params.pre_market_bids, function (pmb) { if (pmb.deal_id == smartxBid.id) { diff --git a/modules/smartyadsBidAdapter.md b/modules/smartyadsBidAdapter.md index f078d905e62..e0d6023a794 100644 --- a/modules/smartyadsBidAdapter.md +++ b/modules/smartyadsBidAdapter.md @@ -10,6 +10,15 @@ Maintainer: supply@smartyads.com Module that connects to SmartyAds' demand sources +# Parameters + +| Name | Scope | Description | Example | +| :------------ | :------- | :------------------------ | :------------------- | +| `sourceid` | required (for prebid.js) | placement ID | "0" | +| `host` | required (for prebid-server) | const value, set to "prebid" | "prebid" | +| `accountid` | required (for prebid-server) | partner ID | "1901" | +| `traffic` | optional (for prebid.js) | Configures the mediaType that should be used. Values can be banner, native or video | "banner" | + # Test Parameters ``` var adUnits = [ diff --git a/modules/smartytechBidAdapter.js b/modules/smartytechBidAdapter.js new file mode 100644 index 00000000000..9f275a761c7 --- /dev/null +++ b/modules/smartytechBidAdapter.js @@ -0,0 +1,135 @@ +import {buildUrl, deepAccess} from '../src/utils.js' +import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; + +const BIDDER_CODE = 'smartytech'; +export const ENDPOINT_PROTOCOL = 'https'; +export const ENDPOINT_DOMAIN = 'server.smartytech.io'; +export const ENDPOINT_PATH = '/hb/v2/bidder'; + +export const spec = { + supportedMediaTypes: [ BANNER, VIDEO ], + code: BIDDER_CODE, + + isBidRequestValid: function (bidRequest) { + return ( + !!parseInt(bidRequest.params.endpointId) && + spec._validateBanner(bidRequest) && + spec._validateVideo(bidRequest) + ); + }, + + _validateBanner: function(bidRequest) { + const bannerAdUnit = deepAccess(bidRequest, 'mediaTypes.banner'); + + if (bannerAdUnit === undefined) { + return true; + } + + if (!Array.isArray(bannerAdUnit.sizes)) { + return false; + } + + return true; + }, + + _validateVideo: function(bidRequest) { + const videoAdUnit = deepAccess(bidRequest, 'mediaTypes.video'); + + if (videoAdUnit === undefined) { + return true; + } + + if (!Array.isArray(videoAdUnit.playerSize)) { + return false; + } + + if (!videoAdUnit.context) { + return false; + } + + return true; + }, + + buildRequests: function (validBidRequests, bidderRequest) { + const referer = bidderRequest?.refererInfo?.page || window.location.href; + + const bidRequests = validBidRequests.map((validBidRequest) => { + let video = deepAccess(validBidRequest, 'mediaTypes.video', false); + let banner = deepAccess(validBidRequest, 'mediaTypes.banner', false); + + let oneRequest = { + endpointId: validBidRequest.params.endpointId, + adUnitCode: validBidRequest.adUnitCode, + referer: referer, + bidId: validBidRequest.bidId + }; + + if (video) { + oneRequest.video = video; + } else if (banner) { + oneRequest.banner = banner; + } + + return oneRequest + }); + + let adPartnerRequestUrl = buildUrl({ + protocol: ENDPOINT_PROTOCOL, + hostname: ENDPOINT_DOMAIN, + pathname: ENDPOINT_PATH, + }); + + return { + method: 'POST', + url: adPartnerRequestUrl, + data: bidRequests + }; + }, + + interpretResponse: function (serverResponse, bidRequest) { + if (typeof serverResponse.body === 'undefined') { + return []; + } + + const validBids = bidRequest.data; + const keys = Object.keys(serverResponse.body) + const responseBody = serverResponse.body; + + return keys.filter(key => { + return responseBody[key].ad + }).map(key => { + return { + bid: validBids.find(b => b.adUnitCode === key), + response: responseBody[key] + } + }).map(item => spec._adResponse(item.bid, item.response)); + }, + + _adResponse: function (request, response) { + const bidObject = { + requestId: request.bidId, + adUnitCode: request.adUnitCode, + bidderCode: BIDDER_CODE, + ad: response.ad, + cpm: response.cpm, + width: response.width, + height: response.height, + ttl: 60, + creativeId: response.creativeId, + netRevenue: true, + currency: response.currency, + mediaType: BANNER + } + + if (response.mediaType === VIDEO) { + bidObject.vastXml = response.ad; + bidObject.mediaType = VIDEO; + } + + return bidObject; + }, + +} + +registerBidder(spec); diff --git a/modules/smartytechBidAdapter.md b/modules/smartytechBidAdapter.md new file mode 100644 index 00000000000..9df57ddbde7 --- /dev/null +++ b/modules/smartytechBidAdapter.md @@ -0,0 +1,55 @@ +# Overview + +``` +Module Name: SmartyTech Bid Adapter +Module Type: Bidder Adapter +Maintainer: info@adpartner.pro +``` + +# Description + +Connects to SmartyTech's exchange for bids. + +SmartyTech bid adapter supports Banner and Video + +# Sample Ad Unit: For Publishers +## Sample Banner Ad Unit +``` +var adUnits = [{ + code: '/123123123/prebidjs-banner', + mediaTypes: { + banner: { + sizes: [ + [300, 301], + [300, 250] + ] + } + }, + bids: [{ + bidder: 'smartytech', + params: { + endpointId: 12 + } + }] +}]; +``` + +## Sample Video Ad Unit +``` +var videoAdUnit = { + code: '/123123123/video-vast-banner', + mediaTypes: { + video: { + context: 'instream', + playerSize: [640, 480], + mimes: ['video/mp4'], + } + }, + bids: [{ + bidder: 'smartytech', + params: { + endpointId: 12 + } + }] +}; +``` diff --git a/modules/smilewantedBidAdapter.js b/modules/smilewantedBidAdapter.js index f82e7c9258f..fe14c57d641 100644 --- a/modules/smilewantedBidAdapter.js +++ b/modules/smilewantedBidAdapter.js @@ -63,6 +63,11 @@ export const spec = { payload.gdpr_consent = bidderRequest.gdprConsent.consentString; payload.gdpr = bidderRequest.gdprConsent.gdprApplies; // we're handling the undefined case server side } + + if (bid && bid.userIdAsEids) { + payload.eids = bid.userIdAsEids; + } + var payloadString = JSON.stringify(payload); return { method: 'POST', diff --git a/modules/smnBidAdapter.md b/modules/smnBidAdapter.md new file mode 100644 index 00000000000..c9cb777e743 --- /dev/null +++ b/modules/smnBidAdapter.md @@ -0,0 +1,52 @@ +# Overview + +Module Name: SMN Bidder Adapter +Module Type: Bidder Adapter +Maintainer: smnoffice.belgrade@gmail.com + +# Description + +Connects to SMN demand source to fetch bids. +Banner and Video formats are supported. +Please use ```smn``` as the bidder code. + +# Test Parameters +``` + var adUnits = [ + { + code: 'desktop-banner-ad-div', + sizes: [[300, 250]], // a display size + bids: [ + { + bidder: "smn", + params: { + zone: '2eb6bd58-865c-47ce-af7f-a918108c3fd2' + } + } + ] + },{ + code: 'mobile-banner-ad-div', + sizes: [[300, 50]], // a mobile size + bids: [ + { + bidder: "smn", + params: { + zone: '62211486-c50b-4356-9f0f-411778d31fcc' + } + } + ] + },{ + code: 'video-ad', + sizes: [[300, 50]], + mediaType: 'video', + bids: [ + { + bidder: "smn", + params: { + zone: 'ebeb1e79-8cb4-4473-b2d0-2e24b7ff47fd' + } + } + ] + }, + ]; +``` diff --git a/modules/sonobiBidAdapter.js b/modules/sonobiBidAdapter.js index 3c841cc4d8a..87358705cb5 100644 --- a/modules/sonobiBidAdapter.js +++ b/modules/sonobiBidAdapter.js @@ -1,5 +1,5 @@ import { registerBidder } from '../src/adapters/bidderFactory.js'; -import { parseSizesInput, logError, generateUUID, isEmpty, deepAccess, logWarn, logMessage, deepClone, getGptSlotInfoForAdUnitCode, isFn, isPlainObject } from '../src/utils.js'; +import { parseSizesInput, logError, generateUUID, isEmpty, deepAccess, logWarn, logMessage, getGptSlotInfoForAdUnitCode, isFn, isPlainObject } from '../src/utils.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; import { config } from '../src/config.js'; import { Renderer } from '../src/Renderer.js'; @@ -132,15 +132,6 @@ export const spec = { if (validBidRequests[0].schain) { payload.schain = JSON.stringify(validBidRequests[0].schain); } - if (deepAccess(validBidRequests[0], 'userId') && Object.keys(validBidRequests[0].userId).length > 0) { - const userIds = deepClone(validBidRequests[0].userId); - - if (userIds.id5id) { - userIds.id5id = deepAccess(userIds, 'id5id.uid'); - } - - payload.userid = JSON.stringify(userIds); - } const eids = deepAccess(validBidRequests[0], 'userIdAsEids'); if (Array.isArray(eids) && eids.length > 0) { @@ -295,22 +286,29 @@ function _findBidderRequest(bidderRequests, bidId) { } } +// This function takes all the possible sizes. +// returns string csv. function _validateSize(bid) { - if (deepAccess(bid, 'mediaTypes.video')) { - return ''; // Video bids arent allowed to override sizes via the trinity request + let size = []; + if (deepAccess(bid, 'mediaTypes.video.playerSize')) { + size.push(deepAccess(bid, 'mediaTypes.video.playerSize')) } - - if (bid.params.sizes) { - return parseSizesInput(bid.params.sizes).join(','); + if (deepAccess(bid, 'mediaTypes.video.sizes')) { + size.push(deepAccess(bid, 'mediaTypes.video.sizes')) + } + if (deepAccess(bid, 'params.sizes')) { + size.push(deepAccess(bid, 'params.sizes')); } if (deepAccess(bid, 'mediaTypes.banner.sizes')) { - return parseSizesInput(deepAccess(bid, 'mediaTypes.banner.sizes')).join(','); + size.push(deepAccess(bid, 'mediaTypes.banner.sizes')) } - - // Handle deprecated sizes definition - if (bid.sizes) { - return parseSizesInput(bid.sizes).join(','); + if (deepAccess(bid, 'sizes')) { + size.push(deepAccess(bid, 'sizes')) } + // Pass the 2d sizes array into parseSizeInput to flatten it into an array of x separated sizes. + // Then throw it into Set to uniquify it. + // Then spread it to an array again. Then join it into a csv of sizes. + return [...new Set(parseSizesInput(...size))].join(','); } function _validateSlot(bid) { diff --git a/modules/sspBCBidAdapter.js b/modules/sspBCBidAdapter.js index ffe2bef054c..acfa9fe7945 100644 --- a/modules/sspBCBidAdapter.js +++ b/modules/sspBCBidAdapter.js @@ -10,10 +10,9 @@ const BIDDER_CODE = 'sspBC'; const BIDDER_URL = 'https://ssp.wp.pl/bidder/'; const SYNC_URL = 'https://ssp.wp.pl/bidder/usersync'; const NOTIFY_URL = 'https://ssp.wp.pl/bidder/notify'; -const TRACKER_URL = 'https://bdr.wpcdn.pl/tag/jstracker.js'; const GVLID = 676; const TMAX = 450; -const BIDDER_VERSION = '5.7'; +const BIDDER_VERSION = '5.8'; const DEFAULT_CURRENCY = 'PLN'; const W = window; const { navigator } = W; @@ -23,6 +22,39 @@ const adSizesCalled = {}; const pageView = {}; var consentApiVersion; +/** + * Native asset mapping - we use constant id per type + * id > 10 indicates additional images + */ +var nativeAssetMap = { + title: 0, + cta: 1, + icon: 2, + image: 3, + body: 4, + sponsoredBy: 5 +}; + +/** + * return native asset type, based on asset id + * @param {int} id - native asset id + * @returns {string} asset type + */ +const getNativeAssetType = id => { + // id>10 will always be an image... + if (id > 10) { + return 'image'; + } + + // ...others should be decoded from nativeAssetMap + for (let assetName in nativeAssetMap) { + const assetId = nativeAssetMap[assetName]; + if (assetId === id) { + return assetName; + } + } +} + /** * Get preferred language of browser (i.e. user) * @returns {string} languageCode - ISO language code @@ -42,6 +74,16 @@ const getContentLanguage = () => { } }; +/** + * Get Bid parameters - returns bid params from Object, or 1el array + * @param {*} bidData - bid (bidWon), or array of bids (timeout) + * @returns {object} params object + */ +const unpackParams = (bidParams) => { + const result = isArray(bidParams) ? bidParams[0] : bidParams; + return result || {}; +} + /** * Get bid parameters for notification * @param {*} bidData - bid (bidWon), or array of bids (timeout) @@ -58,8 +100,7 @@ const getNotificationPayload = bidData => { } bids.forEach(bid => { const { adUnitCode, auctionId, cpm, creativeId, meta, params: bidParams, requestId, timeout } = bid; - let params = isArray(bidParams) ? bidParams[0] : bidParams; - params = params || {}; + const params = unpackParams(bidParams); // basic notification data const bidBasicData = { @@ -178,6 +219,46 @@ const applyGdpr = (bidderRequest, ortbRequest) => { } } +/** + * Get highest floorprice for a given adslot + * (sspBC adapter accepts one floor per imp) + * returns floor = 0 if getFloor() is not defined + * + * @param {object} slot bid request adslot + * @returns {float} floorprice + */ +const getHighestFloor = (slot) => { + const currency = getCurrency(); + let result = { floor: 0, currency }; + + if (typeof slot.getFloor === 'function') { + let bannerFloor = 0; + + if (slot.sizes.length) { + bannerFloor = slot.sizes.reduce(function (prev, next) { + const { floor: currentFloor = 0 } = slot.getFloor({ + mediaType: 'banner', + size: next, + currency + }); + return prev > currentFloor ? prev : currentFloor; + }, 0); + } + + const { floor: nativeFloor = 0 } = slot.getFloor({ + mediaType: 'native', currency + }); + + const { floor: videoFloor = 0 } = slot.getFloor({ + mediaType: 'video', currency + }); + + result.floor = Math.max(bannerFloor, nativeFloor, videoFloor); + } + + return result; +}; + /** * Get currency (either default or adserver) * @returns {string} currency name @@ -226,71 +307,111 @@ const mapBanner = slot => { * @param {object} paramValue Native parameter value * @returns {object} native asset object that conforms to ortb native ads spec */ -const mapAsset = (paramName, paramValue) => { - let asset; - switch (paramName) { - case 'title': - asset = { - id: 0, - required: paramValue.required, - title: { len: paramValue.len } - } - break; - case 'cta': - asset = { - id: 1, - required: paramValue.required, - data: { type: 12 } - } - break; - case 'icon': - asset = { - id: 2, - required: paramValue.required, - img: { type: 1, w: paramValue.sizes[0], h: paramValue.sizes[1] } - } - break; - case 'image': - asset = { - id: 3, - required: paramValue.required, - img: { type: 3, w: paramValue.sizes[0], h: paramValue.sizes[1] } - } - break; - case 'body': - asset = { - id: 4, - required: paramValue.required, - data: { type: 2 } - } - break; - case 'sponsoredBy': - asset = { - id: 5, - required: paramValue.required, - data: { type: 1 } - } - break; +var mapAsset = function mapAsset(paramName, paramValue) { + const { required, sizes, wmin, hmin, len } = paramValue; + var id = nativeAssetMap[paramName]; + var assets = []; + + if (id !== undefined) { + switch (paramName) { + case 'title': + assets.push({ + id: id, + required: required, + title: { + len: len + } + }); + break; + + case 'cta': + assets.push({ + id: id, + required: required, + data: { + type: 12 + } + }); + break; + + case 'icon': + assets.push({ + id: id, + required: required, + img: { + type: 1, + w: sizes && sizes[0], + h: sizes && sizes[1] + } + }); + break; + + case 'image': + var hasMultipleImages = sizes && Array.isArray(sizes[0]); + var imageSizes = hasMultipleImages ? sizes : [sizes]; + + for (var i = 0; i < imageSizes.length; i++) { + assets.push({ + id: i > 0 ? 10 + i : id, + required: required, + img: { + type: 3, + w: imageSizes[i][0], + h: imageSizes[i][1], + wmin: wmin, + hmin: hmin + } + }); + } + + break; + + case 'body': + assets.push({ + id: id, + required: required, + data: { + type: 2 + } + }); + break; + + case 'sponsoredBy': + assets.push({ + id: id, + required: required, + data: { + type: 1 + } + }); + break; + } } - return asset; -} + + return assets; +}; /** * @param {object} slot Ad Unit Params by Prebid * @returns {object} native object that conforms to ortb native ads spec */ -const mapNative = slot => { +const mapNative = (slot) => { const native = deepAccess(slot, 'mediaTypes.native'); - let assets; if (native) { - const nativeParams = Object.keys(native); - assets = []; - nativeParams.forEach(par => { - const newAsset = mapAsset(par, native[par]); - if (newAsset) { assets.push(newAsset) }; + var nativeParams = Object.keys(native); + var assets = []; + nativeParams.forEach(function (par) { + var newAssets = mapAsset(par, native[par]); + assets = assets.concat(newAssets); }); + return { + request: JSON.stringify({ + native: { + assets: assets + } + }) + }; } - return assets ? { request: JSON.stringify({ native: { assets } }) } : undefined; } var mapVideo = (slot, videoFromBid) => { @@ -346,41 +467,18 @@ const mapImpression = slot => { const imp = { id: id && siteId ? id.padStart(3, '0') : 'bidid-' + bidId, banner: mapBanner(slot), - native: mapNative(slot), + native: mapNative(slot, bidId), video: mapVideo(slot, video), tagid: adUnitCode, ext, }; // Check floorprices for this imp - const currency = getCurrency(); - if (typeof slot.getFloor === 'function') { - var bannerFloor = 0; - var nativeFloor = 0; - var videoFloor = 0; // sspBC adapter accepts only floor per imp - check for maximum value for requested ad types and sizes - - if (slot.sizes.length) { - bannerFloor = slot.sizes.reduce(function (prev, next) { - var currentFloor = slot.getFloor({ - mediaType: 'banner', - size: next, - currency - }).floor; - return prev > currentFloor ? prev : currentFloor; - }, 0); - } + const { floor, currency } = getHighestFloor(slot); - nativeFloor = slot.getFloor({ - mediaType: 'native', currency - }); - videoFloor = slot.getFloor({ - mediaType: 'video', currency - }); - imp.bidfloor = Math.max(bannerFloor, nativeFloor, videoFloor); - } else { - imp.bidfloor = 0; - } + imp.bidfloor = floor; imp.bidfloorcur = currency; + return imp; } @@ -395,50 +493,51 @@ const isNativeAd = bid => { return bid.admNative || (bid.adm && bid.adm.match(xmlTester)); } -const parseNative = nativeData => { - const result = {}; - nativeData.assets.forEach(asset => { - const id = parseInt(asset.id); - switch (id) { - case 0: - result.title = asset.title.text; - break; - case 1: - result.cta = asset.data.value; - break; - case 2: - result.icon = { - url: asset.img.url, - width: asset.img.w, - height: asset.img.h, - }; - break; - case 3: - result.image = { - url: asset.img.url, - width: asset.img.w, - height: asset.img.h, - }; - break; - case 4: - result.body = asset.data.value; - break; - case 5: - result.sponsoredBy = asset.data.value; - break; +const parseNative = (nativeData) => { + const { link = {}, imptrackers: impressionTrackers, jstracker } = nativeData; + const { url: clickUrl, clicktrackers: clickTrackers = [] } = link; - default: - logWarn('Unrecognized native asset', asset); + const result = { + clickUrl, + clickTrackers, + impressionTrackers, + javascriptTrackers: isArray(jstracker) ? jstracker : jstracker && [jstracker], + }; + + nativeData.assets.forEach(asset => { + const { id, img = {}, title = {}, data = {} } = asset; + const { w: imgWidth, h: imgHeight, url: imgUrl, type: imgType } = img; + const { type: dataType, value: dataValue } = data; + const { text: titleText } = title; + const detectedType = getNativeAssetType(id); + if (titleText) { + result.title = titleText; + } + if (imgUrl) { + // image or icon + const thisImage = { + url: imgUrl, + width: imgWidth, + height: imgHeight, + }; + if (imgType === 3 || detectedType === 'image') { + result.image = thisImage; + } else if (imgType === 1 || detectedType === 'icon') { + result.icon = thisImage; + } + } + if (dataValue) { + // call-to-action, sponsored-by or body + if (dataType === 1 || detectedType === 'sponsoredBy') { + result.sponsoredBy = dataValue; + } else if (dataType === 2 || detectedType === 'body') { + result.body = dataValue; + } else if (dataType === 12 || detectedType === 'cta') { + result.cta = dataValue; + } } }); - result.clickUrl = nativeData.link.url; - result.impressionTrackers = nativeData.imptrackers; - if (isArray(nativeData.jstracker)) { - result.javascriptTrackers = nativeData.jstracker; - } else if (nativeData.jstracker) { - result.javascriptTrackers = [nativeData.jstracker]; - } return result; } @@ -505,10 +604,6 @@ const renderCreative = (site, auctionId, bid, seat, request) => { window.requestPVID = "${pageView.id}"; `; - if (gam) { - adcode += `window.gam = ${JSON.stringify(gam)};`; - } - adcode += ` @@ -550,7 +645,7 @@ const spec = { const payload = { id: bidderRequest.auctionId, site: { - id: siteId, + id: siteId ? `${siteId}` : undefined, publisher: publisherId ? { id: publisherId } : undefined, page, domain, @@ -586,7 +681,7 @@ const spec = { const { bidderRequest } = request; const response = serverResponse.body; const bids = []; - const site = JSON.parse(request.data).site; // get page and referer data from request + let site = JSON.parse(request.data).site; // get page and referer data from request site.sn = response.sn || 'mc_adapter'; // WPM site name (wp_sn) pageView.sn = site.sn; // store site_name (for syncing and notifications) let seat; @@ -597,39 +692,35 @@ const spec = { 'bidid-' prefix indicates oneCode (parameterless) request and response */ response.seatbid.forEach(seatbid => { - let creativeCache; seat = seatbid.seat; seatbid.bid.forEach(serverBid => { // get data from bid response - const { adomain, crid = `mcad_${bidderRequest.auctionId}_${site.slot}`, impid, exp = 300, ext, price, w, h } = serverBid; + const { adomain, crid = `mcad_${bidderRequest.auctionId}_${site.slot}`, impid, exp = 300, ext = {}, price, w, h } = serverBid; const bidRequest = bidderRequest.bids.filter(b => { - const { bidId, params = {} } = b; + const { bidId, params: requestParams = {} } = b; + const params = unpackParams(requestParams); const { id, siteId } = params; const currentBidId = id && siteId ? id : 'bidid-' + bidId; return currentBidId === impid; })[0]; - // get data from linked bidRequest - const { bidId, params } = bidRequest || {}; - - // get slot id for current bid - site.slot = params && params.id; - - if (ext) { - /* - bid response might include ext object containing siteId / slotId, as detected by OneCode - update site / slot data in this case - - ext also might contain publisherId and custom ad label - */ - const { siteid, slotid, pubid, adlabel, cache } = ext; - site.id = siteid || site.id; - site.slot = slotid || site.slot; - site.publisherId = pubid; - site.adLabel = adlabel; - creativeCache = cache; - } + // get bidid from linked bidRequest + const { bidId } = bidRequest || {}; + + // get ext data from bid + const { siteid = site.id, slotid = site.slot, pubid, adlabel, cache: creativeCache, vurls = [] } = ext; + + // update site data + site = { + ...site, + ...{ + id: siteid, + slot: slotid, + publisherId: pubid, + adLabel: adlabel + } + }; if (bidRequest && site.id && !strIncludes(site.id, 'bidid')) { // found a matching request; add this bid @@ -652,6 +743,7 @@ const spec = { pricepl: ext && ext.pricepl, }, netRevenue: true, + vurls, }; // mediaType and ad data for instream / native / banner @@ -671,24 +763,6 @@ const spec = { bid.native = parseNative(nativeData); bid.width = 1; bid.height = 1; - - // append viewability tracker - const jsData = { - rid: bidRequest.auctionId, - crid: bid.creativeId, - adunit: bidRequest.adUnitCode, - url: bid.native.clickUrl, - vendor: seat, - site: site.id, - slot: site.slot, - cpm: bid.cpm.toPrecision(4), - }; - const jsTracker = '`, meta: { - advertiserDomains: (matchedBid.advertiser) ? matchedBid.advertiser : 'n/a' - } - } + advertiserDomains: (matchedBid.advertiser) ? matchedBid.advertiser : 'n/a', + }, + }; if (isVideo(bidRequest, adType)) { - const playersize = getPlayerSize(bidRequest) + const playersize = getPlayerSize(bidRequest); if (playersize) { - bidResponse.width = playersize[0] - bidResponse.height = playersize[1] + bidResponse.width = playersize[0]; + bidResponse.height = playersize[1]; } - bidResponse.mediaType = VIDEO - bidResponse.vastUrl = `${ENDPOINT}/d/${matchedBid.id}/${bidRequest.params.supplyId}/?ts=${timestamp}${extId}${gdprApplies}${gdprConsent}${pvId}${iabContent}` + bidResponse.mediaType = VIDEO; + bidResponse.vastUrl = `${ENDPOINT}/d/${matchedBid.id}/${bidRequest.params.supplyId}/?ts=${timestamp}${extId}${gdprApplies}${gdprConsent}${pvId}${iabContent}`; if (isOutstream(bidRequest)) { const renderer = Renderer.install({ id: bidRequest.bidId, url: OUTSTREAMPLAYER_URL, - loaded: false - }) - renderer.setRender(outstreamRender) - bidResponse.renderer = renderer + loaded: false, + }); + renderer.setRender(outstreamRender); + bidResponse.renderer = renderer; } } if (isNative(bidRequest, adType)) { // there may be publishers still rely on it - const url = `${ENDPOINT}/d/${matchedBid.id}/${bidRequest.params.supplyId}/?ts=${timestamp}${extId}${gdprApplies}${gdprConsent}${pvId}` - bidResponse.adUrl = url - bidResponse.mediaType = NATIVE - const nativeImageAssetObj = find(matchedBid.native.assets, e => e.id === 2) + const url = `${ENDPOINT}/d/${matchedBid.id}/${bidRequest.params.supplyId}/?ts=${timestamp}${extId}${gdprApplies}${gdprConsent}${pvId}`; + bidResponse.adUrl = url; + bidResponse.mediaType = NATIVE; + const nativeImageAssetObj = find(matchedBid.native.assets, e => e.id === 2); const nativeImageAsset = nativeImageAssetObj ? nativeImageAssetObj.img : { url: '', w: 0, h: 0 }; - const nativeTitleAsset = find(matchedBid.native.assets, e => e.id === 1) - const nativeBodyAsset = find(matchedBid.native.assets, e => e.id === 3) + const nativeTitleAsset = find(matchedBid.native.assets, e => e.id === 1); + const nativeBodyAsset = find(matchedBid.native.assets, e => e.id === 3); bidResponse.native = { title: nativeTitleAsset ? nativeTitleAsset.title.text : '', body: nativeBodyAsset ? nativeBodyAsset.data.value : '', @@ -197,10 +204,10 @@ export const spec = { }; } - bidResponses.push(bidResponse) + bidResponses.push(bidResponse); } - }) - return bidResponses + }); + return bidResponses; }, /** @@ -212,13 +219,13 @@ export const spec = { * @param {string} uspConsent Is the US Privacy Consent string. * @return {UserSync[]} The user syncs which should be dropped. */ - getUserSyncs: function (syncOptions, serverResponses, gdprConsent, uspConsent) { + getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent) { const syncs = []; if (syncOptions.iframeEnabled) { const params = []; params.push(`ts=${timestamp()}`); - params.push(`type=h`) + params.push(`type=h`); if (gdprConsent && (typeof gdprConsent.gdprApplies === 'boolean')) { params.push(`gdpr=${Number(gdprConsent.gdprApplies)}`); } @@ -227,12 +234,12 @@ export const spec = { } syncs.push({ type: 'iframe', - url: `${ENDPOINT}/d/6846326/766/2x2?${params.join('&')}` + url: `${ENDPOINT}/d/6846326/766/2x2?${params.join('&')}`, }); } return syncs; - } + }, }; /** @@ -242,7 +249,7 @@ export const spec = { * @returns {Boolean} */ function isVideo(format, adtype) { - return deepAccess(format, 'mediaTypes.video') && adtype.toLowerCase() === 'video' + return deepAccess(format, 'mediaTypes.video') && adtype.toLowerCase() === 'video'; } /** @@ -252,7 +259,7 @@ function isVideo(format, adtype) { * @returns {Boolean} */ function isNative(format, adtype) { - return deepAccess(format, 'mediaTypes.native') && adtype.toLowerCase() === 'native' + return deepAccess(format, 'mediaTypes.native') && adtype.toLowerCase() === 'native'; } /** @@ -261,8 +268,8 @@ function isNative(format, adtype) { * @returns {Boolean} */ function isOutstream(format) { - const context = deepAccess(format, 'mediaTypes.video.context') - return (context === 'outstream') + const context = deepAccess(format, 'mediaTypes.video.context'); + return (context === 'outstream'); } /** @@ -271,30 +278,45 @@ function isOutstream(format) { * @returns {Array} */ function getPlayerSize(format) { - const playerSize = deepAccess(format, 'mediaTypes.video.playerSize') - return (playerSize && isArray(playerSize[0])) ? playerSize[0] : playerSize + const playerSize = deepAccess(format, 'mediaTypes.video.playerSize'); + return (playerSize && isArray(playerSize[0])) ? playerSize[0] : playerSize; } /** - * Expands a 'WxH' string as a 2-element [W, H] array + * Expands a 'WxH' string to a 2-element [W, H] array * @param {String} size * @returns {Array} */ function parseSize(size) { - return size.split(DIMENSION_SIGN).map(Number) + return size.split(DIMENSION_SIGN).map(Number); } /** * Creates a string out of an array of eids with source and uid - * @param {Array} eids + * @param {Array.<{source: String, uids: Array.<{id: String, atype: Number, ext: Object}>}>} eids * @returns {String} */ function createUserIdString(eids) { - const str = [] + const str = []; for (let i = 0; i < eids.length; i++) { - str.push(eids[i].source + ':' + eids[i].uids[0].id) + str.push(eids[i].source + ':' + eids[i].uids[0].id); } - return str.join(',') + return str.join(','); +} + +/** + * Creates a string from an array of eids with ID provider and atype if atype exists + * @param {Array.<{source: String, uids: Array.<{id: String, atype: Number, ext: Object}>}>} eids + * @returns {String} idprovider:atype,idprovider2:atype2,... + */ +function createUserIdAtypesString(eids) { + const str = []; + for (let i = 0; i < eids.length; i++) { + if (eids[i].uids[0].atype) { + str.push(eids[i].source + ':' + eids[i].uids[0].atype); + } + } + return str.join(','); } /** @@ -303,18 +325,18 @@ function createUserIdString(eids) { * @returns {String} */ function createQueryString(obj) { - const str = [] + const str = []; for (const p in obj) { if (obj.hasOwnProperty(p)) { - const val = obj[p] + const val = obj[p]; if (p !== 'schain' && p !== 'iab_content') { - str.push(encodeURIComponent(p) + '=' + encodeURIComponent(val)) + str.push(encodeURIComponent(p) + '=' + encodeURIComponent(val)); } else { - str.push(p + '=' + val) + str.push(p + '=' + val); } } } - return str.join('&') + return str.join('&'); } /** @@ -323,15 +345,15 @@ function createQueryString(obj) { * @returns {String} */ function createTargetingString(obj) { - const str = [] + const str = []; for (const p in obj) { if (obj.hasOwnProperty(p)) { - const key = p - const val = obj[p] - str.push(key + '=' + val) + const key = p; + const val = obj[p]; + str.push(key + '=' + val); } } - return str.join('&') + return str.join('&'); } /** @@ -340,13 +362,13 @@ function createTargetingString(obj) { * @returns {String} */ function createSchainString(schain) { - const ver = schain.ver || '' - const complete = (schain.complete === 1 || schain.complete === 0) ? schain.complete : '' - const keys = ['asi', 'sid', 'hp', 'rid', 'name', 'domain', 'ext'] + const ver = schain.ver || ''; + const complete = (schain.complete === 1 || schain.complete === 0) ? schain.complete : ''; + const keys = ['asi', 'sid', 'hp', 'rid', 'name', 'domain', 'ext']; const nodesString = schain.nodes.reduce((acc, node) => { - return acc += `!${keys.map(key => node[key] ? encodeURIComponentWithBangIncluded(node[key]) : '').join(',')}` - }, '') - return `${ver},${complete}${nodesString}` + return acc += `!${keys.map(key => node[key] ? encodeURIComponentWithBangIncluded(node[key]) : '').join(',')}`; + }, ''); + return `${ver},${complete}${nodesString}`; } /** @@ -358,33 +380,44 @@ function createSchainString(schain) { */ function getContentObject(bid) { if (bid.params.iabContent && isPlainObject(bid.params.iabContent)) { - return bid.params.iabContent + return bid.params.iabContent; } const globalContent = deepAccess(bid, 'ortb2.site') ? deepAccess(bid, 'ortb2.site.content') - : deepAccess(bid, 'ortb2.app.content') + : deepAccess(bid, 'ortb2.app.content'); if (globalContent && isPlainObject(globalContent)) { - return globalContent + return globalContent; } - return undefined + return undefined; } /** - * Creates a string for iab_content object + * Creates a string for iab_content object by + * 1. flatten the iab content object + * 2. encoding the values + * 3. joining array of defined keys ('keyword', 'cat') into one value seperated with '|' + * 4. encoding the whole string * @param {Object} iabContent * @returns {String} */ function createIabContentString(iabContent) { - const arrKeys = ['keywords', 'cat'] - const str = [] - for (const key in iabContent) { - if (iabContent.hasOwnProperty(key)) { - const value = (arrKeys.indexOf(key) !== -1 && Array.isArray(iabContent[key])) - ? iabContent[key].map(node => encodeURIComponent(node)).join('|') : encodeURIComponent(iabContent[key]) - str.push(''.concat(key, ':', value)) + const arrKeys = ['keywords', 'cat']; + const str = []; + const transformObjToParam = (obj = {}, extraKey = '') => { + for (const key in obj) { + if ((arrKeys.indexOf(key) !== -1 && Array.isArray(obj[key]))) { + // Array of defined keyword which have to be joined into one value from "key: [value1, value2, value3]" to "key:value1|value2|value3" + str.push(''.concat(key, ':', obj[key].map(node => encodeURIComponent(node)).join('|'))); + } else if (typeof obj[key] !== 'object') { + str.push(''.concat(extraKey + key, ':', encodeURIComponent(obj[key]))); + } else { + // Object has to be further flattened + transformObjToParam(obj[key], ''.concat(extraKey, key, '.')); + } } - } - return encodeURIComponent(str.join(',')) + return str.join(','); + }; + return encodeURIComponent(transformObjToParam(iabContent)); } /** @@ -393,7 +426,7 @@ function createIabContentString(iabContent) { * @returns {String} */ function encodeURIComponentWithBangIncluded(str) { - return encodeURIComponent(str).replace(/!/g, '%21') + return encodeURIComponent(str).replace(/!/g, '%21'); } /** @@ -402,11 +435,11 @@ function encodeURIComponentWithBangIncluded(str) { */ function outstreamRender(bid) { bid.renderer.push(() => { - window.ma_width = bid.width - window.ma_height = bid.height - window.ma_vastUrl = bid.vastUrl - window.ma_container = bid.adUnitCode - window.document.dispatchEvent(new Event('ma-start-event')) + window.ma_width = bid.width; + window.ma_height = bid.height; + window.ma_vastUrl = bid.vastUrl; + window.ma_container = bid.adUnitCode; + window.document.dispatchEvent(new Event('ma-start-event')); }); } @@ -417,33 +450,33 @@ function outstreamRender(bid) { * @returns {string[]} */ function extractSizes(bid) { - const { mediaTypes } = bid // see https://docs.prebid.org/dev-docs/adunit-reference.html#examples - const sizes = [] + const { mediaTypes } = bid; // see https://docs.prebid.org/dev-docs/adunit-reference.html#examples + const sizes = []; if (isPlainObject(mediaTypes)) { - const { [BANNER]: bannerType } = mediaTypes + const { [BANNER]: bannerType } = mediaTypes; // only applies for multi size Adslots -> BANNER if (bannerType && isArray(bannerType.sizes)) { if (isArray(bannerType.sizes[0])) { // multiple sizes given - sizes.push(bannerType.sizes) + sizes.push(bannerType.sizes); } else { // just one size provided as array -> wrap to uniformly flatten later - sizes.push([bannerType.sizes]) + sizes.push([bannerType.sizes]); } } // The bid top level field `sizes` is deprecated and should not be used anymore. Keeping it for compatibility. } else if (isArray(bid.sizes)) { if (isArray(bid.sizes[0])) { - sizes.push(bid.sizes) + sizes.push(bid.sizes); } else { - sizes.push([bid.sizes]) + sizes.push([bid.sizes]); } } /** @type {Set} */ - const deduplicatedSizeStrings = new Set(sizes.flat().map(([width, height]) => width + DIMENSION_SIGN + height)) + const deduplicatedSizeStrings = new Set(sizes.flat().map(([width, height]) => width + DIMENSION_SIGN + height)); - return Array.from(deduplicatedSizeStrings) + return Array.from(deduplicatedSizeStrings); } /** @@ -452,7 +485,7 @@ function extractSizes(bid) { * * @param {Object} bid * @param {string[]} sizes - * @returns The floor CPM of a matched rule based on the rule selection process (mediaType, size and currency), + * @returns The floor CPM in cents of a matched rule based on the rule selection process (mediaType, size and currency), * using the getFloor() inputs. Multi sizes and unsupported media types will default to '*' */ function getBidFloor(bid, sizes) { @@ -464,12 +497,12 @@ function getBidFloor(bid, sizes) { const floor = bid.getFloor({ currency: CURRENCY_CODE, mediaType: mediaType !== undefined && spec.supportedMediaTypes.includes(mediaType) ? mediaType : '*', - size: sizes.length !== 1 ? '*' : extractSizes(sizes) + size: sizes.length !== 1 ? '*' : sizes[0].split(DIMENSION_SIGN), }); if (floor.currency === CURRENCY_CODE) { - return floor.floor; + return (floor.floor * 100).toFixed(0); } return undefined; } -registerBidder(spec) +registerBidder(spec); diff --git a/modules/yieldliftBidAdapter.js b/modules/yieldliftBidAdapter.js index 160d7e9a009..6e4bce15187 100644 --- a/modules/yieldliftBidAdapter.js +++ b/modules/yieldliftBidAdapter.js @@ -2,9 +2,9 @@ import {deepSetValue, logInfo, deepAccess} from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER} from '../src/mediaTypes.js'; -const ENDPOINT_URL = 'https://x.yieldlift.com/auction'; +const ENDPOINT_URL = 'https://x.yieldlift.com/pbjs'; -const DEFAULT_BID_TTL = 30; +const DEFAULT_BID_TTL = 300; const DEFAULT_CURRENCY = 'USD'; const DEFAULT_NET_REVENUE = true; @@ -98,7 +98,7 @@ export const spec = { width: bid.w, height: bid.h, ad: bid.adm, - ttl: DEFAULT_BID_TTL, + ttl: typeof bid.exp === 'number' ? bid.exp : DEFAULT_BID_TTL, creativeId: bid.crid, netRevenue: DEFAULT_NET_REVENUE, currency: DEFAULT_CURRENCY, diff --git a/modules/yieldmoBidAdapter.js b/modules/yieldmoBidAdapter.js index 892936ceea5..b4b916a1048 100644 --- a/modules/yieldmoBidAdapter.js +++ b/modules/yieldmoBidAdapter.js @@ -20,12 +20,15 @@ import {find, includes} from '../src/polyfill.js'; import {createEidsArray} from './userId/eids.js'; const BIDDER_CODE = 'yieldmo'; +const GVLID = 173; const CURRENCY = 'USD'; const TIME_TO_LIVE = 300; const NET_REVENUE = true; -const BANNER_SERVER_ENDPOINT = 'https://ads.yieldmo.com/exchange/prebid'; -const VIDEO_SERVER_ENDPOINT = 'https://ads.yieldmo.com/exchange/prebidvideo'; const PB_COOKIE_ASSIST_SYNC_ENDPOINT = `https://ads.yieldmo.com/pbcas`; +const BANNER_PATH = '/exchange/prebid'; +const VIDEO_PATH = '/exchange/prebidvideo'; +const STAGE_DOMAIN = 'https://ads-stg.yieldmo.com'; +const PROD_DOMAIN = 'https://ads.yieldmo.com'; const OUTSTREAM_VIDEO_PLAYER_URL = 'https://prebid-outstream.yieldmo.com/bundle.js'; const OPENRTB_VIDEO_BIDPARAMS = ['mimes', 'startdelay', 'placement', 'startdelay', 'skipafter', 'protocols', 'api', 'playbackmethod', 'maxduration', 'minduration', 'pos', 'skip', 'skippable']; @@ -40,7 +43,7 @@ const BANNER_REQUEST_PROPERTIES_TO_REDUCE = ['description', 'title', 'pr', 'page export const spec = { code: BIDDER_CODE, supportedMediaTypes: [BANNER, VIDEO], - + gvlid: GVLID, /** * Determines whether or not the given bid request is valid. * @param {object} bid, bid to validate @@ -59,6 +62,9 @@ export const spec = { * @return ServerRequest Info describing the request to the server. */ buildRequests: function (bidRequests, bidderRequest) { + const stage = isStage(bidderRequest); + const bannerUrl = getAdserverUrl(BANNER_PATH, stage); + const videoUrl = getAdserverUrl(VIDEO_PATH, stage); const bannerBidRequests = bidRequests.filter(request => hasBannerMediaType(request)); const videoBidRequests = bidRequests.filter(request => hasVideoMediaType(request)); let serverRequests = []; @@ -122,8 +128,8 @@ export const spec = { serverRequest.eids = JSON.stringify(eids); }; // check if url exceeded max length - const url = `${BANNER_SERVER_ENDPOINT}?${parseQueryStringParameters(serverRequest)}`; - let extraCharacters = url.length - MAX_BANNER_REQUEST_URL_LENGTH; + const fullUrl = `${bannerUrl}?${parseQueryStringParameters(serverRequest)}`; + let extraCharacters = fullUrl.length - MAX_BANNER_REQUEST_URL_LENGTH; if (extraCharacters > 0) { for (let i = 0; i < BANNER_REQUEST_PROPERTIES_TO_REDUCE.length; i++) { extraCharacters = shortcutProperty(extraCharacters, serverRequest, BANNER_REQUEST_PROPERTIES_TO_REDUCE[i]); @@ -136,7 +142,7 @@ export const spec = { serverRequests.push({ method: 'GET', - url: BANNER_SERVER_ENDPOINT, + url: bannerUrl, data: serverRequest }); } @@ -148,7 +154,7 @@ export const spec = { }; serverRequests.push({ method: 'POST', - url: VIDEO_SERVER_ENDPOINT, + url: videoUrl, data: serverRequest }); } @@ -249,7 +255,6 @@ function addPlacement(request) { if (transactionId) { placementInfo.tid = transactionId; } - if (request.auctionId) { placementInfo.auctionId = request.auctionId; } @@ -377,10 +382,11 @@ function openRtbRequest(bidRequests, bidderRequest) { const schain = bidRequests[0].schain; let openRtbRequest = { id: bidRequests[0].bidderRequestId, + tmax: bidderRequest.timeout || 400, at: 1, imp: bidRequests.map(bidRequest => openRtbImpression(bidRequest)), site: openRtbSite(bidRequests[0], bidderRequest), - device: openRtbDevice(bidRequests[0]), + device: deepAccess(bidderRequest, 'ortb2.device'), badv: bidRequests[0].params.badv || [], bcat: deepAccess(bidderRequest, 'bcat') || bidRequests[0].params.bcat || [], ext: { @@ -502,17 +508,6 @@ function openRtbSite(bidRequest, bidderRequest) { return result; } -/** - * @return Object OpenRTB's 'device' object - */ -function openRtbDevice(bidRequest) { - const deviceObj = { - ua: navigator.userAgent, - language: (navigator.language || navigator.browserLanguage || navigator.userLanguage || navigator.systemLanguage), - }; - return deviceObj; -} - /** * Updates openRtbRequest with GDPR info from bidderRequest, if present. * @param {Object} openRtbRequest OpenRTB's request to update. @@ -676,3 +671,12 @@ function canAccessTopWindow() { return false; } } + +function isStage(bidderRequest) { + return !!bidderRequest.refererInfo?.referer?.includes('pb_force_a'); +} + +function getAdserverUrl(path, stage) { + const domain = stage ? STAGE_DOMAIN : PROD_DOMAIN; + return `${domain}${path}`; +} diff --git a/modules/yieldoneBidAdapter.js b/modules/yieldoneBidAdapter.js index 4c5f1687641..d408a0595f9 100644 --- a/modules/yieldoneBidAdapter.js +++ b/modules/yieldoneBidAdapter.js @@ -4,6 +4,17 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; import { Renderer } from '../src/Renderer.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; +/** + * @typedef {import('../src/adapters/bidderFactory').Bid} Bid + * @typedef {import('../src/adapters/bidderFactory').BidRequest} BidRequest + * @typedef {import('../src/adapters/bidderFactory').BidderSpec} BidderSpec + * @typedef {import('../src/adapters/bidderFactory').ServerRequest} ServerRequest + * @typedef {import('../src/adapters/bidderFactory').ServerResponse} ServerResponse + * @typedef {import('../src/adapters/bidderFactory').SyncOptions} SyncOptions + * @typedef {import('../src/adapters/bidderFactory').UserSync} UserSync + * @typedef {import('../src/auction').BidderRequest} BidderRequest + */ + const BIDDER_CODE = 'yieldone'; const ENDPOINT_URL = 'https://y.one.impact-ad.jp/h_bid'; const USER_SYNC_URL = 'https://y.one.impact-ad.jp/push_sync'; @@ -13,13 +24,25 @@ const VIEWABLE_PERCENTAGE_URL = 'https://img.ak.impact-ad.jp/ic/pone/ivt/firstvi const DEFAULT_VIDEO_SIZE = {w: 640, h: 360}; +/** @type BidderSpec */ export const spec = { code: BIDDER_CODE, aliases: ['y1'], supportedMediaTypes: [BANNER, VIDEO], + /** + * Determines whether or not the given bid request is valid. + * @param {BidRequest} bid The bid params to validate. + * @returns {boolean} True if this is a valid bid, and false otherwise. + */ isBidRequestValid: function(bid) { return !!(bid.params.placementId); }, + /** + * Make a server request from the list of BidRequests. + * @param {Bid[]} validBidRequests - An array of bids. + * @param {BidderRequest} bidderRequest - bidder request object. + * @returns {ServerRequest|ServerRequest[]} ServerRequest Info describing the request to the server. + */ buildRequests: function(validBidRequests, bidderRequest) { return validBidRequests.map(bidRequest => { const params = bidRequest.params; @@ -96,6 +119,12 @@ export const spec = { }; }); }, + /** + * Unpack the response from the server into a list of bids. + * @param {ServerResponse} serverResponse - A successful response from the server. + * @param {BidRequest} bidRequests + * @returns {Bid[]} - An array of bids which were nested inside the server. + */ interpretResponse: function(serverResponse, bidRequest) { const bidResponses = []; const response = serverResponse.body; @@ -188,6 +217,11 @@ export const spec = { } return bidResponses; }, + /** + * Register the user sync pixels which should be dropped after the auction. + * @param {SyncOptions} syncOptions Which user syncs are allowed? + * @returns {UserSync[]} The user syncs which should be dropped. + */ getUserSyncs: function(syncOptions) { if (syncOptions.iframeEnabled) { return [{ @@ -202,7 +236,7 @@ export const spec = { * NOTE: server side does not yet support multiple formats. * @param {Object} bidRequest - * @param {boolean} [enabledOldFormat = true] - default: `true`. - * @return {string|null} - `"banner"` or `"video"` or `null`. + * @returns {string|null} - `"banner"` or `"video"` or `null`. */ function getMediaType(bidRequest, enabledOldFormat = true) { let hasBannerType = Boolean(deepAccess(bidRequest, 'mediaTypes.banner')); @@ -239,7 +273,7 @@ function getMediaType(bidRequest, enabledOldFormat = true) { * @param {Object} bidRequest.banner - * @param {Array} bidRequest.banner.sizes - * @param {boolean} [enabledOldFormat = true] - default: `true`. - * @return {string} - strings like `"300x250"` or `"300x250,728x90"`. + * @returns {string} - strings like `"300x250"` or `"300x250,728x90"`. */ function getBannerSizes(bidRequest, enabledOldFormat = true) { let sizes = deepAccess(bidRequest, 'mediaTypes.banner.sizes'); @@ -254,10 +288,10 @@ function getBannerSizes(bidRequest, enabledOldFormat = true) { /** * @param {Object} bidRequest - * @param {boolean} [enabledOldFormat = true] - default: `true`. - * @param {boolean} [enabledFlux = true] - default: `true`. - * @return {{w: number, h: number}} - + * @param {boolean} [enabled1x1 = true] - default: `true`. + * @returns {{w: number, h: number}} - */ -function getVideoSize(bidRequest, enabledOldFormat = true, enabledFlux = true) { +function getVideoSize(bidRequest, enabledOldFormat = true, enabled1x1 = true) { /** * @param {Array | Array>} sizes - * @return {{w: number, h: number} | null} - @@ -287,10 +321,10 @@ function getVideoSize(bidRequest, enabledOldFormat = true, enabledFlux = true) { playerSize = playerSize || _getPlayerSize(bidRequest.sizes); } - if (enabledFlux) { - // NOTE: `video.playerSize` in Flux is always [1,1]. + if (enabled1x1) { + // NOTE: `video.playerSize` in 1x1 is always [1,1]. if (playerSize && (playerSize.w === 1 && playerSize.h === 1)) { - // NOTE: `params.playerSize` is a specific object to support `FLUX`. + // NOTE: `params.playerSize` is a specific object to support `1x1`. playerSize = _getPlayerSize(deepAccess(bidRequest, 'params.playerSize')); } } @@ -298,6 +332,11 @@ function getVideoSize(bidRequest, enabledOldFormat = true, enabledFlux = true) { return playerSize || DEFAULT_VIDEO_SIZE; } +/** + * Create render for outstream video. + * @param {Object} serverResponse.body - + * @returns {Renderer} - Prebid Renderer object + */ function newRenderer(response) { const renderer = Renderer.install({ id: response.uid, @@ -314,12 +353,21 @@ function newRenderer(response) { return renderer; } +/** + * Handles an outstream response after the library is loaded + * @param {Object} bid + */ function outstreamRender(bid) { bid.renderer.push(() => { window.DACIVTPREBID.renderPrebid(bid); }); } +/** + * Create render for cmer outstream video. + * @param {Object} serverResponse.body - + * @returns {Renderer} - Prebid Renderer object + */ function newCmerRenderer(response) { const renderer = Renderer.install({ id: response.uid, @@ -336,6 +384,10 @@ function newCmerRenderer(response) { return renderer; } +/** + * Handles an outstream response after the library is loaded + * @param {Object} bid + */ function cmerRender(bid) { bid.renderer.push(() => { window.CMERYONEPREBID.renderPrebid(bid); diff --git a/modules/yieldoneBidAdapter.md b/modules/yieldoneBidAdapter.md index 1414d4e464f..d1306a08202 100644 --- a/modules/yieldoneBidAdapter.md +++ b/modules/yieldoneBidAdapter.md @@ -13,8 +13,7 @@ Connect to YIELDONE for bids. THE YIELDONE adapter requires setup and approval from the YIELDONE team. Please reach out to your account team or y1s@platform-one.co.jp for more information. -Note: THE YIELDONE adapter do not support "multi-format" scenario... if both -banner and video are specified as mediatypes, YIELDONE will treat it as a video unit. +YIELDONE adapter supports Banner, Video and Multi-Format(video, banner) currently. # Test Parameters ```javascript @@ -24,13 +23,16 @@ var adUnits = [ code: 'banner-div', mediaTypes: { banner: { - sizes: [[300, 250], [336, 280]] + sizes: [ + [300, 250], + [336, 280] + ] } }, bids: [{ bidder: 'yieldone', params: { - placementId: '36891' + placementId: '36891' // required } }] }, @@ -44,11 +46,109 @@ var adUnits = [ }, }, bids: [{ - bidder: 'yieldone', - params: { - placementId: '41993' - } - }] + bidder: "yieldone", + params: { + placementId: "36892", // required + playerParams: { // optional + wrapperWidth: "320px", // optional + wrapperHeight: "180px" // optional + }, + } + }] + }, + // Video adUnit(mediaTypes.video.playerSize: [1,1]) + { + code: 'video-1x1-div', + mediaTypes: { + video: { + playerSize: [[1, 1]], + context: 'outstream' + }, + }, + bids: [{ + bidder: 'yieldone', + params: { + placementId: "36892", // required + playerSize: [640, 360], // required + playerParams: { // optional + wrapperWidth: "320px", // optional + wrapperHeight: "180px" // optional + }, + } + }] + }, + // Multi-Format adUnit + { + code: "multi-format-div", + mediaTypes: { + banner: { + sizes: [ + [300, 250], + [1, 1] + ] + }, + video: { + playerSize: [640, 360], + context: "outstream" + } + }, + bids: [{ + // * "video" bid object should be placed before "banner" bid object. + // This bid will request a "video" media type ad. + bidder: "yieldone", + params: { + placementId: "36892", // required + playerParams: { // required + wrapperWidth: "320px", // optional + wrapperHeight: "180px" // optional + }, + } + }, + { + // This bid will request a "banner" media type ad. + bidder: "yieldone", + params: { + placementId: "36891" // required + } + } + ] + }, + // Multi-Format adUnit(mediaTypes.video.playerSize: [1,1]) + { + code: "multi-format-1x1-div", + mediaTypes: { + banner: { + sizes: [ + [300, 250], + [1, 1] + ] + }, + video: { + playerSize: [1, 1], + context: "outstream" + } + }, + bids: [{ + // * "video" bid object should be placed before "banner" bid object. + // This bid will request a "video" media type ad. + bidder: "yieldone", + params: { + placementId: "36892", // required + playerSize: [640, 360], // required + playerParams: { // required + wrapperWidth: "320px", // optional + wrapperHeight: "180px" // optional + }, + } + }, + { + // This bid will request a "banner" media type ad. + bidder: "yieldone", + params: { + placementId: "36891" // required + } + } + ] } ``` diff --git a/modules/zeta_global_sspBidAdapter.js b/modules/zeta_global_sspBidAdapter.js index 4689683fbc7..1ed35792285 100644 --- a/modules/zeta_global_sspBidAdapter.js +++ b/modules/zeta_global_sspBidAdapter.js @@ -3,9 +3,11 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; import {config} from '../src/config.js'; import {parseDomain} from '../src/refererDetection.js'; +import {ajax} from '../src/ajax.js'; const BIDDER_CODE = 'zeta_global_ssp'; const ENDPOINT_URL = 'https://ssp.disqus.com/bid/prebid'; +const TIMEOUT_URL = 'https://ssp.disqus.com/timeout/prebid'; const USER_SYNC_URL_IFRAME = 'https://ssp.disqus.com/sync?type=iframe'; const USER_SYNC_URL_IMAGE = 'https://ssp.disqus.com/sync?type=image'; const DEFAULT_CUR = 'USD'; @@ -90,6 +92,21 @@ export const spec = { if (!impData.banner && !impData.video) { impData.banner = buildBanner(request); } + + if (typeof request.getFloor === 'function') { + const floorInfo = request.getFloor({ + currency: 'USD', + mediaType: impData.video ? 'video' : 'banner', + size: [ impData.video ? impData.video.w : impData.banner.w, impData.video ? impData.video.h : impData.banner.h ] + }); + if (floorInfo && floorInfo.floor) { + impData.bidfloor = floorInfo.floor; + } + } + if (!impData.bidfloor && params.bidfloor) { + impData.bidfloor = params.bidfloor; + } + return impData; }); @@ -129,6 +146,10 @@ export const spec = { deepSetValue(payload, 'regs.ext.us_privacy', bidderRequest.uspConsent); } + if (bidderRequest?.timeout) { + payload.tmax = bidderRequest.timeout; + } + provideEids(validBidRequests[0], payload); const url = params.shortname ? ENDPOINT_URL.concat('?shortname=', params.shortname) : ENDPOINT_URL; return { @@ -208,6 +229,18 @@ export const spec = { url: USER_SYNC_URL_IMAGE + syncurl }]; } + }, + + onTimeout: function(timeoutData) { + if (timeoutData) { + ajax(TIMEOUT_URL, null, JSON.stringify(timeoutData), { + method: 'POST', + options: { + withCredentials: false, + contentType: 'application/json' + } + }); + } } } diff --git a/modules/zeusPrimeRtdProvider.js b/modules/zeusPrimeRtdProvider.js new file mode 100644 index 00000000000..2a455a14f7b --- /dev/null +++ b/modules/zeusPrimeRtdProvider.js @@ -0,0 +1,37 @@ +import { logWarn } from '../src/utils.js' +import { submodule } from '../src/hook.js' + +function initModule() { + logWarn('Zeus Prime has been deprecated. This module will be removed in Prebid 8.') +} + +/** + * @preserve + * @type {RtdSubmodule} + */ +const zeusPrimeSubmodule = { + /** + * @preserve + * The name of the plugin. + * @type {string} + */ + name: 'zeusPrime', + + /** + * @preserve + * ZeusPrime use + */ + init: initModule, +} + +/** + * @preserve + * Register the Sub Module. + */ +function registerSubModule() { + submodule('realTimeData', zeusPrimeSubmodule) +} + +registerSubModule() + +export { zeusPrimeSubmodule } diff --git a/modules/zeusPrimeRtdProvider.md b/modules/zeusPrimeRtdProvider.md new file mode 100644 index 00000000000..40b44e76f1c --- /dev/null +++ b/modules/zeusPrimeRtdProvider.md @@ -0,0 +1,63 @@ +# Overview + +# NOTE: ZEUS PRIME HAS BEEN DEPRECATED! +# THIS MODULE WILL BE REMOVED IN PREBID 8. + +Module Name: Zeus Prime RTD Provider +Module Type: Rtd Provider +Maintainer: support@zeustechnology.com + +## Description + +The Zeus Prime RTD Provider provides integration of Zeus Prime onto sites with Prebid. This module will request information from Zeus Prime servers to add the page level targeting required for Prime into the customer's ad setup. + +Zeus Prime runs as soon as the code is initialized, so it can retrieve the information required from the Zeus Prime server to create the targeting key-values. Zeus Prime will provide two page level key-values: `zeus_` and `zeus_insights`. Zeus Prime provides contextual information about a pages content, and does not provide user information that could present privacy implications. + +For more information and help with setting up Zeus Prime, see the [onboarding documentation site](https://onboarding.zeustechnology.com). + +## Usage + +To use Zeus Prime, add `zeusPrimeRtdProvider` into your Prebid build: + +``` +gulp build --modules=rtdModule,zeusPrimeRtdProvider +``` + +> Note that the global RTD module, `rtdModule`, is required for the Zeus Prime RTD module. + +Once the code is included, configure Zeus Prime in your Prebid configuration: + +```javascript +pbjs.setConfig({ + ..., + realTimeData: { + dataProviders: [{ + name: 'zeusPrime', + waitForIt: false, + params: { + gamId: '' + } + }] + }, + ... +}) +``` + +## Parameters + +The parameters below describe the configuration object used to configure Zeus Prime. + +| Name | Type | Description | Default | +|------------------------|----------|-----------------------------------------------------------------------------------------------|---------| +| name | String | This will always be `zeusPrime` | - | +| waitForIt | Boolean | Should be false since Zeus Prime runs on initial load and not during the bidding cycle. | `false` | +| params | Object | | - | +| params.gamId | String | The gamId or Google Ad Manager Network Code to access your Google Ad Manager instance. | - | + +### `gamId` Parameter + +Zeus Prime requires the gamId parameter, or the Google Ad Manager Network Code, to reference your account. See the [Google documentation](https://support.google.com/admanager/answer/7674889?hl=en) to find out where you can retrieve the Network Code. + +## Troubleshooting + +For troubleshooting steps and guides to assist with verifying your Zeus Prime installation, see our [installation documentation](https://onboarding.zeustechnology.com/docs/installation). \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index ec0bebcd2d9..66295994170 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "prebid.js", - "version": "7.23.0-pre", + "version": "7.39.0-pre", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "prebid.js", - "version": "7.23.0-pre", + "version": "7.36.0-pre", "license": "Apache-2.0", "dependencies": { "@babel/core": "^7.16.7", @@ -22,17 +22,17 @@ "express": "^4.15.4", "fun-hooks": "^0.9.9", "just-clone": "^1.0.2", - "live-connect-js": "2.4.0" + "live-connect-js": "^4.0.0" }, "devDependencies": { "@babel/eslint-parser": "^7.16.5", - "@wdio/browserstack-service": "^7.16.0", - "@wdio/cli": "^7.5.2", - "@wdio/concise-reporter": "^7.5.2", - "@wdio/local-runner": "^7.5.2", - "@wdio/mocha-framework": "^7.5.2", - "@wdio/spec-reporter": "^7.19.0", - "@wdio/sync": "^7.5.2", + "@wdio/browserstack-service": "~7.16.0", + "@wdio/cli": "~7.5.2", + "@wdio/concise-reporter": "~7.5.2", + "@wdio/local-runner": "~7.5.2", + "@wdio/mocha-framework": "~7.5.2", + "@wdio/spec-reporter": "~7.19.0", + "@wdio/sync": "~7.5.2", "ajv": "6.12.3", "assert": "^2.0.0", "babel-loader": "^8.0.5", @@ -115,11 +115,12 @@ } }, "node_modules/@ampproject/remapping": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", - "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.0" + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" }, "engines": { "node": ">=6.0.0" @@ -137,28 +138,28 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.0.tgz", - "integrity": "sha512-y5rqgTTPTmaF5e2nVhOxw+Ur9HDJLsWb6U/KpgUzRZEdPfE6VOubXBKLdbcUTijzRptednSBDQbYZBOSqJxpJw==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.1.tgz", + "integrity": "sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.0.tgz", - "integrity": "sha512-reM4+U7B9ss148rh2n1Qs9ASS+w94irYXga7c2jaQv9RVzpS7Mv1a9rnYYwuDa45G+DkORt9g6An2k/V4d9LbQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.6.tgz", + "integrity": "sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg==", "dependencies": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", - "@babel/helper-compilation-targets": "^7.19.0", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helpers": "^7.19.0", - "@babel/parser": "^7.19.0", + "@babel/generator": "^7.19.6", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helpers": "^7.19.4", + "@babel/parser": "^7.19.6", "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0", + "@babel/traverse": "^7.19.6", + "@babel/types": "^7.19.4", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -174,12 +175,12 @@ } }, "node_modules/@babel/eslint-parser": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.17.0.tgz", - "integrity": "sha512-PUEJ7ZBXbRkbq3qqM/jZ2nIuakUBqCYc7Qf52Lj7dlZ6zERnqisdHioL0l4wwQZnmskMeasqUNzLBFKs3nylXA==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz", + "integrity": "sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ==", "dev": true, "dependencies": { - "eslint-scope": "^5.1.1", + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", "eslint-visitor-keys": "^2.1.0", "semver": "^6.3.0" }, @@ -192,11 +193,11 @@ } }, "node_modules/@babel/generator": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.0.tgz", - "integrity": "sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.1.tgz", + "integrity": "sha512-u1dMdBUmA7Z0rBB97xh8pIhviK7oItYOkjbsCxTWMknyvbQRBwX7/gn4JXurRdirWMFh+ZtYARqkA6ydogVZpg==", "dependencies": { - "@babel/types": "^7.19.0", + "@babel/types": "^7.20.0", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" }, @@ -204,37 +205,50 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", - "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.18.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", - "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", + "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", "dependencies": { - "@babel/helper-explode-assignable-expression": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/helper-explode-assignable-expression": "^7.18.6", + "@babel/types": "^7.18.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.0.tgz", - "integrity": "sha512-Ai5bNWXIvwDvWM7njqsG3feMlL9hCVQsPYXodsZyLwshYkZVJt59Gftau4VrE8S9IT9asd2uSP1hG6wCNw+sXA==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", + "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", "dependencies": { - "@babel/compat-data": "^7.19.0", + "@babel/compat-data": "^7.20.0", "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.20.2", + "browserslist": "^4.21.3", "semver": "^6.3.0" }, "engines": { @@ -245,17 +259,17 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.6.tgz", - "integrity": "sha512-SogLLSxXm2OkBbSsHZMM4tUi8fUzjs63AT/d0YQIzr6GSd8Hxsbk2KYDX0k0DweAzGMj/YWeiCsorIdtdcW8Eg==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.19.0.tgz", + "integrity": "sha512-NRz8DwF4jT3UfrmUoZjd0Uph9HQnP30t7Ash+weACcyNkiYTywpIjDBgReJMKgr+n86sn2nPVVmJ28Dm053Kqw==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7" + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -265,12 +279,12 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz", - "integrity": "sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz", + "integrity": "sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "regexpu-core": "^5.0.1" + "@babel/helper-annotate-as-pure": "^7.18.6", + "regexpu-core": "^5.1.0" }, "engines": { "node": ">=6.9.0" @@ -280,14 +294,12 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", - "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", "dependencies": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2", @@ -306,11 +318,11 @@ } }, "node_modules/@babel/helper-explode-assignable-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", - "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", + "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -340,11 +352,11 @@ } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", - "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", + "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -362,87 +374,91 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", - "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.6.tgz", + "integrity": "sha512-fCmcfQo/KYr/VXXDIyd3CBGZ6AFhPFy1TfSEJ+PilGVlQT6jcbqtHAM4C1EciRqMza7/TpOUZliuSH+U6HAhJw==", "dependencies": { "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-simple-access": "^7.19.4", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" + "@babel/traverse": "^7.19.6", + "@babel/types": "^7.19.4" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", - "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", + "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.18.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz", - "integrity": "sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", - "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", + "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-wrap-function": "^7.16.8", - "@babel/types": "^7.16.8" + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", - "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz", + "integrity": "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==", "dependencies": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/traverse": "^7.19.1", + "@babel/types": "^7.19.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", - "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz", + "integrity": "sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==", "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.19.4" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", - "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", + "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", "dependencies": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.20.0" }, "engines": { "node": ">=6.9.0" @@ -460,17 +476,17 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", - "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", - "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", "engines": { "node": ">=6.9.0" } @@ -484,27 +500,27 @@ } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", - "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz", + "integrity": "sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==", "dependencies": { - "@babel/helper-function-name": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.8", - "@babel/types": "^7.16.8" + "@babel/helper-function-name": "^7.19.0", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz", - "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.1.tgz", + "integrity": "sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg==", "dependencies": { "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.0" }, "engines": { "node": ">=6.9.0" @@ -524,9 +540,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.0.tgz", - "integrity": "sha512-74bEXKX2h+8rrfQUfsBfuZZHzsEs6Eql4pqy/T4Nn6Y9wNPggQOqD6z6pn5Bl8ZfysKouFZT/UXEH94ummEeQw==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.1.tgz", + "integrity": "sha512-hp0AYxaZJhxULfM1zyp7Wgr+pSUKBcP3M+PHnSzWGdXOzg/kHWIgiUWARvubhUKGOEw3xqY4x+lyZ9ytBVcELw==", "bin": { "parser": "bin/babel-parser.js" }, @@ -535,11 +551,11 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz", - "integrity": "sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", + "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -549,13 +565,13 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz", - "integrity": "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz", + "integrity": "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-proposal-optional-chaining": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -565,12 +581,13 @@ } }, "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz", - "integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.1.tgz", + "integrity": "sha512-Gh5rchzSwE4kC+o/6T8waD0WHEQIsDmjltY8WnWRXHUdH8axZhuH86Ov9M72YhJfDrZseQwuuWaaIT/TmePp3g==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-remap-async-to-generator": "^7.18.9", "@babel/plugin-syntax-async-generators": "^7.8.4" }, "engines": { @@ -581,12 +598,12 @@ } }, "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz", - "integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -596,12 +613,12 @@ } }, "node_modules/@babel/plugin-proposal-class-static-block": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.17.6.tgz", - "integrity": "sha512-X/tididvL2zbs7jZCeeRJ8167U/+Ac135AM6jCAx6gYXDUviZV5Ku9UDvWS2NCuWlFjIRXklYhwo6HhAC7ETnA==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz", + "integrity": "sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.17.6", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-class-static-block": "^7.14.5" }, "engines": { @@ -612,11 +629,11 @@ } }, "node_modules/@babel/plugin-proposal-dynamic-import": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", - "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", + "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-dynamic-import": "^7.8.3" }, "engines": { @@ -627,11 +644,11 @@ } }, "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz", - "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.18.9", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" }, "engines": { @@ -642,11 +659,11 @@ } }, "node_modules/@babel/plugin-proposal-json-strings": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz", - "integrity": "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", + "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-json-strings": "^7.8.3" }, "engines": { @@ -657,11 +674,11 @@ } }, "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz", - "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz", + "integrity": "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.18.9", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" }, "engines": { @@ -672,11 +689,11 @@ } }, "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz", - "integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" }, "engines": { @@ -687,11 +704,11 @@ } }, "node_modules/@babel/plugin-proposal-numeric-separator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", - "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-numeric-separator": "^7.10.4" }, "engines": { @@ -702,15 +719,15 @@ } }, "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.3.tgz", - "integrity": "sha512-yuL5iQA/TbZn+RGAfxQXfi7CNLmKi1f8zInn4IgobuCWcAb7i+zj4TYzQ9l8cEzVyJ89PDGuqxK1xZpUDISesw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.19.4.tgz", + "integrity": "sha512-wHmj6LDxVDnL+3WhXteUBaoM1aVILZODAUjg11kHqG4cOlfgMQGxw6aCgvrXrmaJR3Bn14oZhImyCPZzRpC93Q==", "dependencies": { - "@babel/compat-data": "^7.17.0", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/compat-data": "^7.19.4", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-plugin-utils": "^7.19.0", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.16.7" + "@babel/plugin-transform-parameters": "^7.18.8" }, "engines": { "node": ">=6.9.0" @@ -720,11 +737,11 @@ } }, "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", - "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", + "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" }, "engines": { @@ -735,12 +752,12 @@ } }, "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz", - "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz", + "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, "engines": { @@ -751,12 +768,12 @@ } }, "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz", - "integrity": "sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.10", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -766,13 +783,13 @@ } }, "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz", - "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz", + "integrity": "sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" }, "engines": { @@ -783,12 +800,12 @@ } }, "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz", - "integrity": "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", + "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=4" @@ -855,6 +872,20 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz", + "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-json-strings": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", @@ -961,11 +992,11 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz", - "integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz", + "integrity": "sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -975,13 +1006,13 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz", - "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz", + "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", "dependencies": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8" + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-remap-async-to-generator": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -991,11 +1022,11 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", - "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", + "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1005,11 +1036,11 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz", - "integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.0.tgz", + "integrity": "sha512-sXOohbpHZSk7GjxK9b3dKB7CfqUD5DwOH+DggKzOQ7TXYP+RCSbRykfjQmn/zq+rBjycVRtLf9pYhAaEJA786w==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.19.0" }, "engines": { "node": ">=6.9.0" @@ -1019,17 +1050,18 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz", - "integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.19.0.tgz", + "integrity": "sha512-YfeEE9kCjqTS9IitkgfJuxjcEtLUHMqa8yUJ6zdz8vR7hKuo6mOy2C05P0F1tdMmDCeuyidKnlrw/iTppHcr2A==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-compilation-targets": "^7.19.0", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6", "globals": "^11.1.0" }, "engines": { @@ -1040,11 +1072,11 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz", - "integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz", + "integrity": "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -1054,11 +1086,11 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.3.tgz", - "integrity": "sha512-dDFzegDYKlPqa72xIlbmSkly5MluLoaC1JswABGktyt6NTXSBcUuse/kWE/wvKFWJHPETpi158qJZFS3JmykJg==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.0.tgz", + "integrity": "sha512-1dIhvZfkDVx/zn2S1aFwlruspTt4189j7fEkH0Y0VyuDM6bQt7bD6kLcz3l4IlLG+e5OReaBz9ROAbttRtUHqA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.19.0" }, "engines": { "node": ">=6.9.0" @@ -1068,12 +1100,12 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", - "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", + "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1083,11 +1115,11 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz", - "integrity": "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", + "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -1097,12 +1129,12 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", - "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", + "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1112,11 +1144,11 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz", - "integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==", + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", + "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1126,13 +1158,13 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", - "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", + "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", "dependencies": { - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -1142,11 +1174,11 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz", - "integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", + "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -1156,11 +1188,11 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", - "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", + "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1170,13 +1202,12 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz", - "integrity": "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.19.6.tgz", + "integrity": "sha512-uG3od2mXvAtIFQIh0xrpLH6r5fpSQN04gIVovl+ODLdUMANokxQLZnPBHcjmv3GxRjnqwLuHvppjjcelqUFZvg==", "dependencies": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0" }, "engines": { "node": ">=6.9.0" @@ -1186,14 +1217,13 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz", - "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.19.6.tgz", + "integrity": "sha512-8PIa1ym4XRTKuSsOUXqDG0YaOlEuTVvHMe5JCfgBMOtHvJKw/4NGovEGN33viISshG/rZNVrACiBmPQLvWN8xQ==", "dependencies": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-simple-access": "^7.19.4" }, "engines": { "node": ">=6.9.0" @@ -1203,15 +1233,14 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz", - "integrity": "sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.6.tgz", + "integrity": "sha512-fqGLBepcc3kErfR9R3DnVpURmckXP7gj7bAlrTQyBxrigFqszZCkFkcoxzCp2v32XmwXLvbw+8Yq9/b+QqksjQ==", "dependencies": { - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-validator-identifier": "^7.19.1" }, "engines": { "node": ">=6.9.0" @@ -1221,12 +1250,12 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz", - "integrity": "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", + "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", "dependencies": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1236,11 +1265,12 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz", - "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz", + "integrity": "sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.19.0", + "@babel/helper-plugin-utils": "^7.19.0" }, "engines": { "node": ">=6.9.0" @@ -1250,11 +1280,11 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz", - "integrity": "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", + "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1264,12 +1294,12 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", - "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", + "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1279,11 +1309,11 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz", - "integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.1.tgz", + "integrity": "sha512-nDvKLrAvl+kf6BOy1UJ3MGwzzfTMgppxwiD2Jb4LO3xjYyZq30oQzDNJbCQpMdG9+j2IXHoiMrw5Cm/L6ZoxXQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.19.0" }, "engines": { "node": ">=6.9.0" @@ -1293,11 +1323,11 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", - "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", + "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1307,11 +1337,12 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz", - "integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz", + "integrity": "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==", "dependencies": { - "regenerator-transform": "^0.14.2" + "@babel/helper-plugin-utils": "^7.18.6", + "regenerator-transform": "^0.15.0" }, "engines": { "node": ">=6.9.0" @@ -1321,11 +1352,11 @@ } }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz", - "integrity": "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", + "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1335,15 +1366,15 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.9.tgz", - "integrity": "sha512-wS8uJwBt7/b/mzE13ktsJdmS4JP/j7PQSaADtnb4I2wL0zK51MQ0pmF8/Jy0wUIS96fr+fXT6S/ifiPXnvrlSg==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.6.tgz", + "integrity": "sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw==", "dependencies": { "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.9", - "babel-plugin-polyfill-corejs2": "^0.3.1", - "babel-plugin-polyfill-corejs3": "^0.5.2", - "babel-plugin-polyfill-regenerator": "^0.3.1", + "@babel/helper-plugin-utils": "^7.19.0", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", "semver": "^6.3.0" }, "engines": { @@ -1354,11 +1385,11 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", - "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", + "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1368,12 +1399,12 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz", - "integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz", + "integrity": "sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -1383,11 +1414,11 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", - "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", + "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1397,11 +1428,11 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz", - "integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -1411,11 +1442,11 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz", - "integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", + "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -1425,11 +1456,11 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", - "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", + "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -1439,12 +1470,12 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", - "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", + "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1454,36 +1485,37 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz", - "integrity": "sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.19.4.tgz", + "integrity": "sha512-5QVOTXUdqTCjQuh2GGtdd7YEhoRXBMVGROAtsBeLGIbIz3obCBIfRMT1I3ZKkMgNzwkyCkftDXSSkHxnfVf4qg==", "dependencies": { - "@babel/compat-data": "^7.16.8", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-async-generator-functions": "^7.16.8", - "@babel/plugin-proposal-class-properties": "^7.16.7", - "@babel/plugin-proposal-class-static-block": "^7.16.7", - "@babel/plugin-proposal-dynamic-import": "^7.16.7", - "@babel/plugin-proposal-export-namespace-from": "^7.16.7", - "@babel/plugin-proposal-json-strings": "^7.16.7", - "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", - "@babel/plugin-proposal-numeric-separator": "^7.16.7", - "@babel/plugin-proposal-object-rest-spread": "^7.16.7", - "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", - "@babel/plugin-proposal-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-private-methods": "^7.16.11", - "@babel/plugin-proposal-private-property-in-object": "^7.16.7", - "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", + "@babel/compat-data": "^7.19.4", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.19.1", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.19.4", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.18.6", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", @@ -1493,44 +1525,44 @@ "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.16.7", - "@babel/plugin-transform-async-to-generator": "^7.16.8", - "@babel/plugin-transform-block-scoped-functions": "^7.16.7", - "@babel/plugin-transform-block-scoping": "^7.16.7", - "@babel/plugin-transform-classes": "^7.16.7", - "@babel/plugin-transform-computed-properties": "^7.16.7", - "@babel/plugin-transform-destructuring": "^7.16.7", - "@babel/plugin-transform-dotall-regex": "^7.16.7", - "@babel/plugin-transform-duplicate-keys": "^7.16.7", - "@babel/plugin-transform-exponentiation-operator": "^7.16.7", - "@babel/plugin-transform-for-of": "^7.16.7", - "@babel/plugin-transform-function-name": "^7.16.7", - "@babel/plugin-transform-literals": "^7.16.7", - "@babel/plugin-transform-member-expression-literals": "^7.16.7", - "@babel/plugin-transform-modules-amd": "^7.16.7", - "@babel/plugin-transform-modules-commonjs": "^7.16.8", - "@babel/plugin-transform-modules-systemjs": "^7.16.7", - "@babel/plugin-transform-modules-umd": "^7.16.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.8", - "@babel/plugin-transform-new-target": "^7.16.7", - "@babel/plugin-transform-object-super": "^7.16.7", - "@babel/plugin-transform-parameters": "^7.16.7", - "@babel/plugin-transform-property-literals": "^7.16.7", - "@babel/plugin-transform-regenerator": "^7.16.7", - "@babel/plugin-transform-reserved-words": "^7.16.7", - "@babel/plugin-transform-shorthand-properties": "^7.16.7", - "@babel/plugin-transform-spread": "^7.16.7", - "@babel/plugin-transform-sticky-regex": "^7.16.7", - "@babel/plugin-transform-template-literals": "^7.16.7", - "@babel/plugin-transform-typeof-symbol": "^7.16.7", - "@babel/plugin-transform-unicode-escapes": "^7.16.7", - "@babel/plugin-transform-unicode-regex": "^7.16.7", + "@babel/plugin-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.19.4", + "@babel/plugin-transform-classes": "^7.19.0", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.19.4", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.18.6", + "@babel/plugin-transform-modules-commonjs": "^7.18.6", + "@babel/plugin-transform-modules-systemjs": "^7.19.0", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.18.8", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.19.0", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.10", + "@babel/plugin-transform-unicode-regex": "^7.18.6", "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.16.8", - "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.5.0", - "babel-plugin-polyfill-regenerator": "^0.3.0", - "core-js-compat": "^3.20.2", + "@babel/types": "^7.19.4", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", + "core-js-compat": "^3.25.1", "semver": "^6.3.0" }, "engines": { @@ -1556,20 +1588,28 @@ } }, "node_modules/@babel/runtime": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", - "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.1.tgz", + "integrity": "sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg==", "dependencies": { - "regenerator-runtime": "^0.13.4" + "regenerator-runtime": "^0.13.10" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/runtime/node_modules/regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + "node_modules/@babel/runtime-corejs3": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.20.1.tgz", + "integrity": "sha512-CGulbEDcg/ND1Im7fUNRZdGXmX2MTWVVZacQi/6DiKE5HNwZ3aVTm5PV4lO8HHz0B2h8WQyvKKjbX5XgTtydsg==", + "dev": true, + "dependencies": { + "core-js-pure": "^3.25.1", + "regenerator-runtime": "^0.13.10" + }, + "engines": { + "node": ">=6.9.0" + } }, "node_modules/@babel/template": { "version": "7.18.10", @@ -1585,18 +1625,18 @@ } }, "node_modules/@babel/traverse": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.0.tgz", - "integrity": "sha512-4pKpFRDh+utd2mbRC8JLnlsMUii3PMHjpL6a0SZ4NMZy7YFP9aXORxEhdMVOc9CpWtDF09IkciQLEhK7Ml7gRA==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.1.tgz", + "integrity": "sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==", "dependencies": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", + "@babel/generator": "^7.20.1", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.0", - "@babel/types": "^7.19.0", + "@babel/parser": "^7.20.1", + "@babel/types": "^7.20.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -1605,12 +1645,12 @@ } }, "node_modules/@babel/types": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz", - "integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.0.tgz", + "integrity": "sha512-Jlgt3H0TajCW164wkTOTzHkZb075tMQMULzrLUoUeKmO7eFL96GgDxf7/Axhc5CAuKE3KFyVW1p6ysKsi2oXAg==", "dependencies": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" }, "engines": { @@ -1663,9 +1703,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.12.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", - "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -1774,7 +1814,7 @@ "node_modules/@gulp-sourcemaps/map-sources": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/map-sources/-/map-sources-1.0.0.tgz", - "integrity": "sha1-iQrnxdjId/bThIYCFazp1+yUW9o=", + "integrity": "sha512-o/EatdaGt8+x2qpb0vFLC/2Gug/xYPRXb6a+ET1wGYKozKN3krDWC/zZFZAtrzxJHuDL12mwdfEFKcKMNvc55A==", "dev": true, "dependencies": { "normalize-path": "^2.0.1", @@ -1787,7 +1827,7 @@ "node_modules/@gulp-sourcemaps/map-sources/node_modules/normalize-path": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", "dev": true, "dependencies": { "remove-trailing-separator": "^1.0.1" @@ -1869,76 +1909,6 @@ "node": ">=8" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", @@ -1949,19 +1919,19 @@ } }, "node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", "dev": true, "dependencies": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", - "@types/yargs": "^16.0.0", + "@types/yargs": "^15.0.0", "chalk": "^4.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 10.14.2" } }, "node_modules/@jest/types/node_modules/ansi-styles": { @@ -2013,6 +1983,15 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "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, + "engines": { + "node": ">=8" + } + }, "node_modules/@jest/types/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -2026,22 +2005,21 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", - "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", "engines": { "node": ">=6.0.0" } @@ -2064,18 +2042,41 @@ "@jridgewell/trace-mapping": "^0.3.9" } }, + "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", - "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==" + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.14", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", - "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dev": true, + "dependencies": { + "eslint-scope": "5.1.1" } }, "node_modules/@polka/url": { @@ -2126,19 +2127,16 @@ } }, "node_modules/@sinonjs/text-encoding": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", - "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", + "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", "dev": true }, - "node_modules/@socket.io/base64-arraybuffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@socket.io/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", - "integrity": "sha512-dOlCBKnDw4iShaIsH/bxujKTM18+2TOAsYz+KSc11Am38H4q5Xw8Bbz97ZYdrVNM+um3p7w86Bvvmcn9q+5+eQ==", - "dev": true, - "engines": { - "node": ">= 0.6.0" - } + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", + "dev": true }, "node_modules/@szmarczak/http-timer": { "version": "4.0.6", @@ -2153,9 +2151,9 @@ } }, "node_modules/@types/aria-query": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.0.tgz", - "integrity": "sha512-P+dkdFu0n08PDIvw+9nT9ByQnd+Udc8DaWPb9HKfaPwCvWvQpC5XaMRx2xLWECm9x1VKNps6vEAlirjA6+uNrQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", + "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==", "dev": true }, "node_modules/@types/cacheable-request": { @@ -2170,12 +2168,6 @@ "@types/responselike": "*" } }, - "node_modules/@types/component-emitter": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.11.tgz", - "integrity": "sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ==", - "dev": true - }, "node_modules/@types/cookie": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", @@ -2210,15 +2202,15 @@ "dev": true }, "node_modules/@types/ejs": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-3.1.0.tgz", - "integrity": "sha512-DCg+Ka+uDQ31lJ/UtEXVlaeV3d6t81gifaVWKJy4MYVVgvJttyX/viREy+If7fz+tK/gVxTGMtyrFPnm4gjrVA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-3.1.1.tgz", + "integrity": "sha512-RQul5wEfY7BjWm0sYY86cmUN/pcXWGyVxWX93DFFJvcrxax5zKlieLwA3T77xJGwNcZW0YW6CYG70p1m8xPFmA==", "dev": true }, "node_modules/@types/eslint": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz", - "integrity": "sha512-GE44+DNEyxxh2Kc6ro/VkIj+9ma0pO0bwv9+uHSyBrikYOHr8zYcdPvnBOp1aw8s+CjRvuSx7CyWqRrNFQ59mA==", + "version": "8.4.9", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.9.tgz", + "integrity": "sha512-jFCSo4wJzlHQLCpceUhUnXdrPuCNOjGFMQ8Eg6JXxlz3QaCKOb7eGi2cephQdM4XTYsNej69P9JDJ1zqNIbncQ==", "dev": true, "dependencies": { "@types/estree": "*", @@ -2226,9 +2218,9 @@ } }, "node_modules/@types/eslint-scope": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", - "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", "dev": true, "dependencies": { "@types/eslint": "*", @@ -2290,13 +2282,13 @@ "dev": true }, "node_modules/@types/inquirer": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-8.2.0.tgz", - "integrity": "sha512-BNoMetRf3gmkpAlV5we+kxyZTle7YibdOntIZbU5pyIfMdcwy784KfeZDAcuyMznkh5OLa17RVXZOGA5LTlkgQ==", + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-HhxyLejTHMfohAuhRun4csWigAMjXTmRyiJTU1Y/I1xmggikFMkOUoMQRlFm+zQcPEGHSs3io/0FAmNZf8EymQ==", "dev": true, "dependencies": { "@types/through": "*", - "rxjs": "^7.2.0" + "rxjs": "^6.4.0" } }, "node_modules/@types/istanbul-lib-coverage": { @@ -2324,54 +2316,55 @@ } }, "node_modules/@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, "node_modules/@types/keyv": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.3.tgz", - "integrity": "sha512-FXCJgyyN3ivVgRoml4h94G/p3kY+u/B86La+QptcqJaWtBWtmc6TtkNfS40n9bIvyLteHh7zXOtgbobORKPbDg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-4.2.0.tgz", + "integrity": "sha512-xoBtGl5R9jeKUhc8ZqeYaRDx04qqJ10yhhXYGmJ4Jr8qKpvMsDQQrNUvF/wUJ4klOtmJeJM+p2Xo3zp9uaC3tw==", + "deprecated": "This is a stub types definition. keyv provides its own type definitions, so you do not need this installed.", "dev": true, "dependencies": { - "@types/node": "*" + "keyv": "*" } }, "node_modules/@types/lodash": { - "version": "4.14.179", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.179.tgz", - "integrity": "sha512-uwc1x90yCKqGcIOAT6DwOSuxnrAbpkdPsUOZtwrXb4D/6wZs+6qG7QnIawDuZWg0sWpxl+ltIKCaLoMlna678w==", + "version": "4.14.187", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.187.tgz", + "integrity": "sha512-MrO/xLXCaUgZy3y96C/iOsaIqZSeupyTImKClHunL5GrmaiII2VwvWmLBu2hwa0Kp0sV19CsyjtrTc/Fx8rg/A==", "dev": true }, "node_modules/@types/lodash.flattendeep": { - "version": "4.4.6", - "resolved": "https://registry.npmjs.org/@types/lodash.flattendeep/-/lodash.flattendeep-4.4.6.tgz", - "integrity": "sha512-uLm2MaRVlqJSGsMK0RZpP5T3KqReq+9WbYDHCUhBhp98v56hMG/Yht52bsoTSui9xz2mUvQ9NfG3LrNGDL92Ng==", + "version": "4.4.7", + "resolved": "https://registry.npmjs.org/@types/lodash.flattendeep/-/lodash.flattendeep-4.4.7.tgz", + "integrity": "sha512-1h6GW/AeZw/Wej6uxrqgmdTDZX1yFS39lRsXYkg+3kWvOWWrlGCI6H7lXxlUHOzxDT4QeYGmgPpQ3BX9XevzOg==", "dev": true, "dependencies": { "@types/lodash": "*" } }, "node_modules/@types/lodash.pickby": { - "version": "4.6.6", - "resolved": "https://registry.npmjs.org/@types/lodash.pickby/-/lodash.pickby-4.6.6.tgz", - "integrity": "sha512-NFa13XxlMd9eFi0UFZFWIztpMpXhozbijrx3Yb1viYZphT7jyopIFVoIRF4eYMjruWNEG1rnyrRmg/8ej9T8Iw==", + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/@types/lodash.pickby/-/lodash.pickby-4.6.7.tgz", + "integrity": "sha512-4ebXRusuLflfscbD0PUX4eVknDHD9Yf+uMtBIvA/hrnTqeAzbuHuDjvnYriLjUrI9YrhCPVKUf4wkRSXJQ6gig==", "dev": true, "dependencies": { "@types/lodash": "*" } }, "node_modules/@types/lodash.union": { - "version": "4.6.6", - "resolved": "https://registry.npmjs.org/@types/lodash.union/-/lodash.union-4.6.6.tgz", - "integrity": "sha512-Wu0ZEVNcyCz8eAn6TlUbYWZoGbH9E+iOHxAZbwUoCEXdUiy6qpcz5o44mMXViM4vlPLLCPlkAubEP1gokoSZaw==", + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/@types/lodash.union/-/lodash.union-4.6.7.tgz", + "integrity": "sha512-6HXM6tsnHJzKgJE0gA/LhTGf/7AbjUk759WZ1MziVm+OBNAATHhdgj+a3KVE8g76GCLAnN4ZEQQG1EGgtBIABA==", "dev": true, "dependencies": { "@types/lodash": "*" @@ -2386,16 +2379,10 @@ "@types/unist": "*" } }, - "node_modules/@types/mdurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz", - "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==", - "dev": true - }, "node_modules/@types/mocha": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.0.tgz", - "integrity": "sha512-QCWHkbMv4Y5U9oW10Uxbr45qMMSzl4OzijsozynUAgx3kEHUdXB00udx2dWDQ7f2TU2a2uuiFaRZjCe3unPpeg==", + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.3.tgz", + "integrity": "sha512-ekGvFhFgrc2zYQoX4JeZPmVzZxw6Dtllga7iGHzfbYIYkAMUx/sAFP2GdFpLff+vdHXu5fl7WX9AT+TtqYcsyw==", "dev": true }, "node_modules/@types/ms": { @@ -2405,9 +2392,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "17.0.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", - "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==", + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", "dev": true }, "node_modules/@types/normalize-package-data": { @@ -2423,18 +2410,18 @@ "dev": true }, "node_modules/@types/puppeteer": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/@types/puppeteer/-/puppeteer-5.4.5.tgz", - "integrity": "sha512-lxCjpDEY+DZ66+W3x5Af4oHnEmUXt0HuaRzkBGE2UZiZEp/V1d3StpLPlmNVu/ea091bdNmVPl44lu8Wy/0ZCA==", + "version": "5.4.7", + "resolved": "https://registry.npmjs.org/@types/puppeteer/-/puppeteer-5.4.7.tgz", + "integrity": "sha512-JdGWZZYL0vKapXF4oQTC5hLVNfOgdPrqeZ1BiQnGk5cB7HeE91EWUiTdVSdQPobRN8rIcdffjiOgCYJ/S8QrnQ==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/recursive-readdir": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@types/recursive-readdir/-/recursive-readdir-2.2.0.tgz", - "integrity": "sha512-HGk753KRu2N4mWduovY4BLjYq4jTOL29gV2OfGdGxHcPSWGFkC5RRIdk+VTs5XmYd7MVAD+JwKrcb5+5Y7FOCg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@types/recursive-readdir/-/recursive-readdir-2.2.1.tgz", + "integrity": "sha512-Xd+Ptc4/F2ueInqy5yK2FI5FxtwwbX2+VZpcg+9oYsFJVen8qQKGapCr+Bi5wQtHU1cTXT8s+07lo/nKPgu8Gg==", "dev": true, "dependencies": { "@types/node": "*" @@ -2514,9 +2501,9 @@ "dev": true }, "node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "version": "15.0.14", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", + "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -2529,9 +2516,9 @@ "dev": true }, "node_modules/@types/yauzl": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.2.tgz", - "integrity": "sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", "dev": true, "optional": true, "dependencies": { @@ -2545,9 +2532,9 @@ "dev": true }, "node_modules/@videojs/http-streaming": { - "version": "2.14.2", - "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.14.2.tgz", - "integrity": "sha512-K1raSfO/pq5r8iUas3OSYni0kXOj91n8ealIpV02khghzGv9LQ6O3YUqYd/eAhJ1HIrmZWOnrYpK/P+mhUExXQ==", + "version": "2.14.3", + "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.14.3.tgz", + "integrity": "sha512-2tFwxCaNbcEZzQugWf8EERwNMyNtspfHnvxRGRABQs09W/5SqmkWFuGWfUAm4wQKlXGfdPyAJ1338ASl459xAA==", "dev": true, "dependencies": { "@babel/runtime": "^7.12.5", @@ -2594,14 +2581,14 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.2.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.38.tgz", - "integrity": "sha512-/FsvnSu7Z+lkd/8KXMa4yYNUiqQrI22135gfsQYVGuh5tqEgOB0XqrUdb/KnCLa5+TmQLPwvyUnKMyCpu+SX3Q==", + "version": "3.2.41", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.41.tgz", + "integrity": "sha512-oA4mH6SA78DT+96/nsi4p9DX97PHcNROxs51lYk7gb9Z4BPKQ3Mh+BLn6CQZBw857Iuhu28BfMSRHAlPvD4vlw==", "dev": true, "optional": true, "dependencies": { "@babel/parser": "^7.16.4", - "@vue/shared": "3.2.38", + "@vue/shared": "3.2.41", "estree-walker": "^2.0.2", "source-map": "^0.6.1" } @@ -2617,29 +2604,29 @@ } }, "node_modules/@vue/compiler-dom": { - "version": "3.2.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.38.tgz", - "integrity": "sha512-zqX4FgUbw56kzHlgYuEEJR8mefFiiyR3u96498+zWPsLeh1WKvgIReoNE+U7gG8bCUdvsrJ0JRmev0Ky6n2O0g==", + "version": "3.2.41", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.41.tgz", + "integrity": "sha512-xe5TbbIsonjENxJsYRbDJvthzqxLNk+tb3d/c47zgREDa/PCp6/Y4gC/skM4H6PIuX5DAxm7fFJdbjjUH2QTMw==", "dev": true, "optional": true, "dependencies": { - "@vue/compiler-core": "3.2.38", - "@vue/shared": "3.2.38" + "@vue/compiler-core": "3.2.41", + "@vue/shared": "3.2.41" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.2.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.38.tgz", - "integrity": "sha512-KZjrW32KloMYtTcHAFuw3CqsyWc5X6seb8KbkANSWt3Cz9p2qA8c1GJpSkksFP9ABb6an0FLCFl46ZFXx3kKpg==", + "version": "3.2.41", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.41.tgz", + "integrity": "sha512-+1P2m5kxOeaxVmJNXnBskAn3BenbTmbxBxWOtBq3mQTCokIreuMULFantBUclP0+KnzNCMOvcnKinqQZmiOF8w==", "dev": true, "optional": true, "dependencies": { "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.38", - "@vue/compiler-dom": "3.2.38", - "@vue/compiler-ssr": "3.2.38", - "@vue/reactivity-transform": "3.2.38", - "@vue/shared": "3.2.38", + "@vue/compiler-core": "3.2.41", + "@vue/compiler-dom": "3.2.41", + "@vue/compiler-ssr": "3.2.41", + "@vue/reactivity-transform": "3.2.41", + "@vue/shared": "3.2.41", "estree-walker": "^2.0.2", "magic-string": "^0.25.7", "postcss": "^8.1.10", @@ -2657,34 +2644,34 @@ } }, "node_modules/@vue/compiler-ssr": { - "version": "3.2.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.38.tgz", - "integrity": "sha512-bm9jOeyv1H3UskNm4S6IfueKjUNFmi2kRweFIGnqaGkkRePjwEcfCVqyS3roe7HvF4ugsEkhf4+kIvDhip6XzQ==", + "version": "3.2.41", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.41.tgz", + "integrity": "sha512-Y5wPiNIiaMz/sps8+DmhaKfDm1xgj6GrH99z4gq2LQenfVQcYXmHIOBcs5qPwl7jaW3SUQWjkAPKMfQemEQZwQ==", "dev": true, "optional": true, "dependencies": { - "@vue/compiler-dom": "3.2.38", - "@vue/shared": "3.2.38" + "@vue/compiler-dom": "3.2.41", + "@vue/shared": "3.2.41" } }, "node_modules/@vue/reactivity-transform": { - "version": "3.2.38", - "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.38.tgz", - "integrity": "sha512-3SD3Jmi1yXrDwiNJqQ6fs1x61WsDLqVk4NyKVz78mkaIRh6d3IqtRnptgRfXn+Fzf+m6B1KxBYWq1APj6h4qeA==", + "version": "3.2.41", + "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.41.tgz", + "integrity": "sha512-mK5+BNMsL4hHi+IR3Ft/ho6Za+L3FA5j8WvreJ7XzHrqkPq8jtF/SMo7tuc9gHjLDwKZX1nP1JQOKo9IEAn54A==", "dev": true, "optional": true, "dependencies": { "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.38", - "@vue/shared": "3.2.38", + "@vue/compiler-core": "3.2.41", + "@vue/shared": "3.2.41", "estree-walker": "^2.0.2", "magic-string": "^0.25.7" } }, "node_modules/@vue/shared": { - "version": "3.2.38", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.38.tgz", - "integrity": "sha512-dTyhTIRmGXBjxJE+skC8tTWCGLCVc4wQgRRLt8+O9p5ewBAjoBwtCAkLPrtToSr1xltoe3st21Pv953aOZ7alg==", + "version": "3.2.41", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.41.tgz", + "integrity": "sha512-W9mfWLHmJhkfAmV+7gDjcHeAWALQtgGT3JErxULl0oz6R6+3ug91I7IErs93eCFhPCZPHBs4QJS7YWEV7A3sxw==", "dev": true, "optional": true }, @@ -2708,37 +2695,224 @@ "@wdio/cli": "^7.0.0" } }, - "node_modules/@wdio/cli": { + "node_modules/@wdio/browserstack-service/node_modules/@wdio/config": { "version": "7.16.16", - "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-7.16.16.tgz", - "integrity": "sha512-Wz/e5zm1UNHB9RAIsJIM7ioDzVllUwTvhVWOrI7HR/53GmO/cIvAVjpnlglizJNgK8WlbnM/cKNVIXxqxrnFmw==", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-7.16.16.tgz", + "integrity": "sha512-K/ObPuo6Da2liz++OKOIfbdpFwI7UWiFcBylfJkCYbweuXCoW1aUqlKI6rmKPwCH9Uqr/RHWu6p8eo0zWe6xVA==", + "dev": true, + "dependencies": { + "@wdio/logger": "7.16.0", + "@wdio/types": "7.16.14", + "deepmerge": "^4.0.0", + "glob": "^7.1.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/@wdio/protocols": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-7.16.7.tgz", + "integrity": "sha512-Wv40pNQcLiPzQ3o98Mv4A8T1EBQ6k4khglz/e2r16CTm+F3DDYh8eLMAsU5cgnmuwwDKX1EyOiFwieykBn5MCg==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/@wdio/repl": { + "version": "7.16.14", + "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-7.16.14.tgz", + "integrity": "sha512-Ezih0Y+lsGkKv3H3U56hdWgZiQGA3VaAYguSLd9+g1xbQq+zMKqSmfqECD9bAy+OgCCiVTRstES6lHZxJVPhAg==", + "dev": true, + "dependencies": { + "@wdio/utils": "7.16.14" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/@wdio/utils": { + "version": "7.16.14", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-7.16.14.tgz", + "integrity": "sha512-wwin8nVpIlhmXJkq6GJw9aDDzgLOJKgXTcEua0T2sdXjoW78u5Ly/GZrFXTjMGhacFvoZfitTrjyfyy4CxMVvw==", + "dev": true, + "dependencies": { + "@wdio/logger": "7.16.0", + "@wdio/types": "7.16.14", + "p-iteration": "^1.1.8" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "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, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/devtools": { + "version": "7.16.16", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.16.16.tgz", + "integrity": "sha512-M0kzkuSgfEhpqIis3gdtWsNjn/HQ+vRAmEzDnbYx/7FfjFxhSv1d+rOOT20pvd60soItMYpsOova1igACEGkGQ==", + "dev": true, + "dependencies": { + "@types/node": "^17.0.4", + "@types/ua-parser-js": "^0.7.33", + "@wdio/config": "7.16.16", + "@wdio/logger": "7.16.0", + "@wdio/protocols": "7.16.7", + "@wdio/types": "7.16.14", + "@wdio/utils": "7.16.14", + "chrome-launcher": "^0.15.0", + "edge-paths": "^2.1.0", + "puppeteer-core": "^13.1.3", + "query-selector-shadow-dom": "^1.0.0", + "ua-parser-js": "^1.0.1", + "uuid": "^8.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/devtools-protocol": { + "version": "0.0.973690", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.973690.tgz", + "integrity": "sha512-myh3hSFp0YWa2GED11PmbLhV4dv9RdO7YUz27XJrbQLnP5bMbZL6dfOOILTHO57yH0kX5GfuOZBsg/4NamfPvQ==", + "dev": true + }, + "node_modules/@wdio/browserstack-service/node_modules/minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/ua-parser-js": { + "version": "1.0.33", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.33.tgz", + "integrity": "sha512-RqshF7TPTE0XLYAqmjlu5cLLuGdKrNu9O1KLA/qp39QtbZwuzwv1dT46DZSopoUMsYgXpB3Cv8a03FI8b74oFQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + } + ], + "engines": { + "node": "*" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/webdriver": { + "version": "7.16.16", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-7.16.16.tgz", + "integrity": "sha512-x8UoG9k/P8KDrfSh1pOyNevt9tns3zexoMxp9cKnyA/7HYSErhZYTLGlgxscAXLtQG41cMH/Ba/oBmOx7Hgd8w==", + "dev": true, + "dependencies": { + "@types/node": "^17.0.4", + "@wdio/config": "7.16.16", + "@wdio/logger": "7.16.0", + "@wdio/protocols": "7.16.7", + "@wdio/types": "7.16.14", + "@wdio/utils": "7.16.14", + "got": "^11.0.2", + "ky": "^0.29.0", + "lodash.merge": "^4.6.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/webdriverio": { + "version": "7.16.16", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.16.16.tgz", + "integrity": "sha512-caPaEWyuD3Qoa7YkW4xCCQA4v9Pa9wmhFGPvNZh3ERtjMCNi8L/XXOdkekWNZmFh3tY0kFguBj7+fAwSY7HAGw==", + "dev": true, + "dependencies": { + "@types/aria-query": "^5.0.0", + "@types/node": "^17.0.4", + "@wdio/config": "7.16.16", + "@wdio/logger": "7.16.0", + "@wdio/protocols": "7.16.7", + "@wdio/repl": "7.16.14", + "@wdio/types": "7.16.14", + "@wdio/utils": "7.16.14", + "archiver": "^5.0.0", + "aria-query": "^5.0.0", + "css-shorthand-properties": "^1.1.1", + "css-value": "^0.0.1", + "devtools": "7.16.16", + "devtools-protocol": "^0.0.973690", + "fs-extra": "^10.0.0", + "get-port": "^5.1.1", + "grapheme-splitter": "^1.0.2", + "lodash.clonedeep": "^4.5.0", + "lodash.isobject": "^3.0.2", + "lodash.isplainobject": "^4.0.6", + "lodash.zip": "^4.2.0", + "minimatch": "^5.0.0", + "puppeteer-core": "^13.1.3", + "query-selector-shadow-dom": "^1.0.0", + "resq": "^1.9.1", + "rgb2hex": "0.2.5", + "serialize-error": "^8.0.0", + "webdriver": "7.16.16" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/cli": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-7.5.7.tgz", + "integrity": "sha512-nOQJLskrY+UECDd3NxE7oBzb6cDA7e7x02YWQugOlOgnZ4a+PJmkFoSsO8C2uNCpdFngy5rJKGUo5vbtAHEF9Q==", "dev": true, "dependencies": { "@types/ejs": "^3.0.5", "@types/fs-extra": "^9.0.4", - "@types/inquirer": "^8.1.2", + "@types/inquirer": "^7.3.1", "@types/lodash.flattendeep": "^4.4.6", "@types/lodash.pickby": "^4.6.6", "@types/lodash.union": "^4.6.6", - "@types/node": "^17.0.4", "@types/recursive-readdir": "^2.2.0", - "@wdio/config": "7.16.16", - "@wdio/logger": "7.16.0", - "@wdio/types": "7.16.14", - "@wdio/utils": "7.16.14", + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", "async-exit-hook": "^2.0.1", "chalk": "^4.0.0", "chokidar": "^3.0.0", "cli-spinners": "^2.1.0", "ejs": "^3.0.1", "fs-extra": "^10.0.0", - "inquirer": "8.1.5", + "inquirer": "^8.0.0", "lodash.flattendeep": "^4.4.0", "lodash.pickby": "^4.6.0", "lodash.union": "^4.6.0", "mkdirp": "^1.0.4", "recursive-readdir": "^2.2.2", - "webdriverio": "7.16.16", + "webdriverio": "7.5.7", "yargs": "^17.0.0", "yarn-install": "^1.0.0" }, @@ -2749,6 +2923,39 @@ "node": ">=12.0.0" } }, + "node_modules/@wdio/cli/node_modules/@types/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", + "dev": true + }, + "node_modules/@wdio/cli/node_modules/@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/cli/node_modules/@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "dependencies": { + "got": "^11.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/@wdio/cli/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -2764,6 +2971,19 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/@wdio/cli/node_modules/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + }, + "engines": { + "node": ">=6.0" + } + }, "node_modules/@wdio/cli/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -2780,6 +3000,32 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/@wdio/cli/node_modules/chrome-launcher": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.13.4.tgz", + "integrity": "sha512-nnzXiDbGKjDSK6t2I+35OAPBy5Pw/39bgkb/ZAFwMhwJbdYBp6aH+vW28ZgtjdU890Q7D+3wN/tB8N66q5Gi2A==", + "dev": true, + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^1.0.5", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0", + "mkdirp": "^0.5.3", + "rimraf": "^3.0.2" + } + }, + "node_modules/@wdio/cli/node_modules/chrome-launcher/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, "node_modules/@wdio/cli/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -2798,6 +3044,72 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/@wdio/cli/node_modules/devtools": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.5.7.tgz", + "integrity": "sha512-+kqmvFbceElhYpN35yjm1T4Rz3VbH0QaqrNWKRpeyFp657Y5W0bm1s5FyMUeIv0aTNkAgWcETtqL+EG9X9uvjQ==", + "dev": true, + "dependencies": { + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/protocols": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", + "chrome-launcher": "^0.13.1", + "edge-paths": "^2.1.0", + "puppeteer-core": "^9.1.0", + "query-selector-shadow-dom": "^1.0.0", + "ua-parser-js": "^0.7.21", + "uuid": "^8.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/cli/node_modules/devtools-protocol": { + "version": "0.0.878340", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.878340.tgz", + "integrity": "sha512-W0q8Y02r1RNwfZtI4Jjh1/MZxRHyrIgy9FvElbJzQelZjmNH197H4mBQs7DZjlUUDA9s6Zz2jl+zUYFgLgEnzw==", + "dev": true + }, + "node_modules/@wdio/cli/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wdio/cli/node_modules/puppeteer-core": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-9.1.1.tgz", + "integrity": "sha512-zbedbitVIGhmgz0nt7eIdLsnaoVZSlNJfBivqm2w67T8LR2bU1dvnruDZ8nQO0zn++Iet7zHbAOdnuS5+H2E7A==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "devtools-protocol": "0.0.869402", + "extract-zip": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "pkg-dir": "^4.2.0", + "progress": "^2.0.1", + "proxy-from-env": "^1.1.0", + "rimraf": "^3.0.2", + "tar-fs": "^2.0.0", + "unbzip2-stream": "^1.3.3", + "ws": "^7.2.3" + }, + "engines": { + "node": ">=10.18.1" + } + }, + "node_modules/@wdio/cli/node_modules/puppeteer-core/node_modules/devtools-protocol": { + "version": "0.0.869402", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.869402.tgz", + "integrity": "sha512-VvlVYY+VDJe639yHs5PHISzdWTLL3Aw8rO4cvUtwvoxFd6FHbE4OpHHcde52M6096uYYazAmd4l0o5VuFRO2WA==", + "dev": true + }, "node_modules/@wdio/cli/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -2810,13 +3122,82 @@ "node": ">=8" } }, + "node_modules/@wdio/cli/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@wdio/cli/node_modules/webdriverio": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.5.7.tgz", + "integrity": "sha512-TLluVPLo6Snn/dxEITvMz7ZuklN4qZOBddDuLb9LO3rhsfKDMNbnhcBk0SLdFsWny0aCuhWNpJ6co93702XC0A==", + "dev": true, + "dependencies": { + "@types/aria-query": "^4.2.1", + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/protocols": "7.5.3", + "@wdio/repl": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", + "archiver": "^5.0.0", + "aria-query": "^4.2.2", + "atob": "^2.1.2", + "css-shorthand-properties": "^1.1.1", + "css-value": "^0.0.1", + "devtools": "7.5.7", + "devtools-protocol": "^0.0.878340", + "fs-extra": "^10.0.0", + "get-port": "^5.1.1", + "grapheme-splitter": "^1.0.2", + "lodash.clonedeep": "^4.5.0", + "lodash.isobject": "^3.0.2", + "lodash.isplainobject": "^4.0.6", + "lodash.zip": "^4.2.0", + "minimatch": "^3.0.4", + "puppeteer-core": "^9.1.0", + "query-selector-shadow-dom": "^1.0.0", + "resq": "^1.9.1", + "rgb2hex": "0.2.5", + "serialize-error": "^8.0.0", + "webdriver": "7.5.3" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/cli/node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/@wdio/cli/node_modules/yargs": { - "version": "17.3.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz", - "integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==", + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", + "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", "dev": true, "dependencies": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", @@ -2829,13 +3210,13 @@ } }, "node_modules/@wdio/concise-reporter": { - "version": "7.16.14", - "resolved": "https://registry.npmjs.org/@wdio/concise-reporter/-/concise-reporter-7.16.14.tgz", - "integrity": "sha512-CR+9+skJ3mXPIdRo0AnIJTJHOArrWdKlXTnyZ/DD6M9VrNk5aiTWQyphT/IeHV5+fxjHlMNIf/KgIhj1ewschQ==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@wdio/concise-reporter/-/concise-reporter-7.5.7.tgz", + "integrity": "sha512-964i7eQ4sboSla2bdR8714Er82QBgS6u39GmDFX8Izy9Ge38xaE75HuF5S7mnOWGzSojCWgqtwy5k7Rfg6GE3g==", "dev": true, "dependencies": { - "@wdio/reporter": "7.16.14", - "@wdio/types": "7.16.14", + "@wdio/reporter": "7.5.7", + "@wdio/types": "7.5.3", "chalk": "^4.0.0", "pretty-ms": "^7.0.0" }, @@ -2846,6 +3227,18 @@ "@wdio/cli": "^7.0.0" } }, + "node_modules/@wdio/concise-reporter/node_modules/@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "dependencies": { + "got": "^11.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/@wdio/concise-reporter/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -2895,6 +3288,15 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/@wdio/concise-reporter/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, + "engines": { + "node": ">=8" + } + }, "node_modules/@wdio/concise-reporter/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -2908,13 +3310,13 @@ } }, "node_modules/@wdio/config": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-7.16.16.tgz", - "integrity": "sha512-K/ObPuo6Da2liz++OKOIfbdpFwI7UWiFcBylfJkCYbweuXCoW1aUqlKI6rmKPwCH9Uqr/RHWu6p8eo0zWe6xVA==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-7.5.3.tgz", + "integrity": "sha512-udvVizYoilOxuWj/BmoN6y7ZCd4wPdYNlSfWznrbCezAdaLZ4/pNDOO0WRWx2C4+q1wdkXZV/VuQPUGfL0lEHQ==", "dev": true, "dependencies": { - "@wdio/logger": "7.16.0", - "@wdio/types": "7.16.14", + "@wdio/logger": "7.5.3", + "@wdio/types": "7.5.3", "deepmerge": "^4.0.0", "glob": "^7.1.2" }, @@ -2922,19 +3324,116 @@ "node": ">=12.0.0" } }, + "node_modules/@wdio/config/node_modules/@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/config/node_modules/@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "dependencies": { + "got": "^11.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/config/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@wdio/config/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@wdio/config/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@wdio/config/node_modules/color-name": { + "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 + }, + "node_modules/@wdio/config/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wdio/config/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@wdio/local-runner": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-7.16.16.tgz", - "integrity": "sha512-AJaOyM842PWgMffrrXyHJjouVseLHoiL5U1sw2VVproi3ORWHbltl1AMnreU/lrGu9L0CVKHYT1pxu5UbSOCxQ==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-7.5.7.tgz", + "integrity": "sha512-aYc0XUV+/e3cg8Fp+CWlC4FbwSSG3mKAv1iuy/+Hwzg2kJE+aa+Rf2p2BQYc7HPRtKNW0bM8o+aCImZLAiPM+A==", "dev": true, "dependencies": { "@types/stream-buffers": "^3.0.3", - "@wdio/logger": "7.16.0", - "@wdio/repl": "7.16.14", - "@wdio/runner": "7.16.16", - "@wdio/types": "7.16.14", + "@wdio/logger": "7.5.3", + "@wdio/repl": "7.5.3", + "@wdio/runner": "7.5.7", + "@wdio/types": "7.5.3", "async-exit-hook": "^2.0.1", - "split2": "^4.0.0", + "split2": "^3.2.2", "stream-buffers": "^3.0.2" }, "engines": { @@ -2944,6 +3443,103 @@ "@wdio/cli": "^7.0.0" } }, + "node_modules/@wdio/local-runner/node_modules/@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/local-runner/node_modules/@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "dependencies": { + "got": "^11.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/local-runner/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@wdio/local-runner/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@wdio/local-runner/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@wdio/local-runner/node_modules/color-name": { + "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 + }, + "node_modules/@wdio/local-runner/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wdio/local-runner/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@wdio/logger": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.16.0.tgz", @@ -3008,6 +3604,15 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/@wdio/logger/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, + "engines": { + "node": ">=8" + } + }, "node_modules/@wdio/logger/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -3021,22 +3626,58 @@ } }, "node_modules/@wdio/mocha-framework": { - "version": "7.16.15", - "resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-7.16.15.tgz", - "integrity": "sha512-XRya85/RYPZk4MZ7Cvl3oudTdrOo+RyO8b5Ff+dH8hD3GBCACaWgW9AjbsyhvbSTdUlF0gNLPdqOCsxV5XyM3w==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-7.5.3.tgz", + "integrity": "sha512-96QCVWsiyZxEgOZP3oTq2B2T7zne5dCdehLa2n4q/BLjk96Rj0jifidJZfd/1+vdNPKX0gWWAzpy98Znn8MVMw==", "dev": true, "dependencies": { - "@types/mocha": "^9.0.0", - "@wdio/logger": "7.16.0", - "@wdio/types": "7.16.14", - "@wdio/utils": "7.16.14", - "expect-webdriverio": "^3.0.0", - "mocha": "^9.0.0" + "@types/mocha": "^8.0.0", + "@wdio/logger": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", + "expect-webdriverio": "^2.0.0", + "mocha": "^8.0.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/mocha-framework/node_modules/@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/mocha-framework/node_modules/@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "dependencies": { + "got": "^11.8.1" }, "engines": { "node": ">=12.0.0" } }, + "node_modules/@wdio/mocha-framework/node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/@wdio/mocha-framework/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -3074,16 +3715,36 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@wdio/mocha-framework/node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@wdio/mocha-framework/node_modules/chokidar": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", + "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" }, "engines": { - "node": ">=8" + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.1" + } + }, + "node_modules/@wdio/mocha-framework/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, "node_modules/@wdio/mocha-framework/node_modules/color-convert": { @@ -3104,6 +3765,32 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/@wdio/mocha-framework/node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@wdio/mocha-framework/node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/@wdio/mocha-framework/node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -3132,10 +3819,39 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@wdio/mocha-framework/node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@wdio/mocha-framework/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, + "engines": { + "node": ">=8" + } + }, "node_modules/@wdio/mocha-framework/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", "dev": true, "dependencies": { "argparse": "^2.0.1" @@ -3160,19 +3876,15 @@ } }, "node_modules/@wdio/mocha-framework/node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", + "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", "dev": true, "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" + "chalk": "^4.0.0" }, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@wdio/mocha-framework/node_modules/minimatch": { @@ -3188,32 +3900,33 @@ } }, "node_modules/@wdio/mocha-framework/node_modules/mocha": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.1.tgz", - "integrity": "sha512-T7uscqjJVS46Pq1XDXyo9Uvey9gd3huT/DD9cYBb4K2Xc/vbKRPUWK067bxDQRK0yIz6Jxk73IrnimvASzBNAQ==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.4.0.tgz", + "integrity": "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==", "dev": true, "dependencies": { "@ungap/promise-all-settled": "1.1.2", "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.3", + "chokidar": "3.5.1", + "debug": "4.3.1", "diff": "5.0.0", "escape-string-regexp": "4.0.0", "find-up": "5.0.0", - "glob": "7.2.0", + "glob": "7.1.6", "growl": "1.10.5", "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", + "js-yaml": "4.0.0", + "log-symbols": "4.0.0", "minimatch": "3.0.4", "ms": "2.1.3", - "nanoid": "3.2.0", - "serialize-javascript": "6.0.0", + "nanoid": "3.1.20", + "serialize-javascript": "5.0.1", "strip-json-comments": "3.1.1", "supports-color": "8.1.1", "which": "2.0.2", - "workerpool": "6.2.0", + "wide-align": "1.1.3", + "workerpool": "6.1.0", "yargs": "16.2.0", "yargs-parser": "20.2.4", "yargs-unparser": "2.0.0" @@ -3223,23 +3936,38 @@ "mocha": "bin/mocha" }, "engines": { - "node": ">= 12.0.0" + "node": ">= 10.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/mochajs" } }, - "node_modules/@wdio/mocha-framework/node_modules/ms": { + "node_modules/@wdio/mocha-framework/node_modules/mocha/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, + "node_modules/@wdio/mocha-framework/node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/@wdio/mocha-framework/node_modules/nanoid": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", - "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", + "version": "3.1.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz", + "integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==", "dev": true, "bin": { "nanoid": "bin/nanoid.cjs" @@ -3278,13 +4006,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@wdio/mocha-framework/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "node_modules/@wdio/mocha-framework/node_modules/readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, "engines": { - "node": ">=8" + "node": ">=8.10.0" + } + }, + "node_modules/@wdio/mocha-framework/node_modules/serialize-javascript": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", + "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" } }, "node_modules/@wdio/mocha-framework/node_modules/strip-json-comments": { @@ -3299,6 +4039,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@wdio/mocha-framework/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wdio/mocha-framework/node_modules/workerpool": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.0.tgz", + "integrity": "sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==", + "dev": true + }, "node_modules/@wdio/mocha-framework/node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -3327,75 +4085,347 @@ } }, "node_modules/@wdio/protocols": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-7.16.7.tgz", - "integrity": "sha512-Wv40pNQcLiPzQ3o98Mv4A8T1EBQ6k4khglz/e2r16CTm+F3DDYh8eLMAsU5cgnmuwwDKX1EyOiFwieykBn5MCg==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-7.5.3.tgz", + "integrity": "sha512-lpNaKwxYhDSL6neDtQQYXvzMAw+u4PXx65ryeMEX82mkARgzSZps5Kyrg9ub7X4T17K1NPfnY6UhZEWg6cKJCg==", "dev": true, "engines": { "node": ">=12.0.0" } }, "node_modules/@wdio/repl": { - "version": "7.16.14", - "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-7.16.14.tgz", - "integrity": "sha512-Ezih0Y+lsGkKv3H3U56hdWgZiQGA3VaAYguSLd9+g1xbQq+zMKqSmfqECD9bAy+OgCCiVTRstES6lHZxJVPhAg==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-7.5.3.tgz", + "integrity": "sha512-jfNJwNoc2nWdnLsFoGHmOJR9zaWfDTBMWM3W1eR5kXIjevD6gAfWsB5ZoA4IdybujCXxdnhlsm4o2jIzp/6f7A==", "dev": true, "dependencies": { - "@wdio/utils": "7.16.14" + "@wdio/utils": "7.5.3" }, "engines": { "node": ">=12.0.0" } }, "node_modules/@wdio/reporter": { - "version": "7.16.14", - "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-7.16.14.tgz", - "integrity": "sha512-e/I2oGfqjx9+zI4NT/garqxm7Afnos1EcrGSNu75WmP3PNJt4i+9DKkROu4PM6XWcpUB4v2UF7Mv/NrL3TU9aA==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-7.5.7.tgz", + "integrity": "sha512-9PXqZtCXDtU6UYLNDPu9MZQ8BiABGnRlJTrlbYB3gBfZDibMkJMvwXzPderipBv2+ifDZXmGe3Njf1ao2TkbFA==", "dev": true, "dependencies": { - "@types/diff": "^5.0.0", - "@types/node": "^17.0.4", - "@types/object-inspect": "^1.8.0", - "@types/supports-color": "^8.1.0", - "@types/tmp": "^0.2.0", - "@wdio/types": "7.16.14", - "diff": "^5.0.0", - "fs-extra": "^10.0.0", - "object-inspect": "^1.10.3", - "supports-color": "8.1.1" + "@wdio/types": "7.5.3", + "fs-extra": "^10.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/reporter/node_modules/@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "dependencies": { + "got": "^11.8.1" }, "engines": { "node": ">=12.0.0" } }, "node_modules/@wdio/runner": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-7.16.16.tgz", - "integrity": "sha512-Tt2ja6GukGPq1m98WP26yOWUGwzK1y7gPTLy6rKlamz3mOBC7koL0T9+iqcFREquUe4CMy2jWp1lqvPlwMbu7g==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-7.5.7.tgz", + "integrity": "sha512-RzVXd+xnwK/thkx1/xo9K5iscQ0Ofobgsx5dNVtwLDVMn9V7jCW/WX4dSCPAPaVSqnUCmkcQp3P5AoSBPpCZnQ==", "dev": true, "dependencies": { - "@wdio/config": "7.16.16", - "@wdio/logger": "7.16.0", - "@wdio/types": "7.16.14", - "@wdio/utils": "7.16.14", + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", "deepmerge": "^4.0.0", "gaze": "^1.1.2", - "webdriver": "7.16.16", - "webdriverio": "7.16.16" + "webdriver": "7.5.3", + "webdriverio": "7.5.7" }, "engines": { "node": ">=12.0.0" } }, - "node_modules/@wdio/spec-reporter": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-7.19.1.tgz", - "integrity": "sha512-qnZkn3VcyBPtcorUtpyCFE8v5ubyWmR7mFETXNzyriHyvjvk+NeFCWaFcIehpXYXiAmNpAwyfnZoIY6tkKQixQ==", + "node_modules/@wdio/runner/node_modules/@types/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", + "dev": true + }, + "node_modules/@wdio/runner/node_modules/@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", "dev": true, "dependencies": { - "@types/easy-table": "^0.0.33", - "@wdio/reporter": "7.19.1", - "@wdio/types": "7.19.1", + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/runner/node_modules/@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "dependencies": { + "got": "^11.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/runner/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@wdio/runner/node_modules/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/@wdio/runner/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@wdio/runner/node_modules/chrome-launcher": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.13.4.tgz", + "integrity": "sha512-nnzXiDbGKjDSK6t2I+35OAPBy5Pw/39bgkb/ZAFwMhwJbdYBp6aH+vW28ZgtjdU890Q7D+3wN/tB8N66q5Gi2A==", + "dev": true, + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^1.0.5", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0", + "mkdirp": "^0.5.3", + "rimraf": "^3.0.2" + } + }, + "node_modules/@wdio/runner/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@wdio/runner/node_modules/color-name": { + "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 + }, + "node_modules/@wdio/runner/node_modules/devtools": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.5.7.tgz", + "integrity": "sha512-+kqmvFbceElhYpN35yjm1T4Rz3VbH0QaqrNWKRpeyFp657Y5W0bm1s5FyMUeIv0aTNkAgWcETtqL+EG9X9uvjQ==", + "dev": true, + "dependencies": { + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/protocols": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", + "chrome-launcher": "^0.13.1", + "edge-paths": "^2.1.0", + "puppeteer-core": "^9.1.0", + "query-selector-shadow-dom": "^1.0.0", + "ua-parser-js": "^0.7.21", + "uuid": "^8.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/runner/node_modules/devtools-protocol": { + "version": "0.0.878340", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.878340.tgz", + "integrity": "sha512-W0q8Y02r1RNwfZtI4Jjh1/MZxRHyrIgy9FvElbJzQelZjmNH197H4mBQs7DZjlUUDA9s6Zz2jl+zUYFgLgEnzw==", + "dev": true + }, + "node_modules/@wdio/runner/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wdio/runner/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/@wdio/runner/node_modules/puppeteer-core": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-9.1.1.tgz", + "integrity": "sha512-zbedbitVIGhmgz0nt7eIdLsnaoVZSlNJfBivqm2w67T8LR2bU1dvnruDZ8nQO0zn++Iet7zHbAOdnuS5+H2E7A==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "devtools-protocol": "0.0.869402", + "extract-zip": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "pkg-dir": "^4.2.0", + "progress": "^2.0.1", + "proxy-from-env": "^1.1.0", + "rimraf": "^3.0.2", + "tar-fs": "^2.0.0", + "unbzip2-stream": "^1.3.3", + "ws": "^7.2.3" + }, + "engines": { + "node": ">=10.18.1" + } + }, + "node_modules/@wdio/runner/node_modules/puppeteer-core/node_modules/devtools-protocol": { + "version": "0.0.869402", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.869402.tgz", + "integrity": "sha512-VvlVYY+VDJe639yHs5PHISzdWTLL3Aw8rO4cvUtwvoxFd6FHbE4OpHHcde52M6096uYYazAmd4l0o5VuFRO2WA==", + "dev": true + }, + "node_modules/@wdio/runner/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wdio/runner/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@wdio/runner/node_modules/webdriverio": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.5.7.tgz", + "integrity": "sha512-TLluVPLo6Snn/dxEITvMz7ZuklN4qZOBddDuLb9LO3rhsfKDMNbnhcBk0SLdFsWny0aCuhWNpJ6co93702XC0A==", + "dev": true, + "dependencies": { + "@types/aria-query": "^4.2.1", + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/protocols": "7.5.3", + "@wdio/repl": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", + "archiver": "^5.0.0", + "aria-query": "^4.2.2", + "atob": "^2.1.2", + "css-shorthand-properties": "^1.1.1", + "css-value": "^0.0.1", + "devtools": "7.5.7", + "devtools-protocol": "^0.0.878340", + "fs-extra": "^10.0.0", + "get-port": "^5.1.1", + "grapheme-splitter": "^1.0.2", + "lodash.clonedeep": "^4.5.0", + "lodash.isobject": "^3.0.2", + "lodash.isplainobject": "^4.0.6", + "lodash.zip": "^4.2.0", + "minimatch": "^3.0.4", + "puppeteer-core": "^9.1.0", + "query-selector-shadow-dom": "^1.0.0", + "resq": "^1.9.1", + "rgb2hex": "0.2.5", + "serialize-error": "^8.0.0", + "webdriver": "7.5.3" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/runner/node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@wdio/spec-reporter": { + "version": "7.19.7", + "resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-7.19.7.tgz", + "integrity": "sha512-BDBZU2EK/GuC9VxtfqPtoW43FmvKxYDsvcDVDi3F7o+9fkcuGSJiWbw1AX251ZzzVQ7YP9ImTitSpdpUKXkilQ==", + "dev": true, + "dependencies": { + "@types/easy-table": "^0.0.33", + "@wdio/reporter": "7.19.7", + "@wdio/types": "7.19.5", "chalk": "^4.0.0", "easy-table": "^1.1.1", "pretty-ms": "^7.0.0" @@ -3408,9 +4438,9 @@ } }, "node_modules/@wdio/spec-reporter/node_modules/@wdio/reporter": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-7.19.1.tgz", - "integrity": "sha512-sWmBBV4dPCZkGk9Qq0m35T/vHGen0N10nH4osQcVP3IZJqpo2eLIH4w+X6EUbjZ2GdgOA2bLMMzb1bl9JqnGPg==", + "version": "7.19.7", + "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-7.19.7.tgz", + "integrity": "sha512-Dum19gpfru66FnIq78/4HTuW87B7ceLDp6PJXwQM5kXyN7Gb7zhMgp6FZTM0FCYLyi6U/zXZSvpNUYl77caS6g==", "dev": true, "dependencies": { "@types/diff": "^5.0.0", @@ -3418,7 +4448,7 @@ "@types/object-inspect": "^1.8.0", "@types/supports-color": "^8.1.0", "@types/tmp": "^0.2.0", - "@wdio/types": "7.19.1", + "@wdio/types": "7.19.5", "diff": "^5.0.0", "fs-extra": "^10.0.0", "object-inspect": "^1.10.3", @@ -3428,7 +4458,93 @@ "node": ">=12.0.0" } }, - "node_modules/@wdio/spec-reporter/node_modules/@wdio/reporter/node_modules/supports-color": { + "node_modules/@wdio/spec-reporter/node_modules/@wdio/types": { + "version": "7.19.5", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.19.5.tgz", + "integrity": "sha512-S1lC0pmtEO7NVH/2nM1c7NHbkgxLZH3VVG/z6ym3Bbxdtcqi2LMsEvvawMAU/fmhyiIkMsGZCO8vxG9cRw4z4A==", + "dev": true, + "dependencies": { + "@types/node": "^17.0.4", + "got": "^11.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "^4.6.2" + } + }, + "node_modules/@wdio/spec-reporter/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@wdio/spec-reporter/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@wdio/spec-reporter/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wdio/spec-reporter/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@wdio/spec-reporter/node_modules/color-name": { + "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 + }, + "node_modules/@wdio/spec-reporter/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wdio/spec-reporter/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", @@ -3443,23 +4559,57 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/@wdio/spec-reporter/node_modules/@wdio/types": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.19.1.tgz", - "integrity": "sha512-mOodKlmvYxpj8P5BhjggEGpXuiRSlsyn2ClG8QqJ3lfXgOtOVEzFNfv/Ai7TkHr+lHDQNXLjllCjSqoCHhwlqg==", + "node_modules/@wdio/sync": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@wdio/sync/-/sync-7.5.7.tgz", + "integrity": "sha512-Zu/AYLjwqbFSbaOU1US7ownv3ov8JrtoGHq51JfJ4masefJDXNkHix2cZ0qEgl3IvkkWQ0ewL0G8GTXb3KOemA==", "dev": true, "dependencies": { - "@types/node": "^17.0.4", - "got": "^11.8.1" + "@types/fibers": "^3.1.0", + "@types/puppeteer": "^5.4.0", + "@wdio/logger": "7.5.3", + "@wdio/types": "7.5.3", + "fibers": "^5.0.0", + "webdriverio": "7.5.7" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/sync/node_modules/@types/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", + "dev": true + }, + "node_modules/@wdio/sync/node_modules/@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" }, "engines": { "node": ">=12.0.0" + } + }, + "node_modules/@wdio/sync/node_modules/@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "dependencies": { + "got": "^11.8.1" }, - "peerDependencies": { - "typescript": "^4.6.2" + "engines": { + "node": ">=12.0.0" } }, - "node_modules/@wdio/spec-reporter/node_modules/ansi-styles": { + "node_modules/@wdio/sync/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", @@ -3474,7 +4624,20 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@wdio/spec-reporter/node_modules/chalk": { + "node_modules/@wdio/sync/node_modules/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/@wdio/sync/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", @@ -3490,7 +4653,21 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@wdio/spec-reporter/node_modules/color-convert": { + "node_modules/@wdio/sync/node_modules/chrome-launcher": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.13.4.tgz", + "integrity": "sha512-nnzXiDbGKjDSK6t2I+35OAPBy5Pw/39bgkb/ZAFwMhwJbdYBp6aH+vW28ZgtjdU890Q7D+3wN/tB8N66q5Gi2A==", + "dev": true, + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^1.0.5", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0", + "mkdirp": "^0.5.3", + "rimraf": "^3.0.2" + } + }, + "node_modules/@wdio/sync/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", @@ -3502,13 +4679,91 @@ "node": ">=7.0.0" } }, - "node_modules/@wdio/spec-reporter/node_modules/color-name": { + "node_modules/@wdio/sync/node_modules/color-name": { "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 }, - "node_modules/@wdio/spec-reporter/node_modules/supports-color": { + "node_modules/@wdio/sync/node_modules/devtools": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.5.7.tgz", + "integrity": "sha512-+kqmvFbceElhYpN35yjm1T4Rz3VbH0QaqrNWKRpeyFp657Y5W0bm1s5FyMUeIv0aTNkAgWcETtqL+EG9X9uvjQ==", + "dev": true, + "dependencies": { + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/protocols": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", + "chrome-launcher": "^0.13.1", + "edge-paths": "^2.1.0", + "puppeteer-core": "^9.1.0", + "query-selector-shadow-dom": "^1.0.0", + "ua-parser-js": "^0.7.21", + "uuid": "^8.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/sync/node_modules/devtools-protocol": { + "version": "0.0.878340", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.878340.tgz", + "integrity": "sha512-W0q8Y02r1RNwfZtI4Jjh1/MZxRHyrIgy9FvElbJzQelZjmNH197H4mBQs7DZjlUUDA9s6Zz2jl+zUYFgLgEnzw==", + "dev": true + }, + "node_modules/@wdio/sync/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wdio/sync/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/@wdio/sync/node_modules/puppeteer-core": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-9.1.1.tgz", + "integrity": "sha512-zbedbitVIGhmgz0nt7eIdLsnaoVZSlNJfBivqm2w67T8LR2bU1dvnruDZ8nQO0zn++Iet7zHbAOdnuS5+H2E7A==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "devtools-protocol": "0.0.869402", + "extract-zip": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "pkg-dir": "^4.2.0", + "progress": "^2.0.1", + "proxy-from-env": "^1.1.0", + "rimraf": "^3.0.2", + "tar-fs": "^2.0.0", + "unbzip2-stream": "^1.3.3", + "ws": "^7.2.3" + }, + "engines": { + "node": ">=10.18.1" + } + }, + "node_modules/@wdio/sync/node_modules/puppeteer-core/node_modules/devtools-protocol": { + "version": "0.0.869402", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.869402.tgz", + "integrity": "sha512-VvlVYY+VDJe639yHs5PHISzdWTLL3Aw8rO4cvUtwvoxFd6FHbE4OpHHcde52M6096uYYazAmd4l0o5VuFRO2WA==", + "dev": true + }, + "node_modules/@wdio/sync/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", @@ -3520,21 +4775,73 @@ "node": ">=8" } }, - "node_modules/@wdio/sync": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/@wdio/sync/-/sync-7.16.16.tgz", - "integrity": "sha512-MbVFAteaAOxHLKkMiMzOnh1hzINAK2U41GDIfy1yaPumcw1pNuJIhWrBYxprNMlqt8srk++wqQWgj5XpFjCL6g==", + "node_modules/@wdio/sync/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@wdio/sync/node_modules/webdriverio": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.5.7.tgz", + "integrity": "sha512-TLluVPLo6Snn/dxEITvMz7ZuklN4qZOBddDuLb9LO3rhsfKDMNbnhcBk0SLdFsWny0aCuhWNpJ6co93702XC0A==", "dev": true, "dependencies": { - "@types/fibers": "^3.1.0", - "@types/puppeteer": "^5.4.0", - "@wdio/logger": "7.16.0", - "@wdio/types": "7.16.14", - "fibers": "^5.0.0", - "webdriverio": "7.16.16" + "@types/aria-query": "^4.2.1", + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/protocols": "7.5.3", + "@wdio/repl": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", + "archiver": "^5.0.0", + "aria-query": "^4.2.2", + "atob": "^2.1.2", + "css-shorthand-properties": "^1.1.1", + "css-value": "^0.0.1", + "devtools": "7.5.7", + "devtools-protocol": "^0.0.878340", + "fs-extra": "^10.0.0", + "get-port": "^5.1.1", + "grapheme-splitter": "^1.0.2", + "lodash.clonedeep": "^4.5.0", + "lodash.isobject": "^3.0.2", + "lodash.isplainobject": "^4.0.6", + "lodash.zip": "^4.2.0", + "minimatch": "^3.0.4", + "puppeteer-core": "^9.1.0", + "query-selector-shadow-dom": "^1.0.0", + "resq": "^1.9.1", + "rgb2hex": "0.2.5", + "serialize-error": "^8.0.0", + "webdriver": "7.5.3" }, "engines": { - "node": ">=12.0.0 <16" + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/sync/node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, "node_modules/@wdio/types": { @@ -3551,19 +4858,115 @@ } }, "node_modules/@wdio/utils": { - "version": "7.16.14", - "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-7.16.14.tgz", - "integrity": "sha512-wwin8nVpIlhmXJkq6GJw9aDDzgLOJKgXTcEua0T2sdXjoW78u5Ly/GZrFXTjMGhacFvoZfitTrjyfyy4CxMVvw==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-7.5.3.tgz", + "integrity": "sha512-nlLDKr8v8abLOHCKroBwQkGPdCIxjID2MllgWX23xqkYZylM9RdwPBdL8osQt9m3rq2TxiPAT4OlbzNt2WtN6Q==", "dev": true, "dependencies": { - "@wdio/logger": "7.16.0", - "@wdio/types": "7.16.14", - "p-iteration": "^1.1.8" + "@wdio/logger": "7.5.3", + "@wdio/types": "7.5.3" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/utils/node_modules/@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" }, "engines": { "node": ">=12.0.0" } }, + "node_modules/@wdio/utils/node_modules/@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "dependencies": { + "got": "^11.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/utils/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@wdio/utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@wdio/utils/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@wdio/utils/node_modules/color-name": { + "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 + }, + "node_modules/@wdio/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wdio/utils/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", @@ -3711,9 +5114,9 @@ } }, "node_modules/@xmldom/xmldom": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.6.tgz", - "integrity": "sha512-HHXP9hskkFQHy8QxxUXkS7946FFIhYVfGqsk0WLwllmexN9x/+R4UBLvurHEuyXRfVEObVR8APuQehykLviwSQ==", + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.8.tgz", + "integrity": "sha512-PrJx38EfpitFhwmILRl37jAdBlsww6AZ6rRVK4QS7T7RHLhX7mSs647sTmgr9GIxe3qjXdesmomEgbgaokrVFg==", "dev": true, "engines": { "node": ">=10.0.0" @@ -3734,7 +5137,7 @@ "node_modules/abbrev": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", - "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", + "integrity": "sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==", "dev": true }, "node_modules/accepts": { @@ -3770,6 +5173,15 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/aes-decrypter": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-3.1.3.tgz", @@ -3783,10 +5195,13 @@ } }, "node_modules/agent-base": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", - "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==", + "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, + "dependencies": { + "debug": "4" + }, "engines": { "node": ">= 6.0.0" } @@ -3807,10 +5222,19 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, "node_modules/amdefine": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", "dev": true, "optional": true, "engines": { @@ -3818,9 +5242,9 @@ } }, "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true, "engines": { "node": ">=6" @@ -3856,7 +5280,7 @@ "node_modules/ansi-gray": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", - "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", + "integrity": "sha512-HrgGIZUl8h2EHuZaU9hTR/cU5nhKxpVE1V6kdGsQ8e4zirElJ5fvtfc8N7Q1oq1aatO275i8pUFUCpNWCAnVWw==", "dev": true, "dependencies": { "ansi-wrap": "0.1.0" @@ -3900,7 +5324,7 @@ "node_modules/ansi-wrap": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", - "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", + "integrity": "sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -3922,7 +5346,7 @@ "node_modules/append-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", - "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=", + "integrity": "sha512-WLbYiXzD3y/ATLZFufV/rZvWdZOs+Z/+5v1rBZ463Jn398pa6kcde27cvozYnBoxXblGZTFfoPpsaEw0orU5BA==", "dev": true, "dependencies": { "buffer-equal": "^1.0.0" @@ -3932,13 +5356,13 @@ } }, "node_modules/archiver": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.0.tgz", - "integrity": "sha512-iUw+oDwK0fgNpvveEsdQ0Ase6IIKztBJU2U0E9MzszMfmVVUyv1QJhS2ITW9ZCqx8dktAxVAjWWkKehuZE8OPg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.1.tgz", + "integrity": "sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w==", "dev": true, "dependencies": { "archiver-utils": "^2.1.0", - "async": "^3.2.0", + "async": "^3.2.3", "buffer-crc32": "^0.2.1", "readable-stream": "^3.6.0", "readdir-glob": "^1.0.0", @@ -3971,9 +5395,9 @@ } }, "node_modules/archiver/node_modules/async": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", - "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", "dev": true }, "node_modules/archiver/node_modules/readable-stream": { @@ -3993,7 +5417,7 @@ "node_modules/archy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", "dev": true }, "node_modules/argparse": { @@ -4006,18 +5430,31 @@ } }, "node_modules/aria-query": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.0.0.tgz", - "integrity": "sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", "dev": true, - "engines": { - "node": ">=6.0" + "dependencies": { + "deep-equal": "^2.0.5" } }, "node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz", + "integrity": "sha512-OQwDZUqYaQwyyhDJHThmzId8daf4/RFNLaeh3AevmSeZ5Y7ug4Ga/yKc6l6kTZOBW781rCj103ZuTh8GAsB3+Q==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.0.1", + "array-slice": "^0.2.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-diff/node_modules/array-slice": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", + "integrity": "sha512-rlVfZW/1Ph2SNySXwR9QYkChp8EkOEiTMO5Vwx60usw04i4nWemkm9RXmQqgkQFaLHsqLuADvjp6IfgL9l2M8Q==", "dev": true, "engines": { "node": ">=0.10.0" @@ -4026,7 +5463,7 @@ "node_modules/arr-filter": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", - "integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=", + "integrity": "sha512-A2BETWCqhsecSvCkWAeVBFLH6sXEUGASuzkpjL3GR1SlL/PWL6M3J8EAAld2Uubmh39tvkJTqC9LeLHCUKmFXA==", "dev": true, "dependencies": { "make-iterator": "^1.0.0" @@ -4047,7 +5484,7 @@ "node_modules/arr-map": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", - "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=", + "integrity": "sha512-tVqVTHt+Q5Xb09qRkbu+DidW1yYzz5izWS2Xm2yFm7qJnmUfz4HPzNxbHkdRJbz2lrqI7S+z17xNYdFcBBO8Hw==", "dev": true, "dependencies": { "make-iterator": "^1.0.0" @@ -4057,9 +5494,9 @@ } }, "node_modules/arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz", + "integrity": "sha512-t5db90jq+qdgk8aFnxEkjqta0B/GHrM1pxzuuZz2zWsOXc5nKu3t+76s/PQBA8FTcM/ipspIH9jWG4OxCBc2eA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -4068,7 +5505,7 @@ "node_modules/array-differ": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", - "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", + "integrity": "sha512-LeZY+DZDRnvP7eMuQ6LHfCzUGxAAIViUBliK24P3hWXL6y4SortgR6Nim6xrkfSLlmH0+k+9NYNwVC2s53ZrYQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -4077,7 +5514,7 @@ "node_modules/array-each": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", - "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", + "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -4086,23 +5523,23 @@ "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, "node_modules/array-from": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", - "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", + "integrity": "sha512-GQTc6Uupx1FCavi5mPzBvVT7nEOeWMmUA9P95wpfpW1XwMSKs+KaymD5C2Up7KAUKg/mYwbsUYzdZWcoajlNZg==", "dev": true }, "node_modules/array-includes": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", - "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", + "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5", "get-intrinsic": "^1.1.1", "is-string": "^1.0.7" }, @@ -4116,7 +5553,7 @@ "node_modules/array-initial": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", - "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=", + "integrity": "sha512-BC4Yl89vneCYfpLrs5JU2aAu9/a+xWbeKhvISg9PT7eWFB9UlRvI+rKEtk6mgxWr3dSkk9gQ8hCrdqt06NXPdw==", "dev": true, "dependencies": { "array-slice": "^1.0.0", @@ -4182,7 +5619,7 @@ "node_modules/array-uniq": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", "dev": true, "engines": { "node": ">=0.10.0" @@ -4191,21 +5628,22 @@ "node_modules/array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/array.prototype.flat": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", - "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", + "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -4238,7 +5676,7 @@ "node_modules/assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "dev": true, "engines": { "node": ">=0.8" @@ -4256,7 +5694,7 @@ "node_modules/assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -4274,7 +5712,7 @@ "node_modules/async": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "integrity": "sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==", "dev": true }, "node_modules/async-done": { @@ -4310,7 +5748,7 @@ "node_modules/async-settle": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", - "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=", + "integrity": "sha512-VPXfB4Vk49z1LHHodrEQ6Xf7W4gg1w0dAPROHngx7qgDjqmIQ+fXmwgGXTW/ITLai0YLSvWepJOP9EVpMnEAcw==", "dev": true, "dependencies": { "async-done": "^1.2.2" @@ -4322,7 +5760,7 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, "node_modules/atob": { @@ -4352,7 +5790,7 @@ "node_modules/aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", "dev": true, "engines": { "node": "*" @@ -4367,7 +5805,7 @@ "node_modules/babel-code-frame": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "integrity": "sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g==", "dev": true, "dependencies": { "chalk": "^1.1.3", @@ -4378,7 +5816,7 @@ "node_modules/babel-code-frame/node_modules/ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -4387,7 +5825,7 @@ "node_modules/babel-code-frame/node_modules/ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -4396,7 +5834,7 @@ "node_modules/babel-code-frame/node_modules/chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "dependencies": { "ansi-styles": "^2.2.1", @@ -4412,13 +5850,13 @@ "node_modules/babel-code-frame/node_modules/js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "integrity": "sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==", "dev": true }, "node_modules/babel-code-frame/node_modules/strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "dependencies": { "ansi-regex": "^2.0.0" @@ -4430,7 +5868,7 @@ "node_modules/babel-code-frame/node_modules/supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, "engines": { "node": ">=0.8.0" @@ -4475,7 +5913,7 @@ "node_modules/babel-core/node_modules/json5": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "integrity": "sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw==", "dev": true, "bin": { "json5": "lib/cli.js" @@ -4484,18 +5922,9 @@ "node_modules/babel-core/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, - "node_modules/babel-core/node_modules/slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/babel-generator": { "version": "6.26.1", "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", @@ -4512,22 +5941,10 @@ "trim-right": "^1.0.1" } }, - "node_modules/babel-generator/node_modules/detect-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", - "dev": true, - "dependencies": { - "repeating": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/babel-generator/node_modules/jsesc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", - "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "integrity": "sha512-Mke0DA0QjUWuJlhsE0ZPPhYiJkRap642SmI/4ztCFaUs6V2AiH1sfecc+57NgaryfAA2VR3v6O+CSjC1jZJKOA==", "dev": true, "bin": { "jsesc": "bin/jsesc" @@ -4536,7 +5953,7 @@ "node_modules/babel-helpers": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", - "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "integrity": "sha512-n7pFrqQm44TCYvrCDb0MqabAF+JUBq+ijBvNMUxpkLjJaAu32faIexewMumrH5KLLJ1HDyT0PTEqRyAe/GwwuQ==", "dev": true, "dependencies": { "babel-runtime": "^6.22.0", @@ -4544,13 +5961,13 @@ } }, "node_modules/babel-loader": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.3.tgz", - "integrity": "sha512-n4Zeta8NC3QAsuyiizu0GkmRcQ6clkV9WFUnUf1iXP//IeSKbWjofW3UHyZVwlOB4y039YQKefawyTn64Zwbuw==", + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", + "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", "dev": true, "dependencies": { "find-cache-dir": "^3.3.1", - "loader-utils": "^1.4.0", + "loader-utils": "^2.0.0", "make-dir": "^3.1.0", "schema-utils": "^2.6.5" }, @@ -4562,49 +5979,15 @@ "webpack": ">=2" } }, - "node_modules/babel-loader/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/babel-loader/node_modules/loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", - "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/babel-messages": { "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "integrity": "sha512-Bl3ZiA+LjqaMtNYopA9TYE9HP1tQ+E5dLxE0XrAzcIJeK2UqF0/EaqXwBn9esd4UmTfEab+P+UYQ1GnioFIb/w==", "dev": true, "dependencies": { "babel-runtime": "^6.22.0" } }, - "node_modules/babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "dependencies": { - "object.assign": "^4.1.0" - } - }, "node_modules/babel-plugin-istanbul": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", @@ -4621,29 +6004,13 @@ "node": ">=8" } }, - "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", - "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", - "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", "dependencies": { - "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.3.1", + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", "semver": "^6.1.1" }, "peerDependencies": { @@ -4651,23 +6018,23 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", - "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", + "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.1", - "core-js-compat": "^3.21.0" + "@babel/helper-define-polyfill-provider": "^0.3.3", + "core-js-compat": "^3.25.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", - "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.1" + "@babel/helper-define-polyfill-provider": "^0.3.3" }, "peerDependencies": { "@babel/core": "^7.0.0-0" @@ -4676,7 +6043,7 @@ "node_modules/babel-register": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", - "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", + "integrity": "sha512-veliHlHX06wjaeY8xNITbveXSiI+ASFnOqvne/LaIJIqOWi2Ogmj91KOugEz/hoh/fwMhXNBJPCv8Xaz5CyM4A==", "dev": true, "dependencies": { "babel-core": "^6.26.0", @@ -4708,19 +6075,10 @@ "mkdirp": "bin/cmd.js" } }, - "node_modules/babel-register/node_modules/source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "dev": true, - "dependencies": { - "source-map": "^0.5.6" - } - }, "node_modules/babel-runtime": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==", "dev": true, "dependencies": { "core-js": "^2.4.0", @@ -4735,10 +6093,16 @@ "dev": true, "hasInstallScript": true }, + "node_modules/babel-runtime/node_modules/regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + }, "node_modules/babel-template": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", - "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "integrity": "sha512-PCOcLFW7/eazGUKIoqH97sO9A2UYMahsn/yRQ7uOk37iutwjq7ODtcTNF+iFDSHNfkctqsLRjLP7URnOx0T1fg==", "dev": true, "dependencies": { "babel-runtime": "^6.26.0", @@ -4751,7 +6115,7 @@ "node_modules/babel-traverse": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "integrity": "sha512-iSxeXx7apsjCHe9c7n8VtRXGzI2Bk1rBSOJgCCjfyXb6v1aCqE1KSEpq/8SXuVN8Ka/Rh1WDTF0MDzkvTA4MIA==", "dev": true, "dependencies": { "babel-code-frame": "^6.26.0", @@ -4786,13 +6150,13 @@ "node_modules/babel-traverse/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "node_modules/babel-types": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "integrity": "sha512-zhe3V/26rCWsEZK8kZN+HaQj5yQ1CilTObixFzKW1UWjqG7618Twz6YEsCnjfg5gBcJh02DrpCkS9h98ZqDY+g==", "dev": true, "dependencies": { "babel-runtime": "^6.26.0", @@ -4804,7 +6168,7 @@ "node_modules/babel-types/node_modules/to-fast-properties": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "integrity": "sha512-lxrWP8ejsq+7E3nNjwYmUBMAgjMTZoTI+sdBOpvNyijeDLa29LUn9QaoXAHv4+Z578hbmHHJKZknzxVtvo77og==", "dev": true, "engines": { "node": ">=0.10.0" @@ -4822,7 +6186,7 @@ "node_modules/bach": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", - "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=", + "integrity": "sha512-bZOOfCb3gXBXbTFXq3OZtGR88LwGeJvzu6szttaIzymOTS4ZttBNOWSv7aLZja2EMycKtRYV0Oa8SNKH/zkxvg==", "dev": true, "dependencies": { "arr-filter": "^1.1.1", @@ -4876,7 +6240,7 @@ "node_modules/base/node_modules/define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, "dependencies": { "is-descriptor": "^1.0.0" @@ -4926,16 +6290,22 @@ "node": ">= 0.8" } }, + "node_modules/basic-auth/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, "node_modules/batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", "dev": true }, "node_modules/bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", "dev": true, "dependencies": { "tweetnacl": "^0.14.3" @@ -4944,7 +6314,7 @@ "node_modules/beeper": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", - "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=", + "integrity": "sha512-3vqtKL1N45I5dV0RdssXZG7X6pCqQrWPNOlBPZPrd+QkE2HEhR57Z04m0KtpbsZH73j+a3F8UD1TQnn+ExTvIA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -4971,7 +6341,7 @@ "node_modules/binary": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", - "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=", + "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", "dev": true, "dependencies": { "buffers": "~0.1.1", @@ -5040,13 +6410,13 @@ "node_modules/bluebird": { "version": "3.4.7", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", - "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=", + "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", "dev": true }, "node_modules/body": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/body/-/body-5.1.0.tgz", - "integrity": "sha1-5LoM5BCkaTYyM2dgnstOZVMSUGk=", + "integrity": "sha512-chUsBxGRtuElD6fmw1gHLpvnKdVLK302peeFa9ZqAEk8TyzZ3fygLyUEDDPTJvL9+Bor0dIwn6ePOsRM2y0zQQ==", "dev": true, "dependencies": { "continuable-cache": "^0.3.1", @@ -5056,23 +6426,26 @@ } }, "node_modules/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.8.1", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.9.7", - "raw-body": "2.4.3", - "type-is": "~1.6.18" + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, "node_modules/body-parser/node_modules/debug": { @@ -5086,18 +6459,18 @@ "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/body/node_modules/bytes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz", - "integrity": "sha1-NWnt6Lo0MV+rmcPpLLBMciDeH6g=", + "integrity": "sha512-/x68VkHLeTl3/Ll8IvxdwzhrT+IyKc52e/oyHhA2RwqPqswSnjVbSddfPRwAsJtbilMAPSRWwAlpxdYsSWOTKQ==", "dev": true }, "node_modules/body/node_modules/raw-body": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz", - "integrity": "sha1-HQJ8K/oRasxmI7yo8AAWVyqH1CU=", + "integrity": "sha512-WmJJU2e9Y6M5UzTOkHaM7xJGAPQD8PNzx3bAd2+uhZAim6wDk6dAZxPVYLF67XhbR4hmKGh33Lpmh4XWrCH5Mg==", "dev": true, "dependencies": { "bytes": "1", @@ -5110,7 +6483,7 @@ "node_modules/body/node_modules/string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", "dev": true }, "node_modules/brace-expansion": { @@ -5142,9 +6515,9 @@ "dev": true }, "node_modules/browserslist": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", - "integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==", + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", "funding": [ { "type": "opencollective", @@ -5156,10 +6529,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001370", - "electron-to-chromium": "^1.4.202", + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.5" + "update-browserslist-db": "^1.0.9" }, "bin": { "browserslist": "cli.js" @@ -5178,12 +6551,13 @@ } }, "node_modules/browserstack-local": { - "version": "1.4.9", - "resolved": "https://registry.npmjs.org/browserstack-local/-/browserstack-local-1.4.9.tgz", - "integrity": "sha512-V+q8HQwRQFr9nd32xR66ZZ3VDWa3Kct4IMMudhKgcuD7cWrvvFARZOibx71II+Rf7P5nMQpWWxl9z/3p927nbg==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/browserstack-local/-/browserstack-local-1.5.1.tgz", + "integrity": "sha512-T/wxyWDzvBHbDvl7fZKpFU7mYze6nrUkBhNy+d+8bXBqgQX10HTYvajIGO0wb49oGSLCPM0CMZTV/s7e6LF0sA==", "dev": true, "dependencies": { - "https-proxy-agent": "^4.0.0", + "agent-base": "^6.0.2", + "https-proxy-agent": "^5.0.1", "is-running": "^2.1.0", "ps-tree": "=1.2.0", "temp-fs": "^0.9.9" @@ -5224,9 +6598,9 @@ } }, "node_modules/browserstacktunnel-wrapper": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/browserstacktunnel-wrapper/-/browserstacktunnel-wrapper-2.0.4.tgz", - "integrity": "sha512-GCV599FUUxNOCFl3WgPnfc5dcqq9XTmMXoxWpqkvmk0R9TOIoqmjENNU6LY6DtgIL6WfBVbg/jmWtnM5K6UYSg==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/browserstacktunnel-wrapper/-/browserstacktunnel-wrapper-2.0.5.tgz", + "integrity": "sha512-oociT3nl+FhQnyJbAb1RM4oQ5pN7aKeXEURkTkiEVm/Rji2r0agl3Wbw5V23VFn9lCU5/fGyDejRZPtGYsEcFw==", "dev": true, "dependencies": { "https-proxy-agent": "^2.2.1", @@ -5297,19 +6671,22 @@ "node_modules/buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true, "engines": { "node": "*" } }, "node_modules/buffer-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", - "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.1.tgz", + "integrity": "sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg==", "dev": true, "engines": { - "node": ">=0.4.0" + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/buffer-from": { @@ -5330,7 +6707,7 @@ "node_modules/buffers": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", - "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=", + "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", "dev": true, "engines": { "node": ">=0.2.0" @@ -5347,7 +6724,7 @@ "node_modules/cac": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/cac/-/cac-3.0.4.tgz", - "integrity": "sha1-bSTO7Dcu/lybeYgIvH9JtHJCpO8=", + "integrity": "sha512-hq4rxE3NT5PlaEiVV39Z45d6MoFcQZG5dsgJqtAUeOz3408LEQAElToDkf9i5IYSCOmK0If/81dLg7nKxqPR0w==", "dev": true, "dependencies": { "camelcase-keys": "^3.0.0", @@ -5365,7 +6742,7 @@ "node_modules/cac/node_modules/ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -5374,38 +6751,16 @@ "node_modules/cac/node_modules/ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cac/node_modules/camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/cac/node_modules/camelcase-keys": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-3.0.0.tgz", - "integrity": "sha1-/AxsNgNj9zd+N5O5oWvM8QcMHKQ=", - "dev": true, - "dependencies": { - "camelcase": "^3.0.0", - "map-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/cac/node_modules/chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "dependencies": { "ansi-styles": "^2.2.1", @@ -5421,7 +6776,7 @@ "node_modules/cac/node_modules/find-up": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", "dev": true, "dependencies": { "path-exists": "^2.0.0", @@ -5431,19 +6786,28 @@ "node": ">=0.10.0" } }, - "node_modules/cac/node_modules/indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "node_modules/cac/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/cac/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, - "engines": { - "node": ">=4" + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" } }, "node_modules/cac/node_modules/path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", "dev": true, "dependencies": { "pinkie-promise": "^2.0.0" @@ -5455,7 +6819,7 @@ "node_modules/cac/node_modules/read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", "dev": true, "dependencies": { "load-json-file": "^1.0.0", @@ -5469,7 +6833,7 @@ "node_modules/cac/node_modules/read-pkg-up": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", "dev": true, "dependencies": { "find-up": "^1.0.0", @@ -5479,10 +6843,19 @@ "node": ">=0.10.0" } }, + "node_modules/cac/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, "node_modules/cac/node_modules/strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "dependencies": { "ansi-regex": "^2.0.0" @@ -5494,7 +6867,7 @@ "node_modules/cac/node_modules/supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, "engines": { "node": ">=0.8.0" @@ -5592,6 +6965,28 @@ "node": ">=6" } }, + "node_modules/camelcase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-3.0.0.tgz", + "integrity": "sha512-U4E6A6aFyYnNW+tDt5/yIUKQURKXe3WMFPfX4FxrQFcwZ/R08AUk1xWcUtlr7oq6CV07Ji+aa69V2g7BSpblnQ==", + "dev": true, + "dependencies": { + "camelcase": "^3.0.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/camelcase-keys/node_modules/camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/can-autoplay": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/can-autoplay/-/can-autoplay-3.0.2.tgz", @@ -5599,9 +6994,9 @@ "dev": true }, "node_modules/caniuse-lite": { - "version": "1.0.30001390", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001390.tgz", - "integrity": "sha512-sS4CaUM+/+vqQUlCvCJ2WtDlV81aWtHhqeEVkLokVJJa3ViN4zDxAGfq9R8i1m90uGHxo99cy10Od+lvn3hf0g==", + "version": "1.0.30001429", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001429.tgz", + "integrity": "sha512-511ThLu1hF+5RRRt0zYCf2U2yRr9GPF6m5y90SBCWsvSoYoW7yAGlv/elyPaNfvGCkp6kj/KFZWU0BMA69Prsg==", "funding": [ { "type": "opencollective", @@ -5616,7 +7011,7 @@ "node_modules/caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", "dev": true }, "node_modules/ccount": { @@ -5650,7 +7045,7 @@ "node_modules/chainsaw": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", - "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=", + "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", "dev": true, "dependencies": { "traverse": ">=0.3.0 <0.4" @@ -5672,25 +7067,6 @@ "node": ">=4" } }, - "node_modules/chalk/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/character-entities": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", @@ -5730,7 +7106,7 @@ "node_modules/check-error": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", "dev": true, "engines": { "node": "*" @@ -5770,9 +7146,9 @@ "dev": true }, "node_modules/chrome-launcher": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.0.tgz", - "integrity": "sha512-ZQqX5kb9H0+jy1OqLnWampfocrtSZaGl7Ny3F9GRha85o4odbL8x55paUzh51UC7cEmZ5obp3H2Mm70uC2PpRA==", + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.1.tgz", + "integrity": "sha512-UugC8u59/w2AyX5sHLZUHoxBAiSiunUhZa3zZwMH6zPVis0C3dDKiRWyUGIo14tTbZHGVviWxv3PQWZ7taZ4fg==", "dev": true, "dependencies": { "@types/node": "*", @@ -5823,10 +7199,19 @@ "node": ">=0.10.0" } }, + "node_modules/class-utils/node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/class-utils/node_modules/define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "dependencies": { "is-descriptor": "^0.1.0" @@ -5838,7 +7223,7 @@ "node_modules/class-utils/node_modules/is-accessor-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", "dev": true, "dependencies": { "kind-of": "^3.0.2" @@ -5850,7 +7235,7 @@ "node_modules/class-utils/node_modules/is-accessor-descriptor/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -5868,7 +7253,7 @@ "node_modules/class-utils/node_modules/is-data-descriptor": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", "dev": true, "dependencies": { "kind-of": "^3.0.2" @@ -5880,7 +7265,7 @@ "node_modules/class-utils/node_modules/is-data-descriptor/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -5916,9 +7301,9 @@ } }, "node_modules/cli-spinners": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", - "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", + "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==", "dev": true, "engines": { "node": ">=6" @@ -5937,20 +7322,23 @@ } }, "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "dependencies": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" } }, "node_modules/clone": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", "dev": true, "engines": { "node": ">=0.8" @@ -5959,25 +7347,28 @@ "node_modules/clone-buffer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", - "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=", + "integrity": "sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==", "dev": true, "engines": { "node": ">= 0.10" } }, "node_modules/clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", "dev": true, "dependencies": { "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/clone-stats": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", - "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", + "integrity": "sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==", "dev": true }, "node_modules/cloneable-readable": { @@ -5994,7 +7385,7 @@ "node_modules/code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -6003,7 +7394,7 @@ "node_modules/collection-map": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", - "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=", + "integrity": "sha512-5D2XXSpkOnleOI21TG7p3T0bGAsZ/XknZpKBmGYyluO8pw4zA3K8ZlrBIbC4FXg3m6z/RNFiUFfT2sQK01+UHA==", "dev": true, "dependencies": { "arr-map": "^2.0.2", @@ -6017,7 +7408,7 @@ "node_modules/collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", "dev": true, "dependencies": { "map-visit": "^1.0.0", @@ -6038,7 +7429,7 @@ "node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "node_modules/color-support": { "version": "1.1.3", @@ -6080,10 +7471,16 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", "dev": true }, "node_modules/component-emitter": { @@ -6124,7 +7521,7 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, "node_modules/concat-stream": { @@ -6193,12 +7590,51 @@ "ms": "2.0.0" } }, + "node_modules/connect/node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/connect/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/connect/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/connect/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -6210,25 +7646,6 @@ "node": ">= 0.6" } }, - "node_modules/content-disposition/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", @@ -6240,21 +7657,18 @@ "node_modules/continuable-cache": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz", - "integrity": "sha1-vXJ6f67XfnH/OYWskzUakSczrQ8=", + "integrity": "sha512-TF30kpKhTH8AGCG3dut0rdd/19B7Z+qCnrMoBLpyQu/2drZdNrrpcjPEoJeSVsQM+8KmWG5O56oPDjSSUsuTyA==", "dev": true }, "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dependencies": { - "safe-buffer": "~5.1.1" - } + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" }, "node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", "engines": { "node": ">= 0.6" } @@ -6262,12 +7676,12 @@ "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, "node_modules/copy-descriptor": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -6284,10 +7698,9 @@ } }, "node_modules/core-js": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.21.1.tgz", - "integrity": "sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig==", - "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "version": "3.26.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.26.0.tgz", + "integrity": "sha512-+DkDrhoR4Y0PxDz6rurahuB+I45OsEUv8E1maPTB6OuHRohMMcznBq9TMpdpDMm/hUPob/mJJS3PqgbHpMTQgw==", "hasInstallScript": true, "funding": { "type": "opencollective", @@ -6295,31 +7708,21 @@ } }, "node_modules/core-js-compat": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.1.tgz", - "integrity": "sha512-gbgX5AUvMb8gwxC7FLVWYT7Kkgu/y7+h/h1X43yJkNqhlK2fuYyQimqvKGNZFAY6CKii/GFKJ2cp/1/42TN36g==", + "version": "3.26.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.26.0.tgz", + "integrity": "sha512-piOX9Go+Z4f9ZiBFLnZ5VrOpBl0h7IGCkiFUN11QTe6LjAvOT3ifL/5TdoizMh99hcGy5SoLyWbapIY/PIb/3A==", "dependencies": { - "browserslist": "^4.19.1", - "semver": "7.0.0" + "browserslist": "^4.21.4" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" } }, - "node_modules/core-js-compat/node_modules/semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/core-js-pure": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.21.1.tgz", - "integrity": "sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ==", - "deprecated": "core-js-pure@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js-pure.", + "version": "3.26.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.26.0.tgz", + "integrity": "sha512-LiN6fylpVBVwT8twhhluD9TzXmZQQsr2I2eIKtWNbZI1XMfBT7CV18itaN6RA7EtQd/SDdRx/wzvAShX2HvhQA==", "hasInstallScript": true, "funding": { "type": "opencollective", @@ -6365,14 +7768,10 @@ } }, "node_modules/crc-32": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.1.tgz", - "integrity": "sha512-Dn/xm/1vFFgs3nfrpEVScHoIslO9NZRITWGz/1E/St6u4xw99vfZzVkW0OSnzx2h9egej9xwMCEut6sqwokM/w==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", "dev": true, - "dependencies": { - "exit-on-epipe": "~1.0.1", - "printj": "~1.3.1" - }, "bin": { "crc32": "bin/crc32.njs" }, @@ -6460,7 +7859,7 @@ "node_modules/css-value": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/css-value/-/css-value-0.0.1.tgz", - "integrity": "sha1-Xv1sLupeof1rasV+wEJ7GEUkJOo=", + "integrity": "sha512-FUV3xaJ63buRLgHrLQVlVgQnQdR4yqdLGaDu7g8CQcWjInDfM9plBTPI9FRfpahju1UBSaMckeb2/46ApS/V1Q==", "dev": true }, "node_modules/css/node_modules/source-map": { @@ -6475,7 +7874,7 @@ "node_modules/custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", - "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", "dev": true }, "node_modules/d": { @@ -6491,7 +7890,7 @@ "node_modules/dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", "dev": true, "dependencies": { "assert-plus": "^1.0.0" @@ -6501,9 +7900,9 @@ } }, "node_modules/date-format": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.4.tgz", - "integrity": "sha512-/jyf4rhB17ge328HJuJjAcmRtCsGd+NDeAtahRBTaK6vSPR6MO5HlrAit3Nn7dVjaa6sowW0WXt8yQtLyZQFRg==", + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", + "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", "dev": true, "engines": { "node": ">=4.0" @@ -6512,7 +7911,7 @@ "node_modules/dateformat": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", - "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=", + "integrity": "sha512-GODcnWq3YGoTnygPfi02ygEiRxqUxpJwuRHjdhJYuxpcZmDq4rjBiXYmbCCzStxo176ixfLT6i4NPwQooRySnw==", "dev": true, "engines": { "node": "*" @@ -6526,9 +7925,9 @@ "optional": true }, "node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dependencies": { "ms": "2.1.2" }, @@ -6562,12 +7961,15 @@ } }, "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/decode-named-character-reference": { @@ -6584,9 +7986,9 @@ } }, "node_modules/decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", "dev": true, "engines": { "node": ">=0.10" @@ -6687,25 +8089,28 @@ "node_modules/default-resolution": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", - "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=", + "integrity": "sha512-2xaP6GiwVwOEbXCGoJ4ufgC76m8cj805jrghScewJC2ZDsb9U0b4BIrba+xt/Uytyd0HvQ6+WymSRTfnYj59GQ==", "dev": true, "engines": { "node": ">= 0.10" } }, "node_modules/defaults": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", "dev": true, "dependencies": { "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/defaults/node_modules/clone": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "dev": true, "engines": { "node": ">=0.8" @@ -6721,14 +8126,19 @@ } }, "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dev": true, "dependencies": { - "object-keys": "^1.0.12" + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/define-property": { @@ -6747,18 +8157,18 @@ "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, "engines": { "node": ">=0.4.0" } }, "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/dequal": { @@ -6771,23 +8181,39 @@ } }, "node_modules/destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } }, "node_modules/detect-file": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", "dev": true, "engines": { "node": ">=0.10.0" } }, + "node_modules/detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha512-BDKtmHlOzwI7iRuEkhzsnPoi5ypEhWAJB5RvHWe1kMr06js3uK5B3734i3ui5Yd+wOJV1cpE4JnivPD283GU/A==", + "dev": true, + "dependencies": { + "repeating": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/detect-libc": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", "dev": true, "bin": { "detect-libc": "bin/detect-libc.js" @@ -6799,46 +8225,237 @@ "node_modules/detect-newline": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", - "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", + "integrity": "sha512-CwffZFvlJffUg9zZA0uqrjQayUTC8ob94pnr5sFwaVv3IOmkfUHcWH+jXaQK3askE51Cqe8/9Ql/0uXNwqZ8Zg==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/devtools": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.16.16.tgz", - "integrity": "sha512-M0kzkuSgfEhpqIis3gdtWsNjn/HQ+vRAmEzDnbYx/7FfjFxhSv1d+rOOT20pvd60soItMYpsOova1igACEGkGQ==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.25.4.tgz", + "integrity": "sha512-R6/S/dCqxoX4Y6PxIGM9JFAuSRZzUeV5r+CoE/frhmno6mTe7dEEgwkJlfit3LkKRoul8n4DsL2A3QtWOvq5IA==", "dev": true, "dependencies": { - "@types/node": "^17.0.4", + "@types/node": "^18.0.0", "@types/ua-parser-js": "^0.7.33", - "@wdio/config": "7.16.16", - "@wdio/logger": "7.16.0", - "@wdio/protocols": "7.16.7", - "@wdio/types": "7.16.14", - "@wdio/utils": "7.16.14", + "@wdio/config": "7.25.4", + "@wdio/logger": "7.19.0", + "@wdio/protocols": "7.22.0", + "@wdio/types": "7.25.4", + "@wdio/utils": "7.25.4", "chrome-launcher": "^0.15.0", "edge-paths": "^2.1.0", "puppeteer-core": "^13.1.3", "query-selector-shadow-dom": "^1.0.0", "ua-parser-js": "^1.0.1", - "uuid": "^8.0.0" + "uuid": "^9.0.0" }, "engines": { "node": ">=12.0.0" } }, "node_modules/devtools-protocol": { - "version": "0.0.973690", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.973690.tgz", - "integrity": "sha512-myh3hSFp0YWa2GED11PmbLhV4dv9RdO7YUz27XJrbQLnP5bMbZL6dfOOILTHO57yH0kX5GfuOZBsg/4NamfPvQ==", + "version": "0.0.1061995", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1061995.tgz", + "integrity": "sha512-pKZZWTjWa/IF4ENCg6GN8bu/AxSZgdhjSa26uc23wz38Blt2Tnm9icOPcSG3Cht55rMq35in1w3rWVPcZ60ArA==", "dev": true }, + "node_modules/devtools/node_modules/@types/node": { + "version": "18.11.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", + "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", + "dev": true + }, + "node_modules/devtools/node_modules/@wdio/config": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-7.25.4.tgz", + "integrity": "sha512-vb0emDtD9FbFh/yqW6oNdo2iuhQp8XKj6GX9fyy9v4wZgg3B0HPMVJxhIfcoHz7LMBWlHSo9YdvhFI5EQHRLBA==", + "dev": true, + "dependencies": { + "@wdio/logger": "7.19.0", + "@wdio/types": "7.25.4", + "@wdio/utils": "7.25.4", + "deepmerge": "^4.0.0", + "glob": "^8.0.3" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/devtools/node_modules/@wdio/logger": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.19.0.tgz", + "integrity": "sha512-xR7SN/kGei1QJD1aagzxs3KMuzNxdT/7LYYx+lt6BII49+fqL/SO+5X0FDCZD0Ds93AuQvvz9eGyzrBI2FFXmQ==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/devtools/node_modules/@wdio/protocols": { + "version": "7.22.0", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-7.22.0.tgz", + "integrity": "sha512-8EXRR+Ymdwousm/VGtW3H1hwxZ/1g1H99A1lF0U4GuJ5cFWHCd0IVE5H31Z52i8ZruouW8jueMkGZPSo2IIUSQ==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/devtools/node_modules/@wdio/types": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.25.4.tgz", + "integrity": "sha512-muvNmq48QZCvocctnbe0URq2FjJjUPIG4iLoeMmyF0AQgdbjaUkMkw3BHYNHVTbSOU9WMsr2z8alhj/I2H6NRQ==", + "dev": true, + "dependencies": { + "@types/node": "^18.0.0", + "got": "^11.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "^4.6.2" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/devtools/node_modules/@wdio/utils": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-7.25.4.tgz", + "integrity": "sha512-8iwQDk+foUqSzKZKfhLxjlCKOkfRJPNHaezQoevNgnrTq/t0ek+ldZCATezb9B8jprAuP4mgS9xi22akc6RkzA==", + "dev": true, + "dependencies": { + "@wdio/logger": "7.19.0", + "@wdio/types": "7.25.4", + "p-iteration": "^1.1.8" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/devtools/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/devtools/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, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/devtools/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/devtools/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/devtools/node_modules/color-name": { + "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 + }, + "node_modules/devtools/node_modules/glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/devtools/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/devtools/node_modules/minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/devtools/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/devtools/node_modules/ua-parser-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.2.tgz", - "integrity": "sha512-00y/AXhx0/SsnI51fTc0rLRmafiGOM4/O+ny10Ps7f+j/b8p/ZY11ytMgznXkOVo4GQ+KwQG5UQLkLGirsACRg==", + "version": "1.0.33", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.33.tgz", + "integrity": "sha512-RqshF7TPTE0XLYAqmjlu5cLLuGdKrNu9O1KLA/qp39QtbZwuzwv1dT46DZSopoUMsYgXpB3Cv8a03FI8b74oFQ==", "dev": true, "funding": [ { @@ -6855,9 +8472,9 @@ } }, "node_modules/devtools/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", "dev": true, "bin": { "uuid": "dist/bin/uuid" @@ -6866,25 +8483,25 @@ "node_modules/di": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", - "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", + "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", "dev": true }, "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", "dev": true, "engines": { "node": ">=0.3.1" } }, "node_modules/diff-sequences": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", - "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", + "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", "dev": true, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 10.14.2" } }, "node_modules/dlv": { @@ -6917,9 +8534,9 @@ } }, "node_modules/documentation": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/documentation/-/documentation-14.0.0.tgz", - "integrity": "sha512-4AwFzdiseEdtqR0KKLrruIQ5fvh7n5epg47P0ZyOidA5Fes5am+6xjqkDECHPwcv4pxJ6zITaHwzCoGblP0+JQ==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/documentation/-/documentation-14.0.1.tgz", + "integrity": "sha512-Y/brACCE3sNnDJPFiWlhXrqGY+NelLYVZShLGse5bT1KdohP4JkPf5T2KNq1YWhIEbDYl/1tebRLC0WYbPQxVw==", "dev": true, "dependencies": { "@babel/core": "^7.18.10", @@ -6931,7 +8548,7 @@ "chokidar": "^3.5.3", "diff": "^5.1.0", "doctrine-temporary-fork": "2.1.0", - "git-url-parse": "^12.0.0", + "git-url-parse": "^13.1.0", "github-slugger": "1.4.0", "glob": "^8.0.3", "globals-docs": "^2.4.1", @@ -6987,9 +8604,9 @@ } }, "node_modules/documentation/node_modules/chalk": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", - "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.1.2.tgz", + "integrity": "sha512-E5CkT4jWURs1Vy5qGJye+XwCkNj7Od3Af7CP6SujMetSMkLs8Do2RWJK5yx1wamHV/op8Rz+9rltjaTQWDnEFQ==", "dev": true, "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -6998,15 +8615,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/documentation/node_modules/diff": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/documentation/node_modules/glob": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", @@ -7026,15 +8634,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/documentation/node_modules/ini": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.1.tgz", - "integrity": "sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/documentation/node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -7059,25 +8658,13 @@ "node": ">=10" } }, - "node_modules/documentation/node_modules/strip-json-comments": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.0.tgz", - "integrity": "sha512-V1LGY4UUo0jgwC+ELQ2BNWfPa17TIuwBLg+j1AA/9RPzKINl1lhxVEu2r+ZTTO8aetIsUzE5Qj6LMSBkoGYKKw==", - "dev": true, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/documentation/node_modules/yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", + "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", "dev": true, "dependencies": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", @@ -7092,7 +8679,7 @@ "node_modules/dom-serialize": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", - "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", + "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", "dev": true, "dependencies": { "custom-event": "~1.0.0", @@ -7122,14 +8709,38 @@ "dev": true }, "node_modules/duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==", "dev": true, "dependencies": { - "readable-stream": "^2.0.2" + "readable-stream": "~1.1.9" + } + }, + "node_modules/duplexer2/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "node_modules/duplexer2/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" } }, + "node_modules/duplexer2/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, "node_modules/duplexify": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", @@ -7199,7 +8810,7 @@ "node_modules/ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", "dev": true, "dependencies": { "jsbn": "~0.1.0", @@ -7219,7 +8830,7 @@ "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/ejs": { "version": "3.1.8", @@ -7237,14 +8848,14 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.243", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.243.tgz", - "integrity": "sha512-BgLD2gBX43OSXwlT01oYRRD5NIB4n3okTRxkzEAC6G0SZG4TTlyrWMjbOo0fajCwqwpRtMHXQNMjtRN6qpNtfw==" + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==" }, "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, "node_modules/emojis-list": { @@ -7259,7 +8870,7 @@ "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "engines": { "node": ">= 0.8" } @@ -7274,9 +8885,9 @@ } }, "node_modules/engine.io": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.1.3.tgz", - "integrity": "sha512-rqs60YwkvWTLLnfazqgZqLa/aKo+9cueVfEi/dZ8PyGyaf8TLOxj++4QMIgeG3Gn0AhrWiFXvghsoY9L9h25GA==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.1.tgz", + "integrity": "sha512-ECceEFcAaNRybd3lsGQKas3ZlMVjN3cyWwMP25D2i0zWfyiytVbTpRPa34qrr+FHddtpBVOmq4H/DCv1O0lZRA==", "dev": true, "dependencies": { "@types/cookie": "^0.4.1", @@ -7295,21 +8906,27 @@ } }, "node_modules/engine.io-parser": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.3.tgz", - "integrity": "sha512-BtQxwF27XUNnSafQLvDi0dQ8s3i6VgzSoQMJacpIcGNrlUdfHSKbgm3jmjCVvQluGzqwujQMPAoMai3oYSTurg==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz", + "integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==", "dev": true, - "dependencies": { - "@socket.io/base64-arraybuffer": "~1.0.2" - }, "engines": { "node": ">=10.0.0" } }, + "node_modules/engine.io/node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/enhanced-resolve": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz", - "integrity": "sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", + "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", "dev": true, "dependencies": { "graceful-fs": "^4.2.4", @@ -7334,7 +8951,7 @@ "node_modules/ent": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", "dev": true }, "node_modules/errno": { @@ -7368,31 +8985,35 @@ } }, "node_modules/es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", + "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.3", "get-symbol-description": "^1.0.0", "has": "^1.0.3", - "has-symbols": "^1.0.2", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", + "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.2", "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -7426,6 +9047,15 @@ "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", "dev": true }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, "node_modules/es-to-primitive": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", @@ -7459,9 +9089,9 @@ } }, "node_modules/es5-shim": { - "version": "4.6.5", - "resolved": "https://registry.npmjs.org/es5-shim/-/es5-shim-4.6.5.tgz", - "integrity": "sha512-vfQ4UAai8szn0sAubCy97xnZ4sJVDD1gt/Grn736hg8D7540wemIb1YPrYZSTqlM2H69EQX1or4HU/tSwRTI3w==", + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/es5-shim/-/es5-shim-4.6.7.tgz", + "integrity": "sha512-jg21/dmlrNQI7JyyA2w7n+yifSxBng0ZralnSfVZjoCawgNTCnS+yBCyVM9DL5itm7SUnDGgv7hcq2XCZX4iRQ==", "dev": true, "engines": { "node": ">=0.4.0" @@ -7470,7 +9100,7 @@ "node_modules/es6-iterator": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", "dev": true, "dependencies": { "d": "1", @@ -7481,7 +9111,7 @@ "node_modules/es6-object-assign": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", - "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=", + "integrity": "sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw==", "dev": true }, "node_modules/es6-promise": { @@ -7493,7 +9123,7 @@ "node_modules/es6-promisify": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", "dev": true, "dependencies": { "es6-promise": "^4.0.3" @@ -7532,12 +9162,12 @@ "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "engines": { "node": ">=0.8.0" } @@ -7545,7 +9175,7 @@ "node_modules/escodegen": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", - "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", + "integrity": "sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A==", "dev": true, "dependencies": { "esprima": "^2.7.1", @@ -7567,7 +9197,7 @@ "node_modules/escodegen/node_modules/estraverse": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", - "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", + "integrity": "sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -7576,7 +9206,7 @@ "node_modules/escodegen/node_modules/levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", "dev": true, "dependencies": { "prelude-ls": "~1.1.2", @@ -7606,7 +9236,7 @@ "node_modules/escodegen/node_modules/prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", "dev": true, "engines": { "node": ">= 0.8.0" @@ -7615,7 +9245,7 @@ "node_modules/escodegen/node_modules/source-map": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", - "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", + "integrity": "sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==", "dev": true, "optional": true, "dependencies": { @@ -7628,7 +9258,7 @@ "node_modules/escodegen/node_modules/type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", "dev": true, "dependencies": { "prelude-ls": "~1.1.2" @@ -7697,7 +9327,7 @@ "node_modules/eslint-config-standard": { "version": "10.2.1", "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz", - "integrity": "sha1-wGHk0GbzedwXzVYsZOgZtN1FRZE=", + "integrity": "sha512-UkFojTV1o0GOe1edOEiuI5ccYLJSuNngtqSeClNzhsmG8KPJ+7mRxgtp2oYhqZAK/brlXMoCd+VgXViE0AfyKw==", "dev": true, "peerDependencies": { "eslint": ">=3.19.0", @@ -7727,16 +9357,20 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", - "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", + "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", "dev": true, "dependencies": { - "debug": "^3.2.7", - "find-up": "^2.1.0" + "debug": "^3.2.7" }, "engines": { "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } } }, "node_modules/eslint-module-utils/node_modules/debug": { @@ -7768,9 +9402,9 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.25.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz", - "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==", + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", + "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", "dev": true, "dependencies": { "array-includes": "^3.1.4", @@ -7778,14 +9412,14 @@ "debug": "^2.6.9", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.2", + "eslint-module-utils": "^2.7.3", "has": "^1.0.3", - "is-core-module": "^2.8.0", + "is-core-module": "^2.8.1", "is-glob": "^4.0.3", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "object.values": "^1.1.5", - "resolve": "^1.20.0", - "tsconfig-paths": "^3.12.0" + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" }, "engines": { "node": ">=4" @@ -7818,7 +9452,7 @@ "node_modules/eslint-plugin-import/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "node_modules/eslint-plugin-node": { @@ -7930,22 +9564,6 @@ "@babel/highlight": "^7.10.4" } }, - "node_modules/eslint/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/eslint/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -8008,9 +9626,9 @@ } }, "node_modules/eslint/node_modules/globals": { - "version": "13.12.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", - "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -8022,10 +9640,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint/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, + "engines": { + "node": ">=8" + } + }, "node_modules/eslint/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -8099,7 +9726,7 @@ "node_modules/esprima": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "integrity": "sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==", "dev": true, "bin": { "esparse": "bin/esparse.js", @@ -8178,7 +9805,7 @@ "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "engines": { "node": ">= 0.6" } @@ -8186,7 +9813,7 @@ "node_modules/event-emitter": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", "dev": true, "dependencies": { "d": "1", @@ -8196,7 +9823,7 @@ "node_modules/event-stream": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", - "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", + "integrity": "sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==", "dev": true, "dependencies": { "duplexer": "~0.1.1", @@ -8211,7 +9838,7 @@ "node_modules/event-stream/node_modules/map-stream": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", - "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", + "integrity": "sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==", "dev": true }, "node_modules/eventemitter3": { @@ -8266,7 +9893,7 @@ "node_modules/execa/node_modules/path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", "dev": true, "engines": { "node": ">=4" @@ -8284,7 +9911,7 @@ "node_modules/execa/node_modules/shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", "dev": true, "dependencies": { "shebang-regex": "^1.0.0" @@ -8296,7 +9923,7 @@ "node_modules/execa/node_modules/shebang-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -8314,19 +9941,10 @@ "which": "bin/which" } }, - "node_modules/exit-on-epipe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", - "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, "node_modules/expand-brackets": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", "dev": true, "dependencies": { "debug": "^2.3.3", @@ -8353,7 +9971,7 @@ "node_modules/expand-brackets/node_modules/define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "dependencies": { "is-descriptor": "^0.1.0" @@ -8365,7 +9983,7 @@ "node_modules/expand-brackets/node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "dependencies": { "is-extendable": "^0.1.0" @@ -8377,7 +9995,7 @@ "node_modules/expand-brackets/node_modules/is-accessor-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", "dev": true, "dependencies": { "kind-of": "^3.0.2" @@ -8389,7 +10007,7 @@ "node_modules/expand-brackets/node_modules/is-accessor-descriptor/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -8407,7 +10025,7 @@ "node_modules/expand-brackets/node_modules/is-data-descriptor": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", "dev": true, "dependencies": { "kind-of": "^3.0.2" @@ -8419,7 +10037,7 @@ "node_modules/expand-brackets/node_modules/is-data-descriptor/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -8445,7 +10063,7 @@ "node_modules/expand-brackets/node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -8454,13 +10072,13 @@ "node_modules/expand-brackets/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "node_modules/expand-tilde": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", "dev": true, "dependencies": { "homedir-polyfill": "^1.0.1" @@ -8470,62 +10088,98 @@ } }, "node_modules/expect": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", - "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", + "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1" + "@jest/types": "^26.6.2", + "ansi-styles": "^4.0.0", + "jest-get-type": "^26.3.0", + "jest-matcher-utils": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-regex-util": "^26.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 10.14.2" } }, "node_modules/expect-webdriverio": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/expect-webdriverio/-/expect-webdriverio-3.1.4.tgz", - "integrity": "sha512-65FTS3bmxcIp0cq6fLb/72TrCQXBCpwPLC7SwMWdpPlLq461mXcK1BPKJJjnIC587aXSKD+3E4hvnlCtwDmXfg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expect-webdriverio/-/expect-webdriverio-2.0.2.tgz", + "integrity": "sha512-dst0tqP1aZ2p7TPmbatqoIQ+7hRTw+IeKNi830XxKhu2DNNe5vQ85i9ttf9rpXgbnUf91HxKcocn4G7A5bQxDA==", "dev": true, "dependencies": { - "expect": "^27.0.2", - "jest-matcher-utils": "^27.0.2" + "expect": "^26.6.2", + "jest-matcher-utils": "^26.6.2" } }, + "node_modules/expect/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/expect/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/expect/node_modules/color-name": { + "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 + }, "node_modules/express": { - "version": "4.17.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", - "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.19.2", + "body-parser": "1.20.1", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.2", + "cookie": "0.5.0", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "~1.1.2", + "depd": "2.0.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "~1.1.2", + "finalhandler": "1.2.0", "fresh": "0.5.2", + "http-errors": "2.0.0", "merge-descriptors": "1.0.1", "methods": "~1.1.2", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", "proxy-addr": "~2.0.7", - "qs": "6.9.7", + "qs": "6.11.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.17.2", - "serve-static": "1.14.2", + "send": "0.18.0", + "serve-static": "1.15.0", "setprototypeof": "1.2.0", - "statuses": "~1.5.0", + "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" @@ -8545,40 +10199,21 @@ "node_modules/express/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/express/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/ext": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz", - "integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", "dev": true, "dependencies": { - "type": "^2.5.0" + "type": "^2.7.2" } }, "node_modules/ext/node_modules/type": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.6.0.tgz", - "integrity": "sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", "dev": true }, "node_modules/extend": { @@ -8588,18 +10223,26 @@ "dev": true }, "node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz", + "integrity": "sha512-L7AGmkO6jhDkEBBGWlLtftA80Xq8DipnrRPr0pyi7GQLXkaq9JYA4xF4z6qnadIC6euiTDKco0cGSU9muw+WTw==", "dev": true, "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "kind-of": "^1.1.0" }, "engines": { "node": ">=0.10.0" } }, + "node_modules/extend-shallow/node_modules/kind-of": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", + "integrity": "sha512-aUH6ElPnMGon2/YkxRIigV32MOpTVcoXQ1Oo8aYn40s+sJ3j+0gFZsT8HKDcxNy7Fi9zuquWtGaGAahOdv5p/g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -8614,18 +10257,6 @@ "node": ">=4" } }, - "node_modules/external-editor/node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/extglob": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", @@ -8648,7 +10279,7 @@ "node_modules/extglob/node_modules/define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, "dependencies": { "is-descriptor": "^1.0.0" @@ -8660,7 +10291,7 @@ "node_modules/extglob/node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "dependencies": { "is-extendable": "^0.1.0" @@ -8672,7 +10303,7 @@ "node_modules/extglob/node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -8716,7 +10347,7 @@ "node_modules/extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", "dev": true, "engines": [ "node >=0.6.0" @@ -8758,13 +10389,13 @@ "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, "node_modules/faye-websocket": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", - "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "integrity": "sha512-Xhj93RXbMSq8urNCUq4p9l0P6hnySJ/7YNRhYNug0bLOuii7pKO7xQFb5mx9xZXWCar88pLPb805PvUkwrLZpQ==", "dev": true, "dependencies": { "websocket-driver": ">=0.5.1" @@ -8776,16 +10407,16 @@ "node_modules/fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", "dev": true, "dependencies": { "pend": "~1.2.0" } }, "node_modules/fibers": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/fibers/-/fibers-5.0.1.tgz", - "integrity": "sha512-VMC7Frt87Oo0AOJ6EcPFbi+tZmkQ4tD85aatwyWL6I9cYMJmm2e+pXUJsfGZ36U7MffXtjou2XIiWJMtHriErw==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/fibers/-/fibers-5.0.3.tgz", + "integrity": "sha512-/qYTSoZydQkM21qZpGLDLuCq8c+B8KhuCQ1kLPvnRNhxhVbvrpmH9l2+Lblf5neDuEsY4bfT7LeO553TXQDvJw==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -8872,16 +10503,16 @@ } }, "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", - "statuses": "~1.5.0", + "statuses": "2.0.1", "unpipe": "~1.0.0" }, "engines": { @@ -8899,7 +10530,7 @@ "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/find-cache-dir": { "version": "3.3.2", @@ -8919,15 +10550,16 @@ } }, "node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "dependencies": { - "locate-path": "^2.0.0" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/findup-sync": { @@ -8945,6 +10577,182 @@ "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", @@ -9005,9 +10813,9 @@ } }, "node_modules/flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, "node_modules/flush-write-stream": { @@ -9021,9 +10829,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.14.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", - "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==", + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", "dev": true, "funding": [ { @@ -9040,10 +10848,19 @@ } } }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, "node_modules/for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -9052,7 +10869,7 @@ "node_modules/for-own": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==", "dev": true, "dependencies": { "for-in": "^1.0.1" @@ -9061,22 +10878,16 @@ "node": ">=0.10.0" } }, - "node_modules/foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", - "dev": true - }, "node_modules/foreachasync": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/foreachasync/-/foreachasync-3.0.0.tgz", - "integrity": "sha1-VQKYfchxS+M5IJfzLgBxyd7gfPY=", + "integrity": "sha512-J+ler7Ta54FwwNcx6wQRDhTIbNeyDcARMkOcguEqnEdtm0jKvN3Li3PDAb2Du3ubJYEWfYL83XMROXdsXAXycw==", "dev": true }, "node_modules/forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", "dev": true, "engines": { "node": "*" @@ -9085,7 +10896,7 @@ "node_modules/fork-stream": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/fork-stream/-/fork-stream-0.0.4.tgz", - "integrity": "sha1-24Sfznf2cIpfjzhq5TOgkHtUrnA=", + "integrity": "sha512-Pqq5NnT78ehvUnAk/We/Jr22vSvanRlFTpAmQ88xBY/M1TlHe+P0ILuEyXS595ysdGfaj22634LBkGMA2GTcpA==", "dev": true }, "node_modules/form-data": { @@ -9113,7 +10924,7 @@ "node_modules/fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", "dev": true, "dependencies": { "map-cache": "^0.2.2" @@ -9125,7 +10936,7 @@ "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "engines": { "node": ">= 0.6" } @@ -9133,7 +10944,7 @@ "node_modules/from": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", + "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==", "dev": true }, "node_modules/fs-constants": { @@ -9143,9 +10954,9 @@ "dev": true }, "node_modules/fs-extra": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", - "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "dependencies": { "graceful-fs": "^4.2.0", @@ -9159,7 +10970,7 @@ "node_modules/fs-mkdirp-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", - "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=", + "integrity": "sha512-+vSd9frUnapVC2RZYfL3FCB2p3g4TBhaUmrsWlSudsGdnxIuUvBB2QM1VZeBtc49QFwrp+wQLrDs3+xxDgI5gQ==", "dev": true, "dependencies": { "graceful-fs": "^4.1.11", @@ -9182,7 +10993,7 @@ "node_modules/fs.extra": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/fs.extra/-/fs.extra-1.3.2.tgz", - "integrity": "sha1-3QI/kwE77iRTHxszUUw3sg/ZM0k=", + "integrity": "sha512-Ig401VXtyrWrz23k9KxAx9OrnL8AHSLNhQ8YJH2wSYuH0ZUfxwBeY6zXkd/oOyVRFTlpEu/0n5gHeuZt7aqbkw==", "dev": true, "dependencies": { "fs-extra": "~0.6.1", @@ -9196,7 +11007,7 @@ "node_modules/fs.extra/node_modules/fs-extra": { "version": "0.6.4", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.6.4.tgz", - "integrity": "sha1-9G8MdbeEH40gCzNIzU1pHVoJnRU=", + "integrity": "sha512-5rU898vl/Z948L+kkJedbmo/iltzmiF5bn/eEk0j/SgrPpI+Ydau9xlJPicV7Av2CHYBGz5LAlwTnBU80j1zPQ==", "dev": true, "dependencies": { "jsonfile": "~1.0.1", @@ -9208,20 +11019,20 @@ "node_modules/fs.extra/node_modules/jsonfile": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-1.0.1.tgz", - "integrity": "sha1-6l7+QLg2kLmGZ2FKc5L8YOhCwN0=", + "integrity": "sha512-KbsDJNRfRPF5v49tMNf9sqyyGqGLBcz1v5kZT01kG5ns5mQSltwxCKVmUzVKtEinkUnTDtSrp6ngWpV7Xw0ZlA==", "dev": true }, "node_modules/fs.extra/node_modules/mkdirp": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", - "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=", + "integrity": "sha512-8OCq0De/h9ZxseqzCH8Kw/Filf5pF/vMI6+BH7Lu0jXz2pqYCjTAQRolSxRIi+Ax+oCCjlxoJMP0YQ4XlrQNHg==", "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", "dev": true }, "node_modules/fs.extra/node_modules/rimraf": { "version": "2.2.8", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", - "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", + "integrity": "sha512-R5KMKHnPAQaZMqLOsyuyUmcIjSeDm+73eoqQpaXA7AZ22BL+6C+1mcUscgOsNd8WVlJuvlgAPsegcx7pjlV0Dg==", "dev": true, "bin": { "rimraf": "bin.js" @@ -9230,7 +11041,7 @@ "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, "node_modules/fsevents": { @@ -9262,12 +11073,12 @@ } }, "node_modules/fstream/node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "dependencies": { - "minimist": "^1.2.5" + "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" @@ -9298,12 +11109,39 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", "dev": true }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/gaze": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", @@ -9336,20 +11174,20 @@ "node_modules/get-func-name": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", "dev": true, "engines": { "node": "*" } }, "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", - "has-symbols": "^1.0.1" + "has-symbols": "^1.0.3" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9407,7 +11245,7 @@ "node_modules/get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -9416,29 +11254,29 @@ "node_modules/getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", "dev": true, "dependencies": { "assert-plus": "^1.0.0" } }, "node_modules/git-up": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/git-up/-/git-up-6.0.0.tgz", - "integrity": "sha512-6RUFSNd1c/D0xtGnyWN2sxza2bZtZ/EmI9448n6rCZruFwV/ezeEn2fJP7XnUQGwf0RAtd/mmUCbtH6JPYA2SA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/git-up/-/git-up-7.0.0.tgz", + "integrity": "sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ==", "dev": true, "dependencies": { "is-ssh": "^1.4.0", - "parse-url": "^7.0.2" + "parse-url": "^8.1.0" } }, "node_modules/git-url-parse": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-12.0.0.tgz", - "integrity": "sha512-I6LMWsxV87vysX1WfsoglXsXg6GjQRKq7+Dgiseo+h0skmp5Hp2rzmcEIRQot9CPA+uzU7x1x7jZdqvTFGnB+Q==", + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-13.1.0.tgz", + "integrity": "sha512-5FvPJP/70WkIprlUZ33bm4UAaFdjcLkJLpWft1BeZKqwR0uhhNGoKwlUaPtVb4LxCSQ++erHapRak9kWGj+FCA==", "dev": true, "dependencies": { - "git-up": "^6.0.0" + "git-up": "^7.0.0" } }, "node_modules/github-slugger": { @@ -9448,15 +11286,15 @@ "dev": true }, "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" }, @@ -9513,7 +11351,7 @@ "node_modules/glob-stream/node_modules/is-glob": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", "dev": true, "dependencies": { "is-extglob": "^2.1.0" @@ -9559,7 +11397,7 @@ "node_modules/glob-watcher/node_modules/anymatch/node_modules/normalize-path": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", "dev": true, "dependencies": { "remove-trailing-separator": "^1.0.1" @@ -9568,6 +11406,15 @@ "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", @@ -9624,7 +11471,7 @@ "node_modules/glob-watcher/node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "dependencies": { "is-extendable": "^0.1.0" @@ -9636,7 +11483,7 @@ "node_modules/glob-watcher/node_modules/fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", "dev": true, "dependencies": { "extend-shallow": "^2.0.1", @@ -9680,7 +11527,7 @@ "node_modules/glob-watcher/node_modules/glob-parent/node_modules/is-glob": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", "dev": true, "dependencies": { "is-extglob": "^2.1.0" @@ -9692,7 +11539,7 @@ "node_modules/glob-watcher/node_modules/is-binary-path": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", "dev": true, "dependencies": { "binary-extensions": "^1.0.0" @@ -9701,10 +11548,110 @@ "node": ">=0.10.0" } }, + "node_modules/glob-watcher/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/glob-watcher/node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-watcher/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/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", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "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" @@ -9727,7 +11674,7 @@ "node_modules/glob-watcher/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": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", "dev": true, "dependencies": { "is-number": "^3.0.0", @@ -9764,7 +11711,7 @@ "node_modules/global-prefix": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", "dev": true, "dependencies": { "expand-tilde": "^2.0.2", @@ -9777,6 +11724,12 @@ "node": ">=0.10.0" } }, + "node_modules/global-prefix/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, "node_modules/global-prefix/node_modules/which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -9804,13 +11757,13 @@ "dev": true }, "node_modules/globule": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.3.tgz", - "integrity": "sha512-mb1aYtDbIjTu4ShMB85m3UzjX9BVKe9WCzsnfMSZk+K5GpIbBOexgg4PPCt5eHDEG5/ZQAUX2Kct02zfiPLsKg==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.4.tgz", + "integrity": "sha512-OPTIfhMBh7JbBYDpa5b+Q5ptmMWKwcNcFSR/0c6t8V4f3ZAVBEsKNY37QdVqmLRYSMhOUGYrY0QhSoEpzGr/Eg==", "dev": true, "dependencies": { "glob": "~7.1.1", - "lodash": "~4.17.10", + "lodash": "^4.17.21", "minimatch": "~3.0.2" }, "engines": { @@ -9887,9 +11840,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, "node_modules/grapheme-splitter": { @@ -9941,74 +11894,6 @@ "node": ">=0.9" } }, - "node_modules/gulp-clean/node_modules/arr-diff": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz", - "integrity": "sha512-OQwDZUqYaQwyyhDJHThmzId8daf4/RFNLaeh3AevmSeZ5Y7ug4Ga/yKc6l6kTZOBW781rCj103ZuTh8GAsB3+Q==", - "dev": true, - "dependencies": { - "arr-flatten": "^1.0.1", - "array-slice": "^0.2.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-clean/node_modules/arr-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz", - "integrity": "sha512-t5db90jq+qdgk8aFnxEkjqta0B/GHrM1pxzuuZz2zWsOXc5nKu3t+76s/PQBA8FTcM/ipspIH9jWG4OxCBc2eA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-clean/node_modules/array-slice": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", - "integrity": "sha512-rlVfZW/1Ph2SNySXwR9QYkChp8EkOEiTMO5Vwx60usw04i4nWemkm9RXmQqgkQFaLHsqLuADvjp6IfgL9l2M8Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-clean/node_modules/extend-shallow": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz", - "integrity": "sha512-L7AGmkO6jhDkEBBGWlLtftA80Xq8DipnrRPr0pyi7GQLXkaq9JYA4xF4z6qnadIC6euiTDKco0cGSU9muw+WTw==", - "dev": true, - "dependencies": { - "kind-of": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-clean/node_modules/kind-of": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", - "integrity": "sha512-aUH6ElPnMGon2/YkxRIigV32MOpTVcoXQ1Oo8aYn40s+sJ3j+0gFZsT8HKDcxNy7Fi9zuquWtGaGAahOdv5p/g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-clean/node_modules/plugin-error": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", - "integrity": "sha512-WzZHcm4+GO34sjFMxQMqZbsz3xiNEgonCskQ9v+IroMmYgk/tas8dG+Hr2D6IbRPybZ12oWpzE/w3cGJ6FJzOw==", - "dev": true, - "dependencies": { - "ansi-cyan": "^0.1.1", - "ansi-red": "^0.1.1", - "arr-diff": "^1.0.1", - "arr-union": "^2.0.1", - "extend-shallow": "^1.1.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/gulp-clean/node_modules/rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -10078,7 +11963,7 @@ "node_modules/gulp-cli/node_modules/ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -10087,7 +11972,7 @@ "node_modules/gulp-cli/node_modules/camelcase": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -10096,7 +11981,7 @@ "node_modules/gulp-cli/node_modules/cliui": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "integrity": "sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==", "dev": true, "dependencies": { "string-width": "^1.0.1", @@ -10104,10 +11989,19 @@ "wrap-ansi": "^2.0.0" } }, + "node_modules/gulp-cli/node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/gulp-cli/node_modules/find-up": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", "dev": true, "dependencies": { "path-exists": "^2.0.0", @@ -10123,10 +12017,16 @@ "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", "dev": true }, + "node_modules/gulp-cli/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, "node_modules/gulp-cli/node_modules/is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", "dev": true, "dependencies": { "number-is-nan": "^1.0.0" @@ -10135,10 +12035,22 @@ "node": ">=0.10.0" } }, + "node_modules/gulp-cli/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, "node_modules/gulp-cli/node_modules/path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", "dev": true, "dependencies": { "pinkie-promise": "^2.0.0" @@ -10150,7 +12062,7 @@ "node_modules/gulp-cli/node_modules/read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", "dev": true, "dependencies": { "load-json-file": "^1.0.0", @@ -10164,7 +12076,7 @@ "node_modules/gulp-cli/node_modules/read-pkg-up": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", "dev": true, "dependencies": { "find-up": "^1.0.0", @@ -10174,16 +12086,19 @@ "node": ">=0.10.0" } }, - "node_modules/gulp-cli/node_modules/require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", - "dev": true + "node_modules/gulp-cli/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } }, "node_modules/gulp-cli/node_modules/string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", "dev": true, "dependencies": { "code-point-at": "^1.0.0", @@ -10197,7 +12112,7 @@ "node_modules/gulp-cli/node_modules/strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "dependencies": { "ansi-regex": "^2.0.0" @@ -10206,16 +12121,10 @@ "node": ">=0.10.0" } }, - "node_modules/gulp-cli/node_modules/which-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", - "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", - "dev": true - }, "node_modules/gulp-cli/node_modules/wrap-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==", "dev": true, "dependencies": { "string-width": "^1.0.1", @@ -10265,7 +12174,7 @@ "node_modules/gulp-concat": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/gulp-concat/-/gulp-concat-2.6.1.tgz", - "integrity": "sha1-Yz0WyV2IUEYorQJmVmPO5aR5M1M=", + "integrity": "sha512-a2scActrQrDBpBbR3WUZGyGS1JEPLg5PZJdIa7/Bi3GuKAmPYDK6SFhy/NZq5R8KsKKFvtfR0fakbUCcKGCCjg==", "dev": true, "dependencies": { "concat-with-sourcemaps": "^1.0.0", @@ -10324,10 +12233,25 @@ "ms": "2.0.0" } }, + "node_modules/gulp-connect/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/gulp-connect/node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==", + "dev": true + }, "node_modules/gulp-connect/node_modules/http-errors": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", "dev": true, "dependencies": { "depd": "~1.1.2", @@ -10342,7 +12266,7 @@ "node_modules/gulp-connect/node_modules/inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", "dev": true }, "node_modules/gulp-connect/node_modules/mime": { @@ -10357,9 +12281,21 @@ "node_modules/gulp-connect/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/gulp-connect/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/gulp-connect/node_modules/send": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", @@ -10410,6 +12346,18 @@ "plugin-error": "^1.0.1" } }, + "node_modules/gulp-eslint/node_modules/ansi-colors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "dev": true, + "dependencies": { + "ansi-wrap": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/gulp-eslint/node_modules/ansi-regex": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", @@ -10419,6 +12367,24 @@ "node": ">=6" } }, + "node_modules/gulp-eslint/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/gulp-eslint/node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/gulp-eslint/node_modules/astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", @@ -10552,22 +12518,6 @@ "node": ">=4" } }, - "node_modules/gulp-eslint/node_modules/eslint/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/gulp-eslint/node_modules/eslint/node_modules/strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -10594,6 +12544,19 @@ "node": ">=6.0.0" } }, + "node_modules/gulp-eslint/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/gulp-eslint/node_modules/file-entry-cache": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", @@ -10641,6 +12604,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gulp-eslint/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, + "engines": { + "node": ">=8" + } + }, "node_modules/gulp-eslint/node_modules/inquirer": { "version": "7.3.3", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", @@ -10756,6 +12728,21 @@ "node": ">=4" } }, + "node_modules/gulp-eslint/node_modules/plugin-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", + "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", + "dev": true, + "dependencies": { + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/gulp-eslint/node_modules/prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -10786,18 +12773,6 @@ "rimraf": "bin.js" } }, - "node_modules/gulp-eslint/node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, "node_modules/gulp-eslint/node_modules/shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -10955,7 +12930,7 @@ "node_modules/gulp-js-escape": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gulp-js-escape/-/gulp-js-escape-1.0.1.tgz", - "integrity": "sha1-HNRF+9AJ4Np2lZoDp/SbNWav+Gg=", + "integrity": "sha512-F+53crhLb78CTlG7ZZJFWzP0+/4q0vt2/pULXFkTMs6AGBo0Eh5cx+eWsqqHv8hrNIUsuTab3Se8rOOzP/6+EQ==", "dev": true, "dependencies": { "through2": "^0.6.3" @@ -10964,13 +12939,13 @@ "node_modules/gulp-js-escape/node_modules/isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", "dev": true }, "node_modules/gulp-js-escape/node_modules/readable-stream": { "version": "1.0.34", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", "dev": true, "dependencies": { "core-util-is": "~1.0.0", @@ -10982,13 +12957,13 @@ "node_modules/gulp-js-escape/node_modules/string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", "dev": true }, "node_modules/gulp-js-escape/node_modules/through2": { "version": "0.6.5", "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "integrity": "sha512-RkK/CCESdTKQZHdmKICijdKKsCRVHs5KsLZ6pACAmF/1GPUQhonHSXWNERctxEp7RmvjdNbZTL5z9V7nSCXKcg==", "dev": true, "dependencies": { "readable-stream": ">=1.0.33-1 <1.1.0-0", @@ -11021,9 +12996,9 @@ } }, "node_modules/gulp-replace/node_modules/@types/node": { - "version": "14.18.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.12.tgz", - "integrity": "sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A==", + "version": "14.18.33", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.33.tgz", + "integrity": "sha512-qelS/Ra6sacc4loe/3MSjXNL1dNQ/GjxNHVzuChwMfmk7HuycRLVQN2qNY3XahK+fZc5E2szqQSKUyAF0E+2bg==", "dev": true }, "node_modules/gulp-shell": { @@ -11043,6 +13018,18 @@ "node": ">=10.0.0" } }, + "node_modules/gulp-shell/node_modules/ansi-colors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "dev": true, + "dependencies": { + "ansi-wrap": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/gulp-shell/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -11058,6 +13045,24 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/gulp-shell/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/gulp-shell/node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/gulp-shell/node_modules/chalk": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", @@ -11089,6 +13094,43 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/gulp-shell/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/gulp-shell/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/gulp-shell/node_modules/plugin-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", + "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", + "dev": true, + "dependencies": { + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/gulp-shell/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -11179,6 +13221,64 @@ "node": ">=10" } }, + "node_modules/gulp-terser/node_modules/ansi-colors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "dev": true, + "dependencies": { + "ansi-wrap": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-terser/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/gulp-terser/node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-terser/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/gulp-terser/node_modules/plugin-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", + "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", + "dev": true, + "dependencies": { + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/gulp-util": { "version": "3.0.8", "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", @@ -11212,7 +13312,7 @@ "node_modules/gulp-util/node_modules/ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -11221,7 +13321,7 @@ "node_modules/gulp-util/node_modules/ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -11230,7 +13330,7 @@ "node_modules/gulp-util/node_modules/chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "dependencies": { "ansi-styles": "^2.2.1", @@ -11246,7 +13346,7 @@ "node_modules/gulp-util/node_modules/clone": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "dev": true, "engines": { "node": ">=0.8" @@ -11255,18 +13355,9 @@ "node_modules/gulp-util/node_modules/clone-stats": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", + "integrity": "sha512-dhUqc57gSMCo6TX85FLfe51eC/s+Im2MLkAgJwfaRRexR2tA4dd3eLEW4L6efzHc2iNorrRRXITifnDLlRrhaA==", "dev": true }, - "node_modules/gulp-util/node_modules/lodash.escape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", - "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", - "dev": true, - "dependencies": { - "lodash._root": "^3.0.0" - } - }, "node_modules/gulp-util/node_modules/lodash.template": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", @@ -11287,7 +13378,7 @@ "node_modules/gulp-util/node_modules/lodash.templatesettings": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", - "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", + "integrity": "sha512-TcrlEr31tDYnWkHFWDCV3dHYroKEXpJZ2YJYvJdhN+y4AkWMDZ5I4I8XDtUKqSAyG81N7w+I1mFEJtcED+tGqQ==", "dev": true, "dependencies": { "lodash._reinterpolate": "^3.0.0", @@ -11297,7 +13388,7 @@ "node_modules/gulp-util/node_modules/object-assign": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=", + "integrity": "sha512-jHP15vXVGeVh1HuaA2wY6lxk+whK/x4KBG88VXeRma7CCun7iGD5qPc4eYykQ9sdQvg8jkwFKsSxHln2ybW3xQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -11306,7 +13397,7 @@ "node_modules/gulp-util/node_modules/strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "dependencies": { "ansi-regex": "^2.0.0" @@ -11318,7 +13409,7 @@ "node_modules/gulp-util/node_modules/supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, "engines": { "node": ">=0.8.0" @@ -11337,7 +13428,7 @@ "node_modules/gulp-util/node_modules/vinyl": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", - "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", + "integrity": "sha512-P5zdf3WB9uzr7IFoVQ2wZTmUwHL8cMZWJGzLBNCHNZ3NB6HTMsYABtt7z8tAGIINLXyAob9B9a1yzVGMFOYKEA==", "dev": true, "dependencies": { "clone": "^1.0.0", @@ -11351,7 +13442,7 @@ "node_modules/gulplog": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", - "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", + "integrity": "sha512-hm6N8nrm3Y08jXie48jsC55eCZz9mnb4OirAStEk2deqeyhXU3C1otDVh+ccttMuc1sBi6RX6ZJ720hs9RCvgw==", "dev": true, "dependencies": { "glogg": "^1.0.0" @@ -11408,7 +13499,7 @@ "node_modules/har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", "dev": true, "engines": { "node": ">=4" @@ -11428,22 +13519,6 @@ "node": ">=6" } }, - "node_modules/har-validator/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -11458,7 +13533,7 @@ "node_modules/has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", "dev": true, "dependencies": { "ansi-regex": "^2.0.0" @@ -11470,34 +13545,33 @@ "node_modules/has-ansi/node_modules/ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "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, + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/has-gulplog": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", - "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", + "integrity": "sha512-+F4GzLjwHNNDEAJW2DC1xXfEoPkRDmUdJ7CBYw4MpqtDwOnqdImJl7GWlpqx+Wko6//J8uKTnIe4wZSv7yCqmw==", "dev": true, "dependencies": { "sparkles": "^1.0.0" @@ -11506,6 +13580,18 @@ "node": ">= 0.10" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -11535,7 +13621,7 @@ "node_modules/has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", "dev": true, "dependencies": { "get-value": "^2.0.6", @@ -11549,7 +13635,7 @@ "node_modules/has-values": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", "dev": true, "dependencies": { "is-number": "^3.0.0", @@ -11565,10 +13651,34 @@ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, + "node_modules/has-values/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/has-values/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/has-values/node_modules/kind-of": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -11657,7 +13767,7 @@ "node_modules/home-or-tmp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", - "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "integrity": "sha512-ycURW7oUxE2sNiPVw1HVEFsW+ecOpJ5zaj7eC0RlwhibhRBod20muUN8qu/gzx956YrLolVvs1MTXwKgC2rVEg==", "dev": true, "dependencies": { "os-homedir": "^1.0.0", @@ -11680,10 +13790,16 @@ } }, "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } }, "node_modules/html-escaper": { "version": "2.0.2", @@ -11702,30 +13818,30 @@ } }, "node_modules/http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", "dev": true }, "node_modules/http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dependencies": { - "depd": "~1.1.2", + "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", + "statuses": "2.0.1", "toidentifier": "1.0.1" }, "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/http-parser-js": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.6.tgz", - "integrity": "sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA==", + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", "dev": true }, "node_modules/http-proxy": { @@ -11745,7 +13861,7 @@ "node_modules/http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", "dev": true, "dependencies": { "assert-plus": "^1.0.0", @@ -11771,16 +13887,16 @@ } }, "node_modules/https-proxy-agent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", - "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==", + "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, "dependencies": { - "agent-base": "5", + "agent-base": "6", "debug": "4" }, "engines": { - "node": ">= 6.0.0" + "node": ">= 6" } }, "node_modules/iconv-lite": { @@ -11851,12 +13967,21 @@ "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, "engines": { "node": ">=0.8.19" } }, + "node_modules/indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha512-BYqTHXTGUIvg7t1r4sJNKcbDZkL92nkXA8YtRpbjFHRHGDL/NtUeiBJMeE60kIFN/Mg8ESaWQvftaYMGJzQZCQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/individual": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/individual/-/individual-2.0.0.tgz", @@ -11866,7 +13991,7 @@ "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dev": true, "dependencies": { "once": "^1.3.0", @@ -11879,15 +14004,18 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.1.tgz", + "integrity": "sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } }, "node_modules/inquirer": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.1.5.tgz", - "integrity": "sha512-G6/9xUqmt/r+UvufSyrPpt84NYwhKZ9jLsgMbQzlx804XErNupor8WQdBnBRrXmBfTPpuwf1sV+ss2ovjgdXIg==", + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", + "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==", "dev": true, "dependencies": { "ansi-escapes": "^4.2.1", @@ -11900,13 +14028,14 @@ "mute-stream": "0.0.8", "ora": "^5.4.1", "run-async": "^2.4.0", - "rxjs": "^7.2.0", + "rxjs": "^7.5.5", "string-width": "^4.1.0", "strip-ansi": "^6.0.0", - "through": "^2.3.6" + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" }, "engines": { - "node": ">=8.0.0" + "node": ">=12.0.0" } }, "node_modules/inquirer/node_modules/ansi-styles": { @@ -11958,6 +14087,24 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/inquirer/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/rxjs": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz", + "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, "node_modules/inquirer/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -11970,6 +14117,12 @@ "node": ">=8" } }, + "node_modules/inquirer/node_modules/tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "dev": true + }, "node_modules/internal-slot": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", @@ -12005,7 +14158,7 @@ "node_modules/invert-kv": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "integrity": "sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -12072,7 +14225,7 @@ "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true }, "node_modules/is-bigint": { @@ -12139,9 +14292,9 @@ } }, "node_modules/is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, "engines": { "node": ">= 0.4" @@ -12151,9 +14304,9 @@ } }, "node_modules/is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dependencies": { "has": "^1.0.3" }, @@ -12262,7 +14415,7 @@ "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -12359,7 +14512,7 @@ "node_modules/is-negated-glob": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", - "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=", + "integrity": "sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==", "dev": true, "engines": { "node": ">=0.10.0" @@ -12378,21 +14531,18 @@ } }, "node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, "engines": { - "node": ">=0.10.0" + "node": ">=0.12.0" } }, "node_modules/is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" @@ -12404,24 +14554,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-number/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/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", @@ -12480,7 +14612,7 @@ "node_modules/is-running": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-running/-/is-running-2.1.0.tgz", - "integrity": "sha1-MKc/9cw4VOT8JUkICen1q/jeCeA=", + "integrity": "sha512-mjJd3PujZMl7j+D395WTIO5tU5RIDBfVSRtRR4VOJou3H66E38UjbjvDGh3slJzPuolsb+yQFqwHNNdyp5jg3w==", "dev": true }, "node_modules/is-set": { @@ -12493,10 +14625,13 @@ } }, "node_modules/is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -12513,7 +14648,7 @@ "node_modules/is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -12550,15 +14685,15 @@ } }, "node_modules/is-typed-array": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.8.tgz", - "integrity": "sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA==", + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.9.tgz", + "integrity": "sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A==", "dev": true, "dependencies": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", - "es-abstract": "^1.18.5", - "foreach": "^2.0.5", + "es-abstract": "^1.20.0", + "for-each": "^0.3.3", "has-tostringtag": "^1.0.0" }, "engines": { @@ -12571,7 +14706,7 @@ "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", "dev": true }, "node_modules/is-unc-path": { @@ -12601,13 +14736,13 @@ "node_modules/is-utf8": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", "dev": true }, "node_modules/is-valid-glob": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", - "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=", + "integrity": "sha512-AhiROmoEFDSsjx8hW+5sGwgKVIORcXnrlAx/R0ZSeaPw70Vw0CqkGBBhHGL58Uox2eXnU1AnvXJl1XlyedO5bA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -12675,9 +14810,9 @@ "dev": true }, "node_modules/isbinaryfile": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.8.tgz", - "integrity": "sha512-53h6XFniq77YdW+spoRrebh0mnmTxRPTlcuIArO57lmMdq4uBKFKaeTjnb92oYWrSn/LVL+LT+Hap2tFQj8V+w==", + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", "dev": true, "engines": { "node": ">= 8.0.0" @@ -12689,13 +14824,13 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, "node_modules/isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -12704,13 +14839,13 @@ "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", "dev": true }, "node_modules/istanbul": { "version": "0.4.5", "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", - "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", + "integrity": "sha512-nMtdn4hvK0HjUlzr1DrKSUY8ychprt8dzHOgY2KXsIhHu5PuQQEOTM27gV9Xblyon7aUH/TSFIjRHEODF/FRPg==", "deprecated": "This module is no longer maintained, try this instead:\n npm i nyc\nVisit https://istanbul.js.org/integrations for other alternatives.", "dev": true, "dependencies": { @@ -12742,6 +14877,22 @@ "node": ">=8" } }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/istanbul-lib-report": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", @@ -12756,6 +14907,15 @@ "node": ">=8" } }, + "node_modules/istanbul-lib-report/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, + "engines": { + "node": ">=8" + } + }, "node_modules/istanbul-lib-report/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -12792,9 +14952,9 @@ } }, "node_modules/istanbul-reports": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", - "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", "dev": true, "dependencies": { "html-escaper": "^2.0.0", @@ -12807,7 +14967,7 @@ "node_modules/istanbul/node_modules/glob": { "version": "5.0.15", "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", - "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", "dev": true, "dependencies": { "inflight": "^1.0.4", @@ -12823,19 +14983,19 @@ "node_modules/istanbul/node_modules/has-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/istanbul/node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "dependencies": { - "minimist": "^1.2.5" + "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" @@ -12844,13 +15004,13 @@ "node_modules/istanbul/node_modules/resolve": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", "dev": true }, "node_modules/istanbul/node_modules/supports-color": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", "dev": true, "dependencies": { "has-flag": "^1.0.0" @@ -12960,6 +15120,15 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/jake/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, + "engines": { + "node": ">=8" + } + }, "node_modules/jake/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -12973,18 +15142,18 @@ } }, "node_modules/jest-diff": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", - "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", + "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", "dev": true, "dependencies": { "chalk": "^4.0.0", - "diff-sequences": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" + "diff-sequences": "^26.6.2", + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 10.14.2" } }, "node_modules/jest-diff/node_modules/ansi-styles": { @@ -13036,6 +15205,15 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "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, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-diff/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -13049,27 +15227,27 @@ } }, "node_modules/jest-get-type": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", - "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "version": "26.3.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", + "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", "dev": true, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 10.14.2" } }, "node_modules/jest-matcher-utils": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", - "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", + "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", "dev": true, "dependencies": { "chalk": "^4.0.0", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" + "jest-diff": "^26.6.2", + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 10.14.2" } }, "node_modules/jest-matcher-utils/node_modules/ansi-styles": { @@ -13121,6 +15299,15 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "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, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-matcher-utils/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -13134,23 +15321,23 @@ } }, "node_modules/jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", + "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", + "@babel/code-frame": "^7.0.0", + "@jest/types": "^26.6.2", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.2", + "pretty-format": "^26.6.2", "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "stack-utils": "^2.0.2" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 10.14.2" } }, "node_modules/jest-message-util/node_modules/ansi-styles": { @@ -13202,17 +15389,22 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/jest-message-util/node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "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, - "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - }, "engines": { - "node": ">=8.6" + "node": ">=8" + } + }, + "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, + "engines": { + "node": ">=8" } }, "node_modules/jest-message-util/node_modules/supports-color": { @@ -13227,6 +15419,15 @@ "node": ">=8" } }, + "node_modules/jest-regex-util": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", + "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", + "dev": true, + "engines": { + "node": ">= 10.14.2" + } + }, "node_modules/jest-worker": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", @@ -13241,6 +15442,30 @@ "node": ">= 10.13.0" } }, + "node_modules/jest-worker/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -13275,7 +15500,7 @@ "node_modules/jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", "dev": true }, "node_modules/jsesc": { @@ -13295,12 +15520,6 @@ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -13322,13 +15541,13 @@ "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", "dev": true }, "node_modules/json5": { @@ -13372,7 +15591,7 @@ "node_modules/just-clone": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/just-clone/-/just-clone-1.0.2.tgz", - "integrity": "sha1-v7P672WqEqMWBYcSlFwyb9jwFDQ=" + "integrity": "sha512-p93GINPwrve0w3HUzpXmpTl7MyzzWz1B5ag44KEtq/hP1mtK8lA2b9Q0VQaPlnY87352osJcE6uBmN0e8kuFMw==" }, "node_modules/just-debounce": { "version": "1.1.0", @@ -13387,9 +15606,9 @@ "dev": true }, "node_modules/karma": { - "version": "6.3.17", - "resolved": "https://registry.npmjs.org/karma/-/karma-6.3.17.tgz", - "integrity": "sha512-2TfjHwrRExC8yHoWlPBULyaLwAFmXmxQrcuFImt/JsAsSZu1uOWTZ1ZsWjqQtWpHLiatJOHL5jFjXSJIgCd01g==", + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.1.tgz", + "integrity": "sha512-Cj57NKOskK7wtFWSlMvZf459iX+kpYIPXmkNUzP2WAFcA7nhr/ALn5R7sw3w+1udFDcpMx/tuB8d5amgm3ijaA==", "dev": true, "dependencies": { "@colors/colors": "1.5.0", @@ -13411,7 +15630,7 @@ "qjobs": "^1.2.0", "range-parser": "^1.2.1", "rimraf": "^3.0.2", - "socket.io": "^4.2.0", + "socket.io": "^4.4.1", "source-map": "^0.6.1", "tmp": "^0.2.1", "ua-parser-js": "^0.7.30", @@ -13453,7 +15672,7 @@ "node_modules/karma-chai": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/karma-chai/-/karma-chai-0.1.0.tgz", - "integrity": "sha1-vuWtQEAFF4Ea40u5RfdikJEIt5o=", + "integrity": "sha512-mqKCkHwzPMhgTYca10S90aCEX9+HjVjjrBFAsw36Zj7BlQNbokXXCAe6Ji04VUMsxcY5RLP7YphpfO06XOubdg==", "dev": true, "peerDependencies": { "chai": "*", @@ -13461,9 +15680,9 @@ } }, "node_modules/karma-chrome-launcher": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.0.tgz", - "integrity": "sha512-3dPs/n7vgz1rxxtynpzZTvb9y/GIaW8xjAwcIGttLbycqoFtI7yo1NGnQi6oFTherRE+GIhCAHZC4vEqWGhNvg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.1.tgz", + "integrity": "sha512-hsIglcq1vtboGPAN+DGCISCFOxW+ZVnIqhDQcCMqqCp+4dmJ0Qpq5QAjkbA0X2L9Mi6OBkHi2Srrbmm7pUKkzQ==", "dev": true, "dependencies": { "which": "^1.2.1" @@ -13591,26 +15810,10 @@ "node": ">=0.10.0" } }, - "node_modules/karma-coverage/node_modules/istanbul-lib-instrument": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", - "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/karma-es5-shim": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/karma-es5-shim/-/karma-es5-shim-0.0.4.tgz", - "integrity": "sha1-zdADM8znfC5M4D46yT8vjs0fuVI=", + "integrity": "sha512-8xU6F2/R6u6HAZ/nlyhhx3WEhj4C6hJorG7FR2REX81pgj2LSo9ADJXxCGIeXg6Qr2BGpxp4hcZcEOYGAwiumg==", "dev": true, "dependencies": { "es5-shim": "^4.0.5" @@ -13629,7 +15832,7 @@ "node_modules/karma-ie-launcher": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/karma-ie-launcher/-/karma-ie-launcher-1.0.0.tgz", - "integrity": "sha1-SXmGhCxJAZA0bNifVJTKmDDG1Zw=", + "integrity": "sha512-ts71ke8pHvw6qdRtq0+7VY3ANLoZuUNNkA8abRaWV13QRPNm7TtSOqyszjHUtuwOWKcsSz4tbUtrNICrQC+SXQ==", "dev": true, "dependencies": { "lodash": "^4.6.1" @@ -13650,7 +15853,7 @@ "node_modules/karma-mocha-reporter": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/karma-mocha-reporter/-/karma-mocha-reporter-2.2.5.tgz", - "integrity": "sha1-FRIAlejtgZGG5HoLAS8810GJVWA=", + "integrity": "sha512-Hr6nhkIp0GIJJrvzY8JFeHpQZNseuIakGac4bpw8K1+5F0tLb6l7uvXRa8mt2Z+NVwYgCct4QAfp2R2QP6o00w==", "dev": true, "dependencies": { "chalk": "^2.1.0", @@ -13673,7 +15876,7 @@ "node_modules/karma-mocha-reporter/node_modules/strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", "dev": true, "dependencies": { "ansi-regex": "^3.0.0" @@ -13685,7 +15888,7 @@ "node_modules/karma-opera-launcher": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/karma-opera-launcher/-/karma-opera-launcher-1.0.0.tgz", - "integrity": "sha1-+lFihTGh0L6EstjcDX7iCfyP+Ro=", + "integrity": "sha512-rdty4FlVIowmUhPuG08TeXKHvaRxeDSzPxGIkWguCF3A32kE0uvXZ6dXW08PuaNjai8Ip3f5Pn9Pm2HlChaxCw==", "dev": true, "peerDependencies": { "karma": ">=0.9" @@ -13694,7 +15897,7 @@ "node_modules/karma-safari-launcher": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/karma-safari-launcher/-/karma-safari-launcher-1.0.0.tgz", - "integrity": "sha1-lpgqLMR9BmquccVTursoMZEVos4=", + "integrity": "sha512-qmypLWd6F2qrDJfAETvXDfxHvKDk+nyIjpH9xIeI3/hENr0U3nuqkxaftq73PfXZ4aOuOChA6SnLW4m4AxfRjQ==", "dev": true, "peerDependencies": { "karma": ">=0.9" @@ -13703,7 +15906,7 @@ "node_modules/karma-script-launcher": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/karma-script-launcher/-/karma-script-launcher-1.0.0.tgz", - "integrity": "sha1-zQF8TeXvCeWp2nkydhdhCN1LVC0=", + "integrity": "sha512-5NRc8KmTBjNPE3dNfpJP90BArnBohYV4//MsLFfUA1e6N+G1/A5WuWctaFBtMQ6MWRybs/oguSej0JwDr8gInA==", "dev": true, "peerDependencies": { "karma": ">=0.9" @@ -13712,7 +15915,7 @@ "node_modules/karma-sinon": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/karma-sinon/-/karma-sinon-1.0.5.tgz", - "integrity": "sha1-TjRD8oMP3s/2JNN0cWPxIX2qKpo=", + "integrity": "sha512-wrkyAxJmJbn75Dqy17L/8aILJWFm7znd1CE8gkyxTBFnjMSOe2XTJ3P30T8SkxWZHmoHX0SCaUJTDBEoXs25Og==", "dev": true, "engines": { "node": ">= 0.10.0" @@ -13734,7 +15937,7 @@ "node_modules/karma-spec-reporter": { "version": "0.0.32", "resolved": "https://registry.npmjs.org/karma-spec-reporter/-/karma-spec-reporter-0.0.32.tgz", - "integrity": "sha1-LpxyB+pyZ3EmAln4K+y1QyCeRAo=", + "integrity": "sha512-ZXsYERZJMTNRR2F3QN11OWF5kgnT/K2dzhM+oY3CDyMrDI3TjIWqYGG7c15rR9wjmy9lvdC+CCshqn3YZqnNrA==", "dev": true, "dependencies": { "colors": "^1.1.2" @@ -13760,13 +15963,24 @@ "webpack": "^5.0.0" } }, + "node_modules/karma/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, "node_modules/karma/node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "dependencies": { - "minimist": "^1.2.5" + "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" @@ -13781,6 +15995,18 @@ "node": ">=0.10.0" } }, + "node_modules/karma/node_modules/tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "dependencies": { + "rimraf": "^3.0.0" + }, + "engines": { + "node": ">=8.17.0" + } + }, "node_modules/karma/node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -13815,9 +16041,9 @@ "dev": true }, "node_modules/keyv": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.1.1.tgz", - "integrity": "sha512-tGv1yP6snQVDSM4X6yxrv2zzq/EvpW+oYiUz6aueW1u9CtS8RzUQYxxmFwgZlO2jSgCxQbchhxaqXXp2hnKGpQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.0.tgz", + "integrity": "sha512-2YvuMsA+jnFGtBareKqgANOEKe1mk3HKiXu2fRmAfyxG0MJAywNhi5ttWA3PMjl4NmpyjZNbFifR2vNjW1znfA==", "dev": true, "dependencies": { "json-buffer": "3.0.1" @@ -13866,7 +16092,7 @@ "node_modules/last-run": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", - "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=", + "integrity": "sha512-U/VxvpX4N/rFvPzr3qG5EtLKEnNI0emvIQB3/ecEwv+8GHaUKbIB8vxv1Oai5FAF0d0r7LXHhLLe5K/yChm5GQ==", "dev": true, "dependencies": { "default-resolution": "^2.0.0", @@ -13891,7 +16117,7 @@ "node_modules/lcid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "integrity": "sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==", "dev": true, "dependencies": { "invert-kv": "^1.0.0" @@ -13903,7 +16129,7 @@ "node_modules/lcov-parse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-1.0.0.tgz", - "integrity": "sha1-6w1GtUER68VhrLTECO+TY73I9+A=", + "integrity": "sha512-aprLII/vPzuQvYZnDRU78Fns9I2Ag3gi4Ipga/hxnVMCZC8DnR2nI7XBqrPoywGfxqIx/DgarGvDJZAD3YBTgQ==", "dev": true, "bin": { "lcov-parse": "bin/cli.js" @@ -13912,7 +16138,7 @@ "node_modules/lead": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", - "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=", + "integrity": "sha512-IpSVCk9AYvLHo5ctcIXxOBpMWUe+4TKN3VPWAKUbJikkmsGp0VrSM8IttVc32D6J4WUsiPE6aEFRNmIoF/gdow==", "dev": true, "dependencies": { "flush-write-stream": "^1.0.2" @@ -13987,7 +16213,7 @@ "node_modules/lighthouse-logger/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "node_modules/lines-and-columns": { @@ -13999,13 +16225,13 @@ "node_modules/listenercount": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", - "integrity": "sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=", + "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==", "dev": true }, "node_modules/live-connect-js": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/live-connect-js/-/live-connect-js-2.4.0.tgz", - "integrity": "sha512-MSBLKfnXoxH+pqwji/Mf8yZu3VZMq4tnNfwMw7NTWN5a+TBM6f0RWgwui1YMA3nHmMhX/nzxxsso0SkyKcF0fA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/live-connect-js/-/live-connect-js-4.0.0.tgz", + "integrity": "sha512-uycBgFBdEwSq95NImrsOSkTlszUMTGf8luK9GZDWw4D+DL5yFNnCPcrjxUk15U9n9aPmaM1SKmWH5qUXFr8aIA==", "dependencies": { "tiny-hashes": "1.0.1" }, @@ -14069,25 +16295,38 @@ } }, "node_modules/loader-runner": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", - "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", "dev": true, "engines": { "node": ">=6.11.5" } }, + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, "node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "p-locate": "^4.1.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/lodash": { @@ -14099,126 +16338,135 @@ "node_modules/lodash._basecopy": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "integrity": "sha512-rFR6Vpm4HeCK1WPGvjZSJ+7yik8d8PVUdCJx5rT2pogG4Ve/2ZS7kfmO5l5T2o5V2mqlNIfSF5MZlr1+xOoYQQ==", "dev": true }, "node_modules/lodash._basetostring": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", - "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=", + "integrity": "sha512-mTzAr1aNAv/i7W43vOR/uD/aJ4ngbtsRaCubp2BfZhlGU/eORUjg/7F6X0orNMdv33JOrdgGybtvMN/po3EWrA==", "dev": true }, "node_modules/lodash._basevalues": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", - "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", + "integrity": "sha512-H94wl5P13uEqlCg7OcNNhMQ8KvWSIyqXzOPusRgHC9DK3o54P6P3xtbXlVbRABG4q5gSmp7EDdJ0MSuW9HX6Mg==", "dev": true }, "node_modules/lodash._getnative": { "version": "3.9.1", "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "integrity": "sha512-RrL9VxMEPyDMHOd9uFbvMe8X55X16/cGM5IgOKgRElQZutpX89iS6vwl64duTV1/16w5JY7tuFNXqoekmh1EmA==", "dev": true }, "node_modules/lodash._isiterateecall": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", - "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "integrity": "sha512-De+ZbrMu6eThFti/CSzhRvTKMgQToLxbij58LMfM8JnYDNSOjkjTCIaa8ixglOeGh2nyPlakbt5bJWJ7gvpYlQ==", "dev": true }, "node_modules/lodash._reescape": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", - "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=", + "integrity": "sha512-Sjlavm5y+FUVIF3vF3B75GyXrzsfYV8Dlv3L4mEpuB9leg8N6yf/7rU06iLPx9fY0Mv3khVp9p7Dx0mGV6V5OQ==", "dev": true }, "node_modules/lodash._reevaluate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", - "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=", + "integrity": "sha512-OrPwdDc65iJiBeUe5n/LIjd7Viy99bKwDdk7Z5ljfZg0uFRFlfQaCy9tZ4YMAag9WAZmlVpe1iZrkIMMSMHD3w==", "dev": true }, "node_modules/lodash._reinterpolate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", + "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==", "dev": true }, "node_modules/lodash._root": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", - "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=", + "integrity": "sha512-O0pWuFSK6x4EXhM1dhZ8gchNtG7JMqBtrHdoUFUWXD7dJnNSUze1GuyQr5sOs0aCvgGeI3o/OJW8f4ca7FDxmQ==", "dev": true }, "node_modules/lodash.clone": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz", - "integrity": "sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y=", + "integrity": "sha512-GhrVeweiTD6uTmmn5hV/lzgCQhccwReIVRLHp7LT4SopOjqEZ5BbX8b5WWEtAKasjmy8hR7ZPwsYlxRCku5odg==", "dev": true }, "node_modules/lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", "dev": true }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, "node_modules/lodash.defaults": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", "dev": true }, "node_modules/lodash.difference": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", - "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", "dev": true }, + "node_modules/lodash.escape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", + "integrity": "sha512-n1PZMXgaaDWZDSvuNZ/8XOcYO2hOKDqZel5adtR30VKQAtoWs/5AOeFA0vPV8moiPzlqe7F4cP2tzpFewQyelQ==", + "dev": true, + "dependencies": { + "lodash._root": "^3.0.0" + } + }, "node_modules/lodash.flatten": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", "dev": true }, "node_modules/lodash.flattendeep": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", - "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", "dev": true }, "node_modules/lodash.get": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", "dev": true }, "node_modules/lodash.isarguments": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==", "dev": true }, "node_modules/lodash.isarray": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "integrity": "sha512-JwObCrNJuT0Nnbuecmqr5DgtuBppuCvGD9lxjFpAzwnVtdGoDQ1zig+5W8k5/6Gcn0gZ3936HDAlGd28i7sOGQ==", "dev": true }, "node_modules/lodash.isobject": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz", - "integrity": "sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0=", + "integrity": "sha512-3/Qptq2vr7WeJbB4KHUSKlq8Pl7ASXi3UG6CMbBm8WRtXi8+GHm7mKaU3urfpSEzWe2wCIChs6/sdocUsTKJiA==", "dev": true }, "node_modules/lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", "dev": true }, "node_modules/lodash.keys": { @@ -14241,19 +16489,19 @@ "node_modules/lodash.pickby": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", - "integrity": "sha1-feoh2MGNdwOifHBMFdO4SmfjOv8=", + "integrity": "sha512-AZV+GsS/6ckvPOVQPXSiFFacKvKB4kOQu6ynt9wz0F3LO4R9Ij4K1ddYsIytDpSgLz88JHd9P+oaLeej5/Sl7Q==", "dev": true }, "node_modules/lodash.restparam": { "version": "3.6.1", "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", + "integrity": "sha512-L4/arjjuq4noiUJpt3yS6KIKDtJwNe2fIYgMqyYYKoeIfV1iEqvPwhCx23o+R9dzouGihDAPN1dTIRWa7zk8tw==", "dev": true }, "node_modules/lodash.some": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", - "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=", + "integrity": "sha512-j7MJE+TuT51q9ggt4fSgVqro163BEFjAt3u97IqU+JA2DkWl80nFTrowzLpZ/BnpN7rrl0JA/593NAdd8p/scQ==", "dev": true }, "node_modules/lodash.template": { @@ -14278,19 +16526,19 @@ "node_modules/lodash.truncate": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", "dev": true }, "node_modules/lodash.union": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", "dev": true }, "node_modules/lodash.zip": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.zip/-/lodash.zip-4.2.0.tgz", - "integrity": "sha1-7GZi5IlkCO1KtsVCo5kLcswIACA=", + "integrity": "sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg==", "dev": true }, "node_modules/log-driver": { @@ -14315,16 +16563,16 @@ } }, "node_modules/log4js": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.4.2.tgz", - "integrity": "sha512-k80cggS2sZQLBwllpT1p06GtfvzMmSdUCkW96f0Hj83rKGJDAu2vZjt9B9ag2vx8Zz1IXzxoLgqvRJCdMKybGg==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.7.0.tgz", + "integrity": "sha512-KA0W9ffgNBLDj6fZCq/lRbgR6ABAodRIDHrZnS48vOtfKa4PzWImb0Md1lmGCdO3n3sbCm/n1/WmrNlZ8kCI3Q==", "dev": true, "dependencies": { - "date-format": "^4.0.4", - "debug": "^4.3.3", - "flatted": "^3.2.5", + "date-format": "^4.0.14", + "debug": "^4.3.4", + "flatted": "^3.2.7", "rfdc": "^1.3.0", - "streamroller": "^3.0.4" + "streamroller": "^3.1.3" }, "engines": { "node": ">=8.0" @@ -14410,7 +16658,7 @@ "node_modules/lru-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", - "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", + "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", "dev": true, "dependencies": { "es5-ext": "~0.10.2" @@ -14476,7 +16724,7 @@ "node_modules/map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -14494,13 +16742,13 @@ "node_modules/map-stream": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", - "integrity": "sha1-ih8HiW2CsQkmvTdEokIACfiJdKg=", + "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==", "dev": true }, "node_modules/map-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", "dev": true, "dependencies": { "object-visit": "^1.0.0" @@ -14520,15 +16768,15 @@ } }, "node_modules/marky": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.4.tgz", - "integrity": "sha512-zd2/GiSn6U3/jeFVZ0J9CA1LzQ8RfIVvXkb/U0swFHF/zT+dVohTAWjmo2DcIuofmIIIROlwTbd+shSeXmxr0w==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.5.tgz", + "integrity": "sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==", "dev": true }, "node_modules/matchdep": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", - "integrity": "sha1-xvNINKDY28OzfCfui7yyfHd1WC4=", + "integrity": "sha512-LFgVbaHIHMqCRuCZyfCtUOq9/Lnzhi7Z0KFUE2fhD54+JN2jLh3hC02RLkqauJ3U4soU6H1J3tfj/Byk7GoEjA==", "dev": true, "dependencies": { "findup-sync": "^2.0.0", @@ -14540,10 +16788,110 @@ "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", - "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "integrity": "sha512-vs+3unmJT45eczmcAZ6zMJtxN3l/QXeccaXQx5cu/MeJMhewVfoWZqibRkOxPnmoR59+Zy5hjabfQc6JLSah4g==", "dev": true, "dependencies": { "detect-file": "^1.0.0", @@ -14555,10 +16903,16 @@ "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", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", "dev": true, "dependencies": { "is-extglob": "^2.1.0" @@ -14567,6 +16921,76 @@ "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.1", "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.1.tgz", @@ -14708,11 +17132,12 @@ } }, "node_modules/mdast-util-gfm-table": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.4.tgz", - "integrity": "sha512-aEuoPwZyP4iIMkf2cLWXxx3EQ6Bmh2yKy9MVCg4i6Sd3cX80dcLEfXO/V4ul3pGH9czBK4kp+FAl+ZHmSUt9/w==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.6.tgz", + "integrity": "sha512-uHR+fqFq3IvB3Rd4+kzXW8dmpxUhvgCQZep6KdjsLK4O6meK5dYZEayLtIxNus1XO3gfjfcIFe8a7L0HZRGgag==", "dev": true, "dependencies": { + "@types/mdast": "^3.0.0", "markdown-table": "^3.0.0", "mdast-util-from-markdown": "^1.0.0", "mdast-util-to-markdown": "^1.3.0" @@ -14739,24 +17164,22 @@ "node_modules/mdast-util-inject": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/mdast-util-inject/-/mdast-util-inject-1.1.0.tgz", - "integrity": "sha1-2wa4tYW+lZotzS+H9HK6m3VvNnU=", + "integrity": "sha512-CcJ0mHa36QYumDKiZ2OIR+ClhfOM7zIzN+Wfy8tRZ1hpH9DKLCS+Mh4DyK5bCxzE9uxMWcbIpeNFWsg1zrj/2g==", "dev": true, "dependencies": { "mdast-util-to-string": "^1.0.0" } }, "node_modules/mdast-util-to-hast": { - "version": "12.2.1", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-12.2.1.tgz", - "integrity": "sha512-dyindR2P7qOqXO1hQirZeGtVbiX7xlNQbw7gGaAwN4A1dh4+X8xU/JyYmRoyB8Fu1uPXzp7mlL5QwW7k+knvgA==", + "version": "12.2.4", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-12.2.4.tgz", + "integrity": "sha512-a21xoxSef1l8VhHxS1Dnyioz6grrJkoaCUgGzMD/7dWHvboYX3VW53esRUfB5tgTyz4Yos1n25SPcj35dJqmAg==", "dev": true, "dependencies": { "@types/hast": "^2.0.0", "@types/mdast": "^3.0.0", - "@types/mdurl": "^1.0.0", "mdast-util-definitions": "^5.0.0", - "mdurl": "^1.0.0", - "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-sanitize-uri": "^1.1.0", "trim-lines": "^3.0.0", "unist-builder": "^3.0.0", "unist-util-generated": "^2.0.0", @@ -14866,16 +17289,10 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", - "dev": true - }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "engines": { "node": ">= 0.6" } @@ -14912,7 +17329,7 @@ "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" }, "node_modules/merge-stream": { "version": "2.0.0", @@ -14923,15 +17340,15 @@ "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "engines": { "node": ">= 0.6" } }, "node_modules/micromark": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.0.10.tgz", - "integrity": "sha512-ryTDy6UUunOXy2HPjelppgJ2sNfcPz1pLlMdA6Rz9jPzhLikWXv/irpWV/I2jd68Uhmny7hHxAlAhk4+vWggpg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.1.0.tgz", + "integrity": "sha512-6Mj0yHLdUZjHnOPgr5xfWIMqMWS12zDN6iws9SLuSz76W8jTtAv24MN4/CL7gJrl5vtxGInkkqDv/JIoRsQOvA==", "dev": true, "funding": [ { @@ -15419,9 +17836,9 @@ } }, "node_modules/micromark-util-sanitize-uri": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.0.0.tgz", - "integrity": "sha512-cCxvBKlmac4rxCGx6ejlIviRaMKZc0fWm5HdCHEeDWRSkn44l6NdYVRyU+0nT1XC72EQJMZV8IPHF+jTr56lAg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.1.0.tgz", + "integrity": "sha512-RoxtuSCX6sUNtxhbmsEFQfWzs8VN7cTctmBPvYivo98xb/kDEoTCtJQX5wyzIYEmk/lvNFTat4hL8oW0KndFpg==", "dev": true, "funding": [ { @@ -15494,118 +17911,16 @@ ] }, "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/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, - "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": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "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": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "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/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": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/micromatch/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true, - "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, - "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": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "braces": "^3.0.2", + "picomatch": "^2.3.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8.6" } }, "node_modules/mime": { @@ -15621,19 +17936,19 @@ } }, "node_modules/mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dependencies": { - "mime-db": "1.51.0" + "mime-db": "1.52.0" }, "engines": { "node": ">= 0.6" @@ -15679,10 +17994,13 @@ } }, "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/mixin-deep": { "version": "1.3.2", @@ -15755,6 +18073,15 @@ "url": "https://opencollective.com/mochajs" } }, + "node_modules/mocha/node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/mocha/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -15776,15 +18103,6 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "node_modules/mocha/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, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/mocha/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -15813,6 +18131,17 @@ "node": ">=8" } }, + "node_modules/mocha/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, "node_modules/mocha/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -15831,29 +18160,15 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/mocha/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/mocha/node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", "dev": true, - "dependencies": { - "ms": "2.1.2" - }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=0.3.1" } }, - "node_modules/mocha/node_modules/debug/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/mocha/node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -15882,6 +18197,47 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/mocha/node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mocha/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, + "engines": { + "node": ">=8" + } + }, "node_modules/mocha/node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -15937,24 +18293,21 @@ "node": ">=10" } }, + "node_modules/mocha/node_modules/minimatch/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, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/mocha/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "node_modules/mocha/node_modules/nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/mocha/node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -15985,15 +18338,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mocha/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/mocha/node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -16006,11 +18350,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mocha/node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } }, "node_modules/mocha/node_modules/yargs": { "version": "16.2.0", @@ -16064,21 +18417,24 @@ "ms": "2.0.0" } }, - "node_modules/morgan/node_modules/depd": { + "node_modules/morgan/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/morgan/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, "engines": { "node": ">= 0.8" } }, - "node_modules/morgan/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, "node_modules/mpd-parser": { "version": "0.21.1", "resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-0.21.1.tgz", @@ -16104,9 +18460,9 @@ } }, "node_modules/mrmime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.0.tgz", - "integrity": "sha512-a70zx7zFfVO7XpnQ2IX1Myh9yY4UYvfld/dikWRnsXxbyvMcfz+u6UfgNAtH+k2QqtJuzVpv6eLTx1G2+WKZbQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", + "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", "dev": true, "engines": { "node": ">=10" @@ -16120,45 +18476,12 @@ "node_modules/multipipe": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", - "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", + "integrity": "sha512-7ZxrUybYv9NonoXgwoOqtStIu18D1c3eFZj27hqgf5kBrBF8Q+tE8V0MW8dKM5QLkQPh1JhhbKgHLY9kifov4Q==", "dev": true, "dependencies": { "duplexer2": "0.0.2" } }, - "node_modules/multipipe/node_modules/duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", - "dev": true, - "dependencies": { - "readable-stream": "~1.1.9" - } - }, - "node_modules/multipipe/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "node_modules/multipipe/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/multipipe/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - }, "node_modules/mute-stdout": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", @@ -16199,11 +18522,10 @@ "optional": true }, "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", "dev": true, - "optional": true, "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -16233,6 +18555,28 @@ "node": ">=0.10.0" } }, + "node_modules/nanomatch/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/nanomatch/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/nanomatch/node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -16245,13 +18589,13 @@ "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, "node_modules/ncp": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/ncp/-/ncp-0.4.2.tgz", - "integrity": "sha1-q8xsvT7C7Spyn/bnwfqPAXhKhXQ=", + "integrity": "sha512-PfGU8jYWdRl4FqJfCy0IzbkGyFHntfWygZg46nFk/dJD/XRrk2cj0SsKSX9n5u5gE0E0YfEpKWrEkfjnlZSTXA==", "dev": true, "bin": { "ncp": "bin/ncp" @@ -16309,7 +18653,7 @@ "node_modules/nise/node_modules/isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", "dev": true }, "node_modules/nise/node_modules/lolex": { @@ -16358,7 +18702,7 @@ "node_modules/nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", "dev": true, "dependencies": { "abbrev": "1" @@ -16368,24 +18712,33 @@ } }, "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", "dev": true, "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" } }, "node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, "bin": { - "semver": "bin/semver" + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/normalize-path": { @@ -16424,7 +18777,7 @@ "node_modules/npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", "dev": true, "dependencies": { "path-key": "^2.0.0" @@ -16436,7 +18789,7 @@ "node_modules/npm-run-path/node_modules/path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", "dev": true, "engines": { "node": ">=4" @@ -16445,7 +18798,7 @@ "node_modules/number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -16463,7 +18816,7 @@ "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -16472,7 +18825,7 @@ "node_modules/object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", "dev": true, "dependencies": { "copy-descriptor": "^0.1.0", @@ -16486,7 +18839,7 @@ "node_modules/object-copy/node_modules/define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "dependencies": { "is-descriptor": "^0.1.0" @@ -16498,7 +18851,7 @@ "node_modules/object-copy/node_modules/is-accessor-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", "dev": true, "dependencies": { "kind-of": "^3.0.2" @@ -16516,7 +18869,7 @@ "node_modules/object-copy/node_modules/is-data-descriptor": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", "dev": true, "dependencies": { "kind-of": "^3.0.2" @@ -16551,7 +18904,7 @@ "node_modules/object-copy/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -16561,10 +18914,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", - "dev": true, + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -16589,6 +18941,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, "engines": { "node": ">= 0.4" } @@ -16596,7 +18949,7 @@ "node_modules/object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", "dev": true, "dependencies": { "isobject": "^3.0.0" @@ -16606,13 +18959,14 @@ } }, "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", "object-keys": "^1.1.1" }, "engines": { @@ -16625,7 +18979,7 @@ "node_modules/object.defaults": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", - "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", + "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==", "dev": true, "dependencies": { "array-each": "^1.0.1", @@ -16640,7 +18994,7 @@ "node_modules/object.map": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", - "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", + "integrity": "sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==", "dev": true, "dependencies": { "for-own": "^1.0.0", @@ -16653,7 +19007,7 @@ "node_modules/object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", "dev": true, "dependencies": { "isobject": "^3.0.1" @@ -16665,7 +19019,7 @@ "node_modules/object.reduce": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", - "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=", + "integrity": "sha512-naLhxxpUESbNkRqc35oQ2scZSJueHGQNUfMW/0U37IgN6tE2dgDWg3whf+NEliy3F/QysrO48XKUz/nGPe+AQw==", "dev": true, "dependencies": { "for-own": "^1.0.0", @@ -16693,9 +19047,9 @@ } }, "node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dependencies": { "ee-first": "1.1.1" }, @@ -16715,7 +19069,7 @@ "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, "dependencies": { "wrappy": "1" @@ -16760,7 +19114,7 @@ "node_modules/opn/node_modules/is-wsl": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", "dev": true, "engines": { "node": ">=4" @@ -16855,6 +19209,15 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/ora/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, + "engines": { + "node": ">=8" + } + }, "node_modules/ora/node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -16886,7 +19249,7 @@ "node_modules/ordered-read-streams": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", - "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", + "integrity": "sha512-Z87aSjx3r5c0ZB7bcJqIgIRX5bxR7A4aSzvIbaxd0oTkWBCOoKfuGHiKj60CHVUgg1Phm5yMZzBdt8XqRs73Mw==", "dev": true, "dependencies": { "readable-stream": "^2.0.1" @@ -16895,7 +19258,7 @@ "node_modules/os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -16904,7 +19267,7 @@ "node_modules/os-locale": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "integrity": "sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==", "dev": true, "dependencies": { "lcid": "^1.0.0" @@ -16916,7 +19279,7 @@ "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "dev": true, "engines": { "node": ">=0.10.0" @@ -16934,7 +19297,7 @@ "node_modules/p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", "dev": true, "engines": { "node": ">=4" @@ -16950,36 +19313,39 @@ } }, "node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "dependencies": { - "p-try": "^1.0.0" + "p-try": "^2.0.0" }, "engines": { - "node": ">=4" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "dependencies": { - "p-limit": "^1.1.0" + "p-limit": "^2.2.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/parent-module": { @@ -16997,7 +19363,7 @@ "node_modules/parse-filepath": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", - "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", + "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==", "dev": true, "dependencies": { "is-absolute": "^1.0.0", @@ -17047,31 +19413,28 @@ "node_modules/parse-passwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/parse-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-5.0.0.tgz", - "integrity": "sha512-qOpH55/+ZJ4jUu/oLO+ifUKjFPNZGfnPJtzvGzKN/4oLMil5m9OH4VpOj6++9/ytJcfks4kzH2hhi87GL/OU9A==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-7.0.0.tgz", + "integrity": "sha512-Euf9GG8WT9CdqwuWJGdf3RkUcTBArppHABkO7Lm8IzRQp0e2r/kkFnmhu4TSK30Wcu5rVAZLmfPKSBBi9tWFog==", "dev": true, "dependencies": { "protocols": "^2.0.0" } }, "node_modules/parse-url": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-7.0.2.tgz", - "integrity": "sha512-PqO4Z0eCiQ08Wj6QQmrmp5YTTxpYfONdOEamrtvK63AmzXpcavIVQubGHxOEwiIoDZFb8uDOoQFS0NCcjqIYQg==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-8.1.0.tgz", + "integrity": "sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w==", "dev": true, "dependencies": { - "is-ssh": "^1.4.0", - "normalize-url": "^6.1.0", - "parse-path": "^5.0.0", - "protocols": "^2.0.1" + "parse-path": "^7.0.0" } }, "node_modules/parseurl": { @@ -17085,7 +19448,7 @@ "node_modules/pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -17094,22 +19457,22 @@ "node_modules/path-dirname": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==", "dev": true }, "node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -17132,7 +19495,7 @@ "node_modules/path-root": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", - "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==", "dev": true, "dependencies": { "path-root-regex": "^0.1.0" @@ -17144,7 +19507,7 @@ "node_modules/path-root-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", - "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", + "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -17153,7 +19516,7 @@ "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, "node_modules/path-type": { "version": "1.1.0", @@ -17190,7 +19553,7 @@ "node_modules/pause-stream": { "version": "0.0.11", "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", + "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", "dev": true, "dependencies": { "through": "~2.3" @@ -17199,13 +19562,13 @@ "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", "dev": true }, "node_modules/performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", "dev": true }, "node_modules/picocolors": { @@ -17240,7 +19603,7 @@ "node_modules/pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -17249,7 +19612,7 @@ "node_modules/pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", "dev": true, "dependencies": { "pinkie": "^2.0.0" @@ -17282,98 +19645,17 @@ "node": ">=8" } }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-dir/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/plugin-error": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", - "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", - "dev": true, - "dependencies": { - "ansi-colors": "^1.0.1", - "arr-diff": "^4.0.0", - "arr-union": "^3.1.0", - "extend-shallow": "^3.0.2" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/plugin-error/node_modules/ansi-colors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", - "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", + "integrity": "sha512-WzZHcm4+GO34sjFMxQMqZbsz3xiNEgonCskQ9v+IroMmYgk/tas8dG+Hr2D6IbRPybZ12oWpzE/w3cGJ6FJzOw==", "dev": true, "dependencies": { - "ansi-wrap": "^0.1.0" + "ansi-cyan": "^0.1.1", + "ansi-red": "^0.1.1", + "arr-diff": "^1.0.1", + "arr-union": "^2.0.1", + "extend-shallow": "^1.1.2" }, "engines": { "node": ">=0.10.0" @@ -17382,16 +19664,16 @@ "node_modules/posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/postcss": { - "version": "8.4.16", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz", - "integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==", + "version": "8.4.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.18.tgz", + "integrity": "sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==", "dev": true, "funding": [ { @@ -17413,6 +19695,19 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss/node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true, + "optional": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -17423,35 +19718,57 @@ } }, "node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", "react-is": "^17.0.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 10" } }, "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/pretty-format/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/pretty-format/node_modules/color-name": { + "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 + }, "node_modules/pretty-hrtime": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", - "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", + "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==", "dev": true, "engines": { "node": ">= 0.8" @@ -17472,18 +19789,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/printj": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/printj/-/printj-1.3.1.tgz", - "integrity": "sha512-GA3TdL8szPK4AQ2YnOe/b+Y1jUFwmmGMMK/qbY7VcE3Z7FU8JstbKiKRzO6CIiAKPhTO8m01NoQ0V5f3jc4OGg==", - "dev": true, - "bin": { - "printj": "bin/printj.njs" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", @@ -17554,7 +19859,7 @@ "node_modules/prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", "dev": true }, "node_modules/ps-tree": { @@ -17575,13 +19880,13 @@ "node_modules/pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", "dev": true }, "node_modules/psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", "dev": true }, "node_modules/pump": { @@ -17637,16 +19942,16 @@ } }, "node_modules/puppeteer-core": { - "version": "13.5.1", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-13.5.1.tgz", - "integrity": "sha512-dobVqWjV34ilyfQHR3BBnCYaekBYTi5MgegEYBRYd3s3uFy8jUpZEEWbaFjG9ETm+LGzR5Lmr0aF6LLuHtiuCg==", + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-13.7.0.tgz", + "integrity": "sha512-rXja4vcnAzFAP1OVLq/5dWNfwBGuzcOARJ6qGV7oAZhnLmVRU8G5MsdeQEAOy332ZhkIOnn9jp15R89LKHyp2Q==", "dev": true, "dependencies": { "cross-fetch": "3.1.5", - "debug": "4.3.3", - "devtools-protocol": "0.0.969999", + "debug": "4.3.4", + "devtools-protocol": "0.0.981744", "extract-zip": "2.0.1", - "https-proxy-agent": "5.0.0", + "https-proxy-agent": "5.0.1", "pkg-dir": "4.2.0", "progress": "2.0.3", "proxy-from-env": "1.1.0", @@ -17659,37 +19964,12 @@ "node": ">=10.18.1" } }, - "node_modules/puppeteer-core/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, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, "node_modules/puppeteer-core/node_modules/devtools-protocol": { - "version": "0.0.969999", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.969999.tgz", - "integrity": "sha512-6GfzuDWU0OFAuOvBokXpXPLxjOJ5DZ157Ue3sGQQM3LgAamb8m0R0ruSfN0DDu+XG5XJgT50i6zZ/0o8RglreQ==", + "version": "0.0.981744", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.981744.tgz", + "integrity": "sha512-0cuGS8+jhR67Fy7qG3i3Pc7Aw494sb9yG9QgpG97SFVWwolgYjlhJg7n+UaHxOQT30d1TYu/EYe9k01ivLErIg==", "dev": true }, - "node_modules/puppeteer-core/node_modules/https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/puppeteer-core/node_modules/ws": { "version": "8.5.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", @@ -17714,7 +19994,7 @@ "node_modules/q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", "dev": true, "engines": { "node": ">=0.6.0", @@ -17731,9 +20011,12 @@ } }, "node_modules/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, "engines": { "node": ">=0.6" }, @@ -17750,7 +20033,7 @@ "node_modules/querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", "dev": true, "engines": { @@ -17793,12 +20076,12 @@ } }, "node_modules/raw-body": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", - "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", "dependencies": { "bytes": "3.1.2", - "http-errors": "1.8.1", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, @@ -17941,48 +20224,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/read-pkg/node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/read-pkg/node_modules/normalize-package-data": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/read-pkg/node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/read-pkg/node_modules/type-fest": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", @@ -18013,16 +20254,43 @@ "node_modules/readable-stream/node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, "node_modules/readdir-glob": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.1.tgz", - "integrity": "sha512-91/k1EzZwDx6HbERR+zucygRFfiPl2zkIYZtv3Jjr6Mn7SkKcVct8aVO+sSRiGMc6fLf72du3d92/uY63YPdEA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.2.tgz", + "integrity": "sha512-6RLVvwJtVwEDfPdn6X6Ille4/lxGl0ATOY4FN/B9nxQcgOazvvI0nodiD19ScKq0PvA/29VpaOQML36o5IzZWA==", "dev": true, "dependencies": { - "minimatch": "^3.0.4" + "minimatch": "^5.1.0" + } + }, + "node_modules/readdir-glob/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, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/readdir-glob/node_modules/minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" } }, "node_modules/readdirp": { @@ -18040,7 +20308,7 @@ "node_modules/rechoir": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", "dev": true, "dependencies": { "resolve": "^1.1.6" @@ -18050,27 +20318,15 @@ } }, "node_modules/recursive-readdir": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", - "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", "dev": true, "dependencies": { - "minimatch": "3.0.4" + "minimatch": "^3.0.5" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/recursive-readdir/node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" + "node": ">=6.0.0" } }, "node_modules/regenerate": { @@ -18079,9 +20335,9 @@ "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" }, "node_modules/regenerate-unicode-properties": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", - "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", + "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", "dependencies": { "regenerate": "^1.4.2" }, @@ -18090,15 +20346,14 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true + "version": "0.13.10", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz", + "integrity": "sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==" }, "node_modules/regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", + "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", "dependencies": { "@babel/runtime": "^7.8.4" } @@ -18116,14 +20371,28 @@ "node": ">=0.10.0" } }, + "node_modules/regex-not/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/regexp.prototype.flags": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz", - "integrity": "sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" }, "engines": { "node": ">= 0.4" @@ -18145,14 +20414,14 @@ } }, "node_modules/regexpu-core": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", - "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.1.tgz", + "integrity": "sha512-HrnlNtpvqP1Xkb28tMhBUO2EbyUHdQlsnlAhzWcwHy8WJR53UWr7/MAvqrsQKMbV4qdpv03oTMG8iIhfsPFktQ==", "dependencies": { "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.0.1", - "regjsgen": "^0.6.0", - "regjsparser": "^0.8.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsgen": "^0.7.1", + "regjsparser": "^0.9.1", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.0.0" }, @@ -18161,14 +20430,14 @@ } }, "node_modules/regjsgen": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", - "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==" + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", + "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==" }, "node_modules/regjsparser": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", - "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", "dependencies": { "jsesc": "~0.5.0" }, @@ -18179,7 +20448,7 @@ "node_modules/regjsparser/node_modules/jsesc": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", "bin": { "jsesc": "bin/jsesc" } @@ -18315,7 +20584,7 @@ "node_modules/remove-bom-stream": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", - "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=", + "integrity": "sha512-wigO8/O08XHb8YPzpDDT+QmRANfW6vLqxfaXm1YXhnFf3AkSLyjfG3GEFg4McZkmgL7KvCj5u2KczkvSP6NfHA==", "dev": true, "dependencies": { "remove-bom-buffer": "^3.0.0", @@ -18339,7 +20608,7 @@ "node_modules/remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", "dev": true }, "node_modules/repeat-element": { @@ -18354,7 +20623,7 @@ "node_modules/repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", "dev": true, "engines": { "node": ">=0.10" @@ -18363,7 +20632,7 @@ "node_modules/repeating": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "integrity": "sha512-ZqtSMuVybkISo2OWvqvm7iHSWngvdaW3IpsT9/uP8v4gMi591LY6h35wdOfvQdWCKFWZWm2Y1Opp4kV7vQKT6A==", "dev": true, "dependencies": { "is-finite": "^1.0.0" @@ -18375,7 +20644,7 @@ "node_modules/replace-ext": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", + "integrity": "sha512-AFBWBy9EVRTa/LhEcG8QDP3FvpwZqmvN2QFDuJswFeaVhWnZMp8q3E6Zd90SR04PlIwfGdyVjNyLPyen/ek5CQ==", "dev": true, "engines": { "node": ">= 0.4" @@ -18384,7 +20653,7 @@ "node_modules/replace-homedir": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", - "integrity": "sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=", + "integrity": "sha512-CHPV/GAglbIB1tnQgaiysb8H2yCy8WQ7lcEwQ/eT+kLj0QHV8LnJW0zpqpE7RSkrMSRoa+EBoag86clf7WAgSg==", "dev": true, "dependencies": { "homedir-polyfill": "^1.0.1", @@ -18450,7 +20719,7 @@ "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, "engines": { "node": ">=0.10.0" @@ -18465,10 +20734,16 @@ "node": ">=0.10.0" } }, + "node_modules/require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==", + "dev": true + }, "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true }, "node_modules/resolve": { @@ -18496,7 +20771,7 @@ "node_modules/resolve-dir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", "dev": true, "dependencies": { "expand-tilde": "^2.0.0", @@ -18518,7 +20793,7 @@ "node_modules/resolve-options": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", - "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=", + "integrity": "sha512-NYDgziiroVeDC29xq7bp/CacZERYsA9bXYd1ZmcJlF3BcrZv5pTb4NG7SjdyKDnXZ84aC4vo2u6sNKIA1LCu/A==", "dev": true, "dependencies": { "value-or-function": "^3.0.0" @@ -18530,17 +20805,20 @@ "node_modules/resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", "deprecated": "https://github.com/lydell/resolve-url#deprecated", "dev": true }, "node_modules/responselike": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", - "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", "dev": true, "dependencies": { "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/resq": { @@ -18555,7 +20833,7 @@ "node_modules/resq/node_modules/fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "integrity": "sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==", "dev": true }, "node_modules/restore-cursor": { @@ -18626,20 +20904,17 @@ } }, "node_modules/rxjs": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", - "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", "dev": true, "dependencies": { - "tslib": "^2.1.0" + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" } }, - "node_modules/rxjs/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - }, "node_modules/sade": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", @@ -18653,25 +20928,53 @@ } }, "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, "node_modules/safe-json-parse": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz", - "integrity": "sha1-PnZyPjjf3aE8mx0poeB//uSzC1c=", + "integrity": "sha512-o0JmTu17WGUaUOHa1l0FPGXKBfijbxK6qoHzlkihsDXxzBHvJcA7zgviKR92Xs841rX9pK16unfphLq0/KqX7A==", "dev": true }, "node_modules/safe-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", "dev": true, "dependencies": { "ret": "~0.1.10" } }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -18718,15 +21021,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/schema-utils/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, "node_modules/semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -18738,7 +21032,7 @@ "node_modules/semver-greatest-satisfied-range": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", - "integrity": "sha1-E+jCZYq5aRywzXEJMkAoDTb3els=", + "integrity": "sha512-Ny/iyOzSSa8M5ML46IAx3iXc6tfOsYU2R4AXi2UpHk60Zrgyq6eqPj/xiOfS0rRl/iiQ/rdJkVjw/5cdUyCntQ==", "dev": true, "dependencies": { "sver-compat": "^1.5.0" @@ -18748,23 +21042,23 @@ } }, "node_modules/send": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", - "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "dependencies": { "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", + "depd": "2.0.0", + "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "1.8.1", + "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "range-parser": "~1.2.1", - "statuses": "~1.5.0" + "statuses": "2.0.1" }, "engines": { "node": ">= 0.8.0" @@ -18781,7 +21075,7 @@ "node_modules/send/node_modules/debug/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/send/node_modules/mime": { "version": "1.6.0", @@ -18838,7 +21132,7 @@ "node_modules/serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", "dev": true, "dependencies": { "accepts": "~1.3.4", @@ -18862,10 +21156,19 @@ "ms": "2.0.0" } }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/serve-index/node_modules/http-errors": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", "dev": true, "dependencies": { "depd": "~1.1.2", @@ -18880,13 +21183,13 @@ "node_modules/serve-index/node_modules/inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", "dev": true }, "node_modules/serve-index/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "node_modules/serve-index/node_modules/setprototypeof": { @@ -18895,15 +21198,24 @@ "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", "dev": true }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/serve-static": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", - "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.2" + "send": "0.18.0" }, "engines": { "node": ">= 0.8.0" @@ -18912,7 +21224,7 @@ "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "dev": true }, "node_modules/set-value": { @@ -18933,7 +21245,7 @@ "node_modules/set-value/node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "dependencies": { "is-extendable": "^0.1.0" @@ -18945,7 +21257,7 @@ "node_modules/set-value/node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -18966,7 +21278,7 @@ "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", "dev": true }, "node_modules/setprototypeof": { @@ -18999,7 +21311,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, "dependencies": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -19040,27 +21351,6 @@ "node": ">=0.3.1" } }, - "node_modules/sinon/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/sinon/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/sirv": { "version": "1.0.19", "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz", @@ -19076,12 +21366,12 @@ } }, "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg==", "dev": true, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, "node_modules/slice-ansi": { @@ -19170,7 +21460,7 @@ "node_modules/snapdragon-node/node_modules/define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, "dependencies": { "is-descriptor": "^1.0.0" @@ -19200,7 +21490,7 @@ "node_modules/snapdragon-util/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -19221,7 +21511,7 @@ "node_modules/snapdragon/node_modules/define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "dependencies": { "is-descriptor": "^0.1.0" @@ -19233,7 +21523,7 @@ "node_modules/snapdragon/node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "dependencies": { "is-extendable": "^0.1.0" @@ -19245,7 +21535,7 @@ "node_modules/snapdragon/node_modules/is-accessor-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", "dev": true, "dependencies": { "kind-of": "^3.0.2" @@ -19257,7 +21547,7 @@ "node_modules/snapdragon/node_modules/is-accessor-descriptor/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -19275,7 +21565,7 @@ "node_modules/snapdragon/node_modules/is-data-descriptor": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", "dev": true, "dependencies": { "kind-of": "^3.0.2" @@ -19287,7 +21577,7 @@ "node_modules/snapdragon/node_modules/is-data-descriptor/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -19313,7 +21603,7 @@ "node_modules/snapdragon/node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -19322,7 +21612,7 @@ "node_modules/snapdragon/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "node_modules/snapdragon/node_modules/source-map-resolve": { @@ -19340,36 +21630,35 @@ } }, "node_modules/socket.io": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.4.1.tgz", - "integrity": "sha512-s04vrBswdQBUmuWJuuNTmXUVJhP0cVky8bBDhdkf8y0Ptsu7fKU2LuLbts9g+pdmAdyMMn8F/9Mf1/wbtUN0fg==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.3.tgz", + "integrity": "sha512-zdpnnKU+H6mOp7nYRXH4GNv1ux6HL6+lHL8g7Ds7Lj8CkdK1jJK/dlwsKDculbyOHifcJ0Pr/yeXnZQ5GeFrcg==", "dev": true, "dependencies": { "accepts": "~1.3.4", "base64id": "~2.0.0", "debug": "~4.3.2", - "engine.io": "~6.1.0", - "socket.io-adapter": "~2.3.3", - "socket.io-parser": "~4.0.4" + "engine.io": "~6.2.0", + "socket.io-adapter": "~2.4.0", + "socket.io-parser": "~4.2.0" }, "engines": { "node": ">=10.0.0" } }, "node_modules/socket.io-adapter": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.3.3.tgz", - "integrity": "sha512-Qd/iwn3VskrpNO60BeRyCyr8ZWw9CPZyitW4AQwmRZ8zCiyDiL+znRnWX6tDHXnWn1sJrM1+b6Mn6wEDJJ4aYQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz", + "integrity": "sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg==", "dev": true }, "node_modules/socket.io-parser": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.4.tgz", - "integrity": "sha512-t+b0SS+IxG7Rxzda2EVvyBZbvFPBCjJoyHuE0P//7OAsN23GItzDRdWa6ALxZI/8R5ygK7jAR6t028/z+7295g==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz", + "integrity": "sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==", "dev": true, "dependencies": { - "@types/component-emitter": "^1.2.10", - "component-emitter": "~1.3.0", + "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" }, "engines": { @@ -19385,7 +21674,7 @@ "node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -19413,22 +21702,12 @@ } }, "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", "dev": true, "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" + "source-map": "^0.5.6" } }, "node_modules/source-map-url": { @@ -19491,15 +21770,15 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", - "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==", + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", + "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", "dev": true }, "node_modules/split": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", - "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", + "integrity": "sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==", "dev": true, "dependencies": { "through": "2" @@ -19520,19 +21799,46 @@ "node": ">=0.10.0" } }, + "node_modules/split-string/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/split2": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", - "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "dev": true, + "dependencies": { + "readable-stream": "^3.0.0" + } + }, + "node_modules/split2/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, "engines": { - "node": ">= 10.x" + "node": ">= 6" } }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, "node_modules/sshpk": { @@ -19563,7 +21869,7 @@ "node_modules/stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", "dev": true, "engines": { "node": "*" @@ -19593,7 +21899,7 @@ "node_modules/static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", "dev": true, "dependencies": { "define-property": "^0.2.5", @@ -19606,7 +21912,7 @@ "node_modules/static-extend/node_modules/define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "dependencies": { "is-descriptor": "^0.1.0" @@ -19618,7 +21924,7 @@ "node_modules/static-extend/node_modules/is-accessor-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", "dev": true, "dependencies": { "kind-of": "^3.0.2" @@ -19630,7 +21936,7 @@ "node_modules/static-extend/node_modules/is-accessor-descriptor/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -19648,7 +21954,7 @@ "node_modules/static-extend/node_modules/is-data-descriptor": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", "dev": true, "dependencies": { "kind-of": "^3.0.2" @@ -19660,7 +21966,7 @@ "node_modules/static-extend/node_modules/is-data-descriptor/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -19684,11 +21990,11 @@ } }, "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/stream-buffers": { @@ -19703,7 +22009,7 @@ "node_modules/stream-combiner": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", - "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", + "integrity": "sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==", "dev": true, "dependencies": { "duplexer": "~0.1.1" @@ -19722,19 +22028,51 @@ "dev": true }, "node_modules/streamroller": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.0.4.tgz", - "integrity": "sha512-GI9NzeD+D88UFuIlJkKNDH/IsuR+qIN7Qh8EsmhoRZr9bQoehTraRgwtLUkZbpcAw+hLPfHOypmppz8YyGK68w==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.3.tgz", + "integrity": "sha512-CphIJyFx2SALGHeINanjFRKQ4l7x2c+rXYJ4BMq0gd+ZK0gi4VT8b+eHe2wi58x4UayBAKx4xtHpXT/ea1cz8w==", "dev": true, "dependencies": { - "date-format": "^4.0.4", - "debug": "^4.3.3", - "fs-extra": "^10.0.1" + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" }, "engines": { "node": ">=8.0" } }, + "node_modules/streamroller/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/streamroller/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/streamroller/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -19744,10 +22082,16 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, "node_modules/string-template": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", - "integrity": "sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=", + "integrity": "sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw==", "dev": true }, "node_modules/string-width": { @@ -19764,33 +22108,29 @@ "node": ">=8" } }, - "node_modules/string-width/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, "node_modules/string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", + "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", + "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -19825,7 +22165,7 @@ "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, "engines": { "node": ">=4" @@ -19834,7 +22174,7 @@ "node_modules/strip-bom-string": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", - "integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", "dev": true, "engines": { "node": ">=0.10.0" @@ -19843,34 +22183,42 @@ "node_modules/strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", "dev": true, "engines": { "node": ">=0.10.0" } }, + "node_modules/strip-json-comments": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.0.tgz", + "integrity": "sha512-V1LGY4UUo0jgwC+ELQ2BNWfPa17TIuwBLg+j1AA/9RPzKINl1lhxVEu2r+ZTTO8aetIsUzE5Qj6LMSBkoGYKKw==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/suffix": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/suffix/-/suffix-0.1.1.tgz", - "integrity": "sha1-zFgjFkag7xEC95R47zqSSP2chC8=", + "integrity": "sha512-j5uf6MJtMCfC4vBe5LFktSe4bGyNTBk7I2Kdri0jeLrcv5B9pWfxVa5JQpoxgtR8vaVB7bVxsWgnfQbX5wkhAA==", "dev": true, "engines": { "node": ">=4" } }, "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dependencies": { - "has-flag": "^4.0.0" + "has-flag": "^3.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "node": ">=4" } }, "node_modules/supports-preserve-symlinks-flag": { @@ -19887,7 +22235,7 @@ "node_modules/sver-compat": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", - "integrity": "sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=", + "integrity": "sha512-aFTHfmjwizMNlNE6dsGmoAM4lHjL0CyiobWaFiXWSlD7cIxshW422Nb8KbXCmR6z+0ZEPY+daXJrDyh/vuwTyg==", "dev": true, "dependencies": { "es6-iterator": "^2.0.1", @@ -19911,9 +22259,9 @@ } }, "node_modules/table/node_modules/ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", @@ -19986,7 +22334,7 @@ "node_modules/temp-fs": { "version": "0.9.9", "resolved": "https://registry.npmjs.org/temp-fs/-/temp-fs-0.9.9.tgz", - "integrity": "sha1-gHFzBDeHByDpQxUy/igUNk+IA9c=", + "integrity": "sha512-WfecDCR1xC9b0nsrzSaxPf3ZuWeWLUWblW4vlDQAa1biQaKHiImHnJfeQocQe/hXKMcolRzgkcVX/7kK4zoWbw==", "dev": true, "dependencies": { "rimraf": "~2.5.2" @@ -19998,7 +22346,7 @@ "node_modules/temp-fs/node_modules/rimraf": { "version": "2.5.4", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz", - "integrity": "sha1-loAAk8vxoMhr2VtGJUZ1NcKd+gQ=", + "integrity": "sha512-Lw7SHMjssciQb/rRz7JyPIy9+bbUshEucPoLRvWqy09vC5zQixl8Uet+Zl+SROBB/JMWHJRdCk1qdxNWHNMvlQ==", "dev": true, "dependencies": { "glob": "^7.0.5" @@ -20030,9 +22378,9 @@ } }, "node_modules/terser": { - "version": "5.14.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", - "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", + "version": "5.15.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", + "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.2", @@ -20048,16 +22396,16 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz", - "integrity": "sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g==", + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", + "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", "dev": true, "dependencies": { + "@jridgewell/trace-mapping": "^0.3.14", "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1", - "terser": "^5.7.2" + "terser": "^5.14.1" }, "engines": { "node": ">= 10.13.0" @@ -20097,15 +22445,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, "node_modules/terser-webpack-plugin/node_modules/schema-utils": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", @@ -20124,7 +22463,19 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/terser-webpack-plugin/node_modules/source-map": { + "node_modules/terser/node_modules/acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/terser/node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", @@ -20133,24 +22484,16 @@ "node": ">=0.10.0" } }, - "node_modules/terser/node_modules/acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "node_modules/terser/node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" } }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -20168,7 +22511,7 @@ "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, "node_modules/textextensions": { @@ -20186,7 +22529,7 @@ "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "dev": true }, "node_modules/through2": { @@ -20235,7 +22578,7 @@ "node_modules/time-stamp": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", - "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", + "integrity": "sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -20280,21 +22623,21 @@ } }, "node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "dependencies": { - "rimraf": "^3.0.0" + "os-tmpdir": "~1.0.2" }, "engines": { - "node": ">=8.17.0" + "node": ">=0.6.0" } }, "node_modules/to-absolute-glob": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", - "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", + "integrity": "sha512-rtwLUQEwT8ZeKQbyFJyomBRYXyE16U5VKuy0ftxLMK/PZb2fkOsg5r9kHdauuVDbsNdIBoC/HCthpidamQFXYA==", "dev": true, "dependencies": { "is-absolute": "^1.0.0", @@ -20307,7 +22650,7 @@ "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "engines": { "node": ">=4" } @@ -20315,7 +22658,7 @@ "node_modules/to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", "dev": true, "dependencies": { "kind-of": "^3.0.2" @@ -20333,7 +22676,7 @@ "node_modules/to-object-path/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -20369,19 +22712,23 @@ "node": ">=8.0" } }, - "node_modules/to-regex-range/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/to-regex/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.12.0" + "node": ">=0.10.0" } }, "node_modules/to-through": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", - "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=", + "integrity": "sha512-+QIz37Ly7acM4EMdw2PRN389OneM5+d844tirkGp4dPKzI5OE72V9OsbFp+CIYJDahZ41ZV05hNtcPAQUAm9/Q==", "dev": true, "dependencies": { "through2": "^2.0.3" @@ -20433,13 +22780,13 @@ "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "dev": true }, "node_modules/traverse": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", - "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=", + "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", "dev": true, "engines": { "node": "*" @@ -20458,7 +22805,7 @@ "node_modules/trim-right": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "integrity": "sha512-WZGXGstmCWgeevgTL54hrCuw1dyMQIzWy7ZfqRJfSmJZBwklI15egmQytFP6bPidmw3M8d5yEowl1niq4vmqZw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -20475,14 +22822,14 @@ } }, "node_modules/tsconfig-paths": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.13.0.tgz", - "integrity": "sha512-nWuffZppoaYK0vQ1SQmkSsQzJoHA4s6uzdb2waRpD806x9yfq153AdVsWz4je2qZcW+pENrMQXbGQ3sMCkXuhw==", + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", "dev": true, "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.1", - "minimist": "^1.2.0", + "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, @@ -20507,7 +22854,7 @@ "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, "dependencies": { "safe-buffer": "^5.0.1" @@ -20519,7 +22866,7 @@ "node_modules/tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", "dev": true }, "node_modules/type": { @@ -20576,7 +22923,7 @@ "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", "dev": true }, "node_modules/typescript": { @@ -20615,9 +22962,9 @@ } }, "node_modules/ua-parser-js": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz", - "integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==", + "version": "0.7.33", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.33.tgz", + "integrity": "sha512-s8ax/CeZdK9R/56Sui0WM6y9OFREJarMRHqLB2EwkovemBxNQ+Bqu8GAsUnVcXKgphb++ghr/B2BZx4mahujPw==", "dev": true, "funding": [ { @@ -20634,9 +22981,9 @@ } }, "node_modules/uglify-js": { - "version": "3.15.2", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.2.tgz", - "integrity": "sha512-peeoTk3hSwYdoc9nrdiEJk+gx1ALCtTjdYuKSXMTDqq7n1W7dHPqWDdSi+BPL0ni2YMeHD7hKUSdbj3TZauY2A==", + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", "dev": true, "optional": true, "bin": { @@ -20647,14 +22994,14 @@ } }, "node_modules/unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", "which-boxed-primitive": "^1.0.2" }, "funding": { @@ -20674,7 +23021,7 @@ "node_modules/unc-path-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", - "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", + "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -20704,7 +23051,7 @@ "node_modules/undertaker-registry": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", - "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=", + "integrity": "sha512-UR1khWeAjugW3548EfQmL9Z7pGMlBgXteQpr1IZeZBtnkCJQJIJ1Scj0mb9wQaPvUZ9Q17XqW6TIaPchJkyfqw==", "dev": true, "engines": { "node": ">= 0.10" @@ -20713,7 +23060,7 @@ "node_modules/undertaker/node_modules/fast-levenshtein": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz", - "integrity": "sha1-5qdUzI8V5YmHqpy9J69m/W9OWvk=", + "integrity": "sha512-Ia0sQNrMPXXkqVFt6w6M1n1oKo3NfKs+mvaV811Jwir7vAk9a6PVV9VPYf6X3BU97QiLEmuW3uXH9u87zDFfdw==", "dev": true }, "node_modules/unicode-canonical-property-names-ecmascript": { @@ -20745,9 +23092,9 @@ } }, "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", - "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", "engines": { "node": ">=4" } @@ -20786,10 +23133,19 @@ "node": ">=0.10.0" } }, + "node_modules/union-value/node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/union-value/node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -20905,7 +23261,7 @@ "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "engines": { "node": ">= 0.8" } @@ -20913,7 +23269,7 @@ "node_modules/unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", "dev": true, "dependencies": { "has-value": "^0.3.1", @@ -20926,7 +23282,7 @@ "node_modules/unset-value/node_modules/has-value": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", "dev": true, "dependencies": { "get-value": "^2.0.3", @@ -20940,7 +23296,7 @@ "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", "dev": true, "dependencies": { "isarray": "1.0.0" @@ -20952,7 +23308,7 @@ "node_modules/unset-value/node_modules/has-values": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -20961,7 +23317,7 @@ "node_modules/unset-value/node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true }, "node_modules/unzipper": { @@ -20981,6 +23337,15 @@ "setimmediate": "~1.0.4" } }, + "node_modules/unzipper/node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.2" + } + }, "node_modules/upath": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", @@ -20992,9 +23357,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.7.tgz", - "integrity": "sha512-iN/XYesmZ2RmmWAiI4Z5rq0YqSiv0brj9Ce9CfhNE4xIW2h+MFxcgkxIzZ+ShkFPUkjU3gQ+3oypadD3RAMtrg==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", "funding": [ { "type": "opencollective", @@ -21028,14 +23393,14 @@ "node_modules/urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", "deprecated": "Please see https://github.com/lydell/urix#deprecated", "dev": true }, "node_modules/url": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "integrity": "sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==", "dev": true, "dependencies": { "punycode": "1.3.2", @@ -21061,7 +23426,7 @@ "node_modules/url/node_modules/punycode": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==", "dev": true }, "node_modules/use": { @@ -21074,29 +23439,28 @@ } }, "node_modules/util": { - "version": "0.12.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz", - "integrity": "sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==", + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", "dev": true, "dependencies": { "inherits": "^2.0.3", "is-arguments": "^1.0.4", "is-generator-function": "^1.0.7", "is-typed-array": "^1.1.3", - "safe-buffer": "^5.1.2", "which-typed-array": "^1.1.2" } }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "engines": { "node": ">= 0.4.0" } @@ -21160,7 +23524,7 @@ "node_modules/value-or-function": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", - "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=", + "integrity": "sha512-jdBB2FrWvQC/pnPtIqcLsMaQgjhdb6B7tk1MMyTKapox+tQZbdRP4uLxu/JY0t7fbfDCUMnuelzEYv5GsxHhdg==", "dev": true, "engines": { "node": ">= 0.10" @@ -21169,7 +23533,7 @@ "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "engines": { "node": ">= 0.8" } @@ -21177,7 +23541,7 @@ "node_modules/verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", "dev": true, "engines": [ "node >=0.6.0" @@ -21191,13 +23555,13 @@ "node_modules/verror/node_modules/core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", "dev": true }, "node_modules/vfile": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.4.tgz", - "integrity": "sha512-KI+7cnst03KbEyN1+JE504zF5bJBZa+J+CrevLeyIMq0aPU681I2rQ5p4PlnQ6exFtWiUrg26QUdFMnAKR6PIw==", + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.5.tgz", + "integrity": "sha512-U1ho2ga33eZ8y8pkbQLH54uKqGhFJ6GYIHnnG5AhRpAh3OWjkrRHKa/KogbmQn8We+c0KVV3rTOgR9V/WowbXQ==", "dev": true, "dependencies": { "@types/unist": "^2.0.0", @@ -21254,6 +23618,12 @@ "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, + "node_modules/vfile-reporter/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, "node_modules/vfile-reporter/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -21325,13 +23695,13 @@ } }, "node_modules/video.js": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/video.js/-/video.js-7.20.2.tgz", - "integrity": "sha512-hdvAHKAyaL6bCDkeu0pPtFYKi1EDaOUovm7FN1xqBDolUxgH8FKy1WIgTS+Ouuaw7R54SCTcSeXjZEizhy9ouQ==", + "version": "7.20.3", + "resolved": "https://registry.npmjs.org/video.js/-/video.js-7.20.3.tgz", + "integrity": "sha512-JMspxaK74LdfWcv69XWhX4rILywz/eInOVPdKefpQiZJSMD5O8xXYueqACP2Q5yqKstycgmmEKlJzZ+kVmDciw==", "dev": true, "dependencies": { "@babel/runtime": "^7.12.5", - "@videojs/http-streaming": "2.14.2", + "@videojs/http-streaming": "2.14.3", "@videojs/vhs-utils": "^3.0.4", "@videojs/xhr": "2.6.0", "aes-decrypter": "3.1.3", @@ -21342,7 +23712,7 @@ "mux.js": "6.0.1", "safe-json-parse": "4.0.0", "videojs-font": "3.2.0", - "videojs-vtt.js": "^0.15.3" + "videojs-vtt.js": "^0.15.4" } }, "node_modules/video.js/node_modules/safe-json-parse": { @@ -21474,7 +23844,7 @@ "node_modules/vinyl-sourcemap": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", - "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=", + "integrity": "sha512-NiibMgt6VJGJmyw7vtzhctDcfKch4e4n9TBeoWlirb7FMg9/1Ov9k+A5ZRAtywBpRPiyECvQRQllYM8dECegVA==", "dev": true, "dependencies": { "append-buffer": "^1.0.2", @@ -21492,7 +23862,7 @@ "node_modules/vinyl-sourcemap/node_modules/normalize-path": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", "dev": true, "dependencies": { "remove-trailing-separator": "^1.0.1" @@ -21504,7 +23874,7 @@ "node_modules/vinyl-sourcemaps-apply": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz", - "integrity": "sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=", + "integrity": "sha512-+oDh3KYZBoZC8hfocrbrxbLUeaYtQK7J5WU5Br9VqWqmCll3tFJqKp97GC9GmMsVIL0qnx2DgEDVxdo5EZ5sSw==", "dev": true, "dependencies": { "source-map": "^0.5.1" @@ -21522,16 +23892,16 @@ "node_modules/void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/vue-template-compiler": { - "version": "2.7.10", - "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.10.tgz", - "integrity": "sha512-QO+8R9YRq1Gudm8ZMdo/lImZLJVUIAM8c07Vp84ojdDAf8HmPJc7XB556PcXV218k2AkKznsRz6xB5uOjAC4EQ==", + "version": "2.7.13", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.13.tgz", + "integrity": "sha512-jYM6TClwDS9YqP48gYrtAtaOhRKkbYmbzE+Q51gX5YDr777n7tNI/IZk4QV4l/PjQPNh/FVa/E92sh/RqKMrog==", "dev": true, "optional": true, "dependencies": { @@ -21549,9 +23919,9 @@ } }, "node_modules/watchpack": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", - "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", "dev": true, "dependencies": { "glob-to-regexp": "^0.4.1", @@ -21564,54 +23934,148 @@ "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "dev": true, "dependencies": { "defaults": "^1.0.3" } }, "node_modules/webdriver": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-7.16.16.tgz", - "integrity": "sha512-x8UoG9k/P8KDrfSh1pOyNevt9tns3zexoMxp9cKnyA/7HYSErhZYTLGlgxscAXLtQG41cMH/Ba/oBmOx7Hgd8w==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-7.5.3.tgz", + "integrity": "sha512-cDTn/hYj5x8BYwXxVb/WUwqGxrhCMP2rC8ttIWCfzmiVtmOnJGulC7CyxU3+p9Q5R/gIKTzdJOss16dhb+5CoA==", "dev": true, "dependencies": { - "@types/node": "^17.0.4", - "@wdio/config": "7.16.16", - "@wdio/logger": "7.16.0", - "@wdio/protocols": "7.16.7", - "@wdio/types": "7.16.14", - "@wdio/utils": "7.16.14", + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/protocols": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", "got": "^11.0.2", - "ky": "^0.29.0", "lodash.merge": "^4.6.1" }, "engines": { "node": ">=12.0.0" } }, + "node_modules/webdriver/node_modules/@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/webdriver/node_modules/@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "dependencies": { + "got": "^11.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/webdriver/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/webdriver/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/webdriver/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/webdriver/node_modules/color-name": { + "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 + }, + "node_modules/webdriver/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/webdriver/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/webdriverio": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.16.16.tgz", - "integrity": "sha512-caPaEWyuD3Qoa7YkW4xCCQA4v9Pa9wmhFGPvNZh3ERtjMCNi8L/XXOdkekWNZmFh3tY0kFguBj7+fAwSY7HAGw==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.25.4.tgz", + "integrity": "sha512-agkgwn2SIk5cAJ03uue1GnGZcUZUDN3W4fUMY9/VfO8bVJrPEgWg31bPguEWPu+YhEB/aBJD8ECxJ3OEKdy4qQ==", "dev": true, "dependencies": { "@types/aria-query": "^5.0.0", - "@types/node": "^17.0.4", - "@wdio/config": "7.16.16", - "@wdio/logger": "7.16.0", - "@wdio/protocols": "7.16.7", - "@wdio/repl": "7.16.14", - "@wdio/types": "7.16.14", - "@wdio/utils": "7.16.14", + "@types/node": "^18.0.0", + "@wdio/config": "7.25.4", + "@wdio/logger": "7.19.0", + "@wdio/protocols": "7.22.0", + "@wdio/repl": "7.25.4", + "@wdio/types": "7.25.4", + "@wdio/utils": "7.25.4", "archiver": "^5.0.0", "aria-query": "^5.0.0", "css-shorthand-properties": "^1.1.1", "css-value": "^0.0.1", - "devtools": "7.16.16", - "devtools-protocol": "^0.0.973690", + "devtools": "7.25.4", + "devtools-protocol": "^0.0.1061995", "fs-extra": "^10.0.0", - "get-port": "^5.1.1", "grapheme-splitter": "^1.0.2", "lodash.clonedeep": "^4.5.0", "lodash.isobject": "^3.0.2", @@ -21623,12 +24087,120 @@ "resq": "^1.9.1", "rgb2hex": "0.2.5", "serialize-error": "^8.0.0", - "webdriver": "7.16.16" + "webdriver": "7.25.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/webdriverio/node_modules/@types/node": { + "version": "18.11.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", + "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", + "dev": true + }, + "node_modules/webdriverio/node_modules/@wdio/config": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-7.25.4.tgz", + "integrity": "sha512-vb0emDtD9FbFh/yqW6oNdo2iuhQp8XKj6GX9fyy9v4wZgg3B0HPMVJxhIfcoHz7LMBWlHSo9YdvhFI5EQHRLBA==", + "dev": true, + "dependencies": { + "@wdio/logger": "7.19.0", + "@wdio/types": "7.25.4", + "@wdio/utils": "7.25.4", + "deepmerge": "^4.0.0", + "glob": "^8.0.3" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/webdriverio/node_modules/@wdio/logger": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.19.0.tgz", + "integrity": "sha512-xR7SN/kGei1QJD1aagzxs3KMuzNxdT/7LYYx+lt6BII49+fqL/SO+5X0FDCZD0Ds93AuQvvz9eGyzrBI2FFXmQ==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/webdriverio/node_modules/@wdio/protocols": { + "version": "7.22.0", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-7.22.0.tgz", + "integrity": "sha512-8EXRR+Ymdwousm/VGtW3H1hwxZ/1g1H99A1lF0U4GuJ5cFWHCd0IVE5H31Z52i8ZruouW8jueMkGZPSo2IIUSQ==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/webdriverio/node_modules/@wdio/repl": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-7.25.4.tgz", + "integrity": "sha512-kYhj9gLsUk4HmlXLqkVre+gwbfvw9CcnrHjqIjrmMS4mR9D8zvBb5CItb3ZExfPf9jpFzIFREbCAYoE9x/kMwg==", + "dev": true, + "dependencies": { + "@wdio/utils": "7.25.4" }, "engines": { "node": ">=12.0.0" } }, + "node_modules/webdriverio/node_modules/@wdio/types": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.25.4.tgz", + "integrity": "sha512-muvNmq48QZCvocctnbe0URq2FjJjUPIG4iLoeMmyF0AQgdbjaUkMkw3BHYNHVTbSOU9WMsr2z8alhj/I2H6NRQ==", + "dev": true, + "dependencies": { + "@types/node": "^18.0.0", + "got": "^11.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "^4.6.2" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/webdriverio/node_modules/@wdio/utils": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-7.25.4.tgz", + "integrity": "sha512-8iwQDk+foUqSzKZKfhLxjlCKOkfRJPNHaezQoevNgnrTq/t0ek+ldZCATezb9B8jprAuP4mgS9xi22akc6RkzA==", + "dev": true, + "dependencies": { + "@wdio/logger": "7.19.0", + "@wdio/types": "7.25.4", + "p-iteration": "^1.1.8" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/webdriverio/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/webdriverio/node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -21638,6 +24210,80 @@ "balanced-match": "^1.0.0" } }, + "node_modules/webdriverio/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/webdriverio/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/webdriverio/node_modules/color-name": { + "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 + }, + "node_modules/webdriverio/node_modules/glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/webdriverio/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/webdriverio/node_modules/ky": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/ky/-/ky-0.30.0.tgz", + "integrity": "sha512-X/u76z4JtDVq10u1JA5UQfatPxgPaVDMYTrgHyiTpGN2z4TMEJkIHsoSBBSg9SWZEIXTKsi9kHgiQ9o3Y/4yog==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/ky?sponsor=1" + } + }, "node_modules/webdriverio/node_modules/minimatch": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", @@ -21650,16 +24296,48 @@ "node": ">=10" } }, + "node_modules/webdriverio/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/webdriverio/node_modules/webdriver": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-7.25.4.tgz", + "integrity": "sha512-6nVDwenh0bxbtUkHASz9B8T9mB531Fn1PcQjUGj2t5dolLPn6zuK1D7XYVX40hpn6r3SlYzcZnEBs4X0az5Txg==", + "dev": true, + "dependencies": { + "@types/node": "^18.0.0", + "@wdio/config": "7.25.4", + "@wdio/logger": "7.19.0", + "@wdio/protocols": "7.22.0", + "@wdio/types": "7.25.4", + "@wdio/utils": "7.25.4", + "got": "^11.0.2", + "ky": "0.30.0", + "lodash.merge": "^4.6.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", "dev": true }, "node_modules/webpack": { - "version": "5.70.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.70.0.tgz", - "integrity": "sha512-ZMWWy8CeuTTjCxbeaQI21xSswseF2oNOwc70QSKNePvmxE7XW36i7vpBMYZFAUHPwQiEbNGCEYIOOlyRbdGmxw==", + "version": "5.74.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz", + "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", @@ -21667,24 +24345,24 @@ "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/wasm-edit": "1.11.1", "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.4.1", + "acorn": "^8.7.1", "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.9.2", + "enhanced-resolve": "^5.10.0", "es-module-lexer": "^0.9.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.9", - "json-parse-better-errors": "^1.0.2", + "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", "schema-utils": "^3.1.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.3.1", + "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" }, "bin": { @@ -21704,9 +24382,9 @@ } }, "node_modules/webpack-bundle-analyzer": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.5.0.tgz", - "integrity": "sha512-GUMZlM3SKwS8Z+CKeIFx7CVoHn3dXFcUAjT/dcZQQmfSZGvitPfMob2ipjai7ovFFqPvTqkEZ/leL4O0YOdAYQ==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.7.0.tgz", + "integrity": "sha512-j9b8ynpJS4K+zfO5GGwsAcQX4ZHpWV+yRiHDiL+bE0XHJ8NiPYLTNVQdlFYWxtpg9lfAQNlwJg16J9AJtFSXRg==", "dev": true, "dependencies": { "acorn": "^8.0.4", @@ -21727,9 +24405,9 @@ } }, "node_modules/webpack-bundle-analyzer/node_modules/acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -21738,15 +24416,6 @@ "node": ">=0.4.0" } }, - "node_modules/webpack-bundle-analyzer/node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/webpack-bundle-analyzer/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -21805,6 +24474,15 @@ "node": ">= 10" } }, + "node_modules/webpack-bundle-analyzer/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, + "engines": { + "node": ">=8" + } + }, "node_modules/webpack-bundle-analyzer/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -21818,9 +24496,9 @@ } }, "node_modules/webpack-bundle-analyzer/node_modules/ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "dev": true, "engines": { "node": ">=8.3.0" @@ -21916,10 +24594,92 @@ "webpack": "^5.21.2" } }, + "node_modules/webpack-stream/node_modules/ansi-colors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "dev": true, + "dependencies": { + "ansi-wrap": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-stream/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/webpack-stream/node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-stream/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/webpack-stream/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/webpack-stream/node_modules/plugin-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", + "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", + "dev": true, + "dependencies": { + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/webpack-stream/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/webpack/node_modules/acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -21953,15 +24713,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/webpack/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, "node_modules/webpack/node_modules/schema-utils": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", @@ -22006,7 +24757,7 @@ "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dev": true, "dependencies": { "tr46": "~0.0.3", @@ -22059,18 +24810,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==", + "dev": true + }, "node_modules/which-typed-array": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.7.tgz", - "integrity": "sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.8.tgz", + "integrity": "sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw==", "dev": true, "dependencies": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", - "es-abstract": "^1.18.5", - "foreach": "^2.0.5", + "es-abstract": "^1.20.0", + "for-each": "^0.3.3", "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.7" + "is-typed-array": "^1.1.9" }, "engines": { "node": ">= 0.4" @@ -22079,6 +24836,58 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "dependencies": { + "string-width": "^1.0.2 || 2" + } + }, + "node_modules/wide-align/node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/wide-align/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/wide-align/node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/wide-align/node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -22091,13 +24900,13 @@ "node_modules/wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", "dev": true }, "node_modules/workerpool": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", - "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", "dev": true }, "node_modules/wrap-ansi": { @@ -22153,7 +24962,7 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, "node_modules/write": { @@ -22228,13 +25037,13 @@ "node_modules/yargs": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/yargs/-/yargs-1.3.3.tgz", - "integrity": "sha1-BU3oth8i7v23IHBZ6u+da4P7kxo=", + "integrity": "sha512-7OGt4xXoWJQh5ulgZ78rKaqY7dNWbjfK+UKxGcIlaM2j7C4fqGchyv8CPvEWdRPrHp6Ula/YU8yGRpYGOHrI+g==", "dev": true }, "node_modules/yargs-parser": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", - "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, "engines": { "node": ">=12" @@ -22267,18 +25076,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/yargs-unparser/node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/yargs-unparser/node_modules/is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -22291,7 +25088,7 @@ "node_modules/yarn-install": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/yarn-install/-/yarn-install-1.0.0.tgz", - "integrity": "sha1-V/RQULgu/VcYKzlzxUqgXLXSUjA=", + "integrity": "sha512-VO1u181msinhPcGvQTVMnHVOae8zjX/NSksR17e6eXHRveDvHCF5mGjh9hkN8mzyfnCqcBe42LdTs7bScuTaeg==", "dev": true, "dependencies": { "cac": "^3.0.3", @@ -22309,7 +25106,7 @@ "node_modules/yarn-install/node_modules/ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -22318,7 +25115,7 @@ "node_modules/yarn-install/node_modules/ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -22327,7 +25124,7 @@ "node_modules/yarn-install/node_modules/chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "dependencies": { "ansi-styles": "^2.2.1", @@ -22343,7 +25140,7 @@ "node_modules/yarn-install/node_modules/cross-spawn": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", - "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", + "integrity": "sha512-yAXz/pA1tD8Gtg2S98Ekf/sewp3Lcp3YoFKJ4Hkp5h5yLWnKVTDU0kwjKJ8NDCYcfTLfyGkzTikst+jWypT1iA==", "dev": true, "dependencies": { "lru-cache": "^4.0.1", @@ -22363,7 +25160,7 @@ "node_modules/yarn-install/node_modules/strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "dependencies": { "ansi-regex": "^2.0.0" @@ -22375,7 +25172,7 @@ "node_modules/yarn-install/node_modules/supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, "engines": { "node": ">=0.8.0" @@ -22396,13 +25193,13 @@ "node_modules/yarn-install/node_modules/yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", "dev": true }, "node_modules/yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", "dev": true, "dependencies": { "buffer-crc32": "~0.2.3", @@ -22462,18 +25259,18 @@ "plugins/eslint": { "name": "eslint-plugin-prebid", "version": "1.0.0", - "integrity": "sha512-DH8lk8H4D+XCWtPm7C27IzzD4lkBHv49YTqOHeS/1mYCp4rn1j3NNNA1gl2q+CNYaAPSZDaS5DwRL/ErDP6O4Q==", "dev": true, "license": "Apache-2.0" } }, "dependencies": { "@ampproject/remapping": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", - "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", "requires": { - "@jridgewell/trace-mapping": "^0.3.0" + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" } }, "@babel/code-frame": { @@ -22485,25 +25282,25 @@ } }, "@babel/compat-data": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.0.tgz", - "integrity": "sha512-y5rqgTTPTmaF5e2nVhOxw+Ur9HDJLsWb6U/KpgUzRZEdPfE6VOubXBKLdbcUTijzRptednSBDQbYZBOSqJxpJw==" + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.1.tgz", + "integrity": "sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==" }, "@babel/core": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.0.tgz", - "integrity": "sha512-reM4+U7B9ss148rh2n1Qs9ASS+w94irYXga7c2jaQv9RVzpS7Mv1a9rnYYwuDa45G+DkORt9g6An2k/V4d9LbQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.6.tgz", + "integrity": "sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg==", "requires": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", - "@babel/helper-compilation-targets": "^7.19.0", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helpers": "^7.19.0", - "@babel/parser": "^7.19.0", + "@babel/generator": "^7.19.6", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helpers": "^7.19.4", + "@babel/parser": "^7.19.6", "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0", + "@babel/traverse": "^7.19.6", + "@babel/types": "^7.19.4", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -22512,86 +25309,96 @@ } }, "@babel/eslint-parser": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.17.0.tgz", - "integrity": "sha512-PUEJ7ZBXbRkbq3qqM/jZ2nIuakUBqCYc7Qf52Lj7dlZ6zERnqisdHioL0l4wwQZnmskMeasqUNzLBFKs3nylXA==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz", + "integrity": "sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ==", "dev": true, "requires": { - "eslint-scope": "^5.1.1", + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", "eslint-visitor-keys": "^2.1.0", "semver": "^6.3.0" } }, "@babel/generator": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.0.tgz", - "integrity": "sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.1.tgz", + "integrity": "sha512-u1dMdBUmA7Z0rBB97xh8pIhviK7oItYOkjbsCxTWMknyvbQRBwX7/gn4JXurRdirWMFh+ZtYARqkA6ydogVZpg==", "requires": { - "@babel/types": "^7.19.0", + "@babel/types": "^7.20.0", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } } }, "@babel/helper-annotate-as-pure": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", - "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.18.6" } }, "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", - "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", + "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", "requires": { - "@babel/helper-explode-assignable-expression": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/helper-explode-assignable-expression": "^7.18.6", + "@babel/types": "^7.18.9" } }, "@babel/helper-compilation-targets": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.0.tgz", - "integrity": "sha512-Ai5bNWXIvwDvWM7njqsG3feMlL9hCVQsPYXodsZyLwshYkZVJt59Gftau4VrE8S9IT9asd2uSP1hG6wCNw+sXA==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", + "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", "requires": { - "@babel/compat-data": "^7.19.0", + "@babel/compat-data": "^7.20.0", "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.20.2", + "browserslist": "^4.21.3", "semver": "^6.3.0" } }, "@babel/helper-create-class-features-plugin": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.6.tgz", - "integrity": "sha512-SogLLSxXm2OkBbSsHZMM4tUi8fUzjs63AT/d0YQIzr6GSd8Hxsbk2KYDX0k0DweAzGMj/YWeiCsorIdtdcW8Eg==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.19.0.tgz", + "integrity": "sha512-NRz8DwF4jT3UfrmUoZjd0Uph9HQnP30t7Ash+weACcyNkiYTywpIjDBgReJMKgr+n86sn2nPVVmJ28Dm053Kqw==", "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7" + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6" } }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz", - "integrity": "sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz", + "integrity": "sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==", "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "regexpu-core": "^5.0.1" + "@babel/helper-annotate-as-pure": "^7.18.6", + "regexpu-core": "^5.1.0" } }, "@babel/helper-define-polyfill-provider": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", - "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", "requires": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2", @@ -22604,11 +25411,11 @@ "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" }, "@babel/helper-explode-assignable-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", - "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", + "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.18.6" } }, "@babel/helper-function-name": { @@ -22629,11 +25436,11 @@ } }, "@babel/helper-member-expression-to-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", - "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", + "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.18.9" } }, "@babel/helper-module-imports": { @@ -22645,69 +25452,70 @@ } }, "@babel/helper-module-transforms": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", - "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.6.tgz", + "integrity": "sha512-fCmcfQo/KYr/VXXDIyd3CBGZ6AFhPFy1TfSEJ+PilGVlQT6jcbqtHAM4C1EciRqMza7/TpOUZliuSH+U6HAhJw==", "requires": { "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-simple-access": "^7.19.4", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" + "@babel/traverse": "^7.19.6", + "@babel/types": "^7.19.4" } }, "@babel/helper-optimise-call-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", - "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", + "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.18.6" } }, "@babel/helper-plugin-utils": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz", - "integrity": "sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==" + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" }, "@babel/helper-remap-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", - "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", + "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-wrap-function": "^7.16.8", - "@babel/types": "^7.16.8" + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" } }, "@babel/helper-replace-supers": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", - "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz", + "integrity": "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==", "requires": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/traverse": "^7.19.1", + "@babel/types": "^7.19.0" } }, "@babel/helper-simple-access": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", - "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz", + "integrity": "sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==", "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.19.4" } }, "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", - "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", + "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", "requires": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.20.0" } }, "@babel/helper-split-export-declaration": { @@ -22719,14 +25527,14 @@ } }, "@babel/helper-string-parser": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", - "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==" + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==" }, "@babel/helper-validator-identifier": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", - "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==" }, "@babel/helper-validator-option": { "version": "7.18.6", @@ -22734,24 +25542,24 @@ "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==" }, "@babel/helper-wrap-function": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", - "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz", + "integrity": "sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==", "requires": { - "@babel/helper-function-name": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.8", - "@babel/types": "^7.16.8" + "@babel/helper-function-name": "^7.19.0", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" } }, "@babel/helpers": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz", - "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.1.tgz", + "integrity": "sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg==", "requires": { "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.0" } }, "@babel/highlight": { @@ -22765,169 +25573,170 @@ } }, "@babel/parser": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.0.tgz", - "integrity": "sha512-74bEXKX2h+8rrfQUfsBfuZZHzsEs6Eql4pqy/T4Nn6Y9wNPggQOqD6z6pn5Bl8ZfysKouFZT/UXEH94ummEeQw==" + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.1.tgz", + "integrity": "sha512-hp0AYxaZJhxULfM1zyp7Wgr+pSUKBcP3M+PHnSzWGdXOzg/kHWIgiUWARvubhUKGOEw3xqY4x+lyZ9ytBVcELw==" }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz", - "integrity": "sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", + "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz", - "integrity": "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz", + "integrity": "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-proposal-optional-chaining": "^7.18.9" } }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz", - "integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.1.tgz", + "integrity": "sha512-Gh5rchzSwE4kC+o/6T8waD0WHEQIsDmjltY8WnWRXHUdH8axZhuH86Ov9M72YhJfDrZseQwuuWaaIT/TmePp3g==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-remap-async-to-generator": "^7.18.9", "@babel/plugin-syntax-async-generators": "^7.8.4" } }, "@babel/plugin-proposal-class-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz", - "integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-proposal-class-static-block": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.17.6.tgz", - "integrity": "sha512-X/tididvL2zbs7jZCeeRJ8167U/+Ac135AM6jCAx6gYXDUviZV5Ku9UDvWS2NCuWlFjIRXklYhwo6HhAC7ETnA==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz", + "integrity": "sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==", "requires": { - "@babel/helper-create-class-features-plugin": "^7.17.6", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-class-static-block": "^7.14.5" } }, "@babel/plugin-proposal-dynamic-import": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", - "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", + "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-dynamic-import": "^7.8.3" } }, "@babel/plugin-proposal-export-namespace-from": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz", - "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.18.9", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" } }, "@babel/plugin-proposal-json-strings": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz", - "integrity": "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", + "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-json-strings": "^7.8.3" } }, "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz", - "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz", + "integrity": "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.18.9", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" } }, "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz", - "integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" } }, "@babel/plugin-proposal-numeric-separator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", - "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-numeric-separator": "^7.10.4" } }, "@babel/plugin-proposal-object-rest-spread": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.3.tgz", - "integrity": "sha512-yuL5iQA/TbZn+RGAfxQXfi7CNLmKi1f8zInn4IgobuCWcAb7i+zj4TYzQ9l8cEzVyJ89PDGuqxK1xZpUDISesw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.19.4.tgz", + "integrity": "sha512-wHmj6LDxVDnL+3WhXteUBaoM1aVILZODAUjg11kHqG4cOlfgMQGxw6aCgvrXrmaJR3Bn14oZhImyCPZzRpC93Q==", "requires": { - "@babel/compat-data": "^7.17.0", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/compat-data": "^7.19.4", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-plugin-utils": "^7.19.0", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.16.7" + "@babel/plugin-transform-parameters": "^7.18.8" } }, "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", - "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", + "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" } }, "@babel/plugin-proposal-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz", - "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz", + "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", "@babel/plugin-syntax-optional-chaining": "^7.8.3" } }, "@babel/plugin-proposal-private-methods": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz", - "integrity": "sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.10", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-proposal-private-property-in-object": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz", - "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz", + "integrity": "sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==", "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" } }, "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz", - "integrity": "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", + "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-syntax-async-generators": { @@ -22970,6 +25779,14 @@ "@babel/helper-plugin-utils": "^7.8.3" } }, + "@babel/plugin-syntax-import-assertions": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz", + "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.19.0" + } + }, "@babel/plugin-syntax-json-strings": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", @@ -23043,331 +25860,332 @@ } }, "@babel/plugin-transform-arrow-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz", - "integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz", + "integrity": "sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz", - "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz", + "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", "requires": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8" + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-remap-async-to-generator": "^7.18.6" } }, "@babel/plugin-transform-block-scoped-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", - "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", + "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-block-scoping": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz", - "integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.0.tgz", + "integrity": "sha512-sXOohbpHZSk7GjxK9b3dKB7CfqUD5DwOH+DggKzOQ7TXYP+RCSbRykfjQmn/zq+rBjycVRtLf9pYhAaEJA786w==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.19.0" } }, "@babel/plugin-transform-classes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz", - "integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.19.0.tgz", + "integrity": "sha512-YfeEE9kCjqTS9IitkgfJuxjcEtLUHMqa8yUJ6zdz8vR7hKuo6mOy2C05P0F1tdMmDCeuyidKnlrw/iTppHcr2A==", "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-compilation-targets": "^7.19.0", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6", "globals": "^11.1.0" } }, "@babel/plugin-transform-computed-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz", - "integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz", + "integrity": "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-destructuring": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.3.tgz", - "integrity": "sha512-dDFzegDYKlPqa72xIlbmSkly5MluLoaC1JswABGktyt6NTXSBcUuse/kWE/wvKFWJHPETpi158qJZFS3JmykJg==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.0.tgz", + "integrity": "sha512-1dIhvZfkDVx/zn2S1aFwlruspTt4189j7fEkH0Y0VyuDM6bQt7bD6kLcz3l4IlLG+e5OReaBz9ROAbttRtUHqA==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.19.0" } }, "@babel/plugin-transform-dotall-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", - "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", + "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-duplicate-keys": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz", - "integrity": "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", + "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-exponentiation-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", - "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", + "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-for-of": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz", - "integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==", + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", + "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", - "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", + "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", "requires": { - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz", - "integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", + "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-member-expression-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", - "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", + "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-modules-amd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz", - "integrity": "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.19.6.tgz", + "integrity": "sha512-uG3od2mXvAtIFQIh0xrpLH6r5fpSQN04gIVovl+ODLdUMANokxQLZnPBHcjmv3GxRjnqwLuHvppjjcelqUFZvg==", "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0" } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz", - "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.19.6.tgz", + "integrity": "sha512-8PIa1ym4XRTKuSsOUXqDG0YaOlEuTVvHMe5JCfgBMOtHvJKw/4NGovEGN33viISshG/rZNVrACiBmPQLvWN8xQ==", "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-simple-access": "^7.19.4" } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz", - "integrity": "sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.6.tgz", + "integrity": "sha512-fqGLBepcc3kErfR9R3DnVpURmckXP7gj7bAlrTQyBxrigFqszZCkFkcoxzCp2v32XmwXLvbw+8Yq9/b+QqksjQ==", "requires": { - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-validator-identifier": "^7.19.1" } }, "@babel/plugin-transform-modules-umd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz", - "integrity": "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", + "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz", - "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz", + "integrity": "sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.19.0", + "@babel/helper-plugin-utils": "^7.19.0" } }, "@babel/plugin-transform-new-target": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz", - "integrity": "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", + "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-object-super": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", - "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", + "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.6" } }, "@babel/plugin-transform-parameters": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz", - "integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.1.tgz", + "integrity": "sha512-nDvKLrAvl+kf6BOy1UJ3MGwzzfTMgppxwiD2Jb4LO3xjYyZq30oQzDNJbCQpMdG9+j2IXHoiMrw5Cm/L6ZoxXQ==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.19.0" } }, "@babel/plugin-transform-property-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", - "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", + "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-regenerator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz", - "integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz", + "integrity": "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==", "requires": { - "regenerator-transform": "^0.14.2" + "@babel/helper-plugin-utils": "^7.18.6", + "regenerator-transform": "^0.15.0" } }, "@babel/plugin-transform-reserved-words": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz", - "integrity": "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", + "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-runtime": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.9.tgz", - "integrity": "sha512-wS8uJwBt7/b/mzE13ktsJdmS4JP/j7PQSaADtnb4I2wL0zK51MQ0pmF8/Jy0wUIS96fr+fXT6S/ifiPXnvrlSg==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.6.tgz", + "integrity": "sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw==", "requires": { "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.9", - "babel-plugin-polyfill-corejs2": "^0.3.1", - "babel-plugin-polyfill-corejs3": "^0.5.2", - "babel-plugin-polyfill-regenerator": "^0.3.1", + "@babel/helper-plugin-utils": "^7.19.0", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", "semver": "^6.3.0" } }, "@babel/plugin-transform-shorthand-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", - "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", + "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-spread": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz", - "integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz", + "integrity": "sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" } }, "@babel/plugin-transform-sticky-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", - "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", + "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-template-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz", - "integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz", - "integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", + "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-unicode-escapes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", - "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", + "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-unicode-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", - "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", + "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/preset-env": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz", - "integrity": "sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.19.4.tgz", + "integrity": "sha512-5QVOTXUdqTCjQuh2GGtdd7YEhoRXBMVGROAtsBeLGIbIz3obCBIfRMT1I3ZKkMgNzwkyCkftDXSSkHxnfVf4qg==", "requires": { - "@babel/compat-data": "^7.16.8", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-async-generator-functions": "^7.16.8", - "@babel/plugin-proposal-class-properties": "^7.16.7", - "@babel/plugin-proposal-class-static-block": "^7.16.7", - "@babel/plugin-proposal-dynamic-import": "^7.16.7", - "@babel/plugin-proposal-export-namespace-from": "^7.16.7", - "@babel/plugin-proposal-json-strings": "^7.16.7", - "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", - "@babel/plugin-proposal-numeric-separator": "^7.16.7", - "@babel/plugin-proposal-object-rest-spread": "^7.16.7", - "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", - "@babel/plugin-proposal-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-private-methods": "^7.16.11", - "@babel/plugin-proposal-private-property-in-object": "^7.16.7", - "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", + "@babel/compat-data": "^7.19.4", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.19.1", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.19.4", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.18.6", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", @@ -23377,44 +26195,44 @@ "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.16.7", - "@babel/plugin-transform-async-to-generator": "^7.16.8", - "@babel/plugin-transform-block-scoped-functions": "^7.16.7", - "@babel/plugin-transform-block-scoping": "^7.16.7", - "@babel/plugin-transform-classes": "^7.16.7", - "@babel/plugin-transform-computed-properties": "^7.16.7", - "@babel/plugin-transform-destructuring": "^7.16.7", - "@babel/plugin-transform-dotall-regex": "^7.16.7", - "@babel/plugin-transform-duplicate-keys": "^7.16.7", - "@babel/plugin-transform-exponentiation-operator": "^7.16.7", - "@babel/plugin-transform-for-of": "^7.16.7", - "@babel/plugin-transform-function-name": "^7.16.7", - "@babel/plugin-transform-literals": "^7.16.7", - "@babel/plugin-transform-member-expression-literals": "^7.16.7", - "@babel/plugin-transform-modules-amd": "^7.16.7", - "@babel/plugin-transform-modules-commonjs": "^7.16.8", - "@babel/plugin-transform-modules-systemjs": "^7.16.7", - "@babel/plugin-transform-modules-umd": "^7.16.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.8", - "@babel/plugin-transform-new-target": "^7.16.7", - "@babel/plugin-transform-object-super": "^7.16.7", - "@babel/plugin-transform-parameters": "^7.16.7", - "@babel/plugin-transform-property-literals": "^7.16.7", - "@babel/plugin-transform-regenerator": "^7.16.7", - "@babel/plugin-transform-reserved-words": "^7.16.7", - "@babel/plugin-transform-shorthand-properties": "^7.16.7", - "@babel/plugin-transform-spread": "^7.16.7", - "@babel/plugin-transform-sticky-regex": "^7.16.7", - "@babel/plugin-transform-template-literals": "^7.16.7", - "@babel/plugin-transform-typeof-symbol": "^7.16.7", - "@babel/plugin-transform-unicode-escapes": "^7.16.7", - "@babel/plugin-transform-unicode-regex": "^7.16.7", + "@babel/plugin-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.19.4", + "@babel/plugin-transform-classes": "^7.19.0", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.19.4", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.18.6", + "@babel/plugin-transform-modules-commonjs": "^7.18.6", + "@babel/plugin-transform-modules-systemjs": "^7.19.0", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.18.8", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.19.0", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.10", + "@babel/plugin-transform-unicode-regex": "^7.18.6", "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.16.8", - "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.5.0", - "babel-plugin-polyfill-regenerator": "^0.3.0", - "core-js-compat": "^3.20.2", + "@babel/types": "^7.19.4", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", + "core-js-compat": "^3.25.1", "semver": "^6.3.0" } }, @@ -23431,18 +26249,21 @@ } }, "@babel/runtime": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", - "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.1.tgz", + "integrity": "sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg==", "requires": { - "regenerator-runtime": "^0.13.4" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" - } + "regenerator-runtime": "^0.13.10" + } + }, + "@babel/runtime-corejs3": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.20.1.tgz", + "integrity": "sha512-CGulbEDcg/ND1Im7fUNRZdGXmX2MTWVVZacQi/6DiKE5HNwZ3aVTm5PV4lO8HHz0B2h8WQyvKKjbX5XgTtydsg==", + "dev": true, + "requires": { + "core-js-pure": "^3.25.1", + "regenerator-runtime": "^0.13.10" } }, "@babel/template": { @@ -23456,29 +26277,29 @@ } }, "@babel/traverse": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.0.tgz", - "integrity": "sha512-4pKpFRDh+utd2mbRC8JLnlsMUii3PMHjpL6a0SZ4NMZy7YFP9aXORxEhdMVOc9CpWtDF09IkciQLEhK7Ml7gRA==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.1.tgz", + "integrity": "sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==", "requires": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", + "@babel/generator": "^7.20.1", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.0", - "@babel/types": "^7.19.0", + "@babel/parser": "^7.20.1", + "@babel/types": "^7.20.0", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz", - "integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.0.tgz", + "integrity": "sha512-Jlgt3H0TajCW164wkTOTzHkZb075tMQMULzrLUoUeKmO7eFL96GgDxf7/Axhc5CAuKE3KFyVW1p6ysKsi2oXAg==", "requires": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" } }, @@ -23518,9 +26339,9 @@ } }, "globals": { - "version": "13.12.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", - "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -23596,7 +26417,7 @@ "@gulp-sourcemaps/map-sources": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/map-sources/-/map-sources-1.0.0.tgz", - "integrity": "sha1-iQrnxdjId/bThIYCFazp1+yUW9o=", + "integrity": "sha512-o/EatdaGt8+x2qpb0vFLC/2Gug/xYPRXb6a+ET1wGYKozKN3krDWC/zZFZAtrzxJHuDL12mwdfEFKcKMNvc55A==", "dev": true, "requires": { "normalize-path": "^2.0.1", @@ -23606,7 +26427,7 @@ "normalize-path": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", "dev": true, "requires": { "remove-trailing-separator": "^1.0.1" @@ -23676,57 +26497,6 @@ "get-package-type": "^0.1.0", "js-yaml": "^3.13.1", "resolve-from": "^5.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - } } }, "@istanbuljs/schema": { @@ -23736,15 +26506,15 @@ "dev": true }, "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", - "@types/yargs": "^16.0.0", + "@types/yargs": "^15.0.0", "chalk": "^4.0.0" }, "dependencies": { @@ -23782,6 +26552,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "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 + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -23794,19 +26570,18 @@ } }, "@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, "@jridgewell/resolve-uri": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", - "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" }, "@jridgewell/set-array": { "version": "1.1.2", @@ -23821,20 +26596,42 @@ "requires": { "@jridgewell/gen-mapping": "^0.3.0", "@jridgewell/trace-mapping": "^0.3.9" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } } }, "@jridgewell/sourcemap-codec": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", - "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==" + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" }, "@jridgewell/trace-mapping": { - "version": "0.3.14", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", - "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dev": true, + "requires": { + "eslint-scope": "5.1.1" } }, "@polka/url": { @@ -23879,15 +26676,15 @@ } }, "@sinonjs/text-encoding": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", - "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", + "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", "dev": true }, - "@socket.io/base64-arraybuffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@socket.io/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", - "integrity": "sha512-dOlCBKnDw4iShaIsH/bxujKTM18+2TOAsYz+KSc11Am38H4q5Xw8Bbz97ZYdrVNM+um3p7w86Bvvmcn9q+5+eQ==", + "@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", "dev": true }, "@szmarczak/http-timer": { @@ -23900,9 +26697,9 @@ } }, "@types/aria-query": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.0.tgz", - "integrity": "sha512-P+dkdFu0n08PDIvw+9nT9ByQnd+Udc8DaWPb9HKfaPwCvWvQpC5XaMRx2xLWECm9x1VKNps6vEAlirjA6+uNrQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", + "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==", "dev": true }, "@types/cacheable-request": { @@ -23917,12 +26714,6 @@ "@types/responselike": "*" } }, - "@types/component-emitter": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.11.tgz", - "integrity": "sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ==", - "dev": true - }, "@types/cookie": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", @@ -23957,15 +26748,15 @@ "dev": true }, "@types/ejs": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-3.1.0.tgz", - "integrity": "sha512-DCg+Ka+uDQ31lJ/UtEXVlaeV3d6t81gifaVWKJy4MYVVgvJttyX/viREy+If7fz+tK/gVxTGMtyrFPnm4gjrVA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-3.1.1.tgz", + "integrity": "sha512-RQul5wEfY7BjWm0sYY86cmUN/pcXWGyVxWX93DFFJvcrxax5zKlieLwA3T77xJGwNcZW0YW6CYG70p1m8xPFmA==", "dev": true }, "@types/eslint": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz", - "integrity": "sha512-GE44+DNEyxxh2Kc6ro/VkIj+9ma0pO0bwv9+uHSyBrikYOHr8zYcdPvnBOp1aw8s+CjRvuSx7CyWqRrNFQ59mA==", + "version": "8.4.9", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.9.tgz", + "integrity": "sha512-jFCSo4wJzlHQLCpceUhUnXdrPuCNOjGFMQ8Eg6JXxlz3QaCKOb7eGi2cephQdM4XTYsNej69P9JDJ1zqNIbncQ==", "dev": true, "requires": { "@types/estree": "*", @@ -23973,9 +26764,9 @@ } }, "@types/eslint-scope": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", - "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", "dev": true, "requires": { "@types/eslint": "*", @@ -24037,13 +26828,13 @@ "dev": true }, "@types/inquirer": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-8.2.0.tgz", - "integrity": "sha512-BNoMetRf3gmkpAlV5we+kxyZTle7YibdOntIZbU5pyIfMdcwy784KfeZDAcuyMznkh5OLa17RVXZOGA5LTlkgQ==", + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-HhxyLejTHMfohAuhRun4csWigAMjXTmRyiJTU1Y/I1xmggikFMkOUoMQRlFm+zQcPEGHSs3io/0FAmNZf8EymQ==", "dev": true, "requires": { "@types/through": "*", - "rxjs": "^7.2.0" + "rxjs": "^6.4.0" } }, "@types/istanbul-lib-coverage": { @@ -24071,54 +26862,54 @@ } }, "@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, "@types/keyv": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.3.tgz", - "integrity": "sha512-FXCJgyyN3ivVgRoml4h94G/p3kY+u/B86La+QptcqJaWtBWtmc6TtkNfS40n9bIvyLteHh7zXOtgbobORKPbDg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-4.2.0.tgz", + "integrity": "sha512-xoBtGl5R9jeKUhc8ZqeYaRDx04qqJ10yhhXYGmJ4Jr8qKpvMsDQQrNUvF/wUJ4klOtmJeJM+p2Xo3zp9uaC3tw==", "dev": true, "requires": { - "@types/node": "*" + "keyv": "*" } }, "@types/lodash": { - "version": "4.14.179", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.179.tgz", - "integrity": "sha512-uwc1x90yCKqGcIOAT6DwOSuxnrAbpkdPsUOZtwrXb4D/6wZs+6qG7QnIawDuZWg0sWpxl+ltIKCaLoMlna678w==", + "version": "4.14.187", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.187.tgz", + "integrity": "sha512-MrO/xLXCaUgZy3y96C/iOsaIqZSeupyTImKClHunL5GrmaiII2VwvWmLBu2hwa0Kp0sV19CsyjtrTc/Fx8rg/A==", "dev": true }, "@types/lodash.flattendeep": { - "version": "4.4.6", - "resolved": "https://registry.npmjs.org/@types/lodash.flattendeep/-/lodash.flattendeep-4.4.6.tgz", - "integrity": "sha512-uLm2MaRVlqJSGsMK0RZpP5T3KqReq+9WbYDHCUhBhp98v56hMG/Yht52bsoTSui9xz2mUvQ9NfG3LrNGDL92Ng==", + "version": "4.4.7", + "resolved": "https://registry.npmjs.org/@types/lodash.flattendeep/-/lodash.flattendeep-4.4.7.tgz", + "integrity": "sha512-1h6GW/AeZw/Wej6uxrqgmdTDZX1yFS39lRsXYkg+3kWvOWWrlGCI6H7lXxlUHOzxDT4QeYGmgPpQ3BX9XevzOg==", "dev": true, "requires": { "@types/lodash": "*" } }, "@types/lodash.pickby": { - "version": "4.6.6", - "resolved": "https://registry.npmjs.org/@types/lodash.pickby/-/lodash.pickby-4.6.6.tgz", - "integrity": "sha512-NFa13XxlMd9eFi0UFZFWIztpMpXhozbijrx3Yb1viYZphT7jyopIFVoIRF4eYMjruWNEG1rnyrRmg/8ej9T8Iw==", + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/@types/lodash.pickby/-/lodash.pickby-4.6.7.tgz", + "integrity": "sha512-4ebXRusuLflfscbD0PUX4eVknDHD9Yf+uMtBIvA/hrnTqeAzbuHuDjvnYriLjUrI9YrhCPVKUf4wkRSXJQ6gig==", "dev": true, "requires": { "@types/lodash": "*" } }, "@types/lodash.union": { - "version": "4.6.6", - "resolved": "https://registry.npmjs.org/@types/lodash.union/-/lodash.union-4.6.6.tgz", - "integrity": "sha512-Wu0ZEVNcyCz8eAn6TlUbYWZoGbH9E+iOHxAZbwUoCEXdUiy6qpcz5o44mMXViM4vlPLLCPlkAubEP1gokoSZaw==", + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/@types/lodash.union/-/lodash.union-4.6.7.tgz", + "integrity": "sha512-6HXM6tsnHJzKgJE0gA/LhTGf/7AbjUk759WZ1MziVm+OBNAATHhdgj+a3KVE8g76GCLAnN4ZEQQG1EGgtBIABA==", "dev": true, "requires": { "@types/lodash": "*" @@ -24133,16 +26924,10 @@ "@types/unist": "*" } }, - "@types/mdurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz", - "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==", - "dev": true - }, "@types/mocha": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.0.tgz", - "integrity": "sha512-QCWHkbMv4Y5U9oW10Uxbr45qMMSzl4OzijsozynUAgx3kEHUdXB00udx2dWDQ7f2TU2a2uuiFaRZjCe3unPpeg==", + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.3.tgz", + "integrity": "sha512-ekGvFhFgrc2zYQoX4JeZPmVzZxw6Dtllga7iGHzfbYIYkAMUx/sAFP2GdFpLff+vdHXu5fl7WX9AT+TtqYcsyw==", "dev": true }, "@types/ms": { @@ -24152,9 +26937,9 @@ "dev": true }, "@types/node": { - "version": "17.0.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", - "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==", + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", "dev": true }, "@types/normalize-package-data": { @@ -24170,18 +26955,18 @@ "dev": true }, "@types/puppeteer": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/@types/puppeteer/-/puppeteer-5.4.5.tgz", - "integrity": "sha512-lxCjpDEY+DZ66+W3x5Af4oHnEmUXt0HuaRzkBGE2UZiZEp/V1d3StpLPlmNVu/ea091bdNmVPl44lu8Wy/0ZCA==", + "version": "5.4.7", + "resolved": "https://registry.npmjs.org/@types/puppeteer/-/puppeteer-5.4.7.tgz", + "integrity": "sha512-JdGWZZYL0vKapXF4oQTC5hLVNfOgdPrqeZ1BiQnGk5cB7HeE91EWUiTdVSdQPobRN8rIcdffjiOgCYJ/S8QrnQ==", "dev": true, "requires": { "@types/node": "*" } }, "@types/recursive-readdir": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@types/recursive-readdir/-/recursive-readdir-2.2.0.tgz", - "integrity": "sha512-HGk753KRu2N4mWduovY4BLjYq4jTOL29gV2OfGdGxHcPSWGFkC5RRIdk+VTs5XmYd7MVAD+JwKrcb5+5Y7FOCg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@types/recursive-readdir/-/recursive-readdir-2.2.1.tgz", + "integrity": "sha512-Xd+Ptc4/F2ueInqy5yK2FI5FxtwwbX2+VZpcg+9oYsFJVen8qQKGapCr+Bi5wQtHU1cTXT8s+07lo/nKPgu8Gg==", "dev": true, "requires": { "@types/node": "*" @@ -24261,9 +27046,9 @@ "dev": true }, "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "version": "15.0.14", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", + "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -24276,9 +27061,9 @@ "dev": true }, "@types/yauzl": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.2.tgz", - "integrity": "sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", "dev": true, "optional": true, "requires": { @@ -24292,9 +27077,9 @@ "dev": true }, "@videojs/http-streaming": { - "version": "2.14.2", - "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.14.2.tgz", - "integrity": "sha512-K1raSfO/pq5r8iUas3OSYni0kXOj91n8ealIpV02khghzGv9LQ6O3YUqYd/eAhJ1HIrmZWOnrYpK/P+mhUExXQ==", + "version": "2.14.3", + "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.14.3.tgz", + "integrity": "sha512-2tFwxCaNbcEZzQugWf8EERwNMyNtspfHnvxRGRABQs09W/5SqmkWFuGWfUAm4wQKlXGfdPyAJ1338ASl459xAA==", "dev": true, "requires": { "@babel/runtime": "^7.12.5", @@ -24330,14 +27115,14 @@ } }, "@vue/compiler-core": { - "version": "3.2.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.38.tgz", - "integrity": "sha512-/FsvnSu7Z+lkd/8KXMa4yYNUiqQrI22135gfsQYVGuh5tqEgOB0XqrUdb/KnCLa5+TmQLPwvyUnKMyCpu+SX3Q==", + "version": "3.2.41", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.41.tgz", + "integrity": "sha512-oA4mH6SA78DT+96/nsi4p9DX97PHcNROxs51lYk7gb9Z4BPKQ3Mh+BLn6CQZBw857Iuhu28BfMSRHAlPvD4vlw==", "dev": true, "optional": true, "requires": { "@babel/parser": "^7.16.4", - "@vue/shared": "3.2.38", + "@vue/shared": "3.2.41", "estree-walker": "^2.0.2", "source-map": "^0.6.1" }, @@ -24352,29 +27137,29 @@ } }, "@vue/compiler-dom": { - "version": "3.2.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.38.tgz", - "integrity": "sha512-zqX4FgUbw56kzHlgYuEEJR8mefFiiyR3u96498+zWPsLeh1WKvgIReoNE+U7gG8bCUdvsrJ0JRmev0Ky6n2O0g==", + "version": "3.2.41", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.41.tgz", + "integrity": "sha512-xe5TbbIsonjENxJsYRbDJvthzqxLNk+tb3d/c47zgREDa/PCp6/Y4gC/skM4H6PIuX5DAxm7fFJdbjjUH2QTMw==", "dev": true, "optional": true, "requires": { - "@vue/compiler-core": "3.2.38", - "@vue/shared": "3.2.38" + "@vue/compiler-core": "3.2.41", + "@vue/shared": "3.2.41" } }, "@vue/compiler-sfc": { - "version": "3.2.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.38.tgz", - "integrity": "sha512-KZjrW32KloMYtTcHAFuw3CqsyWc5X6seb8KbkANSWt3Cz9p2qA8c1GJpSkksFP9ABb6an0FLCFl46ZFXx3kKpg==", + "version": "3.2.41", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.41.tgz", + "integrity": "sha512-+1P2m5kxOeaxVmJNXnBskAn3BenbTmbxBxWOtBq3mQTCokIreuMULFantBUclP0+KnzNCMOvcnKinqQZmiOF8w==", "dev": true, "optional": true, "requires": { "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.38", - "@vue/compiler-dom": "3.2.38", - "@vue/compiler-ssr": "3.2.38", - "@vue/reactivity-transform": "3.2.38", - "@vue/shared": "3.2.38", + "@vue/compiler-core": "3.2.41", + "@vue/compiler-dom": "3.2.41", + "@vue/compiler-ssr": "3.2.41", + "@vue/reactivity-transform": "3.2.41", + "@vue/shared": "3.2.41", "estree-walker": "^2.0.2", "magic-string": "^0.25.7", "postcss": "^8.1.10", @@ -24391,34 +27176,34 @@ } }, "@vue/compiler-ssr": { - "version": "3.2.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.38.tgz", - "integrity": "sha512-bm9jOeyv1H3UskNm4S6IfueKjUNFmi2kRweFIGnqaGkkRePjwEcfCVqyS3roe7HvF4ugsEkhf4+kIvDhip6XzQ==", + "version": "3.2.41", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.41.tgz", + "integrity": "sha512-Y5wPiNIiaMz/sps8+DmhaKfDm1xgj6GrH99z4gq2LQenfVQcYXmHIOBcs5qPwl7jaW3SUQWjkAPKMfQemEQZwQ==", "dev": true, "optional": true, "requires": { - "@vue/compiler-dom": "3.2.38", - "@vue/shared": "3.2.38" + "@vue/compiler-dom": "3.2.41", + "@vue/shared": "3.2.41" } }, "@vue/reactivity-transform": { - "version": "3.2.38", - "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.38.tgz", - "integrity": "sha512-3SD3Jmi1yXrDwiNJqQ6fs1x61WsDLqVk4NyKVz78mkaIRh6d3IqtRnptgRfXn+Fzf+m6B1KxBYWq1APj6h4qeA==", + "version": "3.2.41", + "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.41.tgz", + "integrity": "sha512-mK5+BNMsL4hHi+IR3Ft/ho6Za+L3FA5j8WvreJ7XzHrqkPq8jtF/SMo7tuc9gHjLDwKZX1nP1JQOKo9IEAn54A==", "dev": true, "optional": true, "requires": { "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.38", - "@vue/shared": "3.2.38", + "@vue/compiler-core": "3.2.41", + "@vue/shared": "3.2.41", "estree-walker": "^2.0.2", "magic-string": "^0.25.7" } }, "@vue/shared": { - "version": "3.2.38", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.38.tgz", - "integrity": "sha512-dTyhTIRmGXBjxJE+skC8tTWCGLCVc4wQgRRLt8+O9p5ewBAjoBwtCAkLPrtToSr1xltoe3st21Pv953aOZ7alg==", + "version": "3.2.41", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.41.tgz", + "integrity": "sha512-W9mfWLHmJhkfAmV+7gDjcHeAWALQtgGT3JErxULl0oz6R6+3ug91I7IErs93eCFhPCZPHBs4QJS7YWEV7A3sxw==", "dev": true, "optional": true }, @@ -24434,43 +27219,219 @@ "browserstack-local": "^1.4.5", "got": "^11.0.2", "webdriverio": "7.16.16" + }, + "dependencies": { + "@wdio/config": { + "version": "7.16.16", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-7.16.16.tgz", + "integrity": "sha512-K/ObPuo6Da2liz++OKOIfbdpFwI7UWiFcBylfJkCYbweuXCoW1aUqlKI6rmKPwCH9Uqr/RHWu6p8eo0zWe6xVA==", + "dev": true, + "requires": { + "@wdio/logger": "7.16.0", + "@wdio/types": "7.16.14", + "deepmerge": "^4.0.0", + "glob": "^7.1.2" + } + }, + "@wdio/protocols": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-7.16.7.tgz", + "integrity": "sha512-Wv40pNQcLiPzQ3o98Mv4A8T1EBQ6k4khglz/e2r16CTm+F3DDYh8eLMAsU5cgnmuwwDKX1EyOiFwieykBn5MCg==", + "dev": true + }, + "@wdio/repl": { + "version": "7.16.14", + "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-7.16.14.tgz", + "integrity": "sha512-Ezih0Y+lsGkKv3H3U56hdWgZiQGA3VaAYguSLd9+g1xbQq+zMKqSmfqECD9bAy+OgCCiVTRstES6lHZxJVPhAg==", + "dev": true, + "requires": { + "@wdio/utils": "7.16.14" + } + }, + "@wdio/utils": { + "version": "7.16.14", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-7.16.14.tgz", + "integrity": "sha512-wwin8nVpIlhmXJkq6GJw9aDDzgLOJKgXTcEua0T2sdXjoW78u5Ly/GZrFXTjMGhacFvoZfitTrjyfyy4CxMVvw==", + "dev": true, + "requires": { + "@wdio/logger": "7.16.0", + "@wdio/types": "7.16.14", + "p-iteration": "^1.1.8" + } + }, + "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, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "devtools": { + "version": "7.16.16", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.16.16.tgz", + "integrity": "sha512-M0kzkuSgfEhpqIis3gdtWsNjn/HQ+vRAmEzDnbYx/7FfjFxhSv1d+rOOT20pvd60soItMYpsOova1igACEGkGQ==", + "dev": true, + "requires": { + "@types/node": "^17.0.4", + "@types/ua-parser-js": "^0.7.33", + "@wdio/config": "7.16.16", + "@wdio/logger": "7.16.0", + "@wdio/protocols": "7.16.7", + "@wdio/types": "7.16.14", + "@wdio/utils": "7.16.14", + "chrome-launcher": "^0.15.0", + "edge-paths": "^2.1.0", + "puppeteer-core": "^13.1.3", + "query-selector-shadow-dom": "^1.0.0", + "ua-parser-js": "^1.0.1", + "uuid": "^8.0.0" + } + }, + "devtools-protocol": { + "version": "0.0.973690", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.973690.tgz", + "integrity": "sha512-myh3hSFp0YWa2GED11PmbLhV4dv9RdO7YUz27XJrbQLnP5bMbZL6dfOOILTHO57yH0kX5GfuOZBsg/4NamfPvQ==", + "dev": true + }, + "minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "ua-parser-js": { + "version": "1.0.33", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.33.tgz", + "integrity": "sha512-RqshF7TPTE0XLYAqmjlu5cLLuGdKrNu9O1KLA/qp39QtbZwuzwv1dT46DZSopoUMsYgXpB3Cv8a03FI8b74oFQ==", + "dev": true + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + }, + "webdriver": { + "version": "7.16.16", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-7.16.16.tgz", + "integrity": "sha512-x8UoG9k/P8KDrfSh1pOyNevt9tns3zexoMxp9cKnyA/7HYSErhZYTLGlgxscAXLtQG41cMH/Ba/oBmOx7Hgd8w==", + "dev": true, + "requires": { + "@types/node": "^17.0.4", + "@wdio/config": "7.16.16", + "@wdio/logger": "7.16.0", + "@wdio/protocols": "7.16.7", + "@wdio/types": "7.16.14", + "@wdio/utils": "7.16.14", + "got": "^11.0.2", + "ky": "^0.29.0", + "lodash.merge": "^4.6.1" + } + }, + "webdriverio": { + "version": "7.16.16", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.16.16.tgz", + "integrity": "sha512-caPaEWyuD3Qoa7YkW4xCCQA4v9Pa9wmhFGPvNZh3ERtjMCNi8L/XXOdkekWNZmFh3tY0kFguBj7+fAwSY7HAGw==", + "dev": true, + "requires": { + "@types/aria-query": "^5.0.0", + "@types/node": "^17.0.4", + "@wdio/config": "7.16.16", + "@wdio/logger": "7.16.0", + "@wdio/protocols": "7.16.7", + "@wdio/repl": "7.16.14", + "@wdio/types": "7.16.14", + "@wdio/utils": "7.16.14", + "archiver": "^5.0.0", + "aria-query": "^5.0.0", + "css-shorthand-properties": "^1.1.1", + "css-value": "^0.0.1", + "devtools": "7.16.16", + "devtools-protocol": "^0.0.973690", + "fs-extra": "^10.0.0", + "get-port": "^5.1.1", + "grapheme-splitter": "^1.0.2", + "lodash.clonedeep": "^4.5.0", + "lodash.isobject": "^3.0.2", + "lodash.isplainobject": "^4.0.6", + "lodash.zip": "^4.2.0", + "minimatch": "^5.0.0", + "puppeteer-core": "^13.1.3", + "query-selector-shadow-dom": "^1.0.0", + "resq": "^1.9.1", + "rgb2hex": "0.2.5", + "serialize-error": "^8.0.0", + "webdriver": "7.16.16" + } + } } }, "@wdio/cli": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-7.16.16.tgz", - "integrity": "sha512-Wz/e5zm1UNHB9RAIsJIM7ioDzVllUwTvhVWOrI7HR/53GmO/cIvAVjpnlglizJNgK8WlbnM/cKNVIXxqxrnFmw==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-7.5.7.tgz", + "integrity": "sha512-nOQJLskrY+UECDd3NxE7oBzb6cDA7e7x02YWQugOlOgnZ4a+PJmkFoSsO8C2uNCpdFngy5rJKGUo5vbtAHEF9Q==", "dev": true, "requires": { "@types/ejs": "^3.0.5", "@types/fs-extra": "^9.0.4", - "@types/inquirer": "^8.1.2", + "@types/inquirer": "^7.3.1", "@types/lodash.flattendeep": "^4.4.6", "@types/lodash.pickby": "^4.6.6", "@types/lodash.union": "^4.6.6", - "@types/node": "^17.0.4", "@types/recursive-readdir": "^2.2.0", - "@wdio/config": "7.16.16", - "@wdio/logger": "7.16.0", - "@wdio/types": "7.16.14", - "@wdio/utils": "7.16.14", + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", "async-exit-hook": "^2.0.1", "chalk": "^4.0.0", "chokidar": "^3.0.0", "cli-spinners": "^2.1.0", "ejs": "^3.0.1", "fs-extra": "^10.0.0", - "inquirer": "8.1.5", + "inquirer": "^8.0.0", "lodash.flattendeep": "^4.4.0", "lodash.pickby": "^4.6.0", "lodash.union": "^4.6.0", "mkdirp": "^1.0.4", "recursive-readdir": "^2.2.2", - "webdriverio": "7.16.16", + "webdriverio": "7.5.7", "yargs": "^17.0.0", "yarn-install": "^1.0.0" }, "dependencies": { + "@types/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", + "dev": true + }, + "@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + } + }, + "@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "requires": { + "got": "^11.8.1" + } + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -24480,6 +27441,16 @@ "color-convert": "^2.0.1" } }, + "aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + } + }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -24490,6 +27461,31 @@ "supports-color": "^7.1.0" } }, + "chrome-launcher": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.13.4.tgz", + "integrity": "sha512-nnzXiDbGKjDSK6t2I+35OAPBy5Pw/39bgkb/ZAFwMhwJbdYBp6aH+vW28ZgtjdU890Q7D+3wN/tB8N66q5Gi2A==", + "dev": true, + "requires": { + "@types/node": "*", + "escape-string-regexp": "^1.0.5", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0", + "mkdirp": "^0.5.3", + "rimraf": "^3.0.2" + }, + "dependencies": { + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + } + } + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -24505,6 +27501,65 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "devtools": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.5.7.tgz", + "integrity": "sha512-+kqmvFbceElhYpN35yjm1T4Rz3VbH0QaqrNWKRpeyFp657Y5W0bm1s5FyMUeIv0aTNkAgWcETtqL+EG9X9uvjQ==", + "dev": true, + "requires": { + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/protocols": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", + "chrome-launcher": "^0.13.1", + "edge-paths": "^2.1.0", + "puppeteer-core": "^9.1.0", + "query-selector-shadow-dom": "^1.0.0", + "ua-parser-js": "^0.7.21", + "uuid": "^8.0.0" + } + }, + "devtools-protocol": { + "version": "0.0.878340", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.878340.tgz", + "integrity": "sha512-W0q8Y02r1RNwfZtI4Jjh1/MZxRHyrIgy9FvElbJzQelZjmNH197H4mBQs7DZjlUUDA9s6Zz2jl+zUYFgLgEnzw==", + "dev": true + }, + "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 + }, + "puppeteer-core": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-9.1.1.tgz", + "integrity": "sha512-zbedbitVIGhmgz0nt7eIdLsnaoVZSlNJfBivqm2w67T8LR2bU1dvnruDZ8nQO0zn++Iet7zHbAOdnuS5+H2E7A==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "devtools-protocol": "0.0.869402", + "extract-zip": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "pkg-dir": "^4.2.0", + "progress": "^2.0.1", + "proxy-from-env": "^1.1.0", + "rimraf": "^3.0.2", + "tar-fs": "^2.0.0", + "unbzip2-stream": "^1.3.3", + "ws": "^7.2.3" + }, + "dependencies": { + "devtools-protocol": { + "version": "0.0.869402", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.869402.tgz", + "integrity": "sha512-VvlVYY+VDJe639yHs5PHISzdWTLL3Aw8rO4cvUtwvoxFd6FHbE4OpHHcde52M6096uYYazAmd4l0o5VuFRO2WA==", + "dev": true + } + } + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -24514,13 +27569,62 @@ "has-flag": "^4.0.0" } }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + }, + "webdriverio": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.5.7.tgz", + "integrity": "sha512-TLluVPLo6Snn/dxEITvMz7ZuklN4qZOBddDuLb9LO3rhsfKDMNbnhcBk0SLdFsWny0aCuhWNpJ6co93702XC0A==", + "dev": true, + "requires": { + "@types/aria-query": "^4.2.1", + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/protocols": "7.5.3", + "@wdio/repl": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", + "archiver": "^5.0.0", + "aria-query": "^4.2.2", + "atob": "^2.1.2", + "css-shorthand-properties": "^1.1.1", + "css-value": "^0.0.1", + "devtools": "7.5.7", + "devtools-protocol": "^0.0.878340", + "fs-extra": "^10.0.0", + "get-port": "^5.1.1", + "grapheme-splitter": "^1.0.2", + "lodash.clonedeep": "^4.5.0", + "lodash.isobject": "^3.0.2", + "lodash.isplainobject": "^4.0.6", + "lodash.zip": "^4.2.0", + "minimatch": "^3.0.4", + "puppeteer-core": "^9.1.0", + "query-selector-shadow-dom": "^1.0.0", + "resq": "^1.9.1", + "rgb2hex": "0.2.5", + "serialize-error": "^8.0.0", + "webdriver": "7.5.3" + } + }, + "ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "requires": {} + }, "yargs": { - "version": "17.3.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz", - "integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==", + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", + "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", "dev": true, "requires": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", @@ -24532,17 +27636,26 @@ } }, "@wdio/concise-reporter": { - "version": "7.16.14", - "resolved": "https://registry.npmjs.org/@wdio/concise-reporter/-/concise-reporter-7.16.14.tgz", - "integrity": "sha512-CR+9+skJ3mXPIdRo0AnIJTJHOArrWdKlXTnyZ/DD6M9VrNk5aiTWQyphT/IeHV5+fxjHlMNIf/KgIhj1ewschQ==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@wdio/concise-reporter/-/concise-reporter-7.5.7.tgz", + "integrity": "sha512-964i7eQ4sboSla2bdR8714Er82QBgS6u39GmDFX8Izy9Ge38xaE75HuF5S7mnOWGzSojCWgqtwy5k7Rfg6GE3g==", "dev": true, "requires": { - "@wdio/reporter": "7.16.14", - "@wdio/types": "7.16.14", + "@wdio/reporter": "7.5.7", + "@wdio/types": "7.5.3", "chalk": "^4.0.0", "pretty-ms": "^7.0.0" }, "dependencies": { + "@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "requires": { + "got": "^11.8.1" + } + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -24577,6 +27690,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "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 + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -24589,31 +27708,175 @@ } }, "@wdio/config": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-7.16.16.tgz", - "integrity": "sha512-K/ObPuo6Da2liz++OKOIfbdpFwI7UWiFcBylfJkCYbweuXCoW1aUqlKI6rmKPwCH9Uqr/RHWu6p8eo0zWe6xVA==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-7.5.3.tgz", + "integrity": "sha512-udvVizYoilOxuWj/BmoN6y7ZCd4wPdYNlSfWznrbCezAdaLZ4/pNDOO0WRWx2C4+q1wdkXZV/VuQPUGfL0lEHQ==", "dev": true, "requires": { - "@wdio/logger": "7.16.0", - "@wdio/types": "7.16.14", + "@wdio/logger": "7.5.3", + "@wdio/types": "7.5.3", "deepmerge": "^4.0.0", "glob": "^7.1.2" + }, + "dependencies": { + "@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + } + }, + "@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "requires": { + "got": "^11.8.1" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "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 + }, + "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 + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "@wdio/local-runner": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-7.16.16.tgz", - "integrity": "sha512-AJaOyM842PWgMffrrXyHJjouVseLHoiL5U1sw2VVproi3ORWHbltl1AMnreU/lrGu9L0CVKHYT1pxu5UbSOCxQ==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-7.5.7.tgz", + "integrity": "sha512-aYc0XUV+/e3cg8Fp+CWlC4FbwSSG3mKAv1iuy/+Hwzg2kJE+aa+Rf2p2BQYc7HPRtKNW0bM8o+aCImZLAiPM+A==", "dev": true, "requires": { "@types/stream-buffers": "^3.0.3", - "@wdio/logger": "7.16.0", - "@wdio/repl": "7.16.14", - "@wdio/runner": "7.16.16", - "@wdio/types": "7.16.14", + "@wdio/logger": "7.5.3", + "@wdio/repl": "7.5.3", + "@wdio/runner": "7.5.7", + "@wdio/types": "7.5.3", "async-exit-hook": "^2.0.1", - "split2": "^4.0.0", + "split2": "^3.2.2", "stream-buffers": "^3.0.2" + }, + "dependencies": { + "@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + } + }, + "@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "requires": { + "got": "^11.8.1" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "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 + }, + "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 + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "@wdio/logger": { @@ -24662,6 +27925,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "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 + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -24674,19 +27943,46 @@ } }, "@wdio/mocha-framework": { - "version": "7.16.15", - "resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-7.16.15.tgz", - "integrity": "sha512-XRya85/RYPZk4MZ7Cvl3oudTdrOo+RyO8b5Ff+dH8hD3GBCACaWgW9AjbsyhvbSTdUlF0gNLPdqOCsxV5XyM3w==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-7.5.3.tgz", + "integrity": "sha512-96QCVWsiyZxEgOZP3oTq2B2T7zne5dCdehLa2n4q/BLjk96Rj0jifidJZfd/1+vdNPKX0gWWAzpy98Znn8MVMw==", "dev": true, "requires": { - "@types/mocha": "^9.0.0", - "@wdio/logger": "7.16.0", - "@wdio/types": "7.16.14", - "@wdio/utils": "7.16.14", - "expect-webdriverio": "^3.0.0", - "mocha": "^9.0.0" + "@types/mocha": "^8.0.0", + "@wdio/logger": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", + "expect-webdriverio": "^2.0.0", + "mocha": "^8.0.1" }, "dependencies": { + "@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + } + }, + "@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "requires": { + "got": "^11.8.1" + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -24710,17 +28006,33 @@ "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" - }, - "dependencies": { - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } + } + }, + "chokidar": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", + "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.3.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, "color-convert": { @@ -24738,6 +28050,21 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true + }, "escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -24754,10 +28081,30 @@ "path-exists": "^4.0.0" } }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "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 + }, "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", "dev": true, "requires": { "argparse": "^2.0.1" @@ -24773,13 +28120,12 @@ } }, "log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", + "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", "dev": true, "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" + "chalk": "^4.0.0" } }, "minimatch": { @@ -24792,47 +28138,59 @@ } }, "mocha": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.1.tgz", - "integrity": "sha512-T7uscqjJVS46Pq1XDXyo9Uvey9gd3huT/DD9cYBb4K2Xc/vbKRPUWK067bxDQRK0yIz6Jxk73IrnimvASzBNAQ==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.4.0.tgz", + "integrity": "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==", "dev": true, "requires": { "@ungap/promise-all-settled": "1.1.2", "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.3", + "chokidar": "3.5.1", + "debug": "4.3.1", "diff": "5.0.0", "escape-string-regexp": "4.0.0", "find-up": "5.0.0", - "glob": "7.2.0", + "glob": "7.1.6", "growl": "1.10.5", "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", + "js-yaml": "4.0.0", + "log-symbols": "4.0.0", "minimatch": "3.0.4", "ms": "2.1.3", - "nanoid": "3.2.0", - "serialize-javascript": "6.0.0", + "nanoid": "3.1.20", + "serialize-javascript": "5.0.1", "strip-json-comments": "3.1.1", "supports-color": "8.1.1", "which": "2.0.2", - "workerpool": "6.2.0", + "wide-align": "1.1.3", + "workerpool": "6.1.0", "yargs": "16.2.0", "yargs-parser": "20.2.4", "yargs-unparser": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, "nanoid": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", - "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", + "version": "3.1.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz", + "integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==", "dev": true }, "p-limit": { @@ -24853,11 +28211,23 @@ "p-limit": "^3.0.2" } }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true + "readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "serialize-javascript": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", + "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } }, "strip-json-comments": { "version": "3.1.1", @@ -24865,6 +28235,21 @@ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "workerpool": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.0.tgz", + "integrity": "sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==", + "dev": true + }, "yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -24889,72 +28274,288 @@ } }, "@wdio/protocols": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-7.16.7.tgz", - "integrity": "sha512-Wv40pNQcLiPzQ3o98Mv4A8T1EBQ6k4khglz/e2r16CTm+F3DDYh8eLMAsU5cgnmuwwDKX1EyOiFwieykBn5MCg==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-7.5.3.tgz", + "integrity": "sha512-lpNaKwxYhDSL6neDtQQYXvzMAw+u4PXx65ryeMEX82mkARgzSZps5Kyrg9ub7X4T17K1NPfnY6UhZEWg6cKJCg==", "dev": true }, "@wdio/repl": { - "version": "7.16.14", - "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-7.16.14.tgz", - "integrity": "sha512-Ezih0Y+lsGkKv3H3U56hdWgZiQGA3VaAYguSLd9+g1xbQq+zMKqSmfqECD9bAy+OgCCiVTRstES6lHZxJVPhAg==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-7.5.3.tgz", + "integrity": "sha512-jfNJwNoc2nWdnLsFoGHmOJR9zaWfDTBMWM3W1eR5kXIjevD6gAfWsB5ZoA4IdybujCXxdnhlsm4o2jIzp/6f7A==", "dev": true, "requires": { - "@wdio/utils": "7.16.14" + "@wdio/utils": "7.5.3" } }, "@wdio/reporter": { - "version": "7.16.14", - "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-7.16.14.tgz", - "integrity": "sha512-e/I2oGfqjx9+zI4NT/garqxm7Afnos1EcrGSNu75WmP3PNJt4i+9DKkROu4PM6XWcpUB4v2UF7Mv/NrL3TU9aA==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-7.5.7.tgz", + "integrity": "sha512-9PXqZtCXDtU6UYLNDPu9MZQ8BiABGnRlJTrlbYB3gBfZDibMkJMvwXzPderipBv2+ifDZXmGe3Njf1ao2TkbFA==", "dev": true, "requires": { - "@types/diff": "^5.0.0", - "@types/node": "^17.0.4", - "@types/object-inspect": "^1.8.0", - "@types/supports-color": "^8.1.0", - "@types/tmp": "^0.2.0", - "@wdio/types": "7.16.14", - "diff": "^5.0.0", - "fs-extra": "^10.0.0", - "object-inspect": "^1.10.3", - "supports-color": "8.1.1" + "@wdio/types": "7.5.3", + "fs-extra": "^10.0.0" + }, + "dependencies": { + "@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "requires": { + "got": "^11.8.1" + } + } } }, "@wdio/runner": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-7.16.16.tgz", - "integrity": "sha512-Tt2ja6GukGPq1m98WP26yOWUGwzK1y7gPTLy6rKlamz3mOBC7koL0T9+iqcFREquUe4CMy2jWp1lqvPlwMbu7g==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-7.5.7.tgz", + "integrity": "sha512-RzVXd+xnwK/thkx1/xo9K5iscQ0Ofobgsx5dNVtwLDVMn9V7jCW/WX4dSCPAPaVSqnUCmkcQp3P5AoSBPpCZnQ==", "dev": true, "requires": { - "@wdio/config": "7.16.16", - "@wdio/logger": "7.16.0", - "@wdio/types": "7.16.14", - "@wdio/utils": "7.16.14", + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", "deepmerge": "^4.0.0", "gaze": "^1.1.2", - "webdriver": "7.16.16", - "webdriverio": "7.16.16" + "webdriver": "7.5.3", + "webdriverio": "7.5.7" + }, + "dependencies": { + "@types/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", + "dev": true + }, + "@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + } + }, + "@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "requires": { + "got": "^11.8.1" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "chrome-launcher": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.13.4.tgz", + "integrity": "sha512-nnzXiDbGKjDSK6t2I+35OAPBy5Pw/39bgkb/ZAFwMhwJbdYBp6aH+vW28ZgtjdU890Q7D+3wN/tB8N66q5Gi2A==", + "dev": true, + "requires": { + "@types/node": "*", + "escape-string-regexp": "^1.0.5", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0", + "mkdirp": "^0.5.3", + "rimraf": "^3.0.2" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "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 + }, + "devtools": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.5.7.tgz", + "integrity": "sha512-+kqmvFbceElhYpN35yjm1T4Rz3VbH0QaqrNWKRpeyFp657Y5W0bm1s5FyMUeIv0aTNkAgWcETtqL+EG9X9uvjQ==", + "dev": true, + "requires": { + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/protocols": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", + "chrome-launcher": "^0.13.1", + "edge-paths": "^2.1.0", + "puppeteer-core": "^9.1.0", + "query-selector-shadow-dom": "^1.0.0", + "ua-parser-js": "^0.7.21", + "uuid": "^8.0.0" + } + }, + "devtools-protocol": { + "version": "0.0.878340", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.878340.tgz", + "integrity": "sha512-W0q8Y02r1RNwfZtI4Jjh1/MZxRHyrIgy9FvElbJzQelZjmNH197H4mBQs7DZjlUUDA9s6Zz2jl+zUYFgLgEnzw==", + "dev": true + }, + "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 + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "puppeteer-core": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-9.1.1.tgz", + "integrity": "sha512-zbedbitVIGhmgz0nt7eIdLsnaoVZSlNJfBivqm2w67T8LR2bU1dvnruDZ8nQO0zn++Iet7zHbAOdnuS5+H2E7A==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "devtools-protocol": "0.0.869402", + "extract-zip": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "pkg-dir": "^4.2.0", + "progress": "^2.0.1", + "proxy-from-env": "^1.1.0", + "rimraf": "^3.0.2", + "tar-fs": "^2.0.0", + "unbzip2-stream": "^1.3.3", + "ws": "^7.2.3" + }, + "dependencies": { + "devtools-protocol": { + "version": "0.0.869402", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.869402.tgz", + "integrity": "sha512-VvlVYY+VDJe639yHs5PHISzdWTLL3Aw8rO4cvUtwvoxFd6FHbE4OpHHcde52M6096uYYazAmd4l0o5VuFRO2WA==", + "dev": true + } + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + }, + "webdriverio": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.5.7.tgz", + "integrity": "sha512-TLluVPLo6Snn/dxEITvMz7ZuklN4qZOBddDuLb9LO3rhsfKDMNbnhcBk0SLdFsWny0aCuhWNpJ6co93702XC0A==", + "dev": true, + "requires": { + "@types/aria-query": "^4.2.1", + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/protocols": "7.5.3", + "@wdio/repl": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", + "archiver": "^5.0.0", + "aria-query": "^4.2.2", + "atob": "^2.1.2", + "css-shorthand-properties": "^1.1.1", + "css-value": "^0.0.1", + "devtools": "7.5.7", + "devtools-protocol": "^0.0.878340", + "fs-extra": "^10.0.0", + "get-port": "^5.1.1", + "grapheme-splitter": "^1.0.2", + "lodash.clonedeep": "^4.5.0", + "lodash.isobject": "^3.0.2", + "lodash.isplainobject": "^4.0.6", + "lodash.zip": "^4.2.0", + "minimatch": "^3.0.4", + "puppeteer-core": "^9.1.0", + "query-selector-shadow-dom": "^1.0.0", + "resq": "^1.9.1", + "rgb2hex": "0.2.5", + "serialize-error": "^8.0.0", + "webdriver": "7.5.3" + } + }, + "ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "requires": {} + } } }, "@wdio/spec-reporter": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-7.19.1.tgz", - "integrity": "sha512-qnZkn3VcyBPtcorUtpyCFE8v5ubyWmR7mFETXNzyriHyvjvk+NeFCWaFcIehpXYXiAmNpAwyfnZoIY6tkKQixQ==", + "version": "7.19.7", + "resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-7.19.7.tgz", + "integrity": "sha512-BDBZU2EK/GuC9VxtfqPtoW43FmvKxYDsvcDVDi3F7o+9fkcuGSJiWbw1AX251ZzzVQ7YP9ImTitSpdpUKXkilQ==", "dev": true, "requires": { "@types/easy-table": "^0.0.33", - "@wdio/reporter": "7.19.1", - "@wdio/types": "7.19.1", + "@wdio/reporter": "7.19.7", + "@wdio/types": "7.19.5", "chalk": "^4.0.0", "easy-table": "^1.1.1", "pretty-ms": "^7.0.0" }, "dependencies": { "@wdio/reporter": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-7.19.1.tgz", - "integrity": "sha512-sWmBBV4dPCZkGk9Qq0m35T/vHGen0N10nH4osQcVP3IZJqpo2eLIH4w+X6EUbjZ2GdgOA2bLMMzb1bl9JqnGPg==", + "version": "7.19.7", + "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-7.19.7.tgz", + "integrity": "sha512-Dum19gpfru66FnIq78/4HTuW87B7ceLDp6PJXwQM5kXyN7Gb7zhMgp6FZTM0FCYLyi6U/zXZSvpNUYl77caS6g==", "dev": true, "requires": { "@types/diff": "^5.0.0", @@ -24962,17 +28563,46 @@ "@types/object-inspect": "^1.8.0", "@types/supports-color": "^8.1.0", "@types/tmp": "^0.2.0", - "@wdio/types": "7.19.1", + "@wdio/types": "7.19.5", "diff": "^5.0.0", "fs-extra": "^10.0.0", "object-inspect": "^1.10.3", "supports-color": "8.1.1" + } + }, + "@wdio/types": { + "version": "7.19.5", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.19.5.tgz", + "integrity": "sha512-S1lC0pmtEO7NVH/2nM1c7NHbkgxLZH3VVG/z6ym3Bbxdtcqi2LMsEvvawMAU/fmhyiIkMsGZCO8vxG9cRw4z4A==", + "dev": true, + "requires": { + "@types/node": "^17.0.4", + "got": "^11.8.1" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "dependencies": { "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { "has-flag": "^4.0.0" @@ -24980,13 +28610,303 @@ } } }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "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 + }, + "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 + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@wdio/sync": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@wdio/sync/-/sync-7.5.7.tgz", + "integrity": "sha512-Zu/AYLjwqbFSbaOU1US7ownv3ov8JrtoGHq51JfJ4masefJDXNkHix2cZ0qEgl3IvkkWQ0ewL0G8GTXb3KOemA==", + "dev": true, + "requires": { + "@types/fibers": "^3.1.0", + "@types/puppeteer": "^5.4.0", + "@wdio/logger": "7.5.3", + "@wdio/types": "7.5.3", + "fibers": "^5.0.0", + "webdriverio": "7.5.7" + }, + "dependencies": { + "@types/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", + "dev": true + }, + "@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + } + }, + "@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "requires": { + "got": "^11.8.1" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "chrome-launcher": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.13.4.tgz", + "integrity": "sha512-nnzXiDbGKjDSK6t2I+35OAPBy5Pw/39bgkb/ZAFwMhwJbdYBp6aH+vW28ZgtjdU890Q7D+3wN/tB8N66q5Gi2A==", + "dev": true, + "requires": { + "@types/node": "*", + "escape-string-regexp": "^1.0.5", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0", + "mkdirp": "^0.5.3", + "rimraf": "^3.0.2" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "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 + }, + "devtools": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.5.7.tgz", + "integrity": "sha512-+kqmvFbceElhYpN35yjm1T4Rz3VbH0QaqrNWKRpeyFp657Y5W0bm1s5FyMUeIv0aTNkAgWcETtqL+EG9X9uvjQ==", + "dev": true, + "requires": { + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/protocols": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", + "chrome-launcher": "^0.13.1", + "edge-paths": "^2.1.0", + "puppeteer-core": "^9.1.0", + "query-selector-shadow-dom": "^1.0.0", + "ua-parser-js": "^0.7.21", + "uuid": "^8.0.0" + } + }, + "devtools-protocol": { + "version": "0.0.878340", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.878340.tgz", + "integrity": "sha512-W0q8Y02r1RNwfZtI4Jjh1/MZxRHyrIgy9FvElbJzQelZjmNH197H4mBQs7DZjlUUDA9s6Zz2jl+zUYFgLgEnzw==", + "dev": true + }, + "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 + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "puppeteer-core": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-9.1.1.tgz", + "integrity": "sha512-zbedbitVIGhmgz0nt7eIdLsnaoVZSlNJfBivqm2w67T8LR2bU1dvnruDZ8nQO0zn++Iet7zHbAOdnuS5+H2E7A==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "devtools-protocol": "0.0.869402", + "extract-zip": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "pkg-dir": "^4.2.0", + "progress": "^2.0.1", + "proxy-from-env": "^1.1.0", + "rimraf": "^3.0.2", + "tar-fs": "^2.0.0", + "unbzip2-stream": "^1.3.3", + "ws": "^7.2.3" + }, + "dependencies": { + "devtools-protocol": { + "version": "0.0.869402", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.869402.tgz", + "integrity": "sha512-VvlVYY+VDJe639yHs5PHISzdWTLL3Aw8rO4cvUtwvoxFd6FHbE4OpHHcde52M6096uYYazAmd4l0o5VuFRO2WA==", + "dev": true + } + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + }, + "webdriverio": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.5.7.tgz", + "integrity": "sha512-TLluVPLo6Snn/dxEITvMz7ZuklN4qZOBddDuLb9LO3rhsfKDMNbnhcBk0SLdFsWny0aCuhWNpJ6co93702XC0A==", + "dev": true, + "requires": { + "@types/aria-query": "^4.2.1", + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/protocols": "7.5.3", + "@wdio/repl": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", + "archiver": "^5.0.0", + "aria-query": "^4.2.2", + "atob": "^2.1.2", + "css-shorthand-properties": "^1.1.1", + "css-value": "^0.0.1", + "devtools": "7.5.7", + "devtools-protocol": "^0.0.878340", + "fs-extra": "^10.0.0", + "get-port": "^5.1.1", + "grapheme-splitter": "^1.0.2", + "lodash.clonedeep": "^4.5.0", + "lodash.isobject": "^3.0.2", + "lodash.isplainobject": "^4.0.6", + "lodash.zip": "^4.2.0", + "minimatch": "^3.0.4", + "puppeteer-core": "^9.1.0", + "query-selector-shadow-dom": "^1.0.0", + "resq": "^1.9.1", + "rgb2hex": "0.2.5", + "serialize-error": "^8.0.0", + "webdriver": "7.5.3" + } + }, + "ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "requires": {} + } + } + }, + "@wdio/types": { + "version": "7.16.14", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.16.14.tgz", + "integrity": "sha512-AyNI9iBSos9xWBmiFAF3sBs6AJXO/55VppU/eeF4HRdbZMtMarnvMuahM+jlUrA3vJSmDW+ufelG0MT//6vrnw==", + "dev": true, + "requires": { + "@types/node": "^17.0.4", + "got": "^11.8.1" + } + }, + "@wdio/utils": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-7.5.3.tgz", + "integrity": "sha512-nlLDKr8v8abLOHCKroBwQkGPdCIxjID2MllgWX23xqkYZylM9RdwPBdL8osQt9m3rq2TxiPAT4OlbzNt2WtN6Q==", + "dev": true, + "requires": { + "@wdio/logger": "7.5.3", + "@wdio/types": "7.5.3" + }, + "dependencies": { + "@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + } + }, "@wdio/types": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.19.1.tgz", - "integrity": "sha512-mOodKlmvYxpj8P5BhjggEGpXuiRSlsyn2ClG8QqJ3lfXgOtOVEzFNfv/Ai7TkHr+lHDQNXLjllCjSqoCHhwlqg==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", "dev": true, "requires": { - "@types/node": "^17.0.4", "got": "^11.8.1" } }, @@ -25024,6 +28944,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "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 + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -25035,41 +28961,6 @@ } } }, - "@wdio/sync": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/@wdio/sync/-/sync-7.16.16.tgz", - "integrity": "sha512-MbVFAteaAOxHLKkMiMzOnh1hzINAK2U41GDIfy1yaPumcw1pNuJIhWrBYxprNMlqt8srk++wqQWgj5XpFjCL6g==", - "dev": true, - "requires": { - "@types/fibers": "^3.1.0", - "@types/puppeteer": "^5.4.0", - "@wdio/logger": "7.16.0", - "@wdio/types": "7.16.14", - "fibers": "^5.0.0", - "webdriverio": "7.16.16" - } - }, - "@wdio/types": { - "version": "7.16.14", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.16.14.tgz", - "integrity": "sha512-AyNI9iBSos9xWBmiFAF3sBs6AJXO/55VppU/eeF4HRdbZMtMarnvMuahM+jlUrA3vJSmDW+ufelG0MT//6vrnw==", - "dev": true, - "requires": { - "@types/node": "^17.0.4", - "got": "^11.8.1" - } - }, - "@wdio/utils": { - "version": "7.16.14", - "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-7.16.14.tgz", - "integrity": "sha512-wwin8nVpIlhmXJkq6GJw9aDDzgLOJKgXTcEua0T2sdXjoW78u5Ly/GZrFXTjMGhacFvoZfitTrjyfyy4CxMVvw==", - "dev": true, - "requires": { - "@wdio/logger": "7.16.0", - "@wdio/types": "7.16.14", - "p-iteration": "^1.1.8" - } - }, "@webassemblyjs/ast": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", @@ -25217,9 +29108,9 @@ } }, "@xmldom/xmldom": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.6.tgz", - "integrity": "sha512-HHXP9hskkFQHy8QxxUXkS7946FFIhYVfGqsk0WLwllmexN9x/+R4UBLvurHEuyXRfVEObVR8APuQehykLviwSQ==", + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.8.tgz", + "integrity": "sha512-PrJx38EfpitFhwmILRl37jAdBlsww6AZ6rRVK4QS7T7RHLhX7mSs647sTmgr9GIxe3qjXdesmomEgbgaokrVFg==", "dev": true }, "@xtuc/ieee754": { @@ -25237,7 +29128,7 @@ "abbrev": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", - "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", + "integrity": "sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==", "dev": true }, "accepts": { @@ -25262,6 +29153,12 @@ "dev": true, "requires": {} }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + }, "aes-decrypter": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-3.1.3.tgz", @@ -25275,10 +29172,13 @@ } }, "agent-base": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", - "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==", - "dev": true + "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, + "requires": { + "debug": "4" + } }, "ajv": { "version": "6.12.3", @@ -25292,17 +29192,24 @@ "uri-js": "^4.2.2" } }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, "amdefine": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", "dev": true, "optional": true }, "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true }, "ansi-cyan": { @@ -25326,7 +29233,7 @@ "ansi-gray": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", - "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", + "integrity": "sha512-HrgGIZUl8h2EHuZaU9hTR/cU5nhKxpVE1V6kdGsQ8e4zirElJ5fvtfc8N7Q1oq1aatO275i8pUFUCpNWCAnVWw==", "dev": true, "requires": { "ansi-wrap": "0.1.0" @@ -25358,7 +29265,7 @@ "ansi-wrap": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", - "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", + "integrity": "sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==", "dev": true }, "anymatch": { @@ -25374,20 +29281,20 @@ "append-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", - "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=", + "integrity": "sha512-WLbYiXzD3y/ATLZFufV/rZvWdZOs+Z/+5v1rBZ463Jn398pa6kcde27cvozYnBoxXblGZTFfoPpsaEw0orU5BA==", "dev": true, "requires": { "buffer-equal": "^1.0.0" } }, "archiver": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.0.tgz", - "integrity": "sha512-iUw+oDwK0fgNpvveEsdQ0Ase6IIKztBJU2U0E9MzszMfmVVUyv1QJhS2ITW9ZCqx8dktAxVAjWWkKehuZE8OPg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.1.tgz", + "integrity": "sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w==", "dev": true, "requires": { "archiver-utils": "^2.1.0", - "async": "^3.2.0", + "async": "^3.2.3", "buffer-crc32": "^0.2.1", "readable-stream": "^3.6.0", "readdir-glob": "^1.0.0", @@ -25396,9 +29303,9 @@ }, "dependencies": { "async": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", - "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", "dev": true }, "readable-stream": { @@ -25435,7 +29342,7 @@ "archy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", "dev": true }, "argparse": { @@ -25448,21 +29355,36 @@ } }, "aria-query": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.0.0.tgz", - "integrity": "sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg==", - "dev": true + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dev": true, + "requires": { + "deep-equal": "^2.0.5" + } }, "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz", + "integrity": "sha512-OQwDZUqYaQwyyhDJHThmzId8daf4/RFNLaeh3AevmSeZ5Y7ug4Ga/yKc6l6kTZOBW781rCj103ZuTh8GAsB3+Q==", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1", + "array-slice": "^0.2.3" + }, + "dependencies": { + "array-slice": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", + "integrity": "sha512-rlVfZW/1Ph2SNySXwR9QYkChp8EkOEiTMO5Vwx60usw04i4nWemkm9RXmQqgkQFaLHsqLuADvjp6IfgL9l2M8Q==", + "dev": true + } + } }, "arr-filter": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", - "integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=", + "integrity": "sha512-A2BETWCqhsecSvCkWAeVBFLH6sXEUGASuzkpjL3GR1SlL/PWL6M3J8EAAld2Uubmh39tvkJTqC9LeLHCUKmFXA==", "dev": true, "requires": { "make-iterator": "^1.0.0" @@ -25477,50 +29399,50 @@ "arr-map": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", - "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=", + "integrity": "sha512-tVqVTHt+Q5Xb09qRkbu+DidW1yYzz5izWS2Xm2yFm7qJnmUfz4HPzNxbHkdRJbz2lrqI7S+z17xNYdFcBBO8Hw==", "dev": true, "requires": { "make-iterator": "^1.0.0" } }, "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz", + "integrity": "sha512-t5db90jq+qdgk8aFnxEkjqta0B/GHrM1pxzuuZz2zWsOXc5nKu3t+76s/PQBA8FTcM/ipspIH9jWG4OxCBc2eA==", "dev": true }, "array-differ": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", - "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", + "integrity": "sha512-LeZY+DZDRnvP7eMuQ6LHfCzUGxAAIViUBliK24P3hWXL6y4SortgR6Nim6xrkfSLlmH0+k+9NYNwVC2s53ZrYQ==", "dev": true }, "array-each": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", - "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", + "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", "dev": true }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, "array-from": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", - "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", + "integrity": "sha512-GQTc6Uupx1FCavi5mPzBvVT7nEOeWMmUA9P95wpfpW1XwMSKs+KaymD5C2Up7KAUKg/mYwbsUYzdZWcoajlNZg==", "dev": true }, "array-includes": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", - "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", + "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5", "get-intrinsic": "^1.1.1", "is-string": "^1.0.7" } @@ -25528,7 +29450,7 @@ "array-initial": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", - "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=", + "integrity": "sha512-BC4Yl89vneCYfpLrs5JU2aAu9/a+xWbeKhvISg9PT7eWFB9UlRvI+rKEtk6mgxWr3dSkk9gQ8hCrdqt06NXPdw==", "dev": true, "requires": { "array-slice": "^1.0.0", @@ -25580,24 +29502,25 @@ "array-uniq": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", "dev": true }, "array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", "dev": true }, "array.prototype.flat": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", - "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", + "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" } }, "asn1": { @@ -25624,7 +29547,7 @@ "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "dev": true }, "assertion-error": { @@ -25636,7 +29559,7 @@ "assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", "dev": true }, "astral-regex": { @@ -25648,7 +29571,7 @@ "async": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "integrity": "sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==", "dev": true }, "async-done": { @@ -25678,7 +29601,7 @@ "async-settle": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", - "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=", + "integrity": "sha512-VPXfB4Vk49z1LHHodrEQ6Xf7W4gg1w0dAPROHngx7qgDjqmIQ+fXmwgGXTW/ITLai0YLSvWepJOP9EVpMnEAcw==", "dev": true, "requires": { "async-done": "^1.2.2" @@ -25687,7 +29610,7 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, "atob": { @@ -25705,7 +29628,7 @@ "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", "dev": true }, "aws4": { @@ -25717,7 +29640,7 @@ "babel-code-frame": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "integrity": "sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -25728,19 +29651,19 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true }, "ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "requires": { "ansi-styles": "^2.2.1", @@ -25753,13 +29676,13 @@ "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "integrity": "sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==", "dev": true }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "requires": { "ansi-regex": "^2.0.0" @@ -25768,7 +29691,7 @@ "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true } } @@ -25812,19 +29735,13 @@ "json5": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "integrity": "sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw==", "dev": true }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true } } @@ -25845,19 +29762,10 @@ "trim-right": "^1.0.1" }, "dependencies": { - "detect-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", - "dev": true, - "requires": { - "repeating": "^2.0.0" - } - }, "jsesc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", - "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "integrity": "sha512-Mke0DA0QjUWuJlhsE0ZPPhYiJkRap642SmI/4ztCFaUs6V2AiH1sfecc+57NgaryfAA2VR3v6O+CSjC1jZJKOA==", "dev": true } } @@ -25865,7 +29773,7 @@ "babel-helpers": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", - "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "integrity": "sha512-n7pFrqQm44TCYvrCDb0MqabAF+JUBq+ijBvNMUxpkLjJaAu32faIexewMumrH5KLLJ1HDyT0PTEqRyAe/GwwuQ==", "dev": true, "requires": { "babel-runtime": "^6.22.0", @@ -25873,56 +29781,26 @@ } }, "babel-loader": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.3.tgz", - "integrity": "sha512-n4Zeta8NC3QAsuyiizu0GkmRcQ6clkV9WFUnUf1iXP//IeSKbWjofW3UHyZVwlOB4y039YQKefawyTn64Zwbuw==", + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", + "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", "dev": true, "requires": { "find-cache-dir": "^3.3.1", - "loader-utils": "^1.4.0", + "loader-utils": "^2.0.0", "make-dir": "^3.1.0", "schema-utils": "^2.6.5" - }, - "dependencies": { - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - }, - "loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" - } - } } }, "babel-messages": { "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "integrity": "sha512-Bl3ZiA+LjqaMtNYopA9TYE9HP1tQ+E5dLxE0XrAzcIJeK2UqF0/EaqXwBn9esd4UmTfEab+P+UYQ1GnioFIb/w==", "dev": true, "requires": { "babel-runtime": "^6.22.0" } }, - "babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "requires": { - "object.assign": "^4.1.0" - } - }, "babel-plugin-istanbul": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", @@ -25934,54 +29812,39 @@ "@istanbuljs/schema": "^0.1.2", "istanbul-lib-instrument": "^5.0.4", "test-exclude": "^6.0.0" - }, - "dependencies": { - "istanbul-lib-instrument": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", - "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - } - } } }, "babel-plugin-polyfill-corejs2": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", - "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", "requires": { - "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.3.1", + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", "semver": "^6.1.1" } }, "babel-plugin-polyfill-corejs3": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", - "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", + "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.1", - "core-js-compat": "^3.21.0" + "@babel/helper-define-polyfill-provider": "^0.3.3", + "core-js-compat": "^3.25.1" } }, "babel-plugin-polyfill-regenerator": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", - "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.1" + "@babel/helper-define-polyfill-provider": "^0.3.3" } }, "babel-register": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", - "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", + "integrity": "sha512-veliHlHX06wjaeY8xNITbveXSiI+ASFnOqvne/LaIJIqOWi2Ogmj91KOugEz/hoh/fwMhXNBJPCv8Xaz5CyM4A==", "dev": true, "requires": { "babel-core": "^6.26.0", @@ -26007,22 +29870,13 @@ "requires": { "minimist": "^1.2.6" } - }, - "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "dev": true, - "requires": { - "source-map": "^0.5.6" - } } } }, "babel-runtime": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==", "dev": true, "requires": { "core-js": "^2.4.0", @@ -26034,13 +29888,19 @@ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", "dev": true + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true } } }, "babel-template": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", - "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "integrity": "sha512-PCOcLFW7/eazGUKIoqH97sO9A2UYMahsn/yRQ7uOk37iutwjq7ODtcTNF+iFDSHNfkctqsLRjLP7URnOx0T1fg==", "dev": true, "requires": { "babel-runtime": "^6.26.0", @@ -26053,7 +29913,7 @@ "babel-traverse": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "integrity": "sha512-iSxeXx7apsjCHe9c7n8VtRXGzI2Bk1rBSOJgCCjfyXb6v1aCqE1KSEpq/8SXuVN8Ka/Rh1WDTF0MDzkvTA4MIA==", "dev": true, "requires": { "babel-code-frame": "^6.26.0", @@ -26085,7 +29945,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true } } @@ -26093,7 +29953,7 @@ "babel-types": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "integrity": "sha512-zhe3V/26rCWsEZK8kZN+HaQj5yQ1CilTObixFzKW1UWjqG7618Twz6YEsCnjfg5gBcJh02DrpCkS9h98ZqDY+g==", "dev": true, "requires": { "babel-runtime": "^6.26.0", @@ -26105,7 +29965,7 @@ "to-fast-properties": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "integrity": "sha512-lxrWP8ejsq+7E3nNjwYmUBMAgjMTZoTI+sdBOpvNyijeDLa29LUn9QaoXAHv4+Z578hbmHHJKZknzxVtvo77og==", "dev": true } } @@ -26119,7 +29979,7 @@ "bach": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", - "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=", + "integrity": "sha512-bZOOfCb3gXBXbTFXq3OZtGR88LwGeJvzu6szttaIzymOTS4ZttBNOWSv7aLZja2EMycKtRYV0Oa8SNKH/zkxvg==", "dev": true, "requires": { "arr-filter": "^1.1.1", @@ -26163,7 +30023,7 @@ "define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, "requires": { "is-descriptor": "^1.0.0" @@ -26190,18 +30050,26 @@ "dev": true, "requires": { "safe-buffer": "5.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } } }, "batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", "dev": true }, "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", "dev": true, "requires": { "tweetnacl": "^0.14.3" @@ -26210,7 +30078,7 @@ "beeper": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", - "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=", + "integrity": "sha512-3vqtKL1N45I5dV0RdssXZG7X6pCqQrWPNOlBPZPrd+QkE2HEhR57Z04m0KtpbsZH73j+a3F8UD1TQnn+ExTvIA==", "dev": true }, "big-integer": { @@ -26228,7 +30096,7 @@ "binary": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", - "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=", + "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", "dev": true, "requires": { "buffers": "~0.1.1", @@ -26284,13 +30152,13 @@ "bluebird": { "version": "3.4.7", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", - "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=", + "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", "dev": true }, "body": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/body/-/body-5.1.0.tgz", - "integrity": "sha1-5LoM5BCkaTYyM2dgnstOZVMSUGk=", + "integrity": "sha512-chUsBxGRtuElD6fmw1gHLpvnKdVLK302peeFa9ZqAEk8TyzZ3fygLyUEDDPTJvL9+Bor0dIwn6ePOsRM2y0zQQ==", "dev": true, "requires": { "continuable-cache": "^0.3.1", @@ -26302,13 +30170,13 @@ "bytes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz", - "integrity": "sha1-NWnt6Lo0MV+rmcPpLLBMciDeH6g=", + "integrity": "sha512-/x68VkHLeTl3/Ll8IvxdwzhrT+IyKc52e/oyHhA2RwqPqswSnjVbSddfPRwAsJtbilMAPSRWwAlpxdYsSWOTKQ==", "dev": true }, "raw-body": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz", - "integrity": "sha1-HQJ8K/oRasxmI7yo8AAWVyqH1CU=", + "integrity": "sha512-WmJJU2e9Y6M5UzTOkHaM7xJGAPQD8PNzx3bAd2+uhZAim6wDk6dAZxPVYLF67XhbR4hmKGh33Lpmh4XWrCH5Mg==", "dev": true, "requires": { "bytes": "1", @@ -26318,26 +30186,28 @@ "string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", "dev": true } } }, "body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", "requires": { "bytes": "3.1.2", "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.8.1", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.9.7", - "raw-body": "2.4.3", - "type-is": "~1.6.18" + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" }, "dependencies": { "debug": { @@ -26351,7 +30221,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" } } }, @@ -26381,14 +30251,14 @@ "dev": true }, "browserslist": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", - "integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==", + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", "requires": { - "caniuse-lite": "^1.0.30001370", - "electron-to-chromium": "^1.4.202", + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.5" + "update-browserslist-db": "^1.0.9" } }, "browserstack": { @@ -26431,21 +30301,22 @@ } }, "browserstack-local": { - "version": "1.4.9", - "resolved": "https://registry.npmjs.org/browserstack-local/-/browserstack-local-1.4.9.tgz", - "integrity": "sha512-V+q8HQwRQFr9nd32xR66ZZ3VDWa3Kct4IMMudhKgcuD7cWrvvFARZOibx71II+Rf7P5nMQpWWxl9z/3p927nbg==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/browserstack-local/-/browserstack-local-1.5.1.tgz", + "integrity": "sha512-T/wxyWDzvBHbDvl7fZKpFU7mYze6nrUkBhNy+d+8bXBqgQX10HTYvajIGO0wb49oGSLCPM0CMZTV/s7e6LF0sA==", "dev": true, "requires": { - "https-proxy-agent": "^4.0.0", + "agent-base": "^6.0.2", + "https-proxy-agent": "^5.0.1", "is-running": "^2.1.0", "ps-tree": "=1.2.0", "temp-fs": "^0.9.9" } }, "browserstacktunnel-wrapper": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/browserstacktunnel-wrapper/-/browserstacktunnel-wrapper-2.0.4.tgz", - "integrity": "sha512-GCV599FUUxNOCFl3WgPnfc5dcqq9XTmMXoxWpqkvmk0R9TOIoqmjENNU6LY6DtgIL6WfBVbg/jmWtnM5K6UYSg==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/browserstacktunnel-wrapper/-/browserstacktunnel-wrapper-2.0.5.tgz", + "integrity": "sha512-oociT3nl+FhQnyJbAb1RM4oQ5pN7aKeXEURkTkiEVm/Rji2r0agl3Wbw5V23VFn9lCU5/fGyDejRZPtGYsEcFw==", "dev": true, "requires": { "https-proxy-agent": "^2.2.1", @@ -26495,13 +30366,13 @@ "buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true }, "buffer-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", - "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.1.tgz", + "integrity": "sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg==", "dev": true }, "buffer-from": { @@ -26519,7 +30390,7 @@ "buffers": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", - "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=", + "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", "dev": true }, "bytes": { @@ -26530,7 +30401,7 @@ "cac": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/cac/-/cac-3.0.4.tgz", - "integrity": "sha1-bSTO7Dcu/lybeYgIvH9JtHJCpO8=", + "integrity": "sha512-hq4rxE3NT5PlaEiVV39Z45d6MoFcQZG5dsgJqtAUeOz3408LEQAElToDkf9i5IYSCOmK0If/81dLg7nKxqPR0w==", "dev": true, "requires": { "camelcase-keys": "^3.0.0", @@ -26545,35 +30416,19 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true }, "ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true }, - "camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", - "dev": true - }, - "camelcase-keys": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-3.0.0.tgz", - "integrity": "sha1-/AxsNgNj9zd+N5O5oWvM8QcMHKQ=", - "dev": true, - "requires": { - "camelcase": "^3.0.0", - "map-obj": "^1.0.0" - } - }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "requires": { "ansi-styles": "^2.2.1", @@ -26586,23 +30441,35 @@ "find-up": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", "dev": true, "requires": { "path-exists": "^2.0.0", "pinkie-promise": "^2.0.0" } }, - "indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, "path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", "dev": true, "requires": { "pinkie-promise": "^2.0.0" @@ -26611,7 +30478,7 @@ "read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", "dev": true, "requires": { "load-json-file": "^1.0.0", @@ -26622,17 +30489,23 @@ "read-pkg-up": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", "dev": true, "requires": { "find-up": "^1.0.0", "read-pkg": "^1.0.0" } }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "requires": { "ansi-regex": "^2.0.0" @@ -26641,7 +30514,7 @@ "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true } } @@ -26716,6 +30589,24 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, + "camelcase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-3.0.0.tgz", + "integrity": "sha512-U4E6A6aFyYnNW+tDt5/yIUKQURKXe3WMFPfX4FxrQFcwZ/R08AUk1xWcUtlr7oq6CV07Ji+aa69V2g7BSpblnQ==", + "dev": true, + "requires": { + "camelcase": "^3.0.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", + "dev": true + } + } + }, "can-autoplay": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/can-autoplay/-/can-autoplay-3.0.2.tgz", @@ -26723,14 +30614,14 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001390", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001390.tgz", - "integrity": "sha512-sS4CaUM+/+vqQUlCvCJ2WtDlV81aWtHhqeEVkLokVJJa3ViN4zDxAGfq9R8i1m90uGHxo99cy10Od+lvn3hf0g==" + "version": "1.0.30001429", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001429.tgz", + "integrity": "sha512-511ThLu1hF+5RRRt0zYCf2U2yRr9GPF6m5y90SBCWsvSoYoW7yAGlv/elyPaNfvGCkp6kj/KFZWU0BMA69Prsg==" }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", "dev": true }, "ccount": { @@ -26757,7 +30648,7 @@ "chainsaw": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", - "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=", + "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", "dev": true, "requires": { "traverse": ">=0.3.0 <0.4" @@ -26771,21 +30662,6 @@ "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" - }, - "dependencies": { - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } } }, "character-entities": { @@ -26815,7 +30691,7 @@ "check-error": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", "dev": true }, "chokidar": { @@ -26841,9 +30717,9 @@ "dev": true }, "chrome-launcher": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.0.tgz", - "integrity": "sha512-ZQqX5kb9H0+jy1OqLnWampfocrtSZaGl7Ny3F9GRha85o4odbL8x55paUzh51UC7cEmZ5obp3H2Mm70uC2PpRA==", + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.1.tgz", + "integrity": "sha512-UugC8u59/w2AyX5sHLZUHoxBAiSiunUhZa3zZwMH6zPVis0C3dDKiRWyUGIo14tTbZHGVviWxv3PQWZ7taZ4fg==", "dev": true, "requires": { "@types/node": "*", @@ -26878,10 +30754,16 @@ "static-extend": "^0.1.1" }, "dependencies": { + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true + }, "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "requires": { "is-descriptor": "^0.1.0" @@ -26890,7 +30772,7 @@ "is-accessor-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -26899,7 +30781,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -26916,7 +30798,7 @@ "is-data-descriptor": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -26925,7 +30807,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -26956,9 +30838,9 @@ } }, "cli-spinners": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", - "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", + "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==", "dev": true }, "cli-width": { @@ -26968,32 +30850,32 @@ "dev": true }, "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "requires": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "clone": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", "dev": true }, "clone-buffer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", - "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=", + "integrity": "sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==", "dev": true }, "clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", "dev": true, "requires": { "mimic-response": "^1.0.0" @@ -27002,7 +30884,7 @@ "clone-stats": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", - "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", + "integrity": "sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==", "dev": true }, "cloneable-readable": { @@ -27019,13 +30901,13 @@ "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", "dev": true }, "collection-map": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", - "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=", + "integrity": "sha512-5D2XXSpkOnleOI21TG7p3T0bGAsZ/XknZpKBmGYyluO8pw4zA3K8ZlrBIbC4FXg3m6z/RNFiUFfT2sQK01+UHA==", "dev": true, "requires": { "arr-map": "^2.0.2", @@ -27036,7 +30918,7 @@ "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", "dev": true, "requires": { "map-visit": "^1.0.0", @@ -27054,7 +30936,7 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "color-support": { "version": "1.1.3", @@ -27083,10 +30965,16 @@ "integrity": "sha512-G5yTt3KQN4Yn7Yk4ed73hlZ1evrFKXeUW3086p3PRFNp7m2vIjI6Pg+Kgb+oyzhd9F2qdcoj67+y3SdxL5XWsg==", "dev": true }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", "dev": true }, "component-emitter": { @@ -27123,7 +31011,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, "concat-stream": { @@ -27176,10 +31064,40 @@ "ms": "2.0.0" } }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true } } @@ -27196,13 +31114,6 @@ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "requires": { "safe-buffer": "5.2.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - } } }, "content-type": { @@ -27213,31 +31124,28 @@ "continuable-cache": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz", - "integrity": "sha1-vXJ6f67XfnH/OYWskzUakSczrQ8=", + "integrity": "sha512-TF30kpKhTH8AGCG3dut0rdd/19B7Z+qCnrMoBLpyQu/2drZdNrrpcjPEoJeSVsQM+8KmWG5O56oPDjSSUsuTyA==", "dev": true }, "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "requires": { - "safe-buffer": "~5.1.1" - } + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" }, "cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" }, "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, "copy-descriptor": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", "dev": true }, "copy-props": { @@ -27251,30 +31159,22 @@ } }, "core-js": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.21.1.tgz", - "integrity": "sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig==" + "version": "3.26.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.26.0.tgz", + "integrity": "sha512-+DkDrhoR4Y0PxDz6rurahuB+I45OsEUv8E1maPTB6OuHRohMMcznBq9TMpdpDMm/hUPob/mJJS3PqgbHpMTQgw==" }, "core-js-compat": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.1.tgz", - "integrity": "sha512-gbgX5AUvMb8gwxC7FLVWYT7Kkgu/y7+h/h1X43yJkNqhlK2fuYyQimqvKGNZFAY6CKii/GFKJ2cp/1/42TN36g==", + "version": "3.26.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.26.0.tgz", + "integrity": "sha512-piOX9Go+Z4f9ZiBFLnZ5VrOpBl0h7IGCkiFUN11QTe6LjAvOT3ifL/5TdoizMh99hcGy5SoLyWbapIY/PIb/3A==", "requires": { - "browserslist": "^4.19.1", - "semver": "7.0.0" - }, - "dependencies": { - "semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==" - } + "browserslist": "^4.21.4" } }, "core-js-pure": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.21.1.tgz", - "integrity": "sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ==" + "version": "3.26.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.26.0.tgz", + "integrity": "sha512-LiN6fylpVBVwT8twhhluD9TzXmZQQsr2I2eIKtWNbZI1XMfBT7CV18itaN6RA7EtQd/SDdRx/wzvAShX2HvhQA==" }, "core-util-is": { "version": "1.0.3", @@ -27306,14 +31206,10 @@ } }, "crc-32": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.1.tgz", - "integrity": "sha512-Dn/xm/1vFFgs3nfrpEVScHoIslO9NZRITWGz/1E/St6u4xw99vfZzVkW0OSnzx2h9egej9xwMCEut6sqwokM/w==", - "dev": true, - "requires": { - "exit-on-epipe": "~1.0.1", - "printj": "~1.3.1" - } + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true }, "crc32-stream": { "version": "4.0.2", @@ -27396,13 +31292,13 @@ "css-value": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/css-value/-/css-value-0.0.1.tgz", - "integrity": "sha1-Xv1sLupeof1rasV+wEJ7GEUkJOo=", + "integrity": "sha512-FUV3xaJ63buRLgHrLQVlVgQnQdR4yqdLGaDu7g8CQcWjInDfM9plBTPI9FRfpahju1UBSaMckeb2/46ApS/V1Q==", "dev": true }, "custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", - "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", "dev": true }, "d": { @@ -27418,22 +31314,22 @@ "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", "dev": true, "requires": { "assert-plus": "^1.0.0" } }, "date-format": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.4.tgz", - "integrity": "sha512-/jyf4rhB17ge328HJuJjAcmRtCsGd+NDeAtahRBTaK6vSPR6MO5HlrAit3Nn7dVjaa6sowW0WXt8yQtLyZQFRg==", + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", + "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", "dev": true }, "dateformat": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", - "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=", + "integrity": "sha512-GODcnWq3YGoTnygPfi02ygEiRxqUxpJwuRHjdhJYuxpcZmDq4rjBiXYmbCCzStxo176ixfLT6i4NPwQooRySnw==", "dev": true }, "de-indent": { @@ -27444,9 +31340,9 @@ "optional": true }, "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "requires": { "ms": "2.1.2" } @@ -27474,9 +31370,9 @@ } }, "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", "dev": true }, "decode-named-character-reference": { @@ -27489,9 +31385,9 @@ } }, "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", "dev": true }, "decompress-response": { @@ -27567,13 +31463,13 @@ "default-resolution": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", - "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=", + "integrity": "sha512-2xaP6GiwVwOEbXCGoJ4ufgC76m8cj805jrghScewJC2ZDsb9U0b4BIrba+xt/Uytyd0HvQ6+WymSRTfnYj59GQ==", "dev": true }, "defaults": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", "dev": true, "requires": { "clone": "^1.0.2" @@ -27582,7 +31478,7 @@ "clone": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "dev": true } } @@ -27594,11 +31490,13 @@ "dev": true }, "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dev": true, "requires": { - "object-keys": "^1.0.12" + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" } }, "define-property": { @@ -27614,13 +31512,13 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true }, "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" }, "dequal": { "version": "2.0.3", @@ -27629,85 +31527,232 @@ "dev": true }, "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" }, "detect-file": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", "dev": true }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha512-BDKtmHlOzwI7iRuEkhzsnPoi5ypEhWAJB5RvHWe1kMr06js3uK5B3734i3ui5Yd+wOJV1cpE4JnivPD283GU/A==", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + }, "detect-libc": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", "dev": true }, "detect-newline": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", - "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", + "integrity": "sha512-CwffZFvlJffUg9zZA0uqrjQayUTC8ob94pnr5sFwaVv3IOmkfUHcWH+jXaQK3askE51Cqe8/9Ql/0uXNwqZ8Zg==", "dev": true }, "devtools": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.16.16.tgz", - "integrity": "sha512-M0kzkuSgfEhpqIis3gdtWsNjn/HQ+vRAmEzDnbYx/7FfjFxhSv1d+rOOT20pvd60soItMYpsOova1igACEGkGQ==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.25.4.tgz", + "integrity": "sha512-R6/S/dCqxoX4Y6PxIGM9JFAuSRZzUeV5r+CoE/frhmno6mTe7dEEgwkJlfit3LkKRoul8n4DsL2A3QtWOvq5IA==", "dev": true, "requires": { - "@types/node": "^17.0.4", + "@types/node": "^18.0.0", "@types/ua-parser-js": "^0.7.33", - "@wdio/config": "7.16.16", - "@wdio/logger": "7.16.0", - "@wdio/protocols": "7.16.7", - "@wdio/types": "7.16.14", - "@wdio/utils": "7.16.14", + "@wdio/config": "7.25.4", + "@wdio/logger": "7.19.0", + "@wdio/protocols": "7.22.0", + "@wdio/types": "7.25.4", + "@wdio/utils": "7.25.4", "chrome-launcher": "^0.15.0", "edge-paths": "^2.1.0", "puppeteer-core": "^13.1.3", "query-selector-shadow-dom": "^1.0.0", "ua-parser-js": "^1.0.1", - "uuid": "^8.0.0" + "uuid": "^9.0.0" }, "dependencies": { + "@types/node": { + "version": "18.11.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", + "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", + "dev": true + }, + "@wdio/config": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-7.25.4.tgz", + "integrity": "sha512-vb0emDtD9FbFh/yqW6oNdo2iuhQp8XKj6GX9fyy9v4wZgg3B0HPMVJxhIfcoHz7LMBWlHSo9YdvhFI5EQHRLBA==", + "dev": true, + "requires": { + "@wdio/logger": "7.19.0", + "@wdio/types": "7.25.4", + "@wdio/utils": "7.25.4", + "deepmerge": "^4.0.0", + "glob": "^8.0.3" + } + }, + "@wdio/logger": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.19.0.tgz", + "integrity": "sha512-xR7SN/kGei1QJD1aagzxs3KMuzNxdT/7LYYx+lt6BII49+fqL/SO+5X0FDCZD0Ds93AuQvvz9eGyzrBI2FFXmQ==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + } + }, + "@wdio/protocols": { + "version": "7.22.0", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-7.22.0.tgz", + "integrity": "sha512-8EXRR+Ymdwousm/VGtW3H1hwxZ/1g1H99A1lF0U4GuJ5cFWHCd0IVE5H31Z52i8ZruouW8jueMkGZPSo2IIUSQ==", + "dev": true + }, + "@wdio/types": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.25.4.tgz", + "integrity": "sha512-muvNmq48QZCvocctnbe0URq2FjJjUPIG4iLoeMmyF0AQgdbjaUkMkw3BHYNHVTbSOU9WMsr2z8alhj/I2H6NRQ==", + "dev": true, + "requires": { + "@types/node": "^18.0.0", + "got": "^11.8.1" + } + }, + "@wdio/utils": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-7.25.4.tgz", + "integrity": "sha512-8iwQDk+foUqSzKZKfhLxjlCKOkfRJPNHaezQoevNgnrTq/t0ek+ldZCATezb9B8jprAuP4mgS9xi22akc6RkzA==", + "dev": true, + "requires": { + "@wdio/logger": "7.19.0", + "@wdio/types": "7.25.4", + "p-iteration": "^1.1.8" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "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, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "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 + }, + "glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "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 + }, + "minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, "ua-parser-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.2.tgz", - "integrity": "sha512-00y/AXhx0/SsnI51fTc0rLRmafiGOM4/O+ny10Ps7f+j/b8p/ZY11ytMgznXkOVo4GQ+KwQG5UQLkLGirsACRg==", + "version": "1.0.33", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.33.tgz", + "integrity": "sha512-RqshF7TPTE0XLYAqmjlu5cLLuGdKrNu9O1KLA/qp39QtbZwuzwv1dT46DZSopoUMsYgXpB3Cv8a03FI8b74oFQ==", "dev": true }, "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", "dev": true } } }, "devtools-protocol": { - "version": "0.0.973690", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.973690.tgz", - "integrity": "sha512-myh3hSFp0YWa2GED11PmbLhV4dv9RdO7YUz27XJrbQLnP5bMbZL6dfOOILTHO57yH0kX5GfuOZBsg/4NamfPvQ==", + "version": "0.0.1061995", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1061995.tgz", + "integrity": "sha512-pKZZWTjWa/IF4ENCg6GN8bu/AxSZgdhjSa26uc23wz38Blt2Tnm9icOPcSG3Cht55rMq35in1w3rWVPcZ60ArA==", "dev": true }, "di": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", - "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", + "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", "dev": true }, "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", "dev": true }, "diff-sequences": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", - "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", + "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", "dev": true }, "dlv": { @@ -27734,9 +31779,9 @@ } }, "documentation": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/documentation/-/documentation-14.0.0.tgz", - "integrity": "sha512-4AwFzdiseEdtqR0KKLrruIQ5fvh7n5epg47P0ZyOidA5Fes5am+6xjqkDECHPwcv4pxJ6zITaHwzCoGblP0+JQ==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/documentation/-/documentation-14.0.1.tgz", + "integrity": "sha512-Y/brACCE3sNnDJPFiWlhXrqGY+NelLYVZShLGse5bT1KdohP4JkPf5T2KNq1YWhIEbDYl/1tebRLC0WYbPQxVw==", "dev": true, "requires": { "@babel/core": "^7.18.10", @@ -27749,7 +31794,7 @@ "chokidar": "^3.5.3", "diff": "^5.1.0", "doctrine-temporary-fork": "2.1.0", - "git-url-parse": "^12.0.0", + "git-url-parse": "^13.1.0", "github-slugger": "1.4.0", "glob": "^8.0.3", "globals-docs": "^2.4.1", @@ -27796,15 +31841,9 @@ } }, "chalk": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", - "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", - "dev": true - }, - "diff": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.1.2.tgz", + "integrity": "sha512-E5CkT4jWURs1Vy5qGJye+XwCkNj7Od3Af7CP6SujMetSMkLs8Do2RWJK5yx1wamHV/op8Rz+9rltjaTQWDnEFQ==", "dev": true }, "glob": { @@ -27820,12 +31859,6 @@ "once": "^1.3.0" } }, - "ini": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.1.tgz", - "integrity": "sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==", - "dev": true - }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -27844,19 +31877,13 @@ "brace-expansion": "^2.0.1" } }, - "strip-json-comments": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.0.tgz", - "integrity": "sha512-V1LGY4UUo0jgwC+ELQ2BNWfPa17TIuwBLg+j1AA/9RPzKINl1lhxVEu2r+ZTTO8aetIsUzE5Qj6LMSBkoGYKKw==", - "dev": true - }, "yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", + "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", "dev": true, "requires": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", @@ -27870,7 +31897,7 @@ "dom-serialize": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", - "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", + "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", "dev": true, "requires": { "custom-event": "~1.0.0", @@ -27897,12 +31924,38 @@ "dev": true }, "duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==", "dev": true, "requires": { - "readable-stream": "^2.0.2" + "readable-stream": "~1.1.9" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + } } }, "duplexify": { @@ -27970,7 +32023,7 @@ "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", "dev": true, "requires": { "jsbn": "~0.1.0", @@ -27990,7 +32043,7 @@ "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "ejs": { "version": "3.1.8", @@ -28002,14 +32055,14 @@ } }, "electron-to-chromium": { - "version": "1.4.243", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.243.tgz", - "integrity": "sha512-BgLD2gBX43OSXwlT01oYRRD5NIB4n3okTRxkzEAC6G0SZG4TTlyrWMjbOo0fajCwqwpRtMHXQNMjtRN6qpNtfw==" + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==" }, "emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, "emojis-list": { @@ -28021,7 +32074,7 @@ "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" }, "end-of-stream": { "version": "1.4.4", @@ -28033,9 +32086,9 @@ } }, "engine.io": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.1.3.tgz", - "integrity": "sha512-rqs60YwkvWTLLnfazqgZqLa/aKo+9cueVfEi/dZ8PyGyaf8TLOxj++4QMIgeG3Gn0AhrWiFXvghsoY9L9h25GA==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.1.tgz", + "integrity": "sha512-ECceEFcAaNRybd3lsGQKas3ZlMVjN3cyWwMP25D2i0zWfyiytVbTpRPa34qrr+FHddtpBVOmq4H/DCv1O0lZRA==", "dev": true, "requires": { "@types/cookie": "^0.4.1", @@ -28048,21 +32101,26 @@ "debug": "~4.3.1", "engine.io-parser": "~5.0.3", "ws": "~8.2.3" + }, + "dependencies": { + "cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true + } } }, "engine.io-parser": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.3.tgz", - "integrity": "sha512-BtQxwF27XUNnSafQLvDi0dQ8s3i6VgzSoQMJacpIcGNrlUdfHSKbgm3jmjCVvQluGzqwujQMPAoMai3oYSTurg==", - "dev": true, - "requires": { - "@socket.io/base64-arraybuffer": "~1.0.2" - } + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz", + "integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==", + "dev": true }, "enhanced-resolve": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz", - "integrity": "sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", + "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", "dev": true, "requires": { "graceful-fs": "^4.2.4", @@ -28081,7 +32139,7 @@ "ent": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", "dev": true }, "errno": { @@ -28112,31 +32170,35 @@ } }, "es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", + "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==", "dev": true, "requires": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.3", "get-symbol-description": "^1.0.0", "has": "^1.0.3", - "has-symbols": "^1.0.2", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", + "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.2", "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" } }, "es-get-iterator": { @@ -28161,6 +32223,15 @@ "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", "dev": true }, + "es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, "es-to-primitive": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", @@ -28184,15 +32255,15 @@ } }, "es5-shim": { - "version": "4.6.5", - "resolved": "https://registry.npmjs.org/es5-shim/-/es5-shim-4.6.5.tgz", - "integrity": "sha512-vfQ4UAai8szn0sAubCy97xnZ4sJVDD1gt/Grn736hg8D7540wemIb1YPrYZSTqlM2H69EQX1or4HU/tSwRTI3w==", + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/es5-shim/-/es5-shim-4.6.7.tgz", + "integrity": "sha512-jg21/dmlrNQI7JyyA2w7n+yifSxBng0ZralnSfVZjoCawgNTCnS+yBCyVM9DL5itm7SUnDGgv7hcq2XCZX4iRQ==", "dev": true }, "es6-iterator": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", "dev": true, "requires": { "d": "1", @@ -28203,7 +32274,7 @@ "es6-object-assign": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", - "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=", + "integrity": "sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw==", "dev": true }, "es6-promise": { @@ -28215,7 +32286,7 @@ "es6-promisify": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", "dev": true, "requires": { "es6-promise": "^4.0.3" @@ -28251,17 +32322,17 @@ "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" }, "escodegen": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", - "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", + "integrity": "sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A==", "dev": true, "requires": { "esprima": "^2.7.1", @@ -28274,13 +32345,13 @@ "estraverse": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", - "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", + "integrity": "sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==", "dev": true }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", "dev": true, "requires": { "prelude-ls": "~1.1.2", @@ -28304,13 +32375,13 @@ "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", "dev": true }, "source-map": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", - "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", + "integrity": "sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==", "dev": true, "optional": true, "requires": { @@ -28320,7 +32391,7 @@ "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", "dev": true, "requires": { "prelude-ls": "~1.1.2" @@ -28385,18 +32456,6 @@ "@babel/highlight": "^7.10.4" } }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -28438,18 +32497,24 @@ "dev": true }, "globals": { - "version": "13.12.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", - "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", "dev": true, "requires": { "type-fest": "^0.20.2" } }, + "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 + }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -28481,7 +32546,7 @@ "eslint-config-standard": { "version": "10.2.1", "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz", - "integrity": "sha1-wGHk0GbzedwXzVYsZOgZtN1FRZE=", + "integrity": "sha512-UkFojTV1o0GOe1edOEiuI5ccYLJSuNngtqSeClNzhsmG8KPJ+7mRxgtp2oYhqZAK/brlXMoCd+VgXViE0AfyKw==", "dev": true, "requires": {} }, @@ -28507,13 +32572,12 @@ } }, "eslint-module-utils": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", - "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", + "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", "dev": true, "requires": { - "debug": "^3.2.7", - "find-up": "^2.1.0" + "debug": "^3.2.7" }, "dependencies": { "debug": { @@ -28538,9 +32602,9 @@ } }, "eslint-plugin-import": { - "version": "2.25.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz", - "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==", + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", + "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", "dev": true, "requires": { "array-includes": "^3.1.4", @@ -28548,14 +32612,14 @@ "debug": "^2.6.9", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.2", + "eslint-module-utils": "^2.7.3", "has": "^1.0.3", - "is-core-module": "^2.8.0", + "is-core-module": "^2.8.1", "is-glob": "^4.0.3", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "object.values": "^1.1.5", - "resolve": "^1.20.0", - "tsconfig-paths": "^3.12.0" + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" }, "dependencies": { "debug": { @@ -28579,7 +32643,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true } } @@ -28678,7 +32742,7 @@ "esprima": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "integrity": "sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==", "dev": true }, "esquery": { @@ -28736,12 +32800,12 @@ "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" }, "event-emitter": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", "dev": true, "requires": { "d": "1", @@ -28751,7 +32815,7 @@ "event-stream": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", - "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", + "integrity": "sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==", "dev": true, "requires": { "duplexer": "~0.1.1", @@ -28766,7 +32830,7 @@ "map-stream": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", - "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", + "integrity": "sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==", "dev": true } } @@ -28814,7 +32878,7 @@ "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", "dev": true }, "semver": { @@ -28826,7 +32890,7 @@ "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", "dev": true, "requires": { "shebang-regex": "^1.0.0" @@ -28835,7 +32899,7 @@ "shebang-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", "dev": true }, "which": { @@ -28849,16 +32913,10 @@ } } }, - "exit-on-epipe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", - "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==", - "dev": true - }, "expand-brackets": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", "dev": true, "requires": { "debug": "^2.3.3", @@ -28882,7 +32940,7 @@ "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "requires": { "is-descriptor": "^0.1.0" @@ -28891,7 +32949,7 @@ "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "requires": { "is-extendable": "^0.1.0" @@ -28900,7 +32958,7 @@ "is-accessor-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -28909,7 +32967,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -28926,7 +32984,7 @@ "is-data-descriptor": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -28935,7 +32993,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -28957,13 +33015,13 @@ "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true } } @@ -28971,66 +33029,95 @@ "expand-tilde": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", "dev": true, "requires": { "homedir-polyfill": "^1.0.1" } }, "expect": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", - "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", + "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", "dev": true, "requires": { - "@jest/types": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1" + "@jest/types": "^26.6.2", + "ansi-styles": "^4.0.0", + "jest-get-type": "^26.3.0", + "jest-matcher-utils": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-regex-util": "^26.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "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 + } } }, "expect-webdriverio": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/expect-webdriverio/-/expect-webdriverio-3.1.4.tgz", - "integrity": "sha512-65FTS3bmxcIp0cq6fLb/72TrCQXBCpwPLC7SwMWdpPlLq461mXcK1BPKJJjnIC587aXSKD+3E4hvnlCtwDmXfg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expect-webdriverio/-/expect-webdriverio-2.0.2.tgz", + "integrity": "sha512-dst0tqP1aZ2p7TPmbatqoIQ+7hRTw+IeKNi830XxKhu2DNNe5vQ85i9ttf9rpXgbnUf91HxKcocn4G7A5bQxDA==", "dev": true, "requires": { - "expect": "^27.0.2", - "jest-matcher-utils": "^27.0.2" + "expect": "^26.6.2", + "jest-matcher-utils": "^26.6.2" } }, "express": { - "version": "4.17.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", - "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.19.2", + "body-parser": "1.20.1", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.2", + "cookie": "0.5.0", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "~1.1.2", + "depd": "2.0.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "~1.1.2", + "finalhandler": "1.2.0", "fresh": "0.5.2", + "http-errors": "2.0.0", "merge-descriptors": "1.0.1", "methods": "~1.1.2", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", "proxy-addr": "~2.0.7", - "qs": "6.9.7", + "qs": "6.11.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.17.2", - "serve-static": "1.14.2", + "send": "0.18.0", + "serve-static": "1.15.0", "setprototypeof": "1.2.0", - "statuses": "~1.5.0", + "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" @@ -29047,28 +33134,23 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" } } }, "ext": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz", - "integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", "dev": true, "requires": { - "type": "^2.5.0" + "type": "^2.7.2" }, "dependencies": { "type": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.6.0.tgz", - "integrity": "sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", "dev": true } } @@ -29080,13 +33162,20 @@ "dev": true }, "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz", + "integrity": "sha512-L7AGmkO6jhDkEBBGWlLtftA80Xq8DipnrRPr0pyi7GQLXkaq9JYA4xF4z6qnadIC6euiTDKco0cGSU9muw+WTw==", "dev": true, "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "kind-of": "^1.1.0" + }, + "dependencies": { + "kind-of": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", + "integrity": "sha512-aUH6ElPnMGon2/YkxRIigV32MOpTVcoXQ1Oo8aYn40s+sJ3j+0gFZsT8HKDcxNy7Fi9zuquWtGaGAahOdv5p/g==", + "dev": true + } } }, "external-editor": { @@ -29098,17 +33187,6 @@ "chardet": "^0.7.0", "iconv-lite": "^0.4.24", "tmp": "^0.0.33" - }, - "dependencies": { - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - } } }, "extglob": { @@ -29130,7 +33208,7 @@ "define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, "requires": { "is-descriptor": "^1.0.0" @@ -29139,7 +33217,7 @@ "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "requires": { "is-extendable": "^0.1.0" @@ -29148,7 +33226,7 @@ "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true } } @@ -29179,7 +33257,7 @@ "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", "dev": true }, "faker": { @@ -29215,13 +33293,13 @@ "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, "faye-websocket": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", - "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "integrity": "sha512-Xhj93RXbMSq8urNCUq4p9l0P6hnySJ/7YNRhYNug0bLOuii7pKO7xQFb5mx9xZXWCar88pLPb805PvUkwrLZpQ==", "dev": true, "requires": { "websocket-driver": ">=0.5.1" @@ -29230,16 +33308,16 @@ "fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", "dev": true, "requires": { "pend": "~1.2.0" } }, "fibers": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/fibers/-/fibers-5.0.1.tgz", - "integrity": "sha512-VMC7Frt87Oo0AOJ6EcPFbi+tZmkQ4tD85aatwyWL6I9cYMJmm2e+pXUJsfGZ36U7MffXtjou2XIiWJMtHriErw==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/fibers/-/fibers-5.0.3.tgz", + "integrity": "sha512-/qYTSoZydQkM21qZpGLDLuCq8c+B8KhuCQ1kLPvnRNhxhVbvrpmH9l2+Lblf5neDuEsY4bfT7LeO553TXQDvJw==", "dev": true, "requires": { "detect-libc": "^1.0.3" @@ -29309,16 +33387,16 @@ } }, "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "requires": { "debug": "2.6.9", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", - "statuses": "~1.5.0", + "statuses": "2.0.1", "unpipe": "~1.0.0" }, "dependencies": { @@ -29333,7 +33411,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" } } }, @@ -29349,12 +33427,13 @@ } }, "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "requires": { - "locate-path": "^2.0.0" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" } }, "findup-sync": { @@ -29367,6 +33446,151 @@ "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": { @@ -29416,9 +33640,9 @@ } }, "flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, "flush-write-stream": { @@ -29432,48 +33656,51 @@ } }, "follow-redirects": { - "version": "1.14.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", - "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==", + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", "dev": true }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "requires": { + "is-callable": "^1.1.3" + } + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", "dev": true }, "for-own": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==", "dev": true, "requires": { "for-in": "^1.0.1" } }, - "foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", - "dev": true - }, "foreachasync": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/foreachasync/-/foreachasync-3.0.0.tgz", - "integrity": "sha1-VQKYfchxS+M5IJfzLgBxyd7gfPY=", + "integrity": "sha512-J+ler7Ta54FwwNcx6wQRDhTIbNeyDcARMkOcguEqnEdtm0jKvN3Li3PDAb2Du3ubJYEWfYL83XMROXdsXAXycw==", "dev": true }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", "dev": true }, "fork-stream": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/fork-stream/-/fork-stream-0.0.4.tgz", - "integrity": "sha1-24Sfznf2cIpfjzhq5TOgkHtUrnA=", + "integrity": "sha512-Pqq5NnT78ehvUnAk/We/Jr22vSvanRlFTpAmQ88xBY/M1TlHe+P0ILuEyXS595ysdGfaj22634LBkGMA2GTcpA==", "dev": true }, "form-data": { @@ -29495,7 +33722,7 @@ "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", "dev": true, "requires": { "map-cache": "^0.2.2" @@ -29504,12 +33731,12 @@ "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" }, "from": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", + "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==", "dev": true }, "fs-constants": { @@ -29519,9 +33746,9 @@ "dev": true }, "fs-extra": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", - "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "requires": { "graceful-fs": "^4.2.0", @@ -29532,7 +33759,7 @@ "fs-mkdirp-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", - "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=", + "integrity": "sha512-+vSd9frUnapVC2RZYfL3FCB2p3g4TBhaUmrsWlSudsGdnxIuUvBB2QM1VZeBtc49QFwrp+wQLrDs3+xxDgI5gQ==", "dev": true, "requires": { "graceful-fs": "^4.1.11", @@ -29554,7 +33781,7 @@ "fs.extra": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/fs.extra/-/fs.extra-1.3.2.tgz", - "integrity": "sha1-3QI/kwE77iRTHxszUUw3sg/ZM0k=", + "integrity": "sha512-Ig401VXtyrWrz23k9KxAx9OrnL8AHSLNhQ8YJH2wSYuH0ZUfxwBeY6zXkd/oOyVRFTlpEu/0n5gHeuZt7aqbkw==", "dev": true, "requires": { "fs-extra": "~0.6.1", @@ -29565,7 +33792,7 @@ "fs-extra": { "version": "0.6.4", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.6.4.tgz", - "integrity": "sha1-9G8MdbeEH40gCzNIzU1pHVoJnRU=", + "integrity": "sha512-5rU898vl/Z948L+kkJedbmo/iltzmiF5bn/eEk0j/SgrPpI+Ydau9xlJPicV7Av2CHYBGz5LAlwTnBU80j1zPQ==", "dev": true, "requires": { "jsonfile": "~1.0.1", @@ -29577,19 +33804,19 @@ "jsonfile": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-1.0.1.tgz", - "integrity": "sha1-6l7+QLg2kLmGZ2FKc5L8YOhCwN0=", + "integrity": "sha512-KbsDJNRfRPF5v49tMNf9sqyyGqGLBcz1v5kZT01kG5ns5mQSltwxCKVmUzVKtEinkUnTDtSrp6ngWpV7Xw0ZlA==", "dev": true }, "mkdirp": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", - "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=", + "integrity": "sha512-8OCq0De/h9ZxseqzCH8Kw/Filf5pF/vMI6+BH7Lu0jXz2pqYCjTAQRolSxRIi+Ax+oCCjlxoJMP0YQ4XlrQNHg==", "dev": true }, "rimraf": { "version": "2.2.8", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", - "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", + "integrity": "sha512-R5KMKHnPAQaZMqLOsyuyUmcIjSeDm+73eoqQpaXA7AZ22BL+6C+1mcUscgOsNd8WVlJuvlgAPsegcx7pjlV0Dg==", "dev": true } } @@ -29597,7 +33824,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, "fsevents": { @@ -29619,12 +33846,12 @@ }, "dependencies": { "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "requires": { - "minimist": "^1.2.5" + "minimist": "^1.2.6" } }, "rimraf": { @@ -29651,10 +33878,28 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, + "function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } + }, "functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true }, "gaze": { @@ -29680,17 +33925,17 @@ "get-func-name": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", "dev": true }, "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", - "has-symbols": "^1.0.1" + "has-symbols": "^1.0.3" } }, "get-package-type": { @@ -29727,35 +33972,35 @@ "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", "dev": true }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", "dev": true, "requires": { "assert-plus": "^1.0.0" } }, "git-up": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/git-up/-/git-up-6.0.0.tgz", - "integrity": "sha512-6RUFSNd1c/D0xtGnyWN2sxza2bZtZ/EmI9448n6rCZruFwV/ezeEn2fJP7XnUQGwf0RAtd/mmUCbtH6JPYA2SA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/git-up/-/git-up-7.0.0.tgz", + "integrity": "sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ==", "dev": true, "requires": { "is-ssh": "^1.4.0", - "parse-url": "^7.0.2" + "parse-url": "^8.1.0" } }, "git-url-parse": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-12.0.0.tgz", - "integrity": "sha512-I6LMWsxV87vysX1WfsoglXsXg6GjQRKq7+Dgiseo+h0skmp5Hp2rzmcEIRQot9CPA+uzU7x1x7jZdqvTFGnB+Q==", + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-13.1.0.tgz", + "integrity": "sha512-5FvPJP/70WkIprlUZ33bm4UAaFdjcLkJLpWft1BeZKqwR0uhhNGoKwlUaPtVb4LxCSQ++erHapRak9kWGj+FCA==", "dev": true, "requires": { - "git-up": "^6.0.0" + "git-up": "^7.0.0" } }, "github-slugger": { @@ -29765,15 +34010,15 @@ "dev": true }, "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } @@ -29818,7 +34063,7 @@ "is-glob": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", "dev": true, "requires": { "is-extglob": "^2.1.0" @@ -29860,7 +34105,7 @@ "normalize-path": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", "dev": true, "requires": { "remove-trailing-separator": "^1.0.1" @@ -29868,6 +34113,12 @@ } } }, + "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", @@ -29915,7 +34166,7 @@ "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "requires": { "is-extendable": "^0.1.0" @@ -29924,7 +34175,7 @@ "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", "dev": true, "requires": { "extend-shallow": "^2.0.1", @@ -29957,7 +34208,7 @@ "is-glob": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", "dev": true, "requires": { "is-extglob": "^2.1.0" @@ -29968,18 +34219,99 @@ "is-binary-path": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", "dev": true, "requires": { "binary-extensions": "^1.0.0" } }, + "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-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "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" + } + }, + "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", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "requires": { + "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", @@ -29994,7 +34326,7 @@ "to-regex-range": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", "dev": true, "requires": { "is-number": "^3.0.0", @@ -30027,7 +34359,7 @@ "global-prefix": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", "dev": true, "requires": { "expand-tilde": "^2.0.2", @@ -30037,6 +34369,12 @@ "which": "^1.2.14" }, "dependencies": { + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -30060,13 +34398,13 @@ "dev": true }, "globule": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.3.tgz", - "integrity": "sha512-mb1aYtDbIjTu4ShMB85m3UzjX9BVKe9WCzsnfMSZk+K5GpIbBOexgg4PPCt5eHDEG5/ZQAUX2Kct02zfiPLsKg==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.4.tgz", + "integrity": "sha512-OPTIfhMBh7JbBYDpa5b+Q5ptmMWKwcNcFSR/0c6t8V4f3ZAVBEsKNY37QdVqmLRYSMhOUGYrY0QhSoEpzGr/Eg==", "dev": true, "requires": { "glob": "~7.1.1", - "lodash": "~4.17.10", + "lodash": "^4.17.21", "minimatch": "~3.0.2" }, "dependencies": { @@ -30124,9 +34462,9 @@ } }, "graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, "grapheme-splitter": { @@ -30166,56 +34504,6 @@ "vinyl": "^2.1.0" }, "dependencies": { - "arr-diff": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz", - "integrity": "sha512-OQwDZUqYaQwyyhDJHThmzId8daf4/RFNLaeh3AevmSeZ5Y7ug4Ga/yKc6l6kTZOBW781rCj103ZuTh8GAsB3+Q==", - "dev": true, - "requires": { - "arr-flatten": "^1.0.1", - "array-slice": "^0.2.3" - } - }, - "arr-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz", - "integrity": "sha512-t5db90jq+qdgk8aFnxEkjqta0B/GHrM1pxzuuZz2zWsOXc5nKu3t+76s/PQBA8FTcM/ipspIH9jWG4OxCBc2eA==", - "dev": true - }, - "array-slice": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", - "integrity": "sha512-rlVfZW/1Ph2SNySXwR9QYkChp8EkOEiTMO5Vwx60usw04i4nWemkm9RXmQqgkQFaLHsqLuADvjp6IfgL9l2M8Q==", - "dev": true - }, - "extend-shallow": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz", - "integrity": "sha512-L7AGmkO6jhDkEBBGWlLtftA80Xq8DipnrRPr0pyi7GQLXkaq9JYA4xF4z6qnadIC6euiTDKco0cGSU9muw+WTw==", - "dev": true, - "requires": { - "kind-of": "^1.1.0" - } - }, - "kind-of": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", - "integrity": "sha512-aUH6ElPnMGon2/YkxRIigV32MOpTVcoXQ1Oo8aYn40s+sJ3j+0gFZsT8HKDcxNy7Fi9zuquWtGaGAahOdv5p/g==", - "dev": true - }, - "plugin-error": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", - "integrity": "sha512-WzZHcm4+GO34sjFMxQMqZbsz3xiNEgonCskQ9v+IroMmYgk/tas8dG+Hr2D6IbRPybZ12oWpzE/w3cGJ6FJzOw==", - "dev": true, - "requires": { - "ansi-cyan": "^0.1.1", - "ansi-red": "^0.1.1", - "arr-diff": "^1.0.1", - "arr-union": "^2.0.1", - "extend-shallow": "^1.1.2" - } - }, "rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -30275,19 +34563,19 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true }, "camelcase": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", "dev": true }, "cliui": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "integrity": "sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==", "dev": true, "requires": { "string-width": "^1.0.1", @@ -30295,10 +34583,16 @@ "wrap-ansi": "^2.0.0" } }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true + }, "find-up": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", "dev": true, "requires": { "path-exists": "^2.0.0", @@ -30311,19 +34605,37 @@ "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", "dev": true }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, "is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", "dev": true, "requires": { "number-is-nan": "^1.0.0" } }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, "path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", "dev": true, "requires": { "pinkie-promise": "^2.0.0" @@ -30332,7 +34644,7 @@ "read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", "dev": true, "requires": { "load-json-file": "^1.0.0", @@ -30343,23 +34655,23 @@ "read-pkg-up": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", "dev": true, "requires": { "find-up": "^1.0.0", "read-pkg": "^1.0.0" } }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", "dev": true, "requires": { "code-point-at": "^1.0.0", @@ -30370,22 +34682,16 @@ "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "requires": { "ansi-regex": "^2.0.0" } }, - "which-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", - "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", - "dev": true - }, "wrap-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==", "dev": true, "requires": { "string-width": "^1.0.1", @@ -30434,7 +34740,7 @@ "gulp-concat": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/gulp-concat/-/gulp-concat-2.6.1.tgz", - "integrity": "sha1-Yz0WyV2IUEYorQJmVmPO5aR5M1M=", + "integrity": "sha512-a2scActrQrDBpBbR3WUZGyGS1JEPLg5PZJdIa7/Bi3GuKAmPYDK6SFhy/NZq5R8KsKKFvtfR0fakbUCcKGCCjg==", "dev": true, "requires": { "concat-with-sourcemaps": "^1.0.0", @@ -30486,10 +34792,22 @@ "ms": "2.0.0" } }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==", + "dev": true + }, "http-errors": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", "dev": true, "requires": { "depd": "~1.1.2", @@ -30501,7 +34819,7 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", "dev": true }, "mime": { @@ -30513,9 +34831,18 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, "send": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", @@ -30562,12 +34889,33 @@ "plugin-error": "^1.0.1" }, "dependencies": { + "ansi-colors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "dev": true, + "requires": { + "ansi-wrap": "^0.1.0" + } + }, "ansi-regex": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", "dev": true }, + "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 + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true + }, "astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", @@ -30661,18 +35009,6 @@ "v8-compile-cache": "^2.0.3" }, "dependencies": { - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -30710,6 +35046,16 @@ "eslint-visitor-keys": "^1.1.0" } }, + "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" + } + }, "file-entry-cache": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", @@ -30745,6 +35091,12 @@ "type-fest": "^0.8.1" } }, + "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 + }, "inquirer": { "version": "7.3.3", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", @@ -30832,6 +35184,18 @@ "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", "dev": true }, + "plugin-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", + "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", + "dev": true, + "requires": { + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" + } + }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -30853,15 +35217,6 @@ "glob": "^7.1.3" } }, - "rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -30989,7 +35344,7 @@ "gulp-js-escape": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gulp-js-escape/-/gulp-js-escape-1.0.1.tgz", - "integrity": "sha1-HNRF+9AJ4Np2lZoDp/SbNWav+Gg=", + "integrity": "sha512-F+53crhLb78CTlG7ZZJFWzP0+/4q0vt2/pULXFkTMs6AGBo0Eh5cx+eWsqqHv8hrNIUsuTab3Se8rOOzP/6+EQ==", "dev": true, "requires": { "through2": "^0.6.3" @@ -30998,13 +35353,13 @@ "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", "dev": true }, "readable-stream": { "version": "1.0.34", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -31016,13 +35371,13 @@ "string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", "dev": true }, "through2": { "version": "0.6.5", "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "integrity": "sha512-RkK/CCESdTKQZHdmKICijdKKsCRVHs5KsLZ6pACAmF/1GPUQhonHSXWNERctxEp7RmvjdNbZTL5z9V7nSCXKcg==", "dev": true, "requires": { "readable-stream": ">=1.0.33-1 <1.1.0-0", @@ -31054,9 +35409,9 @@ }, "dependencies": { "@types/node": { - "version": "14.18.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.12.tgz", - "integrity": "sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A==", + "version": "14.18.33", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.33.tgz", + "integrity": "sha512-qelS/Ra6sacc4loe/3MSjXNL1dNQ/GjxNHVzuChwMfmk7HuycRLVQN2qNY3XahK+fZc5E2szqQSKUyAF0E+2bg==", "dev": true } } @@ -31075,6 +35430,15 @@ "tslib": "^1.10.0" }, "dependencies": { + "ansi-colors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "dev": true, + "requires": { + "ansi-wrap": "^0.1.0" + } + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -31084,6 +35448,18 @@ "color-convert": "^2.0.1" } }, + "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 + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true + }, "chalk": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", @@ -31109,6 +35485,34 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "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" + } + }, + "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 + }, + "plugin-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", + "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", + "dev": true, + "requires": { + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" + } + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -31183,6 +35587,51 @@ "terser": "^5.9.0", "through2": "^4.0.2", "vinyl-sourcemaps-apply": "^0.2.1" + }, + "dependencies": { + "ansi-colors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "dev": true, + "requires": { + "ansi-wrap": "^0.1.0" + } + }, + "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 + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "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" + } + }, + "plugin-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", + "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", + "dev": true, + "requires": { + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" + } + } } }, "gulp-util": { @@ -31214,19 +35663,19 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true }, "ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "requires": { "ansi-styles": "^2.2.1", @@ -31239,24 +35688,15 @@ "clone": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "dev": true }, "clone-stats": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", + "integrity": "sha512-dhUqc57gSMCo6TX85FLfe51eC/s+Im2MLkAgJwfaRRexR2tA4dd3eLEW4L6efzHc2iNorrRRXITifnDLlRrhaA==", "dev": true }, - "lodash.escape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", - "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", - "dev": true, - "requires": { - "lodash._root": "^3.0.0" - } - }, "lodash.template": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", @@ -31277,7 +35717,7 @@ "lodash.templatesettings": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", - "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", + "integrity": "sha512-TcrlEr31tDYnWkHFWDCV3dHYroKEXpJZ2YJYvJdhN+y4AkWMDZ5I4I8XDtUKqSAyG81N7w+I1mFEJtcED+tGqQ==", "dev": true, "requires": { "lodash._reinterpolate": "^3.0.0", @@ -31287,13 +35727,13 @@ "object-assign": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=", + "integrity": "sha512-jHP15vXVGeVh1HuaA2wY6lxk+whK/x4KBG88VXeRma7CCun7iGD5qPc4eYykQ9sdQvg8jkwFKsSxHln2ybW3xQ==", "dev": true }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "requires": { "ansi-regex": "^2.0.0" @@ -31302,7 +35742,7 @@ "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true }, "through2": { @@ -31318,7 +35758,7 @@ "vinyl": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", - "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", + "integrity": "sha512-P5zdf3WB9uzr7IFoVQ2wZTmUwHL8cMZWJGzLBNCHNZ3NB6HTMsYABtt7z8tAGIINLXyAob9B9a1yzVGMFOYKEA==", "dev": true, "requires": { "clone": "^1.0.0", @@ -31331,7 +35771,7 @@ "gulplog": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", - "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", + "integrity": "sha512-hm6N8nrm3Y08jXie48jsC55eCZz9mnb4OirAStEk2deqeyhXU3C1otDVh+ccttMuc1sBi6RX6ZJ720hs9RCvgw==", "dev": true, "requires": { "glogg": "^1.0.0" @@ -31370,7 +35810,7 @@ "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", "dev": true }, "har-validator": { @@ -31381,20 +35821,6 @@ "requires": { "ajv": "^6.12.3", "har-schema": "^2.0.0" - }, - "dependencies": { - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - } } }, "has": { @@ -31408,7 +35834,7 @@ "has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", "dev": true, "requires": { "ansi-regex": "^2.0.0" @@ -31417,32 +35843,40 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true } } }, "has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "dev": true }, "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 + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" }, "has-gulplog": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", - "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", + "integrity": "sha512-+F4GzLjwHNNDEAJW2DC1xXfEoPkRDmUdJ7CBYw4MpqtDwOnqdImJl7GWlpqx+Wko6//J8uKTnIe4wZSv7yCqmw==", "dev": true, "requires": { "sparkles": "^1.0.0" } }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.1" + } + }, "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -31460,7 +35894,7 @@ "has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", "dev": true, "requires": { "get-value": "^2.0.6", @@ -31471,7 +35905,7 @@ "has-values": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", "dev": true, "requires": { "is-number": "^3.0.0", @@ -31484,10 +35918,30 @@ "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": "4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -31553,7 +36007,7 @@ "home-or-tmp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", - "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "integrity": "sha512-ycURW7oUxE2sNiPVw1HVEFsW+ecOpJ5zaj7eC0RlwhibhRBod20muUN8qu/gzx956YrLolVvs1MTXwKgC2rVEg==", "dev": true, "requires": { "os-homedir": "^1.0.0", @@ -31570,10 +36024,13 @@ } }, "hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } }, "html-escaper": { "version": "2.0.2", @@ -31588,27 +36045,27 @@ "dev": true }, "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", "dev": true }, "http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "requires": { - "depd": "~1.1.2", + "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", + "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "http-parser-js": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.6.tgz", - "integrity": "sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA==", + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", "dev": true }, "http-proxy": { @@ -31625,7 +36082,7 @@ "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", "dev": true, "requires": { "assert-plus": "^1.0.0", @@ -31644,12 +36101,12 @@ } }, "https-proxy-agent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", - "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==", + "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, "requires": { - "agent-base": "5", + "agent-base": "6", "debug": "4" } }, @@ -31694,7 +36151,13 @@ "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha512-BYqTHXTGUIvg7t1r4sJNKcbDZkL92nkXA8YtRpbjFHRHGDL/NtUeiBJMeE60kIFN/Mg8ESaWQvftaYMGJzQZCQ==", "dev": true }, "individual": { @@ -31706,7 +36169,7 @@ "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dev": true, "requires": { "once": "^1.3.0", @@ -31719,15 +36182,15 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.1.tgz", + "integrity": "sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==", "dev": true }, "inquirer": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.1.5.tgz", - "integrity": "sha512-G6/9xUqmt/r+UvufSyrPpt84NYwhKZ9jLsgMbQzlx804XErNupor8WQdBnBRrXmBfTPpuwf1sV+ss2ovjgdXIg==", + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", + "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==", "dev": true, "requires": { "ansi-escapes": "^4.2.1", @@ -31740,10 +36203,11 @@ "mute-stream": "0.0.8", "ora": "^5.4.1", "run-async": "^2.4.0", - "rxjs": "^7.2.0", + "rxjs": "^7.5.5", "string-width": "^4.1.0", "strip-ansi": "^6.0.0", - "through": "^2.3.6" + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" }, "dependencies": { "ansi-styles": { @@ -31780,6 +36244,21 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "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 + }, + "rxjs": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz", + "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==", + "dev": true, + "requires": { + "tslib": "^2.1.0" + } + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -31788,6 +36267,12 @@ "requires": { "has-flag": "^4.0.0" } + }, + "tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "dev": true } } }, @@ -31820,7 +36305,7 @@ "invert-kv": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "integrity": "sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==", "dev": true }, "ipaddr.js": { @@ -31868,7 +36353,7 @@ "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true }, "is-bigint": { @@ -31906,15 +36391,15 @@ "dev": true }, "is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true }, "is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "requires": { "has": "^1.0.3" } @@ -31993,7 +36478,7 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true }, "is-finite": { @@ -32057,7 +36542,7 @@ "is-negated-glob": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", - "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=", + "integrity": "sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==", "dev": true }, "is-negative-zero": { @@ -32067,35 +36552,15 @@ "dev": true }, "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "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 - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true }, "is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dev": true, "requires": { "has-tostringtag": "^1.0.0" @@ -32141,7 +36606,7 @@ "is-running": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-running/-/is-running-2.1.0.tgz", - "integrity": "sha1-MKc/9cw4VOT8JUkICen1q/jeCeA=", + "integrity": "sha512-mjJd3PujZMl7j+D395WTIO5tU5RIDBfVSRtRR4VOJou3H66E38UjbjvDGh3slJzPuolsb+yQFqwHNNdyp5jg3w==", "dev": true }, "is-set": { @@ -32151,10 +36616,13 @@ "dev": true }, "is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", - "dev": true + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } }, "is-ssh": { "version": "1.4.0", @@ -32168,7 +36636,7 @@ "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", "dev": true }, "is-string": { @@ -32190,22 +36658,22 @@ } }, "is-typed-array": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.8.tgz", - "integrity": "sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA==", + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.9.tgz", + "integrity": "sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A==", "dev": true, "requires": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", - "es-abstract": "^1.18.5", - "foreach": "^2.0.5", + "es-abstract": "^1.20.0", + "for-each": "^0.3.3", "has-tostringtag": "^1.0.0" } }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", "dev": true }, "is-unc-path": { @@ -32226,13 +36694,13 @@ "is-utf8": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", "dev": true }, "is-valid-glob": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", - "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=", + "integrity": "sha512-AhiROmoEFDSsjx8hW+5sGwgKVIORcXnrlAx/R0ZSeaPw70Vw0CqkGBBhHGL58Uox2eXnU1AnvXJl1XlyedO5bA==", "dev": true }, "is-weakmap": { @@ -32282,33 +36750,33 @@ "dev": true }, "isbinaryfile": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.8.tgz", - "integrity": "sha512-53h6XFniq77YdW+spoRrebh0mnmTxRPTlcuIArO57lmMdq4uBKFKaeTjnb92oYWrSn/LVL+LT+Hap2tFQj8V+w==", + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", "dev": true }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", "dev": true }, "istanbul": { "version": "0.4.5", "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", - "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", + "integrity": "sha512-nMtdn4hvK0HjUlzr1DrKSUY8ychprt8dzHOgY2KXsIhHu5PuQQEOTM27gV9Xblyon7aUH/TSFIjRHEODF/FRPg==", "dev": true, "requires": { "abbrev": "1.0.x", @@ -32330,7 +36798,7 @@ "glob": { "version": "5.0.15", "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", - "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", "dev": true, "requires": { "inflight": "^1.0.4", @@ -32343,28 +36811,28 @@ "has-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", "dev": true }, "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "requires": { - "minimist": "^1.2.5" + "minimist": "^1.2.6" } }, "resolve": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", "dev": true }, "supports-color": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", "dev": true, "requires": { "has-flag": "^1.0.0" @@ -32387,6 +36855,19 @@ "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", "dev": true }, + "istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "requires": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + } + }, "istanbul-lib-report": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", @@ -32398,6 +36879,12 @@ "supports-color": "^7.1.0" }, "dependencies": { + "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 + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -32429,9 +36916,9 @@ } }, "istanbul-reports": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", - "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", "dev": true, "requires": { "html-escaper": "^2.0.0", @@ -32500,6 +36987,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "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 + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -32512,15 +37005,15 @@ } }, "jest-diff": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", - "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", + "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", "dev": true, "requires": { "chalk": "^4.0.0", - "diff-sequences": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" + "diff-sequences": "^26.6.2", + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" }, "dependencies": { "ansi-styles": { @@ -32557,6 +37050,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "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 + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -32569,21 +37068,21 @@ } }, "jest-get-type": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", - "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "version": "26.3.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", + "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", "dev": true }, "jest-matcher-utils": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", - "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", + "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", "dev": true, "requires": { "chalk": "^4.0.0", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" + "jest-diff": "^26.6.2", + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" }, "dependencies": { "ansi-styles": { @@ -32620,6 +37119,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "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 + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -32632,20 +37137,20 @@ } }, "jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", + "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", "dev": true, "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", + "@babel/code-frame": "^7.0.0", + "@jest/types": "^26.6.2", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.2", + "pretty-format": "^26.6.2", "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "stack-utils": "^2.0.2" }, "dependencies": { "ansi-styles": { @@ -32682,15 +37187,17 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } + "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 + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true }, "supports-color": { "version": "7.2.0", @@ -32703,6 +37210,12 @@ } } }, + "jest-regex-util": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", + "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", + "dev": true + }, "jest-worker": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", @@ -32712,6 +37225,23 @@ "@types/node": "*", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" + }, + "dependencies": { + "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 + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "js-tokens": { @@ -32740,7 +37270,7 @@ "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", "dev": true }, "jsesc": { @@ -32754,12 +37284,6 @@ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, "json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -32781,13 +37305,13 @@ "json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", "dev": true }, "json5": { @@ -32820,7 +37344,7 @@ "just-clone": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/just-clone/-/just-clone-1.0.2.tgz", - "integrity": "sha1-v7P672WqEqMWBYcSlFwyb9jwFDQ=" + "integrity": "sha512-p93GINPwrve0w3HUzpXmpTl7MyzzWz1B5ag44KEtq/hP1mtK8lA2b9Q0VQaPlnY87352osJcE6uBmN0e8kuFMw==" }, "just-debounce": { "version": "1.1.0", @@ -32835,9 +37359,9 @@ "dev": true }, "karma": { - "version": "6.3.17", - "resolved": "https://registry.npmjs.org/karma/-/karma-6.3.17.tgz", - "integrity": "sha512-2TfjHwrRExC8yHoWlPBULyaLwAFmXmxQrcuFImt/JsAsSZu1uOWTZ1ZsWjqQtWpHLiatJOHL5jFjXSJIgCd01g==", + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.1.tgz", + "integrity": "sha512-Cj57NKOskK7wtFWSlMvZf459iX+kpYIPXmkNUzP2WAFcA7nhr/ALn5R7sw3w+1udFDcpMx/tuB8d5amgm3ijaA==", "dev": true, "requires": { "@colors/colors": "1.5.0", @@ -32859,20 +37383,31 @@ "qjobs": "^1.2.0", "range-parser": "^1.2.1", "rimraf": "^3.0.2", - "socket.io": "^4.2.0", + "socket.io": "^4.4.1", "source-map": "^0.6.1", "tmp": "^0.2.1", "ua-parser-js": "^0.7.30", "yargs": "^16.1.1" }, "dependencies": { + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "requires": { - "minimist": "^1.2.5" + "minimist": "^1.2.6" } }, "source-map": { @@ -32881,6 +37416,15 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, + "tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "requires": { + "rimraf": "^3.0.0" + } + }, "yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -32925,14 +37469,14 @@ "karma-chai": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/karma-chai/-/karma-chai-0.1.0.tgz", - "integrity": "sha1-vuWtQEAFF4Ea40u5RfdikJEIt5o=", + "integrity": "sha512-mqKCkHwzPMhgTYca10S90aCEX9+HjVjjrBFAsw36Zj7BlQNbokXXCAe6Ji04VUMsxcY5RLP7YphpfO06XOubdg==", "dev": true, "requires": {} }, "karma-chrome-launcher": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.0.tgz", - "integrity": "sha512-3dPs/n7vgz1rxxtynpzZTvb9y/GIaW8xjAwcIGttLbycqoFtI7yo1NGnQi6oFTherRE+GIhCAHZC4vEqWGhNvg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.1.tgz", + "integrity": "sha512-hsIglcq1vtboGPAN+DGCISCFOxW+ZVnIqhDQcCMqqCp+4dmJ0Qpq5QAjkbA0X2L9Mi6OBkHi2Srrbmm7pUKkzQ==", "dev": true, "requires": { "which": "^1.2.1" @@ -32961,21 +37505,6 @@ "istanbul-lib-source-maps": "^4.0.1", "istanbul-reports": "^3.0.5", "minimatch": "^3.0.4" - }, - "dependencies": { - "istanbul-lib-instrument": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", - "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - } - } } }, "karma-coverage-istanbul-reporter": { @@ -33054,7 +37583,7 @@ "karma-es5-shim": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/karma-es5-shim/-/karma-es5-shim-0.0.4.tgz", - "integrity": "sha1-zdADM8znfC5M4D46yT8vjs0fuVI=", + "integrity": "sha512-8xU6F2/R6u6HAZ/nlyhhx3WEhj4C6hJorG7FR2REX81pgj2LSo9ADJXxCGIeXg6Qr2BGpxp4hcZcEOYGAwiumg==", "dev": true, "requires": { "es5-shim": "^4.0.5" @@ -33073,7 +37602,7 @@ "karma-ie-launcher": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/karma-ie-launcher/-/karma-ie-launcher-1.0.0.tgz", - "integrity": "sha1-SXmGhCxJAZA0bNifVJTKmDDG1Zw=", + "integrity": "sha512-ts71ke8pHvw6qdRtq0+7VY3ANLoZuUNNkA8abRaWV13QRPNm7TtSOqyszjHUtuwOWKcsSz4tbUtrNICrQC+SXQ==", "dev": true, "requires": { "lodash": "^4.6.1" @@ -33091,7 +37620,7 @@ "karma-mocha-reporter": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/karma-mocha-reporter/-/karma-mocha-reporter-2.2.5.tgz", - "integrity": "sha1-FRIAlejtgZGG5HoLAS8810GJVWA=", + "integrity": "sha512-Hr6nhkIp0GIJJrvzY8JFeHpQZNseuIakGac4bpw8K1+5F0tLb6l7uvXRa8mt2Z+NVwYgCct4QAfp2R2QP6o00w==", "dev": true, "requires": { "chalk": "^2.1.0", @@ -33108,7 +37637,7 @@ "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", "dev": true, "requires": { "ansi-regex": "^3.0.0" @@ -33119,28 +37648,28 @@ "karma-opera-launcher": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/karma-opera-launcher/-/karma-opera-launcher-1.0.0.tgz", - "integrity": "sha1-+lFihTGh0L6EstjcDX7iCfyP+Ro=", + "integrity": "sha512-rdty4FlVIowmUhPuG08TeXKHvaRxeDSzPxGIkWguCF3A32kE0uvXZ6dXW08PuaNjai8Ip3f5Pn9Pm2HlChaxCw==", "dev": true, "requires": {} }, "karma-safari-launcher": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/karma-safari-launcher/-/karma-safari-launcher-1.0.0.tgz", - "integrity": "sha1-lpgqLMR9BmquccVTursoMZEVos4=", + "integrity": "sha512-qmypLWd6F2qrDJfAETvXDfxHvKDk+nyIjpH9xIeI3/hENr0U3nuqkxaftq73PfXZ4aOuOChA6SnLW4m4AxfRjQ==", "dev": true, "requires": {} }, "karma-script-launcher": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/karma-script-launcher/-/karma-script-launcher-1.0.0.tgz", - "integrity": "sha1-zQF8TeXvCeWp2nkydhdhCN1LVC0=", + "integrity": "sha512-5NRc8KmTBjNPE3dNfpJP90BArnBohYV4//MsLFfUA1e6N+G1/A5WuWctaFBtMQ6MWRybs/oguSej0JwDr8gInA==", "dev": true, "requires": {} }, "karma-sinon": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/karma-sinon/-/karma-sinon-1.0.5.tgz", - "integrity": "sha1-TjRD8oMP3s/2JNN0cWPxIX2qKpo=", + "integrity": "sha512-wrkyAxJmJbn75Dqy17L/8aILJWFm7znd1CE8gkyxTBFnjMSOe2XTJ3P30T8SkxWZHmoHX0SCaUJTDBEoXs25Og==", "dev": true, "requires": {} }, @@ -33156,7 +37685,7 @@ "karma-spec-reporter": { "version": "0.0.32", "resolved": "https://registry.npmjs.org/karma-spec-reporter/-/karma-spec-reporter-0.0.32.tgz", - "integrity": "sha1-LpxyB+pyZ3EmAln4K+y1QyCeRAo=", + "integrity": "sha512-ZXsYERZJMTNRR2F3QN11OWF5kgnT/K2dzhM+oY3CDyMrDI3TjIWqYGG7c15rR9wjmy9lvdC+CCshqn3YZqnNrA==", "dev": true, "requires": { "colors": "^1.1.2" @@ -33180,9 +37709,9 @@ "dev": true }, "keyv": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.1.1.tgz", - "integrity": "sha512-tGv1yP6snQVDSM4X6yxrv2zzq/EvpW+oYiUz6aueW1u9CtS8RzUQYxxmFwgZlO2jSgCxQbchhxaqXXp2hnKGpQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.0.tgz", + "integrity": "sha512-2YvuMsA+jnFGtBareKqgANOEKe1mk3HKiXu2fRmAfyxG0MJAywNhi5ttWA3PMjl4NmpyjZNbFifR2vNjW1znfA==", "dev": true, "requires": { "json-buffer": "3.0.1" @@ -33219,7 +37748,7 @@ "last-run": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", - "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=", + "integrity": "sha512-U/VxvpX4N/rFvPzr3qG5EtLKEnNI0emvIQB3/ecEwv+8GHaUKbIB8vxv1Oai5FAF0d0r7LXHhLLe5K/yChm5GQ==", "dev": true, "requires": { "default-resolution": "^2.0.0", @@ -33238,7 +37767,7 @@ "lcid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "integrity": "sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==", "dev": true, "requires": { "invert-kv": "^1.0.0" @@ -33247,13 +37776,13 @@ "lcov-parse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-1.0.0.tgz", - "integrity": "sha1-6w1GtUER68VhrLTECO+TY73I9+A=", + "integrity": "sha512-aprLII/vPzuQvYZnDRU78Fns9I2Ag3gi4Ipga/hxnVMCZC8DnR2nI7XBqrPoywGfxqIx/DgarGvDJZAD3YBTgQ==", "dev": true }, "lead": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", - "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=", + "integrity": "sha512-IpSVCk9AYvLHo5ctcIXxOBpMWUe+4TKN3VPWAKUbJikkmsGp0VrSM8IttVc32D6J4WUsiPE6aEFRNmIoF/gdow==", "dev": true, "requires": { "flush-write-stream": "^1.0.2" @@ -33318,7 +37847,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true } } @@ -33332,13 +37861,13 @@ "listenercount": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", - "integrity": "sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=", + "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==", "dev": true }, "live-connect-js": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/live-connect-js/-/live-connect-js-2.4.0.tgz", - "integrity": "sha512-MSBLKfnXoxH+pqwji/Mf8yZu3VZMq4tnNfwMw7NTWN5a+TBM6f0RWgwui1YMA3nHmMhX/nzxxsso0SkyKcF0fA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/live-connect-js/-/live-connect-js-4.0.0.tgz", + "integrity": "sha512-uycBgFBdEwSq95NImrsOSkTlszUMTGf8luK9GZDWw4D+DL5yFNnCPcrjxUk15U9n9aPmaM1SKmWH5qUXFr8aIA==", "requires": { "tiny-hashes": "1.0.1" } @@ -33389,19 +37918,29 @@ } }, "loader-runner": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", - "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", "dev": true }, + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "p-locate": "^4.1.0" } }, "lodash": { @@ -33413,126 +37952,135 @@ "lodash._basecopy": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "integrity": "sha512-rFR6Vpm4HeCK1WPGvjZSJ+7yik8d8PVUdCJx5rT2pogG4Ve/2ZS7kfmO5l5T2o5V2mqlNIfSF5MZlr1+xOoYQQ==", "dev": true }, "lodash._basetostring": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", - "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=", + "integrity": "sha512-mTzAr1aNAv/i7W43vOR/uD/aJ4ngbtsRaCubp2BfZhlGU/eORUjg/7F6X0orNMdv33JOrdgGybtvMN/po3EWrA==", "dev": true }, "lodash._basevalues": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", - "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", + "integrity": "sha512-H94wl5P13uEqlCg7OcNNhMQ8KvWSIyqXzOPusRgHC9DK3o54P6P3xtbXlVbRABG4q5gSmp7EDdJ0MSuW9HX6Mg==", "dev": true }, "lodash._getnative": { "version": "3.9.1", "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "integrity": "sha512-RrL9VxMEPyDMHOd9uFbvMe8X55X16/cGM5IgOKgRElQZutpX89iS6vwl64duTV1/16w5JY7tuFNXqoekmh1EmA==", "dev": true }, "lodash._isiterateecall": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", - "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "integrity": "sha512-De+ZbrMu6eThFti/CSzhRvTKMgQToLxbij58LMfM8JnYDNSOjkjTCIaa8ixglOeGh2nyPlakbt5bJWJ7gvpYlQ==", "dev": true }, "lodash._reescape": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", - "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=", + "integrity": "sha512-Sjlavm5y+FUVIF3vF3B75GyXrzsfYV8Dlv3L4mEpuB9leg8N6yf/7rU06iLPx9fY0Mv3khVp9p7Dx0mGV6V5OQ==", "dev": true }, "lodash._reevaluate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", - "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=", + "integrity": "sha512-OrPwdDc65iJiBeUe5n/LIjd7Viy99bKwDdk7Z5ljfZg0uFRFlfQaCy9tZ4YMAag9WAZmlVpe1iZrkIMMSMHD3w==", "dev": true }, "lodash._reinterpolate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", + "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==", "dev": true }, "lodash._root": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", - "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=", + "integrity": "sha512-O0pWuFSK6x4EXhM1dhZ8gchNtG7JMqBtrHdoUFUWXD7dJnNSUze1GuyQr5sOs0aCvgGeI3o/OJW8f4ca7FDxmQ==", "dev": true }, "lodash.clone": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz", - "integrity": "sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y=", + "integrity": "sha512-GhrVeweiTD6uTmmn5hV/lzgCQhccwReIVRLHp7LT4SopOjqEZ5BbX8b5WWEtAKasjmy8hR7ZPwsYlxRCku5odg==", "dev": true }, "lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", "dev": true }, "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, "lodash.defaults": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", "dev": true }, "lodash.difference": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", - "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", "dev": true }, + "lodash.escape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", + "integrity": "sha512-n1PZMXgaaDWZDSvuNZ/8XOcYO2hOKDqZel5adtR30VKQAtoWs/5AOeFA0vPV8moiPzlqe7F4cP2tzpFewQyelQ==", + "dev": true, + "requires": { + "lodash._root": "^3.0.0" + } + }, "lodash.flatten": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", "dev": true }, "lodash.flattendeep": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", - "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", "dev": true }, "lodash.get": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", "dev": true }, "lodash.isarguments": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==", "dev": true }, "lodash.isarray": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "integrity": "sha512-JwObCrNJuT0Nnbuecmqr5DgtuBppuCvGD9lxjFpAzwnVtdGoDQ1zig+5W8k5/6Gcn0gZ3936HDAlGd28i7sOGQ==", "dev": true }, "lodash.isobject": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz", - "integrity": "sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0=", + "integrity": "sha512-3/Qptq2vr7WeJbB4KHUSKlq8Pl7ASXi3UG6CMbBm8WRtXi8+GHm7mKaU3urfpSEzWe2wCIChs6/sdocUsTKJiA==", "dev": true }, "lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", "dev": true }, "lodash.keys": { @@ -33555,19 +38103,19 @@ "lodash.pickby": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", - "integrity": "sha1-feoh2MGNdwOifHBMFdO4SmfjOv8=", + "integrity": "sha512-AZV+GsS/6ckvPOVQPXSiFFacKvKB4kOQu6ynt9wz0F3LO4R9Ij4K1ddYsIytDpSgLz88JHd9P+oaLeej5/Sl7Q==", "dev": true }, "lodash.restparam": { "version": "3.6.1", "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", + "integrity": "sha512-L4/arjjuq4noiUJpt3yS6KIKDtJwNe2fIYgMqyYYKoeIfV1iEqvPwhCx23o+R9dzouGihDAPN1dTIRWa7zk8tw==", "dev": true }, "lodash.some": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", - "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=", + "integrity": "sha512-j7MJE+TuT51q9ggt4fSgVqro163BEFjAt3u97IqU+JA2DkWl80nFTrowzLpZ/BnpN7rrl0JA/593NAdd8p/scQ==", "dev": true }, "lodash.template": { @@ -33592,19 +38140,19 @@ "lodash.truncate": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", "dev": true }, "lodash.union": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", "dev": true }, "lodash.zip": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.zip/-/lodash.zip-4.2.0.tgz", - "integrity": "sha1-7GZi5IlkCO1KtsVCo5kLcswIACA=", + "integrity": "sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg==", "dev": true }, "log-driver": { @@ -33623,16 +38171,16 @@ } }, "log4js": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.4.2.tgz", - "integrity": "sha512-k80cggS2sZQLBwllpT1p06GtfvzMmSdUCkW96f0Hj83rKGJDAu2vZjt9B9ag2vx8Zz1IXzxoLgqvRJCdMKybGg==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.7.0.tgz", + "integrity": "sha512-KA0W9ffgNBLDj6fZCq/lRbgR6ABAodRIDHrZnS48vOtfKa4PzWImb0Md1lmGCdO3n3sbCm/n1/WmrNlZ8kCI3Q==", "dev": true, "requires": { - "date-format": "^4.0.4", - "debug": "^4.3.3", - "flatted": "^3.2.5", + "date-format": "^4.0.14", + "debug": "^4.3.4", + "flatted": "^3.2.7", "rfdc": "^1.3.0", - "streamroller": "^3.0.4" + "streamroller": "^3.1.3" } }, "loglevel": { @@ -33695,7 +38243,7 @@ "lru-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", - "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", + "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", "dev": true, "requires": { "es5-ext": "~0.10.2" @@ -33751,7 +38299,7 @@ "map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", "dev": true }, "map-obj": { @@ -33763,13 +38311,13 @@ "map-stream": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", - "integrity": "sha1-ih8HiW2CsQkmvTdEokIACfiJdKg=", + "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==", "dev": true }, "map-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", "dev": true, "requires": { "object-visit": "^1.0.0" @@ -33782,15 +38330,15 @@ "dev": true }, "marky": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.4.tgz", - "integrity": "sha512-zd2/GiSn6U3/jeFVZ0J9CA1LzQ8RfIVvXkb/U0swFHF/zT+dVohTAWjmo2DcIuofmIIIROlwTbd+shSeXmxr0w==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.5.tgz", + "integrity": "sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==", "dev": true }, "matchdep": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", - "integrity": "sha1-xvNINKDY28OzfCfui7yyfHd1WC4=", + "integrity": "sha512-LFgVbaHIHMqCRuCZyfCtUOq9/Lnzhi7Z0KFUE2fhD54+JN2jLh3hC02RLkqauJ3U4soU6H1J3tfj/Byk7GoEjA==", "dev": true, "requires": { "findup-sync": "^2.0.0", @@ -33799,10 +38347,90 @@ "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", - "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "integrity": "sha512-vs+3unmJT45eczmcAZ6zMJtxN3l/QXeccaXQx5cu/MeJMhewVfoWZqibRkOxPnmoR59+Zy5hjabfQc6JLSah4g==", "dev": true, "requires": { "detect-file": "^1.0.0", @@ -33811,14 +38439,77 @@ "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", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", "dev": true, "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" + } } } }, @@ -33929,11 +38620,12 @@ } }, "mdast-util-gfm-table": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.4.tgz", - "integrity": "sha512-aEuoPwZyP4iIMkf2cLWXxx3EQ6Bmh2yKy9MVCg4i6Sd3cX80dcLEfXO/V4ul3pGH9czBK4kp+FAl+ZHmSUt9/w==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.6.tgz", + "integrity": "sha512-uHR+fqFq3IvB3Rd4+kzXW8dmpxUhvgCQZep6KdjsLK4O6meK5dYZEayLtIxNus1XO3gfjfcIFe8a7L0HZRGgag==", "dev": true, "requires": { + "@types/mdast": "^3.0.0", "markdown-table": "^3.0.0", "mdast-util-from-markdown": "^1.0.0", "mdast-util-to-markdown": "^1.3.0" @@ -33952,24 +38644,22 @@ "mdast-util-inject": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/mdast-util-inject/-/mdast-util-inject-1.1.0.tgz", - "integrity": "sha1-2wa4tYW+lZotzS+H9HK6m3VvNnU=", + "integrity": "sha512-CcJ0mHa36QYumDKiZ2OIR+ClhfOM7zIzN+Wfy8tRZ1hpH9DKLCS+Mh4DyK5bCxzE9uxMWcbIpeNFWsg1zrj/2g==", "dev": true, "requires": { "mdast-util-to-string": "^1.0.0" } }, "mdast-util-to-hast": { - "version": "12.2.1", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-12.2.1.tgz", - "integrity": "sha512-dyindR2P7qOqXO1hQirZeGtVbiX7xlNQbw7gGaAwN4A1dh4+X8xU/JyYmRoyB8Fu1uPXzp7mlL5QwW7k+knvgA==", + "version": "12.2.4", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-12.2.4.tgz", + "integrity": "sha512-a21xoxSef1l8VhHxS1Dnyioz6grrJkoaCUgGzMD/7dWHvboYX3VW53esRUfB5tgTyz4Yos1n25SPcj35dJqmAg==", "dev": true, "requires": { "@types/hast": "^2.0.0", "@types/mdast": "^3.0.0", - "@types/mdurl": "^1.0.0", "mdast-util-definitions": "^5.0.0", - "mdurl": "^1.0.0", - "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-sanitize-uri": "^1.1.0", "trim-lines": "^3.0.0", "unist-builder": "^3.0.0", "unist-util-generated": "^2.0.0", @@ -34051,16 +38741,10 @@ } } }, - "mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", - "dev": true - }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" }, "memoizee": { "version": "0.4.15", @@ -34091,7 +38775,7 @@ "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" }, "merge-stream": { "version": "2.0.0", @@ -34102,12 +38786,12 @@ "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" }, "micromark": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.0.10.tgz", - "integrity": "sha512-ryTDy6UUunOXy2HPjelppgJ2sNfcPz1pLlMdA6Rz9jPzhLikWXv/irpWV/I2jd68Uhmny7hHxAlAhk4+vWggpg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.1.0.tgz", + "integrity": "sha512-6Mj0yHLdUZjHnOPgr5xfWIMqMWS12zDN6iws9SLuSz76W8jTtAv24MN4/CL7gJrl5vtxGInkkqDv/JIoRsQOvA==", "dev": true, "requires": { "@types/debug": "^4.0.0", @@ -34397,9 +39081,9 @@ } }, "micromark-util-sanitize-uri": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.0.0.tgz", - "integrity": "sha512-cCxvBKlmac4rxCGx6ejlIviRaMKZc0fWm5HdCHEeDWRSkn44l6NdYVRyU+0nT1XC72EQJMZV8IPHF+jTr56lAg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.1.0.tgz", + "integrity": "sha512-RoxtuSCX6sUNtxhbmsEFQfWzs8VN7cTctmBPvYivo98xb/kDEoTCtJQX5wyzIYEmk/lvNFTat4hL8oW0KndFpg==", "dev": true, "requires": { "micromark-util-character": "^1.0.0", @@ -34432,100 +39116,13 @@ "dev": true }, "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "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": { - "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": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "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": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "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": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "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": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - } + "braces": "^3.0.2", + "picomatch": "^2.3.1" } }, "mime": { @@ -34535,16 +39132,16 @@ "dev": true }, "mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==" + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" }, "mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "requires": { - "mime-db": "1.51.0" + "mime-db": "1.52.0" } }, "mimic-fn": { @@ -34578,9 +39175,9 @@ } }, "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", "dev": true }, "mixin-deep": { @@ -34634,6 +39231,12 @@ "yargs-unparser": "2.0.0" }, "dependencies": { + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -34649,15 +39252,6 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "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, - "requires": { - "balanced-match": "^1.0.0" - } - }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -34679,6 +39273,17 @@ } } }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -34694,22 +39299,11 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "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" - }, - "dependencies": { - "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 - } - } + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true }, "escape-string-regexp": { "version": "4.0.0", @@ -34727,6 +39321,37 @@ "path-exists": "^4.0.0" } }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "dependencies": { + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "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 + }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -34762,6 +39387,17 @@ "dev": true, "requires": { "brace-expansion": "^2.0.1" + }, + "dependencies": { + "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, + "requires": { + "balanced-match": "^1.0.0" + } + } } }, "ms": { @@ -34770,12 +39406,6 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true - }, "p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -34794,23 +39424,20 @@ "p-limit": "^3.0.2" } }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, - "workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } }, "yargs": { "version": "16.2.0", @@ -34857,17 +39484,20 @@ "ms": "2.0.0" } }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true - }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } } } }, @@ -34890,9 +39520,9 @@ "dev": true }, "mrmime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.0.tgz", - "integrity": "sha512-a70zx7zFfVO7XpnQ2IX1Myh9yY4UYvfld/dikWRnsXxbyvMcfz+u6UfgNAtH+k2QqtJuzVpv6eLTx1G2+WKZbQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", + "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", "dev": true }, "ms": { @@ -34903,45 +39533,10 @@ "multipipe": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", - "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", + "integrity": "sha512-7ZxrUybYv9NonoXgwoOqtStIu18D1c3eFZj27hqgf5kBrBF8Q+tE8V0MW8dKM5QLkQPh1JhhbKgHLY9kifov4Q==", "dev": true, "requires": { "duplexer2": "0.0.2" - }, - "dependencies": { - "duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", - "dev": true, - "requires": { - "readable-stream": "~1.1.9" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - } } }, "mute-stdout": { @@ -34974,11 +39569,10 @@ "optional": true }, "nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "dev": true, - "optional": true + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true }, "nanomatch": { "version": "1.2.13", @@ -34999,6 +39593,22 @@ "to-regex": "^3.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 + }, + "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" + } + }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -35010,13 +39620,13 @@ "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, "ncp": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/ncp/-/ncp-0.4.2.tgz", - "integrity": "sha1-q8xsvT7C7Spyn/bnwfqPAXhKhXQ=", + "integrity": "sha512-PfGU8jYWdRl4FqJfCy0IzbkGyFHntfWygZg46nFk/dJD/XRrk2cj0SsKSX9n5u5gE0E0YfEpKWrEkfjnlZSTXA==", "dev": true }, "negotiator": { @@ -35068,7 +39678,7 @@ "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", "dev": true }, "lolex": { @@ -35108,29 +39718,32 @@ "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", "dev": true, "requires": { "abbrev": "1" } }, "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", "dev": true, "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", "validate-npm-package-license": "^3.0.1" }, "dependencies": { "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } } } }, @@ -35158,7 +39771,7 @@ "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", "dev": true, "requires": { "path-key": "^2.0.0" @@ -35167,7 +39780,7 @@ "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", "dev": true } } @@ -35175,7 +39788,7 @@ "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", "dev": true }, "oauth-sign": { @@ -35187,13 +39800,13 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true }, "object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", "dev": true, "requires": { "copy-descriptor": "^0.1.0", @@ -35204,7 +39817,7 @@ "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "requires": { "is-descriptor": "^0.1.0" @@ -35213,7 +39826,7 @@ "is-accessor-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -35228,7 +39841,7 @@ "is-data-descriptor": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -35256,7 +39869,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -35265,10 +39878,9 @@ } }, "object-inspect": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", - "dev": true + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" }, "object-is": { "version": "1.1.5", @@ -35283,32 +39895,34 @@ "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true }, "object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", "dev": true, "requires": { "isobject": "^3.0.0" } }, "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", "object-keys": "^1.1.1" } }, "object.defaults": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", - "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", + "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==", "dev": true, "requires": { "array-each": "^1.0.1", @@ -35320,7 +39934,7 @@ "object.map": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", - "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", + "integrity": "sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==", "dev": true, "requires": { "for-own": "^1.0.0", @@ -35330,7 +39944,7 @@ "object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", "dev": true, "requires": { "isobject": "^3.0.1" @@ -35339,7 +39953,7 @@ "object.reduce": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", - "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=", + "integrity": "sha512-naLhxxpUESbNkRqc35oQ2scZSJueHGQNUfMW/0U37IgN6tE2dgDWg3whf+NEliy3F/QysrO48XKUz/nGPe+AQw==", "dev": true, "requires": { "for-own": "^1.0.0", @@ -35358,9 +39972,9 @@ } }, "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "requires": { "ee-first": "1.1.1" } @@ -35374,7 +39988,7 @@ "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, "requires": { "wrappy": "1" @@ -35407,7 +40021,7 @@ "is-wsl": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", "dev": true } } @@ -35477,6 +40091,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "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 + }, "log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -35501,7 +40121,7 @@ "ordered-read-streams": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", - "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", + "integrity": "sha512-Z87aSjx3r5c0ZB7bcJqIgIRX5bxR7A4aSzvIbaxd0oTkWBCOoKfuGHiKj60CHVUgg1Phm5yMZzBdt8XqRs73Mw==", "dev": true, "requires": { "readable-stream": "^2.0.1" @@ -35510,13 +40130,13 @@ "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", "dev": true }, "os-locale": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "integrity": "sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==", "dev": true, "requires": { "lcid": "^1.0.0" @@ -35525,7 +40145,7 @@ "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "dev": true }, "p-cancelable": { @@ -35537,7 +40157,7 @@ "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", "dev": true }, "p-iteration": { @@ -35547,27 +40167,27 @@ "dev": true }, "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "requires": { - "p-try": "^1.0.0" + "p-try": "^2.0.0" } }, "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "requires": { - "p-limit": "^1.1.0" + "p-limit": "^2.2.0" } }, "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, "parent-module": { @@ -35582,7 +40202,7 @@ "parse-filepath": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", - "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", + "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==", "dev": true, "requires": { "is-absolute": "^1.0.0", @@ -35617,28 +40237,25 @@ "parse-passwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", "dev": true }, "parse-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-5.0.0.tgz", - "integrity": "sha512-qOpH55/+ZJ4jUu/oLO+ifUKjFPNZGfnPJtzvGzKN/4oLMil5m9OH4VpOj6++9/ytJcfks4kzH2hhi87GL/OU9A==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-7.0.0.tgz", + "integrity": "sha512-Euf9GG8WT9CdqwuWJGdf3RkUcTBArppHABkO7Lm8IzRQp0e2r/kkFnmhu4TSK30Wcu5rVAZLmfPKSBBi9tWFog==", "dev": true, "requires": { "protocols": "^2.0.0" } }, "parse-url": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-7.0.2.tgz", - "integrity": "sha512-PqO4Z0eCiQ08Wj6QQmrmp5YTTxpYfONdOEamrtvK63AmzXpcavIVQubGHxOEwiIoDZFb8uDOoQFS0NCcjqIYQg==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-8.1.0.tgz", + "integrity": "sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w==", "dev": true, "requires": { - "is-ssh": "^1.4.0", - "normalize-url": "^6.1.0", - "parse-path": "^5.0.0", - "protocols": "^2.0.1" + "parse-path": "^7.0.0" } }, "parseurl": { @@ -35649,25 +40266,25 @@ "pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", "dev": true }, "path-dirname": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==", "dev": true }, "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true }, "path-key": { @@ -35684,7 +40301,7 @@ "path-root": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", - "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==", "dev": true, "requires": { "path-root-regex": "^0.1.0" @@ -35693,13 +40310,13 @@ "path-root-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", - "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", + "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", "dev": true }, "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, "path-type": { "version": "1.1.0", @@ -35729,7 +40346,7 @@ "pause-stream": { "version": "0.0.11", "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", + "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", "dev": true, "requires": { "through": "~2.3" @@ -35738,13 +40355,13 @@ "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", "dev": true }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", "dev": true }, "picocolors": { @@ -35767,13 +40384,13 @@ "pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", "dev": true }, "pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", "dev": true, "requires": { "pinkie": "^2.0.0" @@ -35795,98 +40412,46 @@ "dev": true, "requires": { "find-up": "^4.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - } } }, "plugin-error": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", - "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", + "integrity": "sha512-WzZHcm4+GO34sjFMxQMqZbsz3xiNEgonCskQ9v+IroMmYgk/tas8dG+Hr2D6IbRPybZ12oWpzE/w3cGJ6FJzOw==", "dev": true, "requires": { - "ansi-colors": "^1.0.1", - "arr-diff": "^4.0.0", - "arr-union": "^3.1.0", - "extend-shallow": "^3.0.2" - }, - "dependencies": { - "ansi-colors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", - "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", - "dev": true, - "requires": { - "ansi-wrap": "^0.1.0" - } - } + "ansi-cyan": "^0.1.1", + "ansi-red": "^0.1.1", + "arr-diff": "^1.0.1", + "arr-union": "^2.0.1", + "extend-shallow": "^1.1.2" } }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", "dev": true }, "postcss": { - "version": "8.4.16", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz", - "integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==", + "version": "8.4.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.18.tgz", + "integrity": "sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==", "dev": true, "optional": true, "requires": { "nanoid": "^3.3.4", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" + }, + "dependencies": { + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true, + "optional": true + } } }, "prelude-ls": { @@ -35896,20 +40461,39 @@ "dev": true }, "pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", "dev": true, "requires": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", "react-is": "^17.0.1" }, "dependencies": { "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "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 } } @@ -35917,7 +40501,7 @@ "pretty-hrtime": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", - "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", + "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==", "dev": true }, "pretty-ms": { @@ -35929,12 +40513,6 @@ "parse-ms": "^2.1.0" } }, - "printj": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/printj/-/printj-1.3.1.tgz", - "integrity": "sha512-GA3TdL8szPK4AQ2YnOe/b+Y1jUFwmmGMMK/qbY7VcE3Z7FU8JstbKiKRzO6CIiAKPhTO8m01NoQ0V5f3jc4OGg==", - "dev": true - }, "private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", @@ -35989,7 +40567,7 @@ "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", "dev": true }, "ps-tree": { @@ -36004,13 +40582,13 @@ "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", "dev": true }, "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", "dev": true }, "pump": { @@ -36065,16 +40643,16 @@ "dev": true }, "puppeteer-core": { - "version": "13.5.1", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-13.5.1.tgz", - "integrity": "sha512-dobVqWjV34ilyfQHR3BBnCYaekBYTi5MgegEYBRYd3s3uFy8jUpZEEWbaFjG9ETm+LGzR5Lmr0aF6LLuHtiuCg==", + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-13.7.0.tgz", + "integrity": "sha512-rXja4vcnAzFAP1OVLq/5dWNfwBGuzcOARJ6qGV7oAZhnLmVRU8G5MsdeQEAOy332ZhkIOnn9jp15R89LKHyp2Q==", "dev": true, "requires": { "cross-fetch": "3.1.5", - "debug": "4.3.3", - "devtools-protocol": "0.0.969999", + "debug": "4.3.4", + "devtools-protocol": "0.0.981744", "extract-zip": "2.0.1", - "https-proxy-agent": "5.0.0", + "https-proxy-agent": "5.0.1", "pkg-dir": "4.2.0", "progress": "2.0.3", "proxy-from-env": "1.1.0", @@ -36084,31 +40662,12 @@ "ws": "8.5.0" }, "dependencies": { - "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, - "requires": { - "debug": "4" - } - }, "devtools-protocol": { - "version": "0.0.969999", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.969999.tgz", - "integrity": "sha512-6GfzuDWU0OFAuOvBokXpXPLxjOJ5DZ157Ue3sGQQM3LgAamb8m0R0ruSfN0DDu+XG5XJgT50i6zZ/0o8RglreQ==", + "version": "0.0.981744", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.981744.tgz", + "integrity": "sha512-0cuGS8+jhR67Fy7qG3i3Pc7Aw494sb9yG9QgpG97SFVWwolgYjlhJg7n+UaHxOQT30d1TYu/EYe9k01ivLErIg==", "dev": true }, - "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, "ws": { "version": "8.5.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", @@ -36121,7 +40680,7 @@ "q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", "dev": true }, "qjobs": { @@ -36131,9 +40690,12 @@ "dev": true }, "qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==" + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "requires": { + "side-channel": "^1.0.4" + } }, "query-selector-shadow-dom": { "version": "1.0.0", @@ -36144,7 +40706,7 @@ "querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", "dev": true }, "querystringify": { @@ -36174,12 +40736,12 @@ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, "raw-body": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", - "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", "requires": { "bytes": "3.1.2", - "http-errors": "1.8.1", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" } @@ -36202,36 +40764,6 @@ "type-fest": "^2.0.0" }, "dependencies": { - "hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "normalize-package-data": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", - "dev": true, - "requires": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - } - }, - "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, "type-fest": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", @@ -36326,18 +40858,44 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true } } }, "readdir-glob": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.1.tgz", - "integrity": "sha512-91/k1EzZwDx6HbERR+zucygRFfiPl2zkIYZtv3Jjr6Mn7SkKcVct8aVO+sSRiGMc6fLf72du3d92/uY63YPdEA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.2.tgz", + "integrity": "sha512-6RLVvwJtVwEDfPdn6X6Ille4/lxGl0ATOY4FN/B9nxQcgOazvvI0nodiD19ScKq0PvA/29VpaOQML36o5IzZWA==", "dev": true, "requires": { - "minimatch": "^3.0.4" + "minimatch": "^5.1.0" + }, + "dependencies": { + "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, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } } }, "readdirp": { @@ -36352,30 +40910,19 @@ "rechoir": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", "dev": true, "requires": { "resolve": "^1.1.6" } }, "recursive-readdir": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", - "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", "dev": true, "requires": { - "minimatch": "3.0.4" - }, - "dependencies": { - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - } + "minimatch": "^3.0.5" } }, "regenerate": { @@ -36384,23 +40931,22 @@ "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" }, "regenerate-unicode-properties": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", - "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", + "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", "requires": { "regenerate": "^1.4.2" } }, "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true + "version": "0.13.10", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz", + "integrity": "sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==" }, "regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", + "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", "requires": { "@babel/runtime": "^7.8.4" } @@ -36413,16 +40959,29 @@ "requires": { "extend-shallow": "^3.0.2", "safe-regex": "^1.1.0" + }, + "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" + } + } } }, "regexp.prototype.flags": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz", - "integrity": "sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" } }, "regexpp": { @@ -36432,27 +40991,27 @@ "dev": true }, "regexpu-core": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", - "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.1.tgz", + "integrity": "sha512-HrnlNtpvqP1Xkb28tMhBUO2EbyUHdQlsnlAhzWcwHy8WJR53UWr7/MAvqrsQKMbV4qdpv03oTMG8iIhfsPFktQ==", "requires": { "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.0.1", - "regjsgen": "^0.6.0", - "regjsparser": "^0.8.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsgen": "^0.7.1", + "regjsparser": "^0.9.1", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.0.0" } }, "regjsgen": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", - "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==" + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", + "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==" }, "regjsparser": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", - "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", "requires": { "jsesc": "~0.5.0" }, @@ -36460,7 +41019,7 @@ "jsesc": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==" } } }, @@ -36566,7 +41125,7 @@ "remove-bom-stream": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", - "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=", + "integrity": "sha512-wigO8/O08XHb8YPzpDDT+QmRANfW6vLqxfaXm1YXhnFf3AkSLyjfG3GEFg4McZkmgL7KvCj5u2KczkvSP6NfHA==", "dev": true, "requires": { "remove-bom-buffer": "^3.0.0", @@ -36589,7 +41148,7 @@ "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", "dev": true }, "repeat-element": { @@ -36601,13 +41160,13 @@ "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", "dev": true }, "repeating": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "integrity": "sha512-ZqtSMuVybkISo2OWvqvm7iHSWngvdaW3IpsT9/uP8v4gMi591LY6h35wdOfvQdWCKFWZWm2Y1Opp4kV7vQKT6A==", "dev": true, "requires": { "is-finite": "^1.0.0" @@ -36616,13 +41175,13 @@ "replace-ext": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", + "integrity": "sha512-AFBWBy9EVRTa/LhEcG8QDP3FvpwZqmvN2QFDuJswFeaVhWnZMp8q3E6Zd90SR04PlIwfGdyVjNyLPyen/ek5CQ==", "dev": true }, "replace-homedir": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", - "integrity": "sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=", + "integrity": "sha512-CHPV/GAglbIB1tnQgaiysb8H2yCy8WQ7lcEwQ/eT+kLj0QHV8LnJW0zpqpE7RSkrMSRoa+EBoag86clf7WAgSg==", "dev": true, "requires": { "homedir-polyfill": "^1.0.1", @@ -36680,7 +41239,7 @@ "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true }, "require-from-string": { @@ -36689,10 +41248,16 @@ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==", + "dev": true + }, "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true }, "resolve": { @@ -36714,7 +41279,7 @@ "resolve-dir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", "dev": true, "requires": { "expand-tilde": "^2.0.0", @@ -36730,7 +41295,7 @@ "resolve-options": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", - "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=", + "integrity": "sha512-NYDgziiroVeDC29xq7bp/CacZERYsA9bXYd1ZmcJlF3BcrZv5pTb4NG7SjdyKDnXZ84aC4vo2u6sNKIA1LCu/A==", "dev": true, "requires": { "value-or-function": "^3.0.0" @@ -36739,13 +41304,13 @@ "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", "dev": true }, "responselike": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", - "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", "dev": true, "requires": { "lowercase-keys": "^2.0.0" @@ -36763,7 +41328,7 @@ "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "integrity": "sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==", "dev": true } } @@ -36821,20 +41386,12 @@ } }, "rxjs": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", - "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", "dev": true, "requires": { - "tslib": "^2.1.0" - }, - "dependencies": { - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - } + "tslib": "^1.9.0" } }, "sade": { @@ -36847,25 +41404,36 @@ } }, "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, "safe-json-parse": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz", - "integrity": "sha1-PnZyPjjf3aE8mx0poeB//uSzC1c=", + "integrity": "sha512-o0JmTu17WGUaUOHa1l0FPGXKBfijbxK6qoHzlkihsDXxzBHvJcA7zgviKR92Xs841rX9pK16unfphLq0/KqX7A==", "dev": true }, "safe-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", "dev": true, "requires": { "ret": "~0.1.10" } }, + "safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + } + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -36899,13 +41467,6 @@ "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } - }, - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} } } }, @@ -36917,30 +41478,30 @@ "semver-greatest-satisfied-range": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", - "integrity": "sha1-E+jCZYq5aRywzXEJMkAoDTb3els=", + "integrity": "sha512-Ny/iyOzSSa8M5ML46IAx3iXc6tfOsYU2R4AXi2UpHk60Zrgyq6eqPj/xiOfS0rRl/iiQ/rdJkVjw/5cdUyCntQ==", "dev": true, "requires": { "sver-compat": "^1.5.0" } }, "send": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", - "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "requires": { "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", + "depd": "2.0.0", + "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "1.8.1", + "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "range-parser": "~1.2.1", - "statuses": "~1.5.0" + "statuses": "2.0.1" }, "dependencies": { "debug": { @@ -36954,7 +41515,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" } } }, @@ -36999,7 +41560,7 @@ "serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", "dev": true, "requires": { "accepts": "~1.3.4", @@ -37020,10 +41581,16 @@ "ms": "2.0.0" } }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true + }, "http-errors": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", "dev": true, "requires": { "depd": "~1.1.2", @@ -37035,13 +41602,13 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", "dev": true }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "setprototypeof": { @@ -37049,24 +41616,30 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", "dev": true + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true } } }, "serve-static": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", - "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "requires": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.2" + "send": "0.18.0" } }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "dev": true }, "set-value": { @@ -37084,7 +41657,7 @@ "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "requires": { "is-extendable": "^0.1.0" @@ -37093,7 +41666,7 @@ "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true }, "is-plain-object": { @@ -37110,7 +41683,7 @@ "setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", "dev": true }, "setprototypeof": { @@ -37137,7 +41710,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, "requires": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -37170,21 +41742,6 @@ "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } } } }, @@ -37200,9 +41757,9 @@ } }, "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg==", "dev": true }, "slice-ansi": { @@ -37270,7 +41827,7 @@ "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "requires": { "is-descriptor": "^0.1.0" @@ -37279,7 +41836,7 @@ "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "requires": { "is-extendable": "^0.1.0" @@ -37288,7 +41845,7 @@ "is-accessor-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -37297,7 +41854,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -37314,7 +41871,7 @@ "is-data-descriptor": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -37323,7 +41880,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -37345,13 +41902,13 @@ "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "source-map-resolve": { @@ -37383,7 +41940,7 @@ "define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, "requires": { "is-descriptor": "^1.0.0" @@ -37409,7 +41966,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -37418,33 +41975,32 @@ } }, "socket.io": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.4.1.tgz", - "integrity": "sha512-s04vrBswdQBUmuWJuuNTmXUVJhP0cVky8bBDhdkf8y0Ptsu7fKU2LuLbts9g+pdmAdyMMn8F/9Mf1/wbtUN0fg==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.3.tgz", + "integrity": "sha512-zdpnnKU+H6mOp7nYRXH4GNv1ux6HL6+lHL8g7Ds7Lj8CkdK1jJK/dlwsKDculbyOHifcJ0Pr/yeXnZQ5GeFrcg==", "dev": true, "requires": { "accepts": "~1.3.4", "base64id": "~2.0.0", "debug": "~4.3.2", - "engine.io": "~6.1.0", - "socket.io-adapter": "~2.3.3", - "socket.io-parser": "~4.0.4" + "engine.io": "~6.2.0", + "socket.io-adapter": "~2.4.0", + "socket.io-parser": "~4.2.0" } }, "socket.io-adapter": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.3.3.tgz", - "integrity": "sha512-Qd/iwn3VskrpNO60BeRyCyr8ZWw9CPZyitW4AQwmRZ8zCiyDiL+znRnWX6tDHXnWn1sJrM1+b6Mn6wEDJJ4aYQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz", + "integrity": "sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg==", "dev": true }, "socket.io-parser": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.4.tgz", - "integrity": "sha512-t+b0SS+IxG7Rxzda2EVvyBZbvFPBCjJoyHuE0P//7OAsN23GItzDRdWa6ALxZI/8R5ygK7jAR6t028/z+7295g==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz", + "integrity": "sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==", "dev": true, "requires": { - "@types/component-emitter": "^1.2.10", - "component-emitter": "~1.3.0", + "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" } }, @@ -37457,7 +42013,7 @@ "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "dev": true }, "source-map-js": { @@ -37478,21 +42034,12 @@ } }, "source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", "dev": true, "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } + "source-map": "^0.5.6" } }, "source-map-url": { @@ -37547,15 +42094,15 @@ } }, "spdx-license-ids": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", - "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==", + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", + "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", "dev": true }, "split": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", - "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", + "integrity": "sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==", "dev": true, "requires": { "through": "2" @@ -37568,18 +42115,46 @@ "dev": true, "requires": { "extend-shallow": "^3.0.0" + }, + "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" + } + } } }, "split2": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", - "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==", - "dev": true + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "dev": true, + "requires": { + "readable-stream": "^3.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, "sshpk": { @@ -37602,7 +42177,7 @@ "stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", "dev": true }, "stack-utils": { @@ -37625,7 +42200,7 @@ "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", "dev": true, "requires": { "define-property": "^0.2.5", @@ -37635,7 +42210,7 @@ "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "requires": { "is-descriptor": "^0.1.0" @@ -37644,7 +42219,7 @@ "is-accessor-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -37653,7 +42228,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -37670,7 +42245,7 @@ "is-data-descriptor": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -37679,7 +42254,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -37701,9 +42276,9 @@ } }, "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" }, "stream-buffers": { "version": "3.0.2", @@ -37714,7 +42289,7 @@ "stream-combiner": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", - "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", + "integrity": "sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==", "dev": true, "requires": { "duplexer": "~0.1.1" @@ -37733,14 +42308,42 @@ "dev": true }, "streamroller": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.0.4.tgz", - "integrity": "sha512-GI9NzeD+D88UFuIlJkKNDH/IsuR+qIN7Qh8EsmhoRZr9bQoehTraRgwtLUkZbpcAw+hLPfHOypmppz8YyGK68w==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.3.tgz", + "integrity": "sha512-CphIJyFx2SALGHeINanjFRKQ4l7x2c+rXYJ4BMq0gd+ZK0gi4VT8b+eHe2wi58x4UayBAKx4xtHpXT/ea1cz8w==", "dev": true, "requires": { - "date-format": "^4.0.4", - "debug": "^4.3.3", - "fs-extra": "^10.0.1" + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" + }, + "dependencies": { + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + } } }, "string_decoder": { @@ -37750,12 +42353,20 @@ "dev": true, "requires": { "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } } }, "string-template": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", - "integrity": "sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=", + "integrity": "sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw==", "dev": true }, "string-width": { @@ -37767,34 +42378,28 @@ "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" - }, - "dependencies": { - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - } } }, "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", + "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" } }, "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", + "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" } }, "stringify-entities": { @@ -37819,34 +42424,39 @@ "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true }, "strip-bom-string": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", - "integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", "dev": true }, "strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", + "dev": true + }, + "strip-json-comments": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.0.tgz", + "integrity": "sha512-V1LGY4UUo0jgwC+ELQ2BNWfPa17TIuwBLg+j1AA/9RPzKINl1lhxVEu2r+ZTTO8aetIsUzE5Qj6LMSBkoGYKKw==", "dev": true }, "suffix": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/suffix/-/suffix-0.1.1.tgz", - "integrity": "sha1-zFgjFkag7xEC95R47zqSSP2chC8=", + "integrity": "sha512-j5uf6MJtMCfC4vBe5LFktSe4bGyNTBk7I2Kdri0jeLrcv5B9pWfxVa5JQpoxgtR8vaVB7bVxsWgnfQbX5wkhAA==", "dev": true }, "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^4.0.0" + "has-flag": "^3.0.0" } }, "supports-preserve-symlinks-flag": { @@ -37857,7 +42467,7 @@ "sver-compat": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", - "integrity": "sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=", + "integrity": "sha512-aFTHfmjwizMNlNE6dsGmoAM4lHjL0CyiobWaFiXWSlD7cIxshW422Nb8KbXCmR6z+0ZEPY+daXJrDyh/vuwTyg==", "dev": true, "requires": { "es6-iterator": "^2.0.1", @@ -37878,9 +42488,9 @@ }, "dependencies": { "ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -37944,7 +42554,7 @@ "temp-fs": { "version": "0.9.9", "resolved": "https://registry.npmjs.org/temp-fs/-/temp-fs-0.9.9.tgz", - "integrity": "sha1-gHFzBDeHByDpQxUy/igUNk+IA9c=", + "integrity": "sha512-WfecDCR1xC9b0nsrzSaxPf3ZuWeWLUWblW4vlDQAa1biQaKHiImHnJfeQocQe/hXKMcolRzgkcVX/7kK4zoWbw==", "dev": true, "requires": { "rimraf": "~2.5.2" @@ -37953,7 +42563,7 @@ "rimraf": { "version": "2.5.4", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz", - "integrity": "sha1-loAAk8vxoMhr2VtGJUZ1NcKd+gQ=", + "integrity": "sha512-Lw7SHMjssciQb/rRz7JyPIy9+bbUshEucPoLRvWqy09vC5zQixl8Uet+Zl+SROBB/JMWHJRdCk1qdxNWHNMvlQ==", "dev": true, "requires": { "glob": "^7.0.5" @@ -37986,9 +42596,9 @@ } }, "terser": { - "version": "5.14.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", - "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", + "version": "5.15.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", + "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", "dev": true, "requires": { "@jridgewell/source-map": "^0.3.2", @@ -37998,30 +42608,40 @@ }, "dependencies": { "acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "dev": true }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } } } }, "terser-webpack-plugin": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz", - "integrity": "sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g==", + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", + "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", "dev": true, "requires": { + "@jridgewell/trace-mapping": "^0.3.14", "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1", - "terser": "^5.7.2" + "terser": "^5.14.1" }, "dependencies": { "ajv": { @@ -38036,13 +42656,6 @@ "uri-js": "^4.2.2" } }, - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} - }, "schema-utils": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", @@ -38053,12 +42666,6 @@ "ajv": "^6.12.5", "ajv-keywords": "^3.5.2" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -38076,7 +42683,7 @@ "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, "textextensions": { @@ -38088,7 +42695,7 @@ "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "dev": true }, "through2": { @@ -38138,7 +42745,7 @@ "time-stamp": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", - "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", + "integrity": "sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw==", "dev": true }, "timers-ext": { @@ -38182,18 +42789,18 @@ } }, "tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "requires": { - "rimraf": "^3.0.0" + "os-tmpdir": "~1.0.2" } }, "to-absolute-glob": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", - "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", + "integrity": "sha512-rtwLUQEwT8ZeKQbyFJyomBRYXyE16U5VKuy0ftxLMK/PZb2fkOsg5r9kHdauuVDbsNdIBoC/HCthpidamQFXYA==", "dev": true, "requires": { "is-absolute": "^1.0.0", @@ -38203,12 +42810,12 @@ "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" }, "to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -38223,7 +42830,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -38241,6 +42848,18 @@ "extend-shallow": "^3.0.2", "regex-not": "^1.0.2", "safe-regex": "^1.1.0" + }, + "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" + } + } } }, "to-regex-range": { @@ -38250,20 +42869,12 @@ "dev": true, "requires": { "is-number": "^7.0.0" - }, - "dependencies": { - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - } } }, "to-through": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", - "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=", + "integrity": "sha512-+QIz37Ly7acM4EMdw2PRN389OneM5+d844tirkGp4dPKzI5OE72V9OsbFp+CIYJDahZ41ZV05hNtcPAQUAm9/Q==", "dev": true, "requires": { "through2": "^2.0.3" @@ -38305,13 +42916,13 @@ "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "dev": true }, "traverse": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", - "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=", + "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", "dev": true }, "trim-lines": { @@ -38323,7 +42934,7 @@ "trim-right": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "integrity": "sha512-WZGXGstmCWgeevgTL54hrCuw1dyMQIzWy7ZfqRJfSmJZBwklI15egmQytFP6bPidmw3M8d5yEowl1niq4vmqZw==", "dev": true }, "trough": { @@ -38333,14 +42944,14 @@ "dev": true }, "tsconfig-paths": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.13.0.tgz", - "integrity": "sha512-nWuffZppoaYK0vQ1SQmkSsQzJoHA4s6uzdb2waRpD806x9yfq153AdVsWz4je2qZcW+pENrMQXbGQ3sMCkXuhw==", + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", "dev": true, "requires": { "@types/json5": "^0.0.29", "json5": "^1.0.1", - "minimist": "^1.2.0", + "minimist": "^1.2.6", "strip-bom": "^3.0.0" }, "dependencies": { @@ -38364,7 +42975,7 @@ "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, "requires": { "safe-buffer": "^5.0.1" @@ -38373,7 +42984,7 @@ "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", "dev": true }, "type": { @@ -38415,7 +43026,7 @@ "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", "dev": true }, "typescript": { @@ -38447,27 +43058,27 @@ } }, "ua-parser-js": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz", - "integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==", + "version": "0.7.33", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.33.tgz", + "integrity": "sha512-s8ax/CeZdK9R/56Sui0WM6y9OFREJarMRHqLB2EwkovemBxNQ+Bqu8GAsUnVcXKgphb++ghr/B2BZx4mahujPw==", "dev": true }, "uglify-js": { - "version": "3.15.2", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.2.tgz", - "integrity": "sha512-peeoTk3hSwYdoc9nrdiEJk+gx1ALCtTjdYuKSXMTDqq7n1W7dHPqWDdSi+BPL0ni2YMeHD7hKUSdbj3TZauY2A==", + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", "dev": true, "optional": true }, "unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "dev": true, "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", "which-boxed-primitive": "^1.0.2" } }, @@ -38484,7 +43095,7 @@ "unc-path-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", - "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", + "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", "dev": true }, "undertaker": { @@ -38508,7 +43119,7 @@ "fast-levenshtein": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz", - "integrity": "sha1-5qdUzI8V5YmHqpy9J69m/W9OWvk=", + "integrity": "sha512-Ia0sQNrMPXXkqVFt6w6M1n1oKo3NfKs+mvaV811Jwir7vAk9a6PVV9VPYf6X3BU97QiLEmuW3uXH9u87zDFfdw==", "dev": true } } @@ -38516,7 +43127,7 @@ "undertaker-registry": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", - "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=", + "integrity": "sha512-UR1khWeAjugW3548EfQmL9Z7pGMlBgXteQpr1IZeZBtnkCJQJIJ1Scj0mb9wQaPvUZ9Q17XqW6TIaPchJkyfqw==", "dev": true }, "unicode-canonical-property-names-ecmascript": { @@ -38539,9 +43150,9 @@ "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==" }, "unicode-property-aliases-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", - "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==" }, "unified": { "version": "10.1.2", @@ -38570,10 +43181,16 @@ "set-value": "^2.0.1" }, "dependencies": { + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true + }, "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true } } @@ -38657,12 +43274,12 @@ "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" }, "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", "dev": true, "requires": { "has-value": "^0.3.1", @@ -38672,7 +43289,7 @@ "has-value": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", "dev": true, "requires": { "get-value": "^2.0.3", @@ -38683,7 +43300,7 @@ "isobject": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", "dev": true, "requires": { "isarray": "1.0.0" @@ -38694,13 +43311,13 @@ "has-values": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", "dev": true }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true } } @@ -38720,6 +43337,17 @@ "listenercount": "~1.0.1", "readable-stream": "~2.3.6", "setimmediate": "~1.0.4" + }, + "dependencies": { + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dev": true, + "requires": { + "readable-stream": "^2.0.2" + } + } } }, "upath": { @@ -38729,9 +43357,9 @@ "dev": true }, "update-browserslist-db": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.7.tgz", - "integrity": "sha512-iN/XYesmZ2RmmWAiI4Z5rq0YqSiv0brj9Ce9CfhNE4xIW2h+MFxcgkxIzZ+ShkFPUkjU3gQ+3oypadD3RAMtrg==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", "requires": { "escalade": "^3.1.1", "picocolors": "^1.0.0" @@ -38749,13 +43377,13 @@ "urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", "dev": true }, "url": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "integrity": "sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==", "dev": true, "requires": { "punycode": "1.3.2", @@ -38765,7 +43393,7 @@ "punycode": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==", "dev": true } } @@ -38793,29 +43421,28 @@ "dev": true }, "util": { - "version": "0.12.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz", - "integrity": "sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==", + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", "dev": true, "requires": { "inherits": "^2.0.3", "is-arguments": "^1.0.4", "is-generator-function": "^1.0.7", "is-typed-array": "^1.1.3", - "safe-buffer": "^5.1.2", "which-typed-array": "^1.1.2" } }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" }, "uuid": { "version": "3.4.0", @@ -38863,18 +43490,18 @@ "value-or-function": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", - "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=", + "integrity": "sha512-jdBB2FrWvQC/pnPtIqcLsMaQgjhdb6B7tk1MMyTKapox+tQZbdRP4uLxu/JY0t7fbfDCUMnuelzEYv5GsxHhdg==", "dev": true }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", "dev": true, "requires": { "assert-plus": "^1.0.0", @@ -38885,15 +43512,15 @@ "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", "dev": true } } }, "vfile": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.4.tgz", - "integrity": "sha512-KI+7cnst03KbEyN1+JE504zF5bJBZa+J+CrevLeyIMq0aPU681I2rQ5p4PlnQ6exFtWiUrg26QUdFMnAKR6PIw==", + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.5.tgz", + "integrity": "sha512-U1ho2ga33eZ8y8pkbQLH54uKqGhFJ6GYIHnnG5AhRpAh3OWjkrRHKa/KogbmQn8We+c0KVV3rTOgR9V/WowbXQ==", "dev": true, "requires": { "@types/unist": "^2.0.0", @@ -38932,6 +43559,12 @@ "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, "string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -38979,13 +43612,13 @@ } }, "video.js": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/video.js/-/video.js-7.20.2.tgz", - "integrity": "sha512-hdvAHKAyaL6bCDkeu0pPtFYKi1EDaOUovm7FN1xqBDolUxgH8FKy1WIgTS+Ouuaw7R54SCTcSeXjZEizhy9ouQ==", + "version": "7.20.3", + "resolved": "https://registry.npmjs.org/video.js/-/video.js-7.20.3.tgz", + "integrity": "sha512-JMspxaK74LdfWcv69XWhX4rILywz/eInOVPdKefpQiZJSMD5O8xXYueqACP2Q5yqKstycgmmEKlJzZ+kVmDciw==", "dev": true, "requires": { "@babel/runtime": "^7.12.5", - "@videojs/http-streaming": "2.14.2", + "@videojs/http-streaming": "2.14.3", "@videojs/vhs-utils": "^3.0.4", "@videojs/xhr": "2.6.0", "aes-decrypter": "3.1.3", @@ -38996,7 +43629,7 @@ "mux.js": "6.0.1", "safe-json-parse": "4.0.0", "videojs-font": "3.2.0", - "videojs-vtt.js": "^0.15.3" + "videojs-vtt.js": "^0.15.4" }, "dependencies": { "safe-json-parse": { @@ -39121,7 +43754,7 @@ "vinyl-sourcemap": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", - "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=", + "integrity": "sha512-NiibMgt6VJGJmyw7vtzhctDcfKch4e4n9TBeoWlirb7FMg9/1Ov9k+A5ZRAtywBpRPiyECvQRQllYM8dECegVA==", "dev": true, "requires": { "append-buffer": "^1.0.2", @@ -39136,7 +43769,7 @@ "normalize-path": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", "dev": true, "requires": { "remove-trailing-separator": "^1.0.1" @@ -39147,7 +43780,7 @@ "vinyl-sourcemaps-apply": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz", - "integrity": "sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=", + "integrity": "sha512-+oDh3KYZBoZC8hfocrbrxbLUeaYtQK7J5WU5Br9VqWqmCll3tFJqKp97GC9GmMsVIL0qnx2DgEDVxdo5EZ5sSw==", "dev": true, "requires": { "source-map": "^0.5.1" @@ -39156,13 +43789,13 @@ "void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", "dev": true }, "vue-template-compiler": { - "version": "2.7.10", - "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.10.tgz", - "integrity": "sha512-QO+8R9YRq1Gudm8ZMdo/lImZLJVUIAM8c07Vp84ojdDAf8HmPJc7XB556PcXV218k2AkKznsRz6xB5uOjAC4EQ==", + "version": "2.7.13", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.13.tgz", + "integrity": "sha512-jYM6TClwDS9YqP48gYrtAtaOhRKkbYmbzE+Q51gX5YDr777n7tNI/IZk4QV4l/PjQPNh/FVa/E92sh/RqKMrog==", "dev": true, "optional": true, "requires": { @@ -39180,9 +43813,9 @@ } }, "watchpack": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", - "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", "dev": true, "requires": { "glob-to-regexp": "^0.4.1", @@ -39192,51 +43825,120 @@ "wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "dev": true, "requires": { "defaults": "^1.0.3" } }, "webdriver": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-7.16.16.tgz", - "integrity": "sha512-x8UoG9k/P8KDrfSh1pOyNevt9tns3zexoMxp9cKnyA/7HYSErhZYTLGlgxscAXLtQG41cMH/Ba/oBmOx7Hgd8w==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-7.5.3.tgz", + "integrity": "sha512-cDTn/hYj5x8BYwXxVb/WUwqGxrhCMP2rC8ttIWCfzmiVtmOnJGulC7CyxU3+p9Q5R/gIKTzdJOss16dhb+5CoA==", "dev": true, "requires": { - "@types/node": "^17.0.4", - "@wdio/config": "7.16.16", - "@wdio/logger": "7.16.0", - "@wdio/protocols": "7.16.7", - "@wdio/types": "7.16.14", - "@wdio/utils": "7.16.14", + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/protocols": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", "got": "^11.0.2", - "ky": "^0.29.0", "lodash.merge": "^4.6.1" + }, + "dependencies": { + "@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + } + }, + "@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "requires": { + "got": "^11.8.1" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "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 + }, + "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 + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "webdriverio": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.16.16.tgz", - "integrity": "sha512-caPaEWyuD3Qoa7YkW4xCCQA4v9Pa9wmhFGPvNZh3ERtjMCNi8L/XXOdkekWNZmFh3tY0kFguBj7+fAwSY7HAGw==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.25.4.tgz", + "integrity": "sha512-agkgwn2SIk5cAJ03uue1GnGZcUZUDN3W4fUMY9/VfO8bVJrPEgWg31bPguEWPu+YhEB/aBJD8ECxJ3OEKdy4qQ==", "dev": true, "requires": { "@types/aria-query": "^5.0.0", - "@types/node": "^17.0.4", - "@wdio/config": "7.16.16", - "@wdio/logger": "7.16.0", - "@wdio/protocols": "7.16.7", - "@wdio/repl": "7.16.14", - "@wdio/types": "7.16.14", - "@wdio/utils": "7.16.14", + "@types/node": "^18.0.0", + "@wdio/config": "7.25.4", + "@wdio/logger": "7.19.0", + "@wdio/protocols": "7.22.0", + "@wdio/repl": "7.25.4", + "@wdio/types": "7.25.4", + "@wdio/utils": "7.25.4", "archiver": "^5.0.0", "aria-query": "^5.0.0", "css-shorthand-properties": "^1.1.1", "css-value": "^0.0.1", - "devtools": "7.16.16", - "devtools-protocol": "^0.0.973690", + "devtools": "7.25.4", + "devtools-protocol": "^0.0.1061995", "fs-extra": "^10.0.0", - "get-port": "^5.1.1", "grapheme-splitter": "^1.0.2", "lodash.clonedeep": "^4.5.0", "lodash.isobject": "^3.0.2", @@ -39248,9 +43950,85 @@ "resq": "^1.9.1", "rgb2hex": "0.2.5", "serialize-error": "^8.0.0", - "webdriver": "7.16.16" + "webdriver": "7.25.4" }, "dependencies": { + "@types/node": { + "version": "18.11.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", + "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", + "dev": true + }, + "@wdio/config": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-7.25.4.tgz", + "integrity": "sha512-vb0emDtD9FbFh/yqW6oNdo2iuhQp8XKj6GX9fyy9v4wZgg3B0HPMVJxhIfcoHz7LMBWlHSo9YdvhFI5EQHRLBA==", + "dev": true, + "requires": { + "@wdio/logger": "7.19.0", + "@wdio/types": "7.25.4", + "@wdio/utils": "7.25.4", + "deepmerge": "^4.0.0", + "glob": "^8.0.3" + } + }, + "@wdio/logger": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.19.0.tgz", + "integrity": "sha512-xR7SN/kGei1QJD1aagzxs3KMuzNxdT/7LYYx+lt6BII49+fqL/SO+5X0FDCZD0Ds93AuQvvz9eGyzrBI2FFXmQ==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + } + }, + "@wdio/protocols": { + "version": "7.22.0", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-7.22.0.tgz", + "integrity": "sha512-8EXRR+Ymdwousm/VGtW3H1hwxZ/1g1H99A1lF0U4GuJ5cFWHCd0IVE5H31Z52i8ZruouW8jueMkGZPSo2IIUSQ==", + "dev": true + }, + "@wdio/repl": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-7.25.4.tgz", + "integrity": "sha512-kYhj9gLsUk4HmlXLqkVre+gwbfvw9CcnrHjqIjrmMS4mR9D8zvBb5CItb3ZExfPf9jpFzIFREbCAYoE9x/kMwg==", + "dev": true, + "requires": { + "@wdio/utils": "7.25.4" + } + }, + "@wdio/types": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.25.4.tgz", + "integrity": "sha512-muvNmq48QZCvocctnbe0URq2FjJjUPIG4iLoeMmyF0AQgdbjaUkMkw3BHYNHVTbSOU9WMsr2z8alhj/I2H6NRQ==", + "dev": true, + "requires": { + "@types/node": "^18.0.0", + "got": "^11.8.1" + } + }, + "@wdio/utils": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-7.25.4.tgz", + "integrity": "sha512-8iwQDk+foUqSzKZKfhLxjlCKOkfRJPNHaezQoevNgnrTq/t0ek+ldZCATezb9B8jprAuP4mgS9xi22akc6RkzA==", + "dev": true, + "requires": { + "@wdio/logger": "7.19.0", + "@wdio/types": "7.25.4", + "p-iteration": "^1.1.8" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -39260,6 +44038,56 @@ "balanced-match": "^1.0.0" } }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "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 + }, + "glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "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 + }, + "ky": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/ky/-/ky-0.30.0.tgz", + "integrity": "sha512-X/u76z4JtDVq10u1JA5UQfatPxgPaVDMYTrgHyiTpGN2z4TMEJkIHsoSBBSg9SWZEIXTKsi9kHgiQ9o3Y/4yog==", + "dev": true + }, "minimatch": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", @@ -39268,19 +44096,45 @@ "requires": { "brace-expansion": "^2.0.1" } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "webdriver": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-7.25.4.tgz", + "integrity": "sha512-6nVDwenh0bxbtUkHASz9B8T9mB531Fn1PcQjUGj2t5dolLPn6zuK1D7XYVX40hpn6r3SlYzcZnEBs4X0az5Txg==", + "dev": true, + "requires": { + "@types/node": "^18.0.0", + "@wdio/config": "7.25.4", + "@wdio/logger": "7.19.0", + "@wdio/protocols": "7.22.0", + "@wdio/types": "7.25.4", + "@wdio/utils": "7.25.4", + "got": "^11.0.2", + "ky": "0.30.0", + "lodash.merge": "^4.6.1" + } } } }, "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", "dev": true }, "webpack": { - "version": "5.70.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.70.0.tgz", - "integrity": "sha512-ZMWWy8CeuTTjCxbeaQI21xSswseF2oNOwc70QSKNePvmxE7XW36i7vpBMYZFAUHPwQiEbNGCEYIOOlyRbdGmxw==", + "version": "5.74.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz", + "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.3", @@ -39288,31 +44142,31 @@ "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/wasm-edit": "1.11.1", "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.4.1", + "acorn": "^8.7.1", "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.9.2", + "enhanced-resolve": "^5.10.0", "es-module-lexer": "^0.9.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.9", - "json-parse-better-errors": "^1.0.2", + "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", "schema-utils": "^3.1.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.3.1", + "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" }, "dependencies": { "acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "dev": true }, "acorn-import-assertions": { @@ -39334,13 +44188,6 @@ "uri-js": "^4.2.2" } }, - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} - }, "schema-utils": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", @@ -39355,9 +44202,9 @@ } }, "webpack-bundle-analyzer": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.5.0.tgz", - "integrity": "sha512-GUMZlM3SKwS8Z+CKeIFx7CVoHn3dXFcUAjT/dcZQQmfSZGvitPfMob2ipjai7ovFFqPvTqkEZ/leL4O0YOdAYQ==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.7.0.tgz", + "integrity": "sha512-j9b8ynpJS4K+zfO5GGwsAcQX4ZHpWV+yRiHDiL+bE0XHJ8NiPYLTNVQdlFYWxtpg9lfAQNlwJg16J9AJtFSXRg==", "dev": true, "requires": { "acorn": "^8.0.4", @@ -39372,15 +44219,9 @@ }, "dependencies": { "acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", - "dev": true - }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "dev": true }, "ansi-styles": { @@ -39423,6 +44264,12 @@ "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "dev": true }, + "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 + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -39433,9 +44280,9 @@ } }, "ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "dev": true, "requires": {} } @@ -39498,6 +44345,66 @@ "supports-color": "^8.1.1", "through": "^2.3.8", "vinyl": "^2.2.1" + }, + "dependencies": { + "ansi-colors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "dev": true, + "requires": { + "ansi-wrap": "^0.1.0" + } + }, + "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 + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "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" + } + }, + "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 + }, + "plugin-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", + "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", + "dev": true, + "requires": { + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "websocket-driver": { @@ -39520,7 +44427,7 @@ "whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dev": true, "requires": { "tr46": "~0.0.3", @@ -39561,18 +44468,66 @@ "is-weakset": "^2.0.1" } }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==", + "dev": true + }, "which-typed-array": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.7.tgz", - "integrity": "sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.8.tgz", + "integrity": "sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw==", "dev": true, "requires": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", - "es-abstract": "^1.18.5", - "foreach": "^2.0.5", + "es-abstract": "^1.20.0", + "for-each": "^0.3.3", "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.7" + "is-typed-array": "^1.1.9" + } + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } } }, "word-wrap": { @@ -39584,13 +44539,13 @@ "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", "dev": true }, "workerpool": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", - "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", "dev": true }, "wrap-ansi": { @@ -39633,7 +44588,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, "write": { @@ -39684,13 +44639,13 @@ "yargs": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/yargs/-/yargs-1.3.3.tgz", - "integrity": "sha1-BU3oth8i7v23IHBZ6u+da4P7kxo=", + "integrity": "sha512-7OGt4xXoWJQh5ulgZ78rKaqY7dNWbjfK+UKxGcIlaM2j7C4fqGchyv8CPvEWdRPrHp6Ula/YU8yGRpYGOHrI+g==", "dev": true }, "yargs-parser": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", - "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true }, "yargs-unparser": { @@ -39711,12 +44666,6 @@ "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true }, - "decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true - }, "is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -39728,7 +44677,7 @@ "yarn-install": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/yarn-install/-/yarn-install-1.0.0.tgz", - "integrity": "sha1-V/RQULgu/VcYKzlzxUqgXLXSUjA=", + "integrity": "sha512-VO1u181msinhPcGvQTVMnHVOae8zjX/NSksR17e6eXHRveDvHCF5mGjh9hkN8mzyfnCqcBe42LdTs7bScuTaeg==", "dev": true, "requires": { "cac": "^3.0.3", @@ -39739,19 +44688,19 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true }, "ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "requires": { "ansi-styles": "^2.2.1", @@ -39764,7 +44713,7 @@ "cross-spawn": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", - "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", + "integrity": "sha512-yAXz/pA1tD8Gtg2S98Ekf/sewp3Lcp3YoFKJ4Hkp5h5yLWnKVTDU0kwjKJ8NDCYcfTLfyGkzTikst+jWypT1iA==", "dev": true, "requires": { "lru-cache": "^4.0.1", @@ -39784,7 +44733,7 @@ "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "requires": { "ansi-regex": "^2.0.0" @@ -39793,7 +44742,7 @@ "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true }, "which": { @@ -39808,7 +44757,7 @@ "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", "dev": true } } @@ -39816,7 +44765,7 @@ "yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", "dev": true, "requires": { "buffer-crc32": "~0.2.3", diff --git a/package.json b/package.json index c5f1b1861a0..a05a958dd17 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.23.0-pre", + "version": "7.39.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { @@ -35,13 +35,13 @@ }, "devDependencies": { "@babel/eslint-parser": "^7.16.5", - "@wdio/browserstack-service": "^7.16.0", - "@wdio/cli": "^7.5.2", - "@wdio/concise-reporter": "^7.5.2", - "@wdio/local-runner": "^7.5.2", - "@wdio/mocha-framework": "^7.5.2", - "@wdio/spec-reporter": "^7.19.0", - "@wdio/sync": "^7.5.2", + "@wdio/browserstack-service": "~7.16.0", + "@wdio/cli": "~7.5.2", + "@wdio/concise-reporter": "~7.5.2", + "@wdio/local-runner": "~7.5.2", + "@wdio/mocha-framework": "~7.5.2", + "@wdio/spec-reporter": "~7.19.0", + "@wdio/sync": "~7.5.2", "ajv": "6.12.3", "assert": "^2.0.0", "babel-loader": "^8.0.5", @@ -130,7 +130,7 @@ "express": "^4.15.4", "fun-hooks": "^0.9.9", "just-clone": "^1.0.2", - "live-connect-js": "2.4.0" + "live-connect-js": "^4.0.0" }, "optionalDependencies": { "fsevents": "^2.3.2" diff --git a/src/adRendering.js b/src/adRendering.js index a645ec77244..0a847d7cc25 100644 --- a/src/adRendering.js +++ b/src/adRendering.js @@ -23,7 +23,7 @@ export function emitAdRenderFail({ reason, message, bid, id }) { /** * Emit the AD_RENDER_SUCCEEDED event. - * + * (Note: Invocation of this function indicates that the render function did not generate an error, it does not guarantee that tracking for this event has occurred yet.) * @param doc document object that was used to `.write` the ad. Should be `null` if unavailable (e.g. for documents in * a cross-origin frame). * @param bid bid response object for the ad that was rendered diff --git a/src/adapterManager.js b/src/adapterManager.js index 4722013d5f0..c9715fe0168 100644 --- a/src/adapterManager.js +++ b/src/adapterManager.js @@ -31,10 +31,11 @@ import {hook} from './hook.js'; import {find, includes} from './polyfill.js'; import {adunitCounter} from './adUnits.js'; import {getRefererInfo} from './refererDetection.js'; -import {GdprConsentHandler, UspConsentHandler} from './consentHandler.js'; +import {GdprConsentHandler, UspConsentHandler, GppConsentHandler} from './consentHandler.js'; import * as events from './events.js'; import CONSTANTS from './constants.json'; import {useMetrics} from './utils/perfMetrics.js'; +import {auctionManager} from './auctionManager.js'; export const PARTITIONS = { CLIENT: 'client', @@ -64,15 +65,21 @@ var _analyticsRegistry = {}; function getBids({bidderCode, auctionId, bidderRequestId, adUnits, src, metrics}) { return adUnits.reduce((result, adUnit) => { - result.push(adUnit.bids.filter(bid => bid.bidder === bidderCode) - .reduce((bids, bid) => { - bid = Object.assign({}, bid, getDefinedParams(adUnit, [ - 'nativeParams', - 'nativeOrtbRequest', - 'ortb2Imp', - 'mediaType', - 'renderer' - ])); + const bids = adUnit.bids.filter(bid => bid.bidder === bidderCode); + if (bidderCode == null && bids.length === 0 && adUnit.s2sBid != null) { + bids.push({bidder: null}); + } + result.push( + bids.reduce((bids, bid) => { + bid = Object.assign({}, bid, + {ortb2Imp: mergeDeep({}, adUnit.ortb2Imp, bid.ortb2Imp)}, + getDefinedParams(adUnit, [ + 'nativeParams', + 'nativeOrtbRequest', + 'mediaType', + 'renderer' + ]) + ); const mediaTypes = bid.mediaTypes == null ? adUnit.mediaTypes : bid.mediaTypes @@ -127,9 +134,18 @@ export const filterBidsForAdUnit = hook('sync', _filterBidsForAdUnit, 'filterBid function getAdUnitCopyForPrebidServer(adUnits, s2sConfig) { let adUnitsCopy = deepClone(adUnits); + let hasModuleBids = false; adUnitsCopy.forEach((adUnit) => { // filter out client side bids + const s2sBids = adUnit.bids.filter((b) => b.module === 'pbsBidAdapter' && b.params?.configName === s2sConfig.configName); + if (s2sBids.length === 1) { + adUnit.s2sBid = s2sBids[0]; + hasModuleBids = true; + adUnit.ortb2Imp = mergeDeep({}, adUnit.s2sBid.ortb2Imp, adUnit.ortb2Imp); + } else if (s2sBids.length > 1) { + logWarn('Multiple "module" bids for the same s2s configuration; all will be ignored', s2sBids); + } adUnit.bids = filterBidsForAdUnit(adUnit.bids, s2sConfig) .map((bid) => { bid.bid_id = getUniqueIdentifierStr(); @@ -139,9 +155,9 @@ function getAdUnitCopyForPrebidServer(adUnits, s2sConfig) { // don't send empty requests adUnitsCopy = adUnitsCopy.filter(adUnit => { - return adUnit.bids.length !== 0; + return adUnit.bids.length !== 0 || adUnit.s2sBid != null; }); - return adUnitsCopy; + return {adUnits: adUnitsCopy, hasModuleBids}; } function getAdUnitCopyForClientAdapters(adUnits) { @@ -160,6 +176,7 @@ function getAdUnitCopyForClientAdapters(adUnits) { export let gdprDataHandler = new GdprConsentHandler(); export let uspDataHandler = new UspConsentHandler(); +export let gppDataHandler = new GppConsentHandler(); export let coppaDataHandler = { getCoppa: function() { @@ -242,11 +259,12 @@ adapterManager.makeBidRequests = hook('sync', function (adUnits, auctionStart, a _s2sConfigs.forEach(s2sConfig => { if (s2sConfig && s2sConfig.enabled) { - let adUnitsS2SCopy = getAdUnitCopyForPrebidServer(adUnits, s2sConfig); + let {adUnits: adUnitsS2SCopy, hasModuleBids} = getAdUnitCopyForPrebidServer(adUnits, s2sConfig); // uniquePbsTid is so we know which server to send which bids to during the callBids function let uniquePbsTid = generateUUID(); - serverBidders.forEach(bidderCode => { + + (serverBidders.length === 0 && hasModuleBids ? [null] : serverBidders).forEach(bidderCode => { const bidderRequestId = getUniqueIdentifierStr(); const metrics = auctionMetrics.fork(); const bidderRequest = addOrtb2({ @@ -277,7 +295,7 @@ adapterManager.makeBidRequests = hook('sync', function (adUnits, auctionStart, a bidRequests.forEach(request => { if (request.adUnitsS2SCopy === undefined) { - request.adUnitsS2SCopy = adUnitsS2SCopy.filter(adUnitCopy => adUnitCopy.bids.length > 0); + request.adUnitsS2SCopy = adUnitsS2SCopy.filter(au => au.bids.length > 0 || au.s2sBid != null); } }); } @@ -308,17 +326,17 @@ adapterManager.makeBidRequests = hook('sync', function (adUnits, auctionStart, a } }); - if (gdprDataHandler.getConsentData()) { - bidRequests.forEach(bidRequest => { + bidRequests.forEach(bidRequest => { + if (gdprDataHandler.getConsentData()) { bidRequest['gdprConsent'] = gdprDataHandler.getConsentData(); - }); - } - - if (uspDataHandler.getConsentData()) { - bidRequests.forEach(bidRequest => { + } + if (uspDataHandler.getConsentData()) { bidRequest['uspConsent'] = uspDataHandler.getConsentData(); - }); - } + } + if (gppDataHandler.getConsentData()) { + bidRequest['gppConsent'] = gppDataHandler.getConsentData(); + } + }); bidRequests.forEach(bidRequest => { config.runWithBidder(bidRequest.bidderCode, () => { @@ -553,19 +571,30 @@ adapterManager.getAnalyticsAdapter = function(code) { return _analyticsRegistry[code]; } -function tryCallBidderMethod(bidder, method, param) { +function getBidderMethod(bidder, method) { + const adapter = _bidderRegistry[bidder]; + const spec = adapter?.getSpec && adapter.getSpec(); + if (spec && spec[method] && typeof spec[method] === 'function') { + return [spec, spec[method]] + } +} + +function invokeBidderMethod(bidder, method, spec, fn, ...params) { try { - const adapter = _bidderRegistry[bidder]; - const spec = adapter.getSpec(); - if (spec && spec[method] && typeof spec[method] === 'function') { - logInfo(`Invoking ${bidder}.${method}`); - config.runWithBidder(bidder, bind.call(spec[method], spec, param)); - } + logInfo(`Invoking ${bidder}.${method}`); + config.runWithBidder(bidder, fn.bind(spec, ...params)); } catch (e) { logWarn(`Error calling ${method} of ${bidder}`); } } +function tryCallBidderMethod(bidder, method, param) { + const target = getBidderMethod(bidder, method); + if (target != null) { + invokeBidderMethod(bidder, method, ...target, param); + } +} + adapterManager.callTimedOutBidders = function(adUnits, timedOutBidders, cbTimeout) { timedOutBidders = timedOutBidders.map((timedOutBidder) => { // Adding user configured params & timeout to timeout event data @@ -600,4 +629,41 @@ adapterManager.callBidderError = function(bidder, error, bidderRequest) { tryCallBidderMethod(bidder, 'onBidderError', param); }; +function resolveAlias(alias) { + const seen = new Set(); + while (_aliasRegistry.hasOwnProperty(alias) && !seen.has(alias)) { + seen.add(alias); + alias = _aliasRegistry[alias]; + } + return alias; +} +/** + * Ask every adapter to delete PII. + * See https://github.com/prebid/Prebid.js/issues/9081 + */ +adapterManager.callDataDeletionRequest = hook('sync', function (...args) { + const method = 'onDataDeletionRequest'; + Object.keys(_bidderRegistry) + .filter((bidder) => !_aliasRegistry.hasOwnProperty(bidder)) + .forEach(bidder => { + const target = getBidderMethod(bidder, method); + if (target != null) { + const bidderRequests = auctionManager.getBidsRequested().filter((br) => + resolveAlias(br.bidderCode) === bidder + ); + invokeBidderMethod(bidder, method, ...target, bidderRequests, ...args); + } + }); + Object.entries(_analyticsRegistry).forEach(([name, entry]) => { + const fn = entry?.adapter?.[method]; + if (typeof fn === 'function') { + try { + fn.apply(entry.adapter, args); + } catch (e) { + logError(`error calling ${method} of ${name}`, e); + } + } + }); +}); + export default adapterManager; diff --git a/src/adapters/bidderFactory.js b/src/adapters/bidderFactory.js index 7e66b849783..55c84e57062 100644 --- a/src/adapters/bidderFactory.js +++ b/src/adapters/bidderFactory.js @@ -214,7 +214,7 @@ export function newBidder(spec) { done(); config.runWithBidder(spec.code, () => { events.emit(CONSTANTS.EVENTS.BIDDER_DONE, bidderRequest); - registerSyncs(responses, bidderRequest.gdprConsent, bidderRequest.uspConsent); + registerSyncs(responses, bidderRequest.gdprConsent, bidderRequest.uspConsent, bidderRequest.gppConsent); }); } @@ -295,8 +295,8 @@ export function newBidder(spec) { return false; } - function registerSyncs(responses, gdprConsent, uspConsent) { - registerSyncInner(spec, responses, gdprConsent, uspConsent); + function registerSyncs(responses, gdprConsent, uspConsent, gppConsent) { + registerSyncInner(spec, responses, gdprConsent, uspConsent, gppConsent); } function filterAndWarn(bid) { @@ -448,14 +448,14 @@ export const processBidderRequests = hook('sync', function (spec, bids, bidderRe }) }, 'processBidderRequests') -export const registerSyncInner = hook('async', function(spec, responses, gdprConsent, uspConsent) { +export const registerSyncInner = hook('async', function(spec, responses, gdprConsent, uspConsent, gppConsent) { const aliasSyncEnabled = config.getConfig('userSync.aliasSyncEnabled'); if (spec.getUserSyncs && (aliasSyncEnabled || !adapterManager.aliasRegistry[spec.code])) { let filterConfig = config.getConfig('userSync.filterSettings'); let syncs = spec.getUserSyncs({ iframeEnabled: !!(filterConfig && (filterConfig.iframe || filterConfig.all)), pixelEnabled: !!(filterConfig && (filterConfig.image || filterConfig.all)), - }, responses, gdprConsent, uspConsent); + }, responses, gdprConsent, uspConsent, gppConsent); if (syncs) { if (!Array.isArray(syncs)) { syncs = [syncs]; diff --git a/src/adloader.js b/src/adloader.js index 6b7427d3e52..f0b7f7f3e8c 100644 --- a/src/adloader.js +++ b/src/adloader.js @@ -19,7 +19,10 @@ const _approvedLoadExternalJSList = [ 'inskin', 'hadron', 'medianet', - 'improvedigital' + 'improvedigital', + 'aaxBlockmeter', + 'confiant', + 'arcspan' ] /** diff --git a/src/auction.js b/src/auction.js index 89b8f21d571..6dd0432712f 100644 --- a/src/auction.js +++ b/src/auction.js @@ -76,7 +76,7 @@ import { timestamp } from './utils.js'; import {getPriceBucketString} from './cpmBucketManager.js'; -import {getNativeTargeting} from './native.js'; +import {getNativeTargeting, toLegacyResponse} from './native.js'; import {getCacheUrl, store} from './videoCache.js'; import {Renderer} from './Renderer.js'; import {config} from './config.js'; @@ -93,6 +93,7 @@ import CONSTANTS from './constants.json'; import {GreedyPromise} from './utils/promise.js'; import {useMetrics} from './utils/perfMetrics.js'; import {createBid} from './bidfactory.js'; +import {adjustCpm} from './utils/cpm.js'; const { syncUsers } = userSync; @@ -150,11 +151,13 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels, a let _auctionEnd; let _timer; let _auctionStatus; + let _nonBids = []; function addBidRequests(bidderRequests) { _bidderRequests = _bidderRequests.concat(bidderRequests); } function addBidReceived(bidsReceived) { _bidsReceived = _bidsReceived.concat(bidsReceived); } function addBidRejected(bidsRejected) { _bidsRejected = _bidsRejected.concat(bidsRejected); } function addNoBid(noBid) { _noBids = _noBids.concat(noBid); } + function addNonBids(seatnonbids) { _nonBids = _nonBids.concat(seatnonbids); } function getProperties() { return { @@ -171,7 +174,8 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels, a bidsRejected: _bidsRejected, winningBids: _winningBids, timeout: _timeout, - metrics: metrics + metrics: metrics, + seatNonBids: _nonBids }; } @@ -368,6 +372,12 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels, a adapterManager.callSetTargetingBidder(bid.adapterCode || bid.bidder, bid); } + events.on(CONSTANTS.EVENTS.SEAT_NON_BID, (event) => { + if (event.auctionId === _auctionId) { + addNonBids(event.seatnonbid) + } + }); + return { addBidReceived, addBidRejected, @@ -386,6 +396,7 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels, a getBidRequests: () => _bidderRequests, getBidsReceived: () => _bidsReceived, getNoBids: () => _noBids, + getNonBids: () => _nonBids, getFPD: () => ortb2Fragments, getMetrics: () => metrics, }; @@ -462,9 +473,14 @@ export function auctionCallbacks(auctionDone, auctionInstance, {index = auctionM handleBidResponse(adUnitCode, bid, (done) => { let bidResponse = getPreparedBidForAuction(bid); - if (bidResponse.mediaType === 'video') { + if (bidResponse.mediaType === VIDEO) { tryAddVideoBid(auctionInstance, bidResponse, done); } else { + if (FEATURES.NATIVE && bidResponse.native != null && typeof bidResponse.native === 'object') { + // NOTE: augment bidResponse.native even if bidResponse.mediaType !== NATIVE; it's possible + // to treat banner responses as native + addLegacyFieldsIfNeeded(bidResponse); + } addBidToAuction(auctionInstance, bidResponse); done(); } @@ -475,7 +491,7 @@ export function auctionCallbacks(auctionDone, auctionInstance, {index = auctionM return handleBidResponse(adUnitCode, bid, (done) => { // return a "NO_BID" replacement that the caller can decide to continue with // TODO: remove this in v8; see https://github.com/prebid/Prebid.js/issues/8956 - const noBid = createBid(CONSTANTS.STATUS.NO_BID, bid.getIdentifiers()); + const noBid = createBid(CONSTANTS.STATUS.NO_BID, bid.getIdentifiers?.()); Object.assign(noBid, Object.fromEntries(Object.entries(bid).filter(([k]) => !noBid.hasOwnProperty(k) && ![ 'ad', 'adUrl', @@ -593,6 +609,17 @@ function tryAddVideoBid(auctionInstance, bidResponse, afterBidAdded, {index = au } } +// Native bid response might be in ortb2 format - adds legacy field for backward compatibility +const addLegacyFieldsIfNeeded = (bidResponse) => { + const nativeOrtbRequest = auctionManager.index.getAdUnit(bidResponse)?.nativeOrtbRequest; + const nativeOrtbResponse = bidResponse.native?.ortb + + if (nativeOrtbRequest && nativeOrtbResponse) { + const legacyResponse = toLegacyResponse(nativeOrtbResponse, nativeOrtbRequest); + Object.assign(bidResponse.native, legacyResponse); + } +} + const storeInCache = (batch) => { store(batch.map(entry => entry.bidResponse), function (error, cacheIds) { cacheIds.forEach((cacheId, i) => { @@ -666,16 +693,21 @@ export const callPrebidCache = hook('async', function(auctionInstance, bidRespon */ function addCommonResponseProperties(bidResponse, adUnitCode, {index = auctionManager.index} = {}) { const bidderRequest = index.getBidderRequest(bidResponse); + const adUnit = index.getAdUnit(bidResponse); const start = (bidderRequest && bidderRequest.start) || bidResponse.requestTimestamp; Object.assign(bidResponse, { responseTimestamp: bidResponse.responseTimestamp || timestamp(), requestTimestamp: bidResponse.requestTimestamp || start, - cpm: bidResponse.cpm || parseFloat(bidResponse.cpm) || 0, + cpm: parseFloat(bidResponse.cpm) || 0, bidder: bidResponse.bidder || bidResponse.bidderCode, adUnitCode }); + if (adUnit?.ttlBuffer != null) { + bidResponse.ttlBuffer = adUnit.ttlBuffer; + } + bidResponse.timeToRespond = bidResponse.responseTimestamp - bidResponse.requestTimestamp; } @@ -807,6 +839,16 @@ export const getAdvertiserDomain = () => { } } +/** + * This function returns a function to get the primary category id from bid response meta + * @returns {function} + */ +export const getPrimaryCatId = () => { + return (bid) => { + return (bid.meta && bid.meta.primaryCatId) ? bid.meta.primaryCatId : ''; + } +} + // factory for key value objs function createKeyVal(key, value) { return { @@ -832,6 +874,7 @@ function defaultAdserverTargeting() { createKeyVal(TARGETING_KEYS.SOURCE, 'source'), createKeyVal(TARGETING_KEYS.FORMAT, 'mediaType'), createKeyVal(TARGETING_KEYS.ADOMAIN, getAdvertiserDomain()), + createKeyVal(TARGETING_KEYS.ACAT, getPrimaryCatId()), ] } @@ -844,7 +887,6 @@ function defaultAdserverTargeting() { export function getStandardBidderSettings(mediaType, bidderCode) { const TARGETING_KEYS = CONSTANTS.TARGETING_KEYS; const standardSettings = Object.assign({}, bidderSettings.settingsFor(null)); - if (!standardSettings[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING]) { standardSettings[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING] = defaultAdserverTargeting(); } @@ -872,6 +914,7 @@ export function getStandardBidderSettings(mediaType, bidderCode) { } } } + return standardSettings; } @@ -923,7 +966,7 @@ function setKeys(keyValues, bidderSettings, custBidObj, bidReq) { if ( ((typeof bidderSettings.suppressEmptyKeys !== 'undefined' && bidderSettings.suppressEmptyKeys === true) || - key === CONSTANTS.TARGETING_KEYS.DEAL) && // hb_deal is suppressed automatically if not set + key === CONSTANTS.TARGETING_KEYS.DEAL || key === CONSTANTS.TARGETING_KEYS.ACAT) && // hb_deal & hb_acat are suppressed automatically if not set ( isEmptyStr(value) || value === null || @@ -940,17 +983,7 @@ function setKeys(keyValues, bidderSettings, custBidObj, bidReq) { } export function adjustBids(bid) { - let code = bid.bidderCode; - let bidPriceAdjusted = bid.cpm; - const bidCpmAdjustment = bidderSettings.get(code || null, 'bidCpmAdjustment'); - - if (bidCpmAdjustment && typeof bidCpmAdjustment === 'function') { - try { - bidPriceAdjusted = bidCpmAdjustment(bid.cpm, Object.assign({}, bid)); - } catch (e) { - logError('Error during bid adjustment', 'bidmanager.js', e); - } - } + let bidPriceAdjusted = adjustCpm(bid.cpm, bid); if (bidPriceAdjusted >= 0) { bid.cpm = bidPriceAdjusted; diff --git a/src/consentHandler.js b/src/consentHandler.js index 861a9894a2c..b1b2a04c043 100644 --- a/src/consentHandler.js +++ b/src/consentHandler.js @@ -1,6 +1,14 @@ import {isStr, timestamp} from './utils.js'; import {defer, GreedyPromise} from './utils/promise.js'; +/** + * Placeholder gvlid for when vendor consent is not required. When this value is used as gvlid, the gdpr + * enforcement module will take it to mean "vendor consent was given". + * + * see https://github.com/prebid/Prebid.js/issues/8161 + */ +export const VENDORLESS_GVLID = Object.freeze({}); + export class ConsentHandler { #enabled; #data; @@ -99,3 +107,14 @@ export class GdprConsentHandler extends ConsentHandler { } } } + +export class GppConsentHandler extends ConsentHandler { + getConsentMeta() { + const consentData = this.getConsentData(); + if (consentData && this.generatedTime) { + return { + generatedAt: this.generatedTime, + } + } + } +} diff --git a/src/constants.json b/src/constants.json index 30ade5fccbe..ef652af1ae5 100644 --- a/src/constants.json +++ b/src/constants.json @@ -31,6 +31,7 @@ "BID_RESPONSE": "bidResponse", "BID_REJECTED": "bidRejected", "NO_BID": "noBid", + "SEAT_NON_BID": "seatNonBid", "BID_WON": "bidWon", "BIDDER_DONE": "bidderDone", "BIDDER_ERROR": "bidderError", @@ -76,7 +77,8 @@ "UUID": "hb_uuid", "CACHE_ID": "hb_cache_id", "CACHE_HOST": "hb_cache_host", - "ADOMAIN": "hb_adomain" + "ADOMAIN": "hb_adomain", + "ACAT": "hb_acat" }, "DEFAULT_TARGETING_KEYS": { "BIDDER": "hb_bidder", diff --git a/src/events.js b/src/events.js index 8e6117c3abf..62f8c070deb 100644 --- a/src/events.js +++ b/src/events.js @@ -157,3 +157,7 @@ const _public = (function () { utils._setEventEmitter(_public.emit.bind(_public)); export const {on, off, get, getEvents, emit, addEvents} = _public; + +export function clearEvents() { + eventsFired.length = 0; +} diff --git a/src/fpd/enrichment.js b/src/fpd/enrichment.js new file mode 100644 index 00000000000..fc50a057378 --- /dev/null +++ b/src/fpd/enrichment.js @@ -0,0 +1,94 @@ +import {hook} from '../hook.js'; +import {getRefererInfo, parseDomain} from '../refererDetection.js'; +import {findRootDomain} from './rootDomain.js'; +import {deepSetValue, getDefinedParams, getDNT, getWindowSelf, getWindowTop, mergeDeep} from '../utils.js'; +import {config} from '../config.js'; +import {getHighEntropySUA, getLowEntropySUA} from '../../libraries/fpd/sua.js'; +import {GreedyPromise} from '../utils/promise.js'; + +export const dep = { + getRefererInfo, + findRootDomain, + getWindowTop, + getWindowSelf, + getHighEntropySUA, + getLowEntropySUA, +}; + +/** + * Enrich an ortb2 object with first party data. + * @param {Promise[{}]} fpd: a promise to an ortb2 object. + * @returns: {Promise[{}]}: a promise to an enriched ortb2 object. + */ +export const enrichFPD = hook('sync', (fpd) => { + return GreedyPromise.all([fpd, getSUA().catch(() => null)]) + .then(([ortb2, sua]) => { + Object.entries(ENRICHMENTS).forEach(([section, getEnrichments]) => { + const data = getEnrichments(); + if (data && Object.keys(data).length > 0) { + ortb2[section] = mergeDeep({}, data, ortb2[section]); + } + }); + if (sua) { + deepSetValue(ortb2, 'device.sua', Object.assign({}, sua, ortb2.device.sua)); + } + return ortb2; + }); +}); + +function winFallback(fn) { + try { + return fn(dep.getWindowTop()); + } catch (e) { + return fn(dep.getWindowSelf()); + } +} + +function getSUA() { + const hints = config.getConfig('firstPartyData.uaHints'); + return Array.isArray(hints) && hints.length === 0 + ? GreedyPromise.resolve(dep.getLowEntropySUA()) + : dep.getHighEntropySUA(hints); +} + +const ENRICHMENTS = { + site() { + const ri = dep.getRefererInfo(); + const domain = parseDomain(ri.page, {noLeadingWww: true}); + const keywords = winFallback((win) => win.document.querySelector('meta[name=\'keywords\']')) + ?.content?.replace?.(/\s/g, ''); + return (site => getDefinedParams(site, Object.keys(site)))({ + page: ri.page, + ref: ri.ref, + domain, + keywords, + publisher: { + domain: dep.findRootDomain(domain) + } + }); + }, + device() { + return winFallback((win) => { + const w = win.innerWidth || win.document.documentElement.clientWidth || win.document.body.clientWidth; + const h = win.innerHeight || win.document.documentElement.clientHeight || win.document.body.clientHeight; + return { + w, + h, + dnt: getDNT() ? 1 : 0, + ua: win.navigator.userAgent, + language: win.navigator.language.split('-').shift(), + }; + }) + }, + regs() { + const regs = {}; + if (winFallback((win) => win.navigator.globalPrivacyControl)) { + deepSetValue(regs, 'ext.gpc', 1); + } + const coppa = config.getConfig('coppa'); + if (typeof coppa === 'boolean') { + regs.coppa = coppa ? 1 : 0; + } + return regs; + } +}; diff --git a/src/fpd/rootDomain.js b/src/fpd/rootDomain.js new file mode 100644 index 00000000000..4095613672f --- /dev/null +++ b/src/fpd/rootDomain.js @@ -0,0 +1,57 @@ +import {memoize, timestamp} from '../utils.js'; +import {getCoreStorageManager} from '../storageManager.js'; + +export const coreStorage = getCoreStorageManager(); + +/** + * Find the root domain by testing for the topmost domain that will allow setting cookies. + */ + +export const findRootDomain = memoize(function findRootDomain(fullDomain = window.location.host) { + if (!coreStorage.cookiesAreEnabled()) { + return fullDomain; + } + + const domainParts = fullDomain.split('.'); + if (domainParts.length === 2) { + return fullDomain; + } + let rootDomain; + let continueSearching; + let startIndex = -2; + const TEST_COOKIE_NAME = `_rdc${Date.now()}`; + const TEST_COOKIE_VALUE = 'writeable'; + do { + rootDomain = domainParts.slice(startIndex).join('.'); + let expirationDate = new Date(timestamp() + 10 * 1000).toUTCString(); + + // Write a test cookie + coreStorage.setCookie( + TEST_COOKIE_NAME, + TEST_COOKIE_VALUE, + expirationDate, + 'Lax', + rootDomain, + undefined + ); + + // See if the write was successful + const value = coreStorage.getCookie(TEST_COOKIE_NAME, undefined); + if (value === TEST_COOKIE_VALUE) { + continueSearching = false; + // Delete our test cookie + coreStorage.setCookie( + TEST_COOKIE_NAME, + '', + 'Thu, 01 Jan 1970 00:00:01 GMT', + undefined, + rootDomain, + undefined + ); + } else { + startIndex += -1; + continueSearching = Math.abs(startIndex) <= domainParts.length; + } + } while (continueSearching); + return rootDomain; +}); diff --git a/src/native.js b/src/native.js index 022ece457f5..25f8c38cb30 100644 --- a/src/native.js +++ b/src/native.js @@ -23,7 +23,7 @@ export const NATIVE_TARGETING_KEYS = Object.keys(CONSTANTS.NATIVE_KEYS).map( key => CONSTANTS.NATIVE_KEYS[key] ); -const IMAGE = { +export const IMAGE = { ortb: { ver: '1.2', assets: [ @@ -385,26 +385,14 @@ export function getNativeTargeting(bid, {index = auctionManager.index} = {}) { return keyValues; } -const getNativeRequest = (bidResponse) => auctionManager.index.getAdUnit(bidResponse)?.nativeOrtbRequest; - -function assetsMessage(data, adObject, keys, {getNativeReq = getNativeRequest} = {}) { +function assetsMessage(data, adObject, keys) { const message = { message: 'assetResponse', adId: data.adId, }; - // Pass to Prebid Universal Creative all assets, the legacy ones + the ortb ones (under ortb property) - const ortbRequest = getNativeReq(adObject); let nativeResp = adObject.native; - const ortbResponse = adObject.native?.ortb; - let legacyResponse = {}; - if (ortbRequest && ortbResponse) { - legacyResponse = toLegacyResponse(ortbResponse, ortbRequest); - nativeResp = { - ...adObject.native, - ...legacyResponse - }; - } + if (adObject.native.ortb) { message.ortb = adObject.native.ortb; } @@ -435,13 +423,13 @@ function assetsMessage(data, adObject, keys, {getNativeReq = getNativeRequest} = * Constructs a message object containing asset values for each of the * requested data keys. */ -export function getAssetMessage(data, adObject, {getNativeReq = getNativeRequest} = {}) { +export function getAssetMessage(data, adObject) { const keys = data.assets.map((k) => getKeyByValue(CONSTANTS.NATIVE_KEYS, k)); - return assetsMessage(data, adObject, keys, {getNativeReq}); + return assetsMessage(data, adObject, keys); } -export function getAllAssetsMessage(data, adObject, {getNativeReq = getNativeRequest} = {}) { - return assetsMessage(data, adObject, null, {getNativeReq}); +export function getAllAssetsMessage(data, adObject) { + return assetsMessage(data, adObject, null); } /** @@ -749,7 +737,7 @@ export function toOrtbNativeResponse(legacyResponse, ortbRequest) { * @param {*} ortbRequest the ortb request, useful to match ids. * @returns an object containing the response in legacy native format: { title: "this is a title", image: ... } */ -function toLegacyResponse(ortbResponse, ortbRequest) { +export function toLegacyResponse(ortbResponse, ortbRequest) { const legacyResponse = {}; const requestAssets = ortbRequest?.assets || []; legacyResponse.clickUrl = ortbResponse.link.url; @@ -764,6 +752,29 @@ function toLegacyResponse(ortbResponse, ortbRequest) { legacyResponse[PREBID_NATIVE_DATA_KEYS_TO_ORTB_INVERSE[NATIVE_ASSET_TYPES_INVERSE[requestAsset.data.type]]] = asset.data.value; } } + + // Handle trackers + legacyResponse.impressionTrackers = []; + let jsTrackers = []; + + if (ortbRequest?.imptrackers) { + legacyResponse.impressionTrackers.push(...ortbRequest.imptrackers); + } + for (const eventTracker of ortbResponse?.eventtrackers || []) { + if (eventTracker.event === TRACKER_EVENTS.impression && eventTracker.method === TRACKER_METHODS.img) { + legacyResponse.impressionTrackers.push(eventTracker.url); + } + if (eventTracker.event === TRACKER_EVENTS.impression && eventTracker.method === TRACKER_METHODS.js) { + jsTrackers.push(eventTracker.url); + } + } + + jsTrackers = jsTrackers.map(url => ``); + if (ortbResponse?.jstracker) { jsTrackers.push(ortbResponse.jstracker); } + if (jsTrackers.length) { + legacyResponse.javascriptTrackers = jsTrackers.join('\n'); + } + return legacyResponse; } diff --git a/src/prebid.js b/src/prebid.js index 7b1cfd258ec..9ad72409990 100644 --- a/src/prebid.js +++ b/src/prebid.js @@ -45,10 +45,12 @@ import {executeRenderer, isRendererRequired} from './Renderer.js'; import {createBid} from './bidfactory.js'; import {storageCallbacks} from './storageManager.js'; import {emitAdRenderFail, emitAdRenderSucceeded} from './adRendering.js'; -import {default as adapterManager, gdprDataHandler, getS2SBidderSet, uspDataHandler} from './adapterManager.js'; +import {default as adapterManager, gdprDataHandler, getS2SBidderSet, gppDataHandler, uspDataHandler} from './adapterManager.js'; import CONSTANTS from './constants.json'; import * as events from './events.js'; import {newMetrics, useMetrics} from './utils/perfMetrics.js'; +import {defer, GreedyPromise} from './utils/promise.js'; +import {enrichFPD} from './fpd/enrichment.js'; const $$PREBID_GLOBAL$$ = getGlobal(); const { triggerUserSyncs } = userSync; @@ -334,6 +336,7 @@ function getConsentMetadata() { return { gdpr: gdprDataHandler.getConsentMeta(), usp: uspDataHandler.getConsentMeta(), + gpp: gppDataHandler.getConsentMeta(), coppa: !!(config.getConfig('coppa')) } } @@ -622,118 +625,126 @@ $$PREBID_GLOBAL$$.removeAdUnit = function (adUnitCode) { * @alias module:pbjs.requestBids */ $$PREBID_GLOBAL$$.requestBids = (function() { - const delegate = hook('sync', function ({ bidsBackHandler, timeout, adUnits, adUnitCodes, labels, auctionId, ortb2, metrics } = {}) { + const delegate = hook('async', function ({ bidsBackHandler, timeout, adUnits, adUnitCodes, labels, auctionId, ttlBuffer, ortb2, metrics, defer } = {}) { events.emit(REQUEST_BIDS); const cbTimeout = timeout || config.getConfig('bidderTimeout'); logInfo('Invoking $$PREBID_GLOBAL$$.requestBids', arguments); + if (adUnitCodes && adUnitCodes.length) { + // if specific adUnitCodes supplied filter adUnits for those codes + adUnits = adUnits.filter(unit => includes(adUnitCodes, unit.code)); + } else { + // otherwise derive adUnitCodes from adUnits + adUnitCodes = adUnits && adUnits.map(unit => unit.code); + } const ortb2Fragments = { global: mergeDeep({}, config.getAnyConfig('ortb2') || {}, ortb2 || {}), bidder: Object.fromEntries(Object.entries(config.getBidderConfig()).map(([bidder, cfg]) => [bidder, cfg.ortb2]).filter(([_, ortb2]) => ortb2 != null)) } - return startAuction({bidsBackHandler, timeout: cbTimeout, adUnits, adUnitCodes, labels, auctionId, ortb2Fragments, metrics}); + return enrichFPD(GreedyPromise.resolve(ortb2Fragments.global)).then(global => { + ortb2Fragments.global = global; + return startAuction({bidsBackHandler, timeout: cbTimeout, adUnits, adUnitCodes, labels, auctionId, ttlBuffer, ortb2Fragments, metrics, defer}); + }) }, 'requestBids'); return wrapHook(delegate, function requestBids(req = {}) { - // if the request does not specify adUnits, clone the global adUnit array - before - // any hook has a chance to run. + // unlike the main body of `delegate`, this runs before any other hook has a chance to; + // it's also not restricted in its return value in the way `async` hooks are. + + // if the request does not specify adUnits, clone the global adUnit array; // otherwise, if the caller goes on to use addAdUnits/removeAdUnits, any asynchronous logic // in any hook might see their effects. - req.metrics = newMetrics(); - req.metrics.checkpoint('requestBids'); let adUnits = req.adUnits || $$PREBID_GLOBAL$$.adUnits; req.adUnits = (isArray(adUnits) ? adUnits.slice() : [adUnits]); - return delegate.call(this, req); + + req.metrics = newMetrics(); + req.metrics.checkpoint('requestBids'); + req.defer = defer({promiseFactory: (r) => new Promise(r)}) + delegate.call(this, req); + return req.defer.promise; }); })(); -export const startAuction = hook('sync', function ({ bidsBackHandler, timeout: cbTimeout, adUnits, adUnitCodes, labels, auctionId, ortb2Fragments, metrics } = {}) { +export const startAuction = hook('async', function ({ bidsBackHandler, timeout: cbTimeout, adUnits, ttlBuffer, adUnitCodes, labels, auctionId, ortb2Fragments, metrics, defer } = {}) { const s2sBidders = getS2SBidderSet(config.getConfig('s2sConfig') || []); adUnits = useMetrics(metrics).measureTime('requestBids.validate', () => checkAdUnitSetup(adUnits)); - if (adUnitCodes && adUnitCodes.length) { - // if specific adUnitCodes supplied filter adUnits for those codes - adUnits = adUnits.filter(unit => includes(adUnitCodes, unit.code)); - } else { - // otherwise derive adUnitCodes from adUnits - adUnitCodes = adUnits && adUnits.map(unit => unit.code); - } - - return new Promise((resolve) => { - function auctionDone(bids, timedOut, auctionId) { - if (typeof bidsBackHandler === 'function') { - try { - bidsBackHandler(bids, timedOut, auctionId); - } catch (e) { - logError('Error executing bidsBackHandler', null, e); - } + function auctionDone(bids, timedOut, auctionId) { + if (typeof bidsBackHandler === 'function') { + try { + bidsBackHandler(bids, timedOut, auctionId); + } catch (e) { + logError('Error executing bidsBackHandler', null, e); } - resolve({bids, timedOut, auctionId}); } + defer.resolve({bids, timedOut, auctionId}) + } - /* - * for a given adunit which supports a set of mediaTypes - * and a given bidder which supports a set of mediaTypes - * a bidder is eligible to participate on the adunit - * if it supports at least one of the mediaTypes on the adunit - */ - adUnits.forEach(adUnit => { - // get the adunit's mediaTypes, defaulting to banner if mediaTypes isn't present - const adUnitMediaTypes = Object.keys(adUnit.mediaTypes || { 'banner': 'banner' }); - - // get the bidder's mediaTypes - const allBidders = adUnit.bids.map(bid => bid.bidder); - const bidderRegistry = adapterManager.bidderRegistry; - - const bidders = allBidders.filter(bidder => !s2sBidders.has(bidder)); - - const tid = adUnit.ortb2Imp?.ext?.tid || generateUUID(); - adUnit.transactionId = tid; - // Populate ortb2Imp.ext.tid with transactionId. Specifying a transaction ID per item in the ortb impression array, lets multiple transaction IDs be transmitted in a single bid request. - deepSetValue(adUnit, 'ortb2Imp.ext.tid', tid); - - bidders.forEach(bidder => { - const adapter = bidderRegistry[bidder]; - const spec = adapter && adapter.getSpec && adapter.getSpec(); - // banner is default if not specified in spec - const bidderMediaTypes = (spec && spec.supportedMediaTypes) || ['banner']; - - // check if the bidder's mediaTypes are not in the adUnit's mediaTypes - const bidderEligible = adUnitMediaTypes.some(type => includes(bidderMediaTypes, type)); - if (!bidderEligible) { - // drop the bidder from the ad unit if it's not compatible - logWarn(unsupportedBidderMessage(adUnit, bidder)); - adUnit.bids = adUnit.bids.filter(bid => bid.bidder !== bidder); - } else { - adunitCounter.incrementBidderRequestsCounter(adUnit.code, bidder); - } - }); - adunitCounter.incrementRequestsCounter(adUnit.code); - }); + /* + * for a given adunit which supports a set of mediaTypes + * and a given bidder which supports a set of mediaTypes + * a bidder is eligible to participate on the adunit + * if it supports at least one of the mediaTypes on the adunit + */ + adUnits.forEach(adUnit => { + // get the adunit's mediaTypes, defaulting to banner if mediaTypes isn't present + const adUnitMediaTypes = Object.keys(adUnit.mediaTypes || { 'banner': 'banner' }); - if (!adUnits || adUnits.length === 0) { - logMessage('No adUnits configured. No bids requested.'); - auctionDone(); - } else { - const auction = auctionManager.createAuction({ - adUnits, - adUnitCodes, - callback: auctionDone, - cbTimeout, - labels, - auctionId, - ortb2Fragments, - metrics, - }); - - let adUnitsLen = adUnits.length; - if (adUnitsLen > 15) { - logInfo(`Current auction ${auction.getAuctionId()} contains ${adUnitsLen} adUnits.`, adUnits); - } + // get the bidder's mediaTypes + const allBidders = adUnit.bids.map(bid => bid.bidder); + const bidderRegistry = adapterManager.bidderRegistry; - adUnitCodes.forEach(code => targeting.setLatestAuctionForAdUnit(code, auction.getAuctionId())); - auction.callBids(); + const bidders = allBidders.filter(bidder => !s2sBidders.has(bidder)); + + const tid = adUnit.ortb2Imp?.ext?.tid || generateUUID(); + adUnit.transactionId = tid; + if (ttlBuffer != null && !adUnit.hasOwnProperty('ttlBuffer')) { + adUnit.ttlBuffer = ttlBuffer; } + // Populate ortb2Imp.ext.tid with transactionId. Specifying a transaction ID per item in the ortb impression array, lets multiple transaction IDs be transmitted in a single bid request. + deepSetValue(adUnit, 'ortb2Imp.ext.tid', tid); + + bidders.forEach(bidder => { + const adapter = bidderRegistry[bidder]; + const spec = adapter && adapter.getSpec && adapter.getSpec(); + // banner is default if not specified in spec + const bidderMediaTypes = (spec && spec.supportedMediaTypes) || ['banner']; + + // check if the bidder's mediaTypes are not in the adUnit's mediaTypes + const bidderEligible = adUnitMediaTypes.some(type => includes(bidderMediaTypes, type)); + if (!bidderEligible) { + // drop the bidder from the ad unit if it's not compatible + logWarn(unsupportedBidderMessage(adUnit, bidder)); + adUnit.bids = adUnit.bids.filter(bid => bid.bidder !== bidder); + } else { + adunitCounter.incrementBidderRequestsCounter(adUnit.code, bidder); + } + }); + adunitCounter.incrementRequestsCounter(adUnit.code); }); + + if (!adUnits || adUnits.length === 0) { + logMessage('No adUnits configured. No bids requested.'); + auctionDone(); + } else { + const auction = auctionManager.createAuction({ + adUnits, + adUnitCodes, + callback: auctionDone, + cbTimeout, + labels, + auctionId, + ortb2Fragments, + metrics, + }); + + let adUnitsLen = adUnits.length; + if (adUnitsLen > 15) { + logInfo(`Current auction ${auction.getAuctionId()} contains ${adUnitsLen} adUnits.`, adUnits); + } + + adUnitCodes.forEach(code => targeting.setLatestAuctionForAdUnit(code, auction.getAuctionId())); + auction.callBids(); + } }, 'startAuction'); export function executeCallbacks(fn, reqBidsConfigObj) { @@ -904,6 +915,14 @@ $$PREBID_GLOBAL$$.aliasBidder = function (bidderCode, alias, options) { } }; +/** + * @alias module:pbjs.aliasRegistry + */ +$$PREBID_GLOBAL$$.aliasRegistry = adapterManager.aliasRegistry; +config.getConfig('aliasRegistry', config => { + if (config.aliasRegistry === 'private') delete $$PREBID_GLOBAL$$.aliasRegistry; +}); + /** * The bid response object returned by an external bidder adapter during the auction. * @typedef {Object} AdapterBidResponse diff --git a/src/refererDetection.js b/src/refererDetection.js index 15c080f5c69..e0cb15522cc 100644 --- a/src/refererDetection.js +++ b/src/refererDetection.js @@ -120,6 +120,7 @@ export function detectReferer(win) { const stack = []; const ancestors = getAncestorOrigins(win); const maxNestedIframes = config.getConfig('maxNestedIframes'); + let currentWindow; let bestLocation; let bestCanonicalUrl; @@ -226,7 +227,11 @@ export function detectReferer(win) { const location = reachedTop || hasTopLocation ? bestLocation : null; const canonicalUrl = config.getConfig('pageUrl') || bestCanonicalUrl || null; - const page = ensureProtocol(canonicalUrl, win) || location; + let page = config.getConfig('pageUrl') || location || ensureProtocol(canonicalUrl, win); + + if (location && location.indexOf('?') > -1 && page.indexOf('?') === -1) { + page = `${page}${location.substring(location.indexOf('?'))}`; + } return { reachedTop, diff --git a/src/storageManager.js b/src/storageManager.js index 4ab224f8d9b..eaf35603c60 100644 --- a/src/storageManager.js +++ b/src/storageManager.js @@ -1,6 +1,7 @@ import {hook} from './hook.js'; import {hasDeviceAccess, checkCookieSupport, logError, logInfo, isPlainObject} from './utils.js'; import {bidderSettings as defaultBidderSettings} from './bidderSettings.js'; +import {VENDORLESS_GVLID} from './consentHandler.js'; const moduleTypeWhiteList = ['core', 'prebid-module']; @@ -33,7 +34,9 @@ export function newStorageManager({gvlid, moduleName, bidderCode, moduleType} = return storageAllowed == null ? false : storageAllowed; } - const isVendorless = moduleTypeWhiteList.includes(moduleType); + if (moduleTypeWhiteList.includes(moduleType)) { + gvlid = gvlid || VENDORLESS_GVLID; + } function isValid(cb) { if (!isBidderAllowed()) { @@ -45,7 +48,7 @@ export function newStorageManager({gvlid, moduleName, bidderCode, moduleType} = let hookDetails = { hasEnforcementHook: false } - validateStorageEnforcement(isVendorless, gvlid, bidderCode || moduleName, hookDetails, function(result) { + validateStorageEnforcement(gvlid, bidderCode || moduleName, hookDetails, function(result) { if (result && result.hasEnforcementHook) { value = cb(result); } else { @@ -296,7 +299,7 @@ export function newStorageManager({gvlid, moduleName, bidderCode, moduleType} = /** * This hook validates the storage enforcement if gdprEnforcement module is included */ -export const validateStorageEnforcement = hook('async', function(isVendorless, gvlid, moduleName, hookDetails, callback) { +export const validateStorageEnforcement = hook('async', function(gvlid, moduleName, hookDetails, callback) { callback(hookDetails); }, 'validateStorageEnforcement'); diff --git a/src/targeting.js b/src/targeting.js index a427867e890..a75c9a2b52f 100644 --- a/src/targeting.js +++ b/src/targeting.js @@ -28,7 +28,15 @@ import CONSTANTS from './constants.json'; var pbTargetingKeys = []; const MAX_DFP_KEYLENGTH = 20; -const TTL_BUFFER = 1000; +let DEFAULT_TTL_BUFFER = 1; + +config.getConfig('ttlBuffer', (cfg) => { + if (typeof cfg.ttlBuffer === 'number') { + DEFAULT_TTL_BUFFER = cfg.ttlBuffer; + } else { + logError('Invalid value for ttlBuffer', cfg.ttlBuffer); + } +}) const CFG_ALLOW_TARGETING_KEYS = `targetingControls.allowTargetingKeys`; const CFG_ADD_TARGETING_KEYS = `targetingControls.addTargetingKeys`; @@ -39,7 +47,7 @@ export const TARGETING_KEYS = Object.keys(CONSTANTS.TARGETING_KEYS).map( ); // return unexpired bids -const isBidNotExpired = (bid) => (bid.responseTimestamp + bid.ttl * 1000 - TTL_BUFFER) > timestamp(); +const isBidNotExpired = (bid) => (bid.responseTimestamp + (bid.ttl - (bid.hasOwnProperty('ttlBuffer') ? bid.ttlBuffer : DEFAULT_TTL_BUFFER)) * 1000) > timestamp(); // return bids whose status is not set. Winning bids can only have a status of `rendered`. const isUnusedBid = (bid) => bid && ((bid.status && !includes([CONSTANTS.BID_STATUS.RENDERED], bid.status)) || !bid.status); diff --git a/src/utils.js b/src/utils.js index 869e1007841..8df45bab9d2 100644 --- a/src/utils.js +++ b/src/utils.js @@ -710,7 +710,7 @@ export function getKeyByValue(obj, value) { export function getBidderCodes(adUnits = $$PREBID_GLOBAL$$.adUnits) { // this could memoize adUnits return adUnits.map(unit => unit.bids.map(bid => bid.bidder) - .reduce(flatten, [])).reduce(flatten, []).filter(uniques); + .reduce(flatten, [])).reduce(flatten, []).filter((bidder) => typeof bidder !== 'undefined').filter(uniques); } export function isGptPubadsDefined() { diff --git a/src/utils/cpm.js b/src/utils/cpm.js new file mode 100644 index 00000000000..07113e7c944 --- /dev/null +++ b/src/utils/cpm.js @@ -0,0 +1,17 @@ +import {auctionManager} from '../auctionManager.js'; +import {bidderSettings} from '../bidderSettings.js'; +import {logError} from '../utils.js'; + +export function adjustCpm(cpm, bidResponse, bidRequest, {index = auctionManager.index, bs = bidderSettings} = {}) { + bidRequest = bidRequest || index.getBidRequest(bidResponse); + const bidCpmAdjustment = bs.get(bidResponse?.bidderCode || bidRequest?.bidder, 'bidCpmAdjustment'); + + if (bidCpmAdjustment && typeof bidCpmAdjustment === 'function') { + try { + return bidCpmAdjustment(cpm, Object.assign({}, bidResponse), bidRequest); + } catch (e) { + logError('Error during bid adjustment', e); + } + } + return cpm; +} diff --git a/src/utils/promise.js b/src/utils/promise.js index 97c64a96f8b..69e40791ab1 100644 --- a/src/utils/promise.js +++ b/src/utils/promise.js @@ -90,6 +90,14 @@ export class GreedyPromise extends (getGlobal().Promise || Promise) { res.#parent = this; return res; } + + static resolve(value) { + return new this(resolve => resolve(value)) + } + + static reject(error) { + return new this((resolve, reject) => reject(error)) + } } /** diff --git a/test/helpers/analytics.js b/test/helpers/analytics.js new file mode 100644 index 00000000000..b376118dc6f --- /dev/null +++ b/test/helpers/analytics.js @@ -0,0 +1,34 @@ +import * as pbEvents from 'src/events.js'; +import constants from '../../src/constants.json'; + +export function fireEvents(events = [ + constants.EVENTS.AUCTION_INIT, + constants.EVENTS.AUCTION_END, + constants.EVENTS.BID_REQUESTED, + constants.EVENTS.BID_RESPONSE, + constants.EVENTS.BID_WON +]) { + return events.map((ev, i) => { + ev = Array.isArray(ev) ? ev : [ev, {i: i}]; + pbEvents.emit.apply(null, ev) + return ev; + }); +} + +export function expectEvents(events) { + events = fireEvents(events); + return { + to: { + beTrackedBy(trackFn) { + events.forEach(([eventType, args]) => { + sinon.assert.calledWithMatch(trackFn, sinon.match({eventType, args})); + }); + }, + beBundledTo(bundleFn) { + events.forEach(([eventType, args]) => { + sinon.assert.calledWithMatch(bundleFn, sinon.match.any, eventType, sinon.match(args)) + }); + }, + }, + }; +} diff --git a/test/helpers/fpd.js b/test/helpers/fpd.js new file mode 100644 index 00000000000..89755f26541 --- /dev/null +++ b/test/helpers/fpd.js @@ -0,0 +1,71 @@ +import {dep, enrichFPD} from 'src/fpd/enrichment.js'; +import {GreedyPromise} from '../../src/utils/promise.js'; +import {deepClone} from '../../src/utils.js'; +import {gdprDataHandler, uspDataHandler} from '../../src/adapterManager.js'; + +export function mockFpdEnrichments(sandbox, overrides = {}) { + overrides = Object.assign({}, { + // override window getters, required for ChromeHeadless, apparently it sees window.self !== window + getWindowTop() { + return window + }, + getWindowSelf() { + return window + }, + getHighEntropySUA() { + return GreedyPromise.resolve() + } + }, overrides) + Object.entries(overrides) + .filter(([k]) => dep[k]) + .forEach(([k, v]) => { + sandbox.stub(dep, k).callsFake(v); + }); + Object.entries({ + gdprConsent: gdprDataHandler, + uspConsent: uspDataHandler, + }).forEach(([ovKey, handler]) => { + const v = overrides[ovKey]; + if (v) { + sandbox.stub(handler, 'getConsentData').callsFake(v); + } + }) +} + +export function addFPDEnrichments(ortb2 = {}, overrides) { + const sandbox = sinon.sandbox.create(); + mockFpdEnrichments(sandbox, overrides) + return enrichFPD(GreedyPromise.resolve(deepClone(ortb2))).finally(() => sandbox.restore()); +} + +export const syncAddFPDEnrichments = synchronize(addFPDEnrichments); + +export function addFPDToBidderRequest(bidderRequest, overrides) { + overrides = Object.assign({}, { + getRefererInfo() { + return bidderRequest.refererInfo || {}; + }, + gdprConsent() { + return bidderRequest.gdprConsent; + }, + uspConsent() { + return bidderRequest.uspConsent; + } + }, overrides); + return addFPDEnrichments(bidderRequest.ortb2 || {}, overrides).then(ortb2 => { + return { + ...bidderRequest, + ortb2 + } + }); +} + +export const syncAddFPDToBidderRequest = synchronize(addFPDToBidderRequest); + +function synchronize(fn) { + return function () { + let result; + fn.apply(this, arguments).then(res => { result = res }); + return result; + } +} diff --git a/test/helpers/hookSetup.js b/test/helpers/hookSetup.js new file mode 100644 index 00000000000..2de35bb1dd4 --- /dev/null +++ b/test/helpers/hookSetup.js @@ -0,0 +1,5 @@ +import {hook} from '../../src/hook.js'; + +before(() => { + hook.ready(); +}); diff --git a/test/helpers/refererDetectionHelper.js b/test/helpers/refererDetectionHelper.js new file mode 100644 index 00000000000..bdbfb205cdb --- /dev/null +++ b/test/helpers/refererDetectionHelper.js @@ -0,0 +1,88 @@ +/** + * Build a walkable linked list of window-like objects for testing. + * + * @param {Array} urls Array of URL strings starting from the top window. + * @param {string} [topReferrer] + * @param {string} [canonicalUrl] + * @param {boolean} [ancestorOrigins] + * @returns {Object} + */ +export function buildWindowTree(urls, topReferrer = null, canonicalUrl = null, ancestorOrigins = false) { + /** + * Find the origin from a given fully-qualified URL. + * + * @param {string} url The fully qualified URL + * @returns {string|null} + */ + function getOrigin(url) { + const originRegex = new RegExp('^(https?://[^/]+/?)'); + + const result = originRegex.exec(url); + + if (result && result[0]) { + return result[0]; + } + + return null; + } + + const inaccessibles = []; + + let previousWindow, topWindow; + const topOrigin = getOrigin(urls[0]); + + const windowList = urls.map((url, index) => { + const thisOrigin = getOrigin(url), + sameOriginAsPrevious = index === 0 ? true : (getOrigin(urls[index - 1]) === thisOrigin), + sameOriginAsTop = thisOrigin === topOrigin; + + const win = { + location: { + href: url, + }, + document: { + referrer: index === 0 ? topReferrer : urls[index - 1] + } + }; + + if (topWindow == null) { + topWindow = win; + win.document.querySelector = function (selector) { + if (selector === 'link[rel=\'canonical\']') { + return { + href: canonicalUrl + }; + } + return null; + }; + } + + if (sameOriginAsPrevious) { + win.parent = previousWindow; + } else { + win.parent = inaccessibles[inaccessibles.length - 1]; + } + if (ancestorOrigins) { + win.location.ancestorOrigins = urls.slice(0, index).reverse().map(getOrigin); + } + win.top = sameOriginAsTop ? topWindow : inaccessibles[0]; + + const inWin = {parent: inaccessibles[inaccessibles.length - 1], top: inaccessibles[0]}; + if (index === 0) { + inWin.top = inWin; + } + ['document', 'location'].forEach((prop) => { + Object.defineProperty(inWin, prop, { + get: function () { + throw new Error('cross-origin access'); + } + }); + }); + inaccessibles.push(inWin); + previousWindow = win; + + return win; + }); + + return windowList[windowList.length - 1]; +} diff --git a/test/mocks/analyticsStub.js b/test/mocks/analyticsStub.js index 8507c5a6275..98e0f56688f 100644 --- a/test/mocks/analyticsStub.js +++ b/test/mocks/analyticsStub.js @@ -1,8 +1,10 @@ -import {_internal} from '../../libraries/analyticsAdapter/AnalyticsAdapter.js'; +import {_internal, setDebounceDelay} from '../../libraries/analyticsAdapter/AnalyticsAdapter.js'; before(() => { // stub out analytics networking to avoid random events polluting the global xhr mock disableAjaxForAnalytics(); + // make analytics event handling synchronous + setDebounceDelay(0); }) export function disableAjaxForAnalytics() { diff --git a/test/mocks/timers.js b/test/mocks/timers.js new file mode 100644 index 00000000000..6efd798c881 --- /dev/null +++ b/test/mocks/timers.js @@ -0,0 +1,84 @@ +/* + * Provides wrappers for timers to allow easy cancelling and/or awaiting of outstanding timers. + * This helps avoid functionality leaking from one test to the next. + */ + +let wrappersActive = false; + +export function configureTimerInterceptors(debugLog = function() {}, generateStackTraces = false) { + if (wrappersActive) throw new Error(`Timer wrappers are already in place.`); + wrappersActive = true; + let theseWrappersActive = true; + + let originalSetTimeout = setTimeout, originalSetInterval = setInterval, originalClearTimeout = clearTimeout, originalClearInterval = clearInterval; + + let timerId = -1; + let timers = []; + + const waitOnTimersResolves = []; + function checkWaits() { + if (timers.length === 0) waitOnTimersResolves.forEach((r) => r()); + } + const waitAllActiveTimers = () => timers.length === 0 ? Promise.resolve() : new Promise((resolve) => waitOnTimersResolves.push(resolve)); + const clearAllActiveTimers = () => timers.forEach((timer) => timer.type === 'timeout' ? clearTimeout(timer.handle) : clearInterval(timer.handle)); + + const generateInterceptor = (type, originalFunctionWrapper) => (fn, delay, ...args) => { + timerId++; + debugLog(`Setting wrapped timeout ${timerId} for ${delay ?? 0}`); + const info = { timerId, type }; + if (generateStackTraces) { + try { + throw new Error(); + } catch (ex) { + info.stack = ex.stack; + } + } + info.handle = originalFunctionWrapper(info, fn, delay, ...args); + timers.push(info); + return info.handle; + }; + const setTimeoutInterceptor = generateInterceptor('timeout', (info, fn, delay, ...args) => originalSetTimeout(() => { + try { + debugLog(`Running timeout ${info.timerId}`); + fn(...args); + } finally { + const infoIndex = timers.indexOf(info); + if (infoIndex > -1) timers.splice(infoIndex, 1); + checkWaits(); + } + }, delay)); + + const setIntervalInterceptor = generateInterceptor('interval', (info, fn, interval, ...args) => originalSetInterval(() => { + debugLog(`Running interval ${info.timerId}`); + fn(...args); + }, interval)); + + const generateClearInterceptor = (type, originalClearFunction) => (handle) => { + originalClearFunction(handle); + const infoIndex = timers.findIndex((i) => i.handle === handle && i.type === type); + if (infoIndex > -1) timers.splice(infoIndex, 1); + checkWaits(); + } + const clearTimeoutInterceptor = generateClearInterceptor('timeout', originalClearTimeout); + const clearIntervalInterceptor = generateClearInterceptor('interval', originalClearInterval); + + setTimeout = setTimeoutInterceptor; + setInterval = setIntervalInterceptor; + clearTimeout = clearTimeoutInterceptor; + clearInterval = clearIntervalInterceptor; + + return { + waitAllActiveTimers, + clearAllActiveTimers, + timers, + restore: () => { + if (theseWrappersActive) { + theseWrappersActive = false; + setTimeout = originalSetTimeout; + setInterval = originalSetInterval; + clearTimeout = originalClearTimeout; + clearInterval = originalClearInterval; + } + } + } +} diff --git a/test/spec/AnalyticsAdapter_spec.js b/test/spec/AnalyticsAdapter_spec.js index 06ab8838985..62c00e04403 100644 --- a/test/spec/AnalyticsAdapter_spec.js +++ b/test/spec/AnalyticsAdapter_spec.js @@ -1,18 +1,17 @@ -import { expect } from 'chai'; +import {expect} from 'chai'; import * as events from 'src/events.js'; import CONSTANTS from 'src/constants.json'; -import { server } from 'test/mocks/xhr.js'; +import {server} from 'test/mocks/xhr.js'; import {disableAjaxForAnalytics, enableAjaxForAnalytics} from '../mocks/analyticsStub.js'; +import {clearEvents} from 'src/events.js'; +import { + DEFAULT_EXCLUDE_EVENTS, + DEFAULT_INCLUDE_EVENTS, + setDebounceDelay +} from '../../libraries/analyticsAdapter/AnalyticsAdapter.js'; -const REQUEST_BIDS = CONSTANTS.EVENTS.REQUEST_BIDS; -const BID_REQUESTED = CONSTANTS.EVENTS.BID_REQUESTED; -const BID_RESPONSE = CONSTANTS.EVENTS.BID_RESPONSE; const BID_WON = CONSTANTS.EVENTS.BID_WON; -const BID_TIMEOUT = CONSTANTS.EVENTS.BID_TIMEOUT; -const AD_RENDER_FAILED = CONSTANTS.EVENTS.AD_RENDER_FAILED; -const AD_RENDER_SUCCEEDED = CONSTANTS.EVENTS.AD_RENDER_SUCCEEDED; -const AUCTION_DEBUG = CONSTANTS.EVENTS.AUCTION_DEBUG; -const ADD_AD_UNITS = CONSTANTS.EVENTS.ADD_AD_UNITS; +const NO_BID = CONSTANTS.EVENTS.NO_BID; const AnalyticsAdapter = require('libraries/analyticsAdapter/AnalyticsAdapter.js').default; const config = { @@ -35,6 +34,7 @@ FEATURE: Analytics Adapters API afterEach(function () { adapter.disableAnalytics(); + clearEvents(); }); it('should track enable status in `enabled`', () => { @@ -43,21 +43,21 @@ FEATURE: Analytics Adapters API expect(adapter.enabled).to.equal(true); adapter.disableAnalytics(); expect(adapter.enabled).to.equal(false); - }) + }); it(`SHOULD call the endpoint WHEN an event occurs that is to be tracked`, function () { - const eventType = BID_REQUESTED; - const args = { some: 'data' }; + const eventType = BID_WON; + const args = {some: 'data'}; - adapter.track({ eventType, args }); + adapter.track({eventType, args}); let result = JSON.parse(server.requests[0].requestBody); - expect(result).to.deep.equal({args: {some: 'data'}, eventType: 'bidRequested'}); + expect(result).to.deep.equal({args: {some: 'data'}, eventType}); }); it(`SHOULD queue the event first and then track it WHEN an event occurs before tracking library is available`, function () { - const eventType = BID_RESPONSE; - const args = { wat: 'wot' }; + const eventType = BID_WON; + const args = {wat: 'wot'}; events.emit(eventType, args); adapter.enableAnalytics(); @@ -65,9 +65,58 @@ FEATURE: Analytics Adapters API // As now AUCTION_DEBUG is triggered for WARNINGS too, the BID_RESPONSE goes last in the array const index = server.requests.length - 1; let result = JSON.parse(server.requests[index].requestBody); - expect(result).to.deep.equal({eventType: 'bidResponse', args: {wat: 'wot'}}); + expect(result).to.deep.equal({eventType, args: {wat: 'wot'}}); }); + describe('event filters', () => { + function fireEvents() { + events.emit(BID_WON, {}); + events.emit(NO_BID, {}); + } + function getEvents(ev) { + return server.requests + .map(r => JSON.parse(r.requestBody)) + .filter(r => r.eventType === ev) + } + + Object.entries({ + 'whitelist includeEvents': { + includeEvents: [BID_WON] + }, + 'blacklist excludeEvents': { + excludeEvents: [NO_BID] + }, + 'give precedence to exclude over include': { + includeEvents: [BID_WON, NO_BID], + excludeEvents: [NO_BID] + } + }).forEach(([t, config]) => { + it(`should ${t}`, () => { + fireEvents(); + adapter.enableAnalytics(config); + expect(getEvents(BID_WON).length).to.eql(1); + expect(getEvents(NO_BID).length).to.eql(0); + fireEvents(); + expect(getEvents(BID_WON).length).to.eql(2); + expect(getEvents(NO_BID).length).to.eql(0); + }) + }) + }) + + it('should prevent infinite loops when track triggers other events', () => { + let i = 0; + adapter.track = ((orig) => { + return function (event) { + i++; + orig.call(this, event); + events.emit(BID_WON, {}) + } + })(adapter.track); + adapter.enableAnalytics(config); + events.emit(BID_WON, {}); + expect(i >= 100).to.eql(false); + }) + describe(`WHEN an event occurs after enable analytics\n`, function () { beforeEach(function () { sinon.stub(events, 'getEvents').returns([]); // these tests shouldn't be affected by previous tests @@ -77,108 +126,26 @@ FEATURE: Analytics Adapters API events.getEvents.restore(); }); - it('SHOULD call global when a bidWon event occurs', function () { - const eventType = BID_WON; - const args = { more: 'info' }; - - adapter.enableAnalytics(); - events.emit(eventType, args); - - let result = JSON.parse(server.requests[0].requestBody); - expect(result).to.deep.equal({args: {more: 'info'}, eventType: 'bidWon'}); - }); - - it('SHOULD call global when a adRenderFailed event occurs', function () { - const eventType = AD_RENDER_FAILED; - const args = { call: 'adRenderFailed' }; - - adapter.enableAnalytics(); - events.emit(eventType, args); - - let result = JSON.parse(server.requests[0].requestBody); - expect(result).to.deep.equal({args: {call: 'adRenderFailed'}, eventType: 'adRenderFailed'}); - }); - - it('SHOULD call global when a adRenderSucceeded event occurs', function () { - const eventType = AD_RENDER_SUCCEEDED; - const args = { call: 'adRenderSucceeded' }; - - adapter.enableAnalytics(); - events.emit(eventType, args); - - let result = JSON.parse(server.requests[0].requestBody); - expect(result).to.deep.equal({args: {call: 'adRenderSucceeded'}, eventType: 'adRenderSucceeded'}); - }); - - it('SHOULD call global when an auction debug event occurs', function () { - const eventType = AUCTION_DEBUG; - const args = { call: 'auctionDebug' }; - - adapter.enableAnalytics(); - events.emit(eventType, args); - - let result = JSON.parse(server.requests[0].requestBody); - expect(result).to.deep.equal({args: {call: 'auctionDebug'}, eventType: 'auctionDebug'}); - }); - - it('SHOULD call global when an addAdUnits event occurs', function () { - const eventType = ADD_AD_UNITS; - const args = { call: 'addAdUnits' }; - - adapter.enableAnalytics(); - events.emit(eventType, args); - - let result = JSON.parse(server.requests[0].requestBody); - expect(result).to.deep.equal({args: {call: 'addAdUnits'}, eventType: 'addAdUnits'}); - }); - - it('SHOULD call global when a requestBids event occurs', function () { - const eventType = REQUEST_BIDS; - const args = { call: 'request' }; - - adapter.enableAnalytics(); - events.emit(eventType, args); - - let result = JSON.parse(server.requests[0].requestBody); - expect(result).to.deep.equal({args: {call: 'request'}, eventType: 'requestBids'}); - }); - - it('SHOULD call global when a bidRequest event occurs', function () { - const eventType = BID_REQUESTED; - const args = { call: 'request' }; - - adapter.enableAnalytics(); - events.emit(eventType, args); - - let result = JSON.parse(server.requests[0].requestBody); - expect(result).to.deep.equal({args: {call: 'request'}, eventType: 'bidRequested'}); - }); - - it('SHOULD call global when a bidResponse event occurs', function () { - const eventType = BID_RESPONSE; - const args = { call: 'response' }; - - adapter.enableAnalytics(); - events.emit(eventType, args); - - let result = JSON.parse(server.requests[0].requestBody); - expect(result).to.deep.equal({args: {call: 'response'}, eventType: 'bidResponse'}); - }); - - it('SHOULD call global when a bidTimeout event occurs', function () { - const eventType = BID_TIMEOUT; - const args = { call: 'timeout' }; + Object.values(DEFAULT_INCLUDE_EVENTS).forEach(eventType => { + it(`SHOULD call global when a ${eventType} event occurs`, () => { + const args = {more: 'info'}; - adapter.enableAnalytics(); - events.emit(eventType, args); + adapter.enableAnalytics(); + events.emit(eventType, args); - let result = JSON.parse(server.requests[0].requestBody); - expect(result).to.deep.equal({args: {call: 'timeout'}, eventType: 'bidTimeout'}); + let result = JSON.parse(server.requests[server.requests.length - 1].requestBody); + sinon.assert.match(result, { + eventType, + args: { + more: 'info' + }, + }); + }); }); it('SHOULD NOT call global again when adapter.enableAnalytics is called with previous timeout', function () { - const eventType = BID_TIMEOUT; - const args = { call: 'timeout' }; + const eventType = BID_WON; + const args = {call: 'timeout'}; events.emit(eventType, args); adapter.enableAnalytics(); @@ -189,7 +156,7 @@ FEATURE: Analytics Adapters API describe(`AND sampling is enabled\n`, function () { const eventType = BID_WON; - const args = { more: 'info' }; + const args = {more: 'info'}; beforeEach(function () { sinon.stub(Math, 'random').returns(0.5); @@ -225,3 +192,39 @@ FEATURE: Analytics Adapters API }); }); }); + +describe('Analytics asynchronous event tracking', () => { + before(() => { + setDebounceDelay(100); + }); + after(() => { + setDebounceDelay(0); + }); + + let adapter, clock; + + beforeEach(() => { + clock = sinon.useFakeTimers(); + adapter = new AnalyticsAdapter(config); + adapter.track = sinon.stub(); + adapter.enableAnalytics({}); + }); + + afterEach(() => { + clock.restore(); + }) + + it('does not call track as long as events are coming', () => { + events.emit(BID_WON, {i: 0}); + sinon.assert.notCalled(adapter.track); + clock.tick(10); + events.emit(BID_WON, {i: 1}); + sinon.assert.notCalled(adapter.track); + clock.tick(10); + sinon.assert.notCalled(adapter.track); + clock.tick(100); + sinon.assert.calledTwice(adapter.track); + sinon.assert.calledWith(adapter.track.firstCall, {eventType: BID_WON, args: {i: 0}}); + sinon.assert.calledWith(adapter.track.secondCall, {eventType: BID_WON, args: {i: 1}}); + }); +}) diff --git a/test/spec/auctionmanager_spec.js b/test/spec/auctionmanager_spec.js index e36b2ccbb07..6a72da8edce 100644 --- a/test/spec/auctionmanager_spec.js +++ b/test/spec/auctionmanager_spec.js @@ -22,6 +22,7 @@ import 'modules/debugging/index.js' // some tests look for debugging side effect import {AuctionIndex} from '../../src/auctionIndex.js'; import {expect} from 'chai'; import {deepClone} from '../../src/utils.js'; +import { IMAGE as ortbNativeRequest } from 'src/native.js'; var assert = require('assert'); @@ -185,7 +186,8 @@ describe('auctionmanager.js', function () { source: 'client', mediaType: 'banner', meta: { - advertiserDomains: ['adomain'] + advertiserDomains: ['adomain'], + primaryCatId: 'IAB-test' } }; @@ -199,6 +201,7 @@ describe('auctionmanager.js', function () { expected[ CONSTANTS.TARGETING_KEYS.SOURCE ] = bid.source; expected[ CONSTANTS.TARGETING_KEYS.FORMAT ] = bid.mediaType; expected[ CONSTANTS.TARGETING_KEYS.ADOMAIN ] = bid.meta.advertiserDomains[0]; + expected[ CONSTANTS.TARGETING_KEYS.ACAT ] = bid.meta.primaryCatId; if (bid.mediaType === 'video') { expected[ CONSTANTS.TARGETING_KEYS.UUID ] = bid.videoCacheKey; expected[ CONSTANTS.TARGETING_KEYS.CACHE_ID ] = bid.videoCacheKey; @@ -229,6 +232,15 @@ describe('auctionmanager.js', function () { assert.deepEqual(response, expected); }); + it('should suppress acat if undefined', function () { + const noAcatBid = deepClone(DEFAULT_BID); + noAcatBid.meta.primaryCatId = '' + let expected = getDefaultExpected(noAcatBid); + delete expected.hb_acat; + let response = getKeyValueTargetingPairs(noAcatBid.bidderCode, noAcatBid); + assert.deepEqual(response, expected); + }); + it('No bidder level configuration defined - default for video', function () { config.setConfig({ cache: { @@ -289,6 +301,12 @@ describe('auctionmanager.js', function () { val: function (bidResponse) { return bidResponse.meta.advertiserDomains[0]; } + }, + { + key: CONSTANTS.TARGETING_KEYS.ACAT, + val: function (bidResponse) { + return bidResponse.meta.primaryCatId; + } } ] @@ -366,6 +384,12 @@ describe('auctionmanager.js', function () { val: function (bidResponse) { return bidResponse.meta.advertiserDomains[0]; } + }, + { + key: CONSTANTS.TARGETING_KEYS.ACAT, + val: function (bidResponse) { + return bidResponse.meta.primaryCatId; + } } ] @@ -454,6 +478,24 @@ describe('auctionmanager.js', function () { assert.deepEqual(response, expected); }); + it('Should set targeting as expecting when pbs is enabled', function () { + config.setConfig({ + s2sConfig: { + accountId: '1', + enabled: true, + defaultVendor: 'appnexus', + bidders: ['appnexus'], + timeout: 1000, + adapter: 'prebidServer' + } + }); + + $$PREBID_GLOBAL$$.bidderSettings = {}; + let expected = getDefaultExpected(bid); + let response = getKeyValueTargetingPairs(bid.bidderCode, bid); + assert.deepEqual(response, expected); + }); + it('Custom bidCpmAdjustment for one bidder and inherit standard but doesn\'t use standard bidCpmAdjustment', function () { $$PREBID_GLOBAL$$.bidderSettings = { @@ -726,6 +768,20 @@ describe('auctionmanager.js', function () { sinon.assert.calledWith(stubMakeBidRequests, ...anyArgs.slice(0, 5).concat([sinon.match.same(ortb2Fragments)])); sinon.assert.calledWith(stubCallAdapters, ...anyArgs.slice(0, 7).concat([sinon.match.same(ortb2Fragments)])); }); + + it('correctly adds nonbids when they are emitted', () => { + const ortb2Fragments = { + global: {}, + bidder: {} + } + const auction = auctionManager.createAuction({adUnits, ortb2Fragments}); + expect(auction.getNonBids()[0]).to.equal(undefined); + events.emit(CONSTANTS.EVENTS.SEAT_NON_BID, { + auctionId: auction.getAuctionId(), + seatnonbid: ['test'] + }); + expect(auction.getNonBids()[0]).to.equal('test'); + }); }); describe('addBidResponse #1', function () { @@ -955,6 +1011,12 @@ describe('auctionmanager.js', function () { const addedBid = find(auction.getBidsReceived(), bid => bid.adUnitCode == ADUNIT_CODE); assert.equal(addedBid.renderer.url, 'renderer.js'); }); + + it('sets bidResponse.ttlBuffer from adUnit.ttlBuffer', () => { + adUnits[0].ttlBuffer = 0; + auction.callBids(); + expect(auction.getBidsReceived()[0].ttlBuffer).to.eql(0); + }); }); describe('when auction timeout is 20', function () { @@ -1270,6 +1332,81 @@ describe('auctionmanager.js', function () { }); }); + if (FEATURES.NATIVE) { + describe('addBidResponse native', function () { + let makeRequestsStub; + let ajaxStub; + let spec; + let auction; + + beforeEach(function () { + makeRequestsStub = sinon.stub(adapterManager, 'makeBidRequests'); + ajaxStub = sinon.stub(ajaxLib, 'ajaxBuilder').callsFake(mockAjaxBuilder); + + const adUnits = [{ + code: ADUNIT_CODE, + transactionId: ADUNIT_CODE, + bids: [ + {bidder: BIDDER_CODE, params: {placementId: 'id'}}, + ], + nativeOrtbRequest: ortbNativeRequest.ortb, + mediaTypes: { native: { type: 'image' } } + }]; + auction = auctionModule.newAuction({adUnits, adUnitCodes: [ADUNIT_CODE], callback: function() {}, cbTimeout: 3000}); + indexAuctions = [auction]; + const createAuctionStub = sinon.stub(auctionModule, 'newAuction'); + createAuctionStub.returns(auction); + + spec = mockBidder(BIDDER_CODE); + registerBidder(spec); + }); + + afterEach(function () { + ajaxStub.restore(); + auctionModule.newAuction.restore(); + adapterManager.makeBidRequests.restore(); + }); + + it('should add legacy fields to native response', function () { + let nativeBid = mockBid(); + nativeBid.mediaType = 'native'; + nativeBid.native = { + ortb: { + ver: '1.2', + assets: [ + { id: 2, title: { text: 'Sample title' } }, + { id: 4, data: { value: 'Sample body' } }, + { id: 3, data: { value: 'Sample sponsoredBy' } }, + { id: 1, img: { url: 'https://www.example.com/image.png', w: 200, h: 200 } }, + { id: 5, img: { url: 'https://www.example.com/icon.png', w: 32, h: 32 } } + ], + link: { url: 'http://www.click.com' }, + eventtrackers: [ + { event: 1, method: 1, url: 'http://www.imptracker.com' }, + { event: 1, method: 2, url: 'http://www.jstracker.com/file.js' } + ] + } + } + + let bidRequest = mockBidRequest(nativeBid, { mediaType: { native: ortbNativeRequest } }); + makeRequestsStub.returns([bidRequest]); + + spec.interpretResponse.returns(nativeBid); + auction.callBids(); + + const addedBid = auction.getBidsReceived().pop(); + assert.equal(addedBid.native.body, 'Sample body') + assert.equal(addedBid.native.title, 'Sample title') + assert.equal(addedBid.native.sponsoredBy, 'Sample sponsoredBy') + assert.equal(addedBid.native.clickUrl, 'http://www.click.com') + assert.equal(addedBid.native.image, 'https://www.example.com/image.png') + assert.equal(addedBid.native.icon, 'https://www.example.com/icon.png') + assert.equal(addedBid.native.impressionTrackers[0], 'http://www.imptracker.com') + assert.equal(addedBid.native.javascriptTrackers, '') + }); + }); + } + describe('getMediaTypeGranularity', function () { it('video', function () { let mediaTypes = { video: {id: '1'} }; @@ -1458,6 +1595,15 @@ describe('auctionmanager.js', function () { assert.equal(doneSpy.callCount, 1); }); + it('should convert cpm to number', () => { + auction.addBidReceived = sinon.spy(); + const cbs = auctionCallbacks(doneSpy, auction); + const bid = {...bids[0], cpm: '1.23'} + bidRequests = [mockBidRequest(bid)]; + cbs.addBidResponse.call(bidRequests[0], ADUNIT_CODE, bid); + sinon.assert.calledWith(auction.addBidReceived, sinon.match({cpm: 1.23})); + }) + describe('when addBidResponse hook returns promises', () => { let resolvers, callbacks, bids; @@ -1599,6 +1745,7 @@ describe('auctionmanager.js', function () { ]; cbs = auctionCallbacks(doneSpy, auction); expectedRejection = sinon.match(Object.assign({}, bid, { + cpm: parseFloat(bid.cpm), rejectionReason: REJECTION_REASON, adUnitCode: AU_CODE })); @@ -1635,6 +1782,15 @@ describe('auctionmanager.js', function () { }); }); + it('should return NO_BID replacement when rejected bid is not a "proper" bid', () => { + const noBid = cbs.addBidResponse.reject(AU_CODE, {}); + sinon.assert.match(noBid, { + status: CONSTANTS.BID_STATUS.BID_REJECTED, + statusMessage: 'Bid returned empty or error response', + cpm: 0, + }); + }) + it('addBidResponse hooks should not be able to reject the same bid twice', () => { cbs.addBidResponse(AU_CODE, bid); expect(auction.addBidRejected.calledOnce).to.be.true; diff --git a/test/spec/fpd/enrichment_spec.js b/test/spec/fpd/enrichment_spec.js new file mode 100644 index 00000000000..3363e1867d3 --- /dev/null +++ b/test/spec/fpd/enrichment_spec.js @@ -0,0 +1,213 @@ +import {dep, enrichFPD} from '../../../src/fpd/enrichment.js'; +import {hook} from '../../../src/hook.js'; +import {expect} from 'chai/index.mjs'; +import {config} from 'src/config.js'; + +describe('FPD enrichment', () => { + let sandbox; + before(() => { + hook.ready(); + }); + beforeEach(() => { + sandbox = sinon.sandbox.create(); + }); + afterEach(() => { + sandbox.restore(); + config.resetConfig(); + }); + + function fpd(ortb2 = {}) { + return enrichFPD(Promise.resolve(ortb2)); + } + + function mockWindow() { + return { + innerHeight: 1, + innerWidth: 1, + navigator: { + language: '' + }, + document: { + querySelector: sinon.stub() + } + }; + } + + function testWindows(getWindow, fn) { + Object.entries({ + 'top': ['getWindowTop', 'getWindowSelf'], + 'self': ['getWindowSelf', 'getWindowTop'] + }).forEach(([t, [winWorks, winThrows]]) => { + describe(`using window.${t}`, () => { + beforeEach(() => { + sandbox.stub(dep, winWorks).callsFake(getWindow); + sandbox.stub(dep, winThrows).throws(new Error()); + }); + fn(); + }); + }); + } + + describe('site', () => { + it('sets page, ref, domain, and publisher.domain', () => { + const refererInfo = { + page: 'www.example.com', + ref: 'referrer.com' + }; + sandbox.stub(dep, 'getRefererInfo').callsFake(() => refererInfo); + sandbox.stub(dep, 'findRootDomain').callsFake((dom) => `publisher.${dom}`); + return fpd().then(ortb2 => { + sinon.assert.match(ortb2.site, { + page: 'www.example.com', + domain: 'example.com', + ref: 'referrer.com', + publisher: { + domain: 'publisher.example.com' + } + }); + }); + }); + + describe('keywords', () => { + let metaTag; + beforeEach(() => { + metaTag = document.createElement('meta'); + metaTag.name = 'keywords'; + metaTag.content = 'kw1, kw2'; + document.head.appendChild(metaTag); + }); + afterEach(() => { + document.head.removeChild(metaTag); + }); + + testWindows(() => window, () => { + it(`sets kewwords from meta tag`, () => { + return fpd().then(ortb2 => { + expect(ortb2.site.keywords).to.eql('kw1,kw2'); + }); + }); + }); + }); + + it('should not set keywords if meta tag is not present', () => { + return fpd().then(ortb2 => { + expect(ortb2.site.hasOwnProperty('keywords')).to.be.false; + }); + }); + + it('respects pub-provided fpd', () => { + return fpd({ + site: { + publisher: { + domain: 'pub.com' + } + } + }).then(ortb2 => { + expect(ortb2.site.publisher.domain).to.eql('pub.com'); + }); + }); + }); + + describe('device', () => { + let win; + beforeEach(() => { + win = mockWindow(); + }); + testWindows(() => win, () => { + it('sets w/h', () => { + win.innerHeight = 123; + win.innerWidth = 321; + return fpd().then(ortb2 => { + sinon.assert.match(ortb2.device, { + w: 321, + h: 123, + }); + }); + }); + + it('sets ua', () => { + win.navigator.userAgent = 'mock-ua'; + return fpd().then(ortb2 => { + expect(ortb2.device.ua).to.eql('mock-ua'); + }) + }); + + it('sets language', () => { + win.navigator.language = 'lang-ignored'; + return fpd().then(ortb2 => { + expect(ortb2.device.language).to.eql('lang'); + }) + }); + }); + }); + + describe('regs', () => { + describe('gpc', () => { + let win; + beforeEach(() => { + win = mockWindow(); + }); + testWindows(() => win, () => { + it('is set if globalPrivacyControl is set', () => { + win.navigator.globalPrivacyControl = true; + return fpd().then(ortb2 => { + expect(ortb2.regs.ext.gpc).to.eql(1); + }); + }); + + it('is not set otherwise', () => { + return fpd().then(ortb2 => { + expect(ortb2.regs?.ext?.gpc).to.not.exist; + }) + }) + }); + }) + describe('coppa', () => { + [[true, 1], [false, 0]].forEach(([cfgVal, regVal]) => { + it(`is set to ${regVal} if config = ${cfgVal}`, () => { + config.setConfig({coppa: cfgVal}); + return fpd().then(ortb2 => { + expect(ortb2.regs.coppa).to.eql(regVal); + }) + }); + }) + + it('is not set if not configured', () => { + return fpd().then(ortb2 => { + expect(ortb2.regs?.coppa).to.not.exist; + }) + }) + }); + }); + + describe('sua', () => { + it('does not set device.sua if resolved sua is null', () => { + sandbox.stub(dep, 'getHighEntropySUA').returns(Promise.resolve()) + return fpd().then(ortb2 => { + expect(ortb2.device.sua).to.not.exist; + }) + }); + it('uses low entropy values if uaHints is []', () => { + sandbox.stub(dep, 'getLowEntropySUA').callsFake(() => ({mock: 'sua'})); + config.setConfig({ + firstPartyData: { + uaHints: [], + } + }) + return fpd().then(ortb2 => { + expect(ortb2.device.sua).to.eql({mock: 'sua'}); + }) + }); + it('uses high entropy values otherwise', () => { + sandbox.stub(dep, 'getHighEntropySUA').callsFake((hints) => Promise.resolve({hints})); + config.setConfig({ + firstPartyData: { + uaHints: ['h1', 'h2'] + } + }); + return fpd().then(ortb2 => { + expect(ortb2.device.sua).to.eql({hints: ['h1', 'h2']}) + }) + }); + }); +}); diff --git a/test/spec/fpd/gdpr_spec.js b/test/spec/fpd/gdpr_spec.js new file mode 100644 index 00000000000..8fc04815112 --- /dev/null +++ b/test/spec/fpd/gdpr_spec.js @@ -0,0 +1,47 @@ +import {gdprDataHandler} from '../../../src/adapterManager.js'; +import {enrichFPDHook} from '../../../modules/consentManagement.js'; + +describe('GDPR FPD enrichment', () => { + let sandbox, consent; + beforeEach(() => { + consent = null; + sandbox = sinon.sandbox.create(); + sandbox.stub(gdprDataHandler, 'getConsentData').callsFake(() => consent); + }); + afterEach(() => { + sandbox.restore(); + }) + + function callHook() { + let result; + enrichFPDHook((res) => { result = res }, Promise.resolve({})); + return result; + } + + it('sets gdpr properties from gdprDataHandler', () => { + consent = {gdprApplies: true, consentString: 'consent'}; + return callHook().then(ortb2 => { + expect(ortb2.regs.ext.gdpr).to.eql(1); + expect(ortb2.user.ext.consent).to.eql('consent'); + }) + }); + + it('does not set it if missing', () => { + return callHook().then((ortb2) => { + expect(ortb2).to.eql({}); + }) + }); + + it('sets user.ext.consent, but not regs.ext.gdpr, if gpdrApplies is not a boolean', () => { + consent = {consentString: 'mock-consent'}; + return callHook().then(ortb2 => { + expect(ortb2).to.eql({ + user: { + ext: { + consent: 'mock-consent' + } + } + }) + }) + }); +}); diff --git a/test/spec/fpd/rootDomain_spec.js b/test/spec/fpd/rootDomain_spec.js new file mode 100644 index 00000000000..008ef749edc --- /dev/null +++ b/test/spec/fpd/rootDomain_spec.js @@ -0,0 +1,61 @@ +import {expect} from 'chai/index.js'; +import {findRootDomain, coreStorage} from 'src/fpd/rootDomain.js'; + +describe('findRootDomain', function () { + let sandbox, cookies, rejectDomain; + + beforeEach(function () { + findRootDomain.clear(); + cookies = {}; + rejectDomain = ''; + sandbox = sinon.createSandbox(); + sandbox.stub(coreStorage, 'cookiesAreEnabled').returns(true); + sandbox.stub(coreStorage, 'setCookie').callsFake((cookie, value, expiration, sameSite, domain) => { + if (rejectDomain !== domain) { + if (new Date(expiration) <= Date.now()) { + delete cookies[cookie]; + } else { + cookies[cookie] = value; + } + } + }) + sandbox.stub(coreStorage, 'getCookie').callsFake((cookie) => { + return cookies[cookie] + }); + }); + + afterEach(function () { + sandbox.restore(); + }); + + after(() => { + findRootDomain.clear(); + }) + + it('should just find the root domain', function () { + rejectDomain = 'co.uk'; + var domain = findRootDomain('sub.realdomain.co.uk'); + expect(domain).to.be.eq('realdomain.co.uk'); + expect(cookies).to.eql({}); + }); + + it('should find the full domain when no subdomain is present', function () { + rejectDomain = 'co.uk'; + var domain = findRootDomain('realdomain.co.uk'); + expect(domain).to.be.eq('realdomain.co.uk'); + expect(cookies).to.eql({}); + }); + + it('should return domain as-is if cookies are disabled', () => { + coreStorage.cookiesAreEnabled.returns(false); + expect(findRootDomain('sub.example.com')).to.eql('sub.example.com'); + sinon.assert.notCalled(coreStorage.setCookie); + }); + + it('should memoize default value', () => { + const domain = findRootDomain(); + expect(domain.length > 0).to.be.true; + expect(findRootDomain()).to.eql(domain); + sinon.assert.calledOnce(coreStorage.getCookie); + }); +}); diff --git a/test/spec/fpd/usp_spec.js b/test/spec/fpd/usp_spec.js new file mode 100644 index 00000000000..f616b086ffa --- /dev/null +++ b/test/spec/fpd/usp_spec.js @@ -0,0 +1,36 @@ +import {enrichFPDHook} from '../../../modules/consentManagementUsp.js'; +import {uspDataHandler} from '../../../src/adapterManager.js'; + +describe('FPD enrichment USP', () => { + let sandbox, consent; + beforeEach(() => { + consent = null; + sandbox = sinon.sandbox.create(); + sandbox.stub(uspDataHandler, 'getConsentData').callsFake(() => consent); + }); + + afterEach(() => { + sandbox.restore(); + }); + + function callHook() { + let result; + enrichFPDHook((res) => { + result = res; + }, Promise.resolve({})); + return result; + } + + it('sets regs.ext.us_privacy from uspDataHandler', () => { + consent = '1NN'; + return callHook().then(ortb2 => { + expect(ortb2.regs.ext.us_privacy).to.eql('1NN'); + }) + }); + + it('does not set if missing', () => { + return callHook().then(ortb2 => { + expect(ortb2).to.eql({}); + }) + }); +}); diff --git a/test/spec/modules/33acrossBidAdapter_spec.js b/test/spec/modules/33acrossBidAdapter_spec.js index 2680544d00b..3b3c05660df 100644 --- a/test/spec/modules/33acrossBidAdapter_spec.js +++ b/test/spec/modules/33acrossBidAdapter_spec.js @@ -218,6 +218,14 @@ describe('33acrossBidAdapter:', function () { return this; }; + this.withReferer = referer => { + Object.assign(ttxRequest.site, { + ref: referer + }); + + return this; + }; + this.withSchain = schain => { Object.assign(ttxRequest, { source: { @@ -1187,26 +1195,51 @@ describe('33acrossBidAdapter:', function () { }); }); - context('when referer value is available', function() { - it('returns corresponding server requests with site.page set', function() { - const bidderRequest = { - refererInfo: { - page: 'http://foo.com/bar' - } - }; + context('when refererInfo values are available', function() { + context('when refererInfo.page is defined', function() { + it('returns corresponding server requests with site.page set', function() { + const bidderRequest = { + refererInfo: { + page: 'http://foo.com/bar' + } + }; - const ttxRequest = new TtxRequestBuilder() - .withBanner() - .withProduct() - .withPageUrl('http://foo.com/bar') - .build(); - const serverRequest = new ServerRequestBuilder() - .withData(ttxRequest) - .build(); + const ttxRequest = new TtxRequestBuilder() + .withBanner() + .withProduct() + .withPageUrl('http://foo.com/bar') + .build(); + const serverRequest = new ServerRequestBuilder() + .withData(ttxRequest) + .build(); - const [ builtServerRequest ] = spec.buildRequests(bidRequests, bidderRequest); + const [ builtServerRequest ] = spec.buildRequests(bidRequests, bidderRequest); - validateBuiltServerRequest(builtServerRequest, serverRequest); + validateBuiltServerRequest(builtServerRequest, serverRequest); + }); + }); + + context('when refererInfo.ref is defined', function() { + it('returns corresponding server requests with site.ref set', function() { + const bidderRequest = { + refererInfo: { + ref: 'google.com' + } + }; + + const ttxRequest = new TtxRequestBuilder() + .withBanner() + .withProduct() + .withReferer('google.com') + .build(); + const serverRequest = new ServerRequestBuilder() + .withData(ttxRequest) + .build(); + + const [ builtServerRequest ] = spec.buildRequests(bidRequests, bidderRequest); + + validateBuiltServerRequest(builtServerRequest, serverRequest); + }); }); }); @@ -1246,7 +1279,7 @@ describe('33acrossBidAdapter:', function () { }); context('when referer value is not available', function() { - it('returns corresponding server requests without site.page set', function() { + it('returns corresponding server requests without site.page and site.ref set', function() { const bidderRequest = { refererInfo: {} }; diff --git a/test/spec/modules/33acrossIdSystem_spec.js b/test/spec/modules/33acrossIdSystem_spec.js index 8198bd75381..765b320f925 100644 --- a/test/spec/modules/33acrossIdSystem_spec.js +++ b/test/spec/modules/33acrossIdSystem_spec.js @@ -43,7 +43,10 @@ describe('33acrossIdSystem', () => { expect(request.method).to.equal('GET'); expect(request.withCredentials).to.be.true; - expect(request.url).to.contain('https://lexicon.33across.com/v1/envelope?pid=12345'); + + const regExp = new RegExp('https://lexicon.33across.com/v1/envelope\\?pid=12345&gdpr=\\d&src=pbjs&ver=$prebid.version$'); + + expect(request.url).to.match(regExp); expect(completeCallback.calledOnceWithExactly('foo')).to.be.true; }); diff --git a/test/spec/modules/ViouslyBidAdapter_spec.js b/test/spec/modules/ViouslyBidAdapter_spec.js new file mode 100644 index 00000000000..612c5f87138 --- /dev/null +++ b/test/spec/modules/ViouslyBidAdapter_spec.js @@ -0,0 +1,378 @@ +import {expect} from 'chai'; + +import { deepClone, mergeDeep } from 'src/utils'; +import { createEidsArray } from 'modules/userId/eids.js'; + +import {spec as adapter} from 'modules/viouslyBidAdapter'; + +import sinon from 'sinon'; +import { config } from 'src/config.js'; + +const CURRENCY = 'EUR'; +const TTL = 60; +const HTTP_METHOD = 'POST'; +const REQUEST_URL = 'https://bidder.viously.com/bid'; + +const VALID_BID_VIDEO = { + bidder: 'viously', + bidId: '5e6f7g8h', + adUnitCode: 'id-5678', + params: { + pid: '123e4567-e89b-12d3-a456-426614174001' + }, + mediaTypes: { + video: { + playerSize: [640, 360], + context: 'instream', + playbackmethod: [1, 2, 3, 4] + } + } +}; + +const VALID_REQUEST_VIDEO = { + method: HTTP_METHOD, + url: REQUEST_URL, + data: { + pid: '123e4567-e89b-12d3-a456-426614174001', + currency_code: CURRENCY, + placements: [ + { + id: 'id-5678', + bid_id: '5e6f7g8h', + video_params: { + context: 'instream', + playbackmethod: [1, 2, 3, 4], + size: ['640x360'] + } + } + ] + } +}; + +const VALID_GDPR = { + gdprApplies: true, + apiVersion: 2, + consentString: 'abcdefgh', + addtlConsent: '1~12345678', + vendorData: { + purpose: { + consents: { + 1: true + } + } + } +}; +const US_PRIVACY = '1YNN'; + +describe('ViouslyAdapter', function () { + describe('isBidRequestValid', function () { + describe('Check method return', function () { + it('should return true', function () { + expect(adapter.isBidRequestValid(VALID_BID_VIDEO)).to.equal(true); + }); + + it('should return false because the pid is missing', function () { + let wrongBid = deepClone(VALID_BID_VIDEO); + delete wrongBid.params.pid; + + expect(adapter.isBidRequestValid(wrongBid)).to.equal(false); + }); + + it('should return false because the video context parameter is missing', function () { + let wrongBid = deepClone(VALID_BID_VIDEO); + + delete wrongBid.mediaTypes.video.context; + expect(adapter.isBidRequestValid(wrongBid)).to.equal(false); + }); + }); + }); + + describe('buildRequests', function () { + describe('Check method return', function () { + it('should return the right formatted video requests', function() { + expect(adapter.buildRequests([VALID_BID_VIDEO])).to.deep.equal(VALID_REQUEST_VIDEO); + }); + + it('should return the right formatted request with the referer info', function() { + let bidderRequest = { + refererInfo: { + page: 'https://www.example.com/test' + } + }; + + let requests = mergeDeep(deepClone(VALID_REQUEST_VIDEO), { + data: { + domain: 'www.example.com', + page_domain: 'https://www.example.com/test' + } + }); + + expect(adapter.buildRequests([VALID_BID_VIDEO], bidderRequest)).to.deep.equal(requests); + }); + + it('should return the right formatted request with the referer info from config', function() { + /** Mock the config.getConfig method */ + sinon.stub(config, 'getConfig') + .withArgs('pageUrl') + .returns('https://www.example.com/page'); + + let requests = mergeDeep(deepClone(VALID_REQUEST_VIDEO), { + data: { + domain: 'www.example.com', + page_domain: 'https://www.example.com/page' + } + }); + + expect(adapter.buildRequests([VALID_BID_VIDEO])).to.deep.equal(requests); + + config.getConfig.restore(); + }); + + it('should return the right formatted request with GDPR Consent info', function() { + let bidderRequest = { + gdprConsent: VALID_GDPR + }; + + let requests = mergeDeep(deepClone(VALID_REQUEST_VIDEO), { + data: { + gdpr: true, + gdpr_consent: 'abcdefgh', + addtl_consent: '1~12345678' + } + }); + + expect(adapter.buildRequests([VALID_BID_VIDEO], bidderRequest)).to.deep.equal(requests); + }); + + it('should return the right formatted request with US Privacy info', function() { + let bidderRequest = { + uspConsent: US_PRIVACY + }; + + let requests = mergeDeep(deepClone(VALID_REQUEST_VIDEO), { + data: { + us_privacy: US_PRIVACY + } + }); + + expect(adapter.buildRequests([VALID_BID_VIDEO], bidderRequest)).to.deep.equal(requests); + }); + + // TODO: Supply chain + it('should return the right formatted request with Supply Chain info', function() { + let schain = { + 'ver': '1.0', + 'complete': 1, + 'nodes': [ + { + 'asi': 'test1.com', + 'sid': '00001', + 'hp': 1 + }, + { + 'asi': 'test2-2.com', + 'sid': '00002', + 'hp': 2 + } + ] + }; + + let bid = mergeDeep(deepClone(VALID_BID_VIDEO), { + schain: schain + }); + + let requests = mergeDeep(deepClone(VALID_REQUEST_VIDEO), { + data: { + schain: schain + } + }); + + expect(adapter.buildRequests([bid])).to.deep.equal(requests); + }); + + it('should return the right formatted request with User Ids info', function() { + let userIds = { + idl_env: '1234-5678-9012-3456', // Liveramp + netId: 'testnetid123', // NetId + IDP: 'userIDP000', // IDP + fabrickId: 'fabrickId9000', // FabrickId + uid2: { id: 'testuid2' } // UID 2.0 + }; + + let bid = mergeDeep(deepClone(VALID_BID_VIDEO), { + userIds: userIds + }, { + userIdAsEids: createEidsArray(userIds) + }); + + let requests = mergeDeep(deepClone(VALID_REQUEST_VIDEO), { + data: { + users_uid: createEidsArray(userIds) + } + }); + + expect(adapter.buildRequests([bid])).to.deep.equal(requests); + }); + + it('should return the right formatted request with endpint test', function() { + let endpoint = 'https://bid-test.viously.com/prebid'; + + let bid = mergeDeep(deepClone(VALID_BID_VIDEO), { + params: { + endpoint: endpoint + } + }); + + let requests = mergeDeep(deepClone(VALID_REQUEST_VIDEO)); + + requests.url = endpoint; + + expect(adapter.buildRequests([bid])).to.deep.equal(requests); + }); + + // TODO: Floor + }); + }); + + describe('interpretResponse', function() { + describe('Check method return', function () { + it('should return the right formatted response', function() { + let response = { + body: { + ads: [ + { + bid: false, + id: 'id-0157324f-bee4-5390-a14c-47a7da3eb73c-0', + bid_id: '1234' + }, + { + bid: true, + creative_id: '2468', + id: 'id-0157324f-bee4-5390-a14c-47a7da3eb73c-1', + bid_id: '5678', + cpm: 8, + ad: 'vast xml', + ad_url: 'http://www.example.com/vast', + type: 'video', + size: '640x480', + nurl: [ + 'win.domain.com' + ] + }, + { + bid: true, + creative_id: '1469', + id: 'id-0157324f-bee4-5390-a14c-47a7da3eb73c-3', + bid_id: '2570', + cpm: 4, + ad: 'vast xml', + type: 'video', + size: '640x480', + } + ] + } + }; + let requests = { + data: { + placements: [ + { + id: 'id-0157324f-bee4-5390-a14c-47a7da3eb73c-0', + bid_id: '1234' + }, + { + id: 'id-0157324f-bee4-5390-a14c-47a7da3eb73c-1', + bid_id: '5678' + }, + { + id: 'id-0157324f-bee4-5390-a14c-47a7da3eb73c-3', + bid_id: '2570' + } + ] + } + }; + + let formattedReponse = [ + { + requestId: '5678', + id: 'id-0157324f-bee4-5390-a14c-47a7da3eb73c-1', + cpm: 8, + width: '640', + height: '480', + creativeId: '2468', + currency: CURRENCY, + netRevenue: true, + ttl: TTL, + mediaType: 'video', + meta: {}, + vastUrl: 'http://www.example.com/vast', + nurl: [ + 'win.domain.com' + ] + }, + { + requestId: '2570', + id: 'id-0157324f-bee4-5390-a14c-47a7da3eb73c-3', + cpm: 4, + width: '640', + height: '480', + creativeId: '1469', + currency: CURRENCY, + netRevenue: true, + ttl: TTL, + mediaType: 'video', + meta: {}, + vastXml: 'vast xml', + nurl: [] + } + ]; + + expect(adapter.interpretResponse(response, requests)).to.deep.equal(formattedReponse); + }); + }); + }); + + describe('onBidWon', function() { + describe('Check methods succeed', function () { + it('should not throw error', function() { + let bids = [ + { + requestId: '5678', + id: 'id-0157324f-bee4-5390-a14c-47a7da3eb73c-1', + cpm: 8, + width: '640', + height: '480', + creativeId: '2468', + currency: CURRENCY, + netRevenue: true, + ttl: TTL, + mediaType: 'video', + meta: {}, + vastUrl: 'http://www.example.com/vast', + nurl: [ + 'win.domain.com' + ] + }, + { + requestId: '2570', + id: 'id-0157324f-bee4-5390-a14c-47a7da3eb73c-3', + cpm: 4, + width: '640', + height: '480', + creativeId: '1469', + currency: CURRENCY, + netRevenue: true, + ttl: TTL, + mediaType: 'video', + meta: {}, + vastXml: 'vast xml', + nurl: [] + } + ]; + + bids.forEach(function(bid) { + expect(adapter.onBidWon.bind(adapter, bid)).to.not.throw(); + }); + }); + }); + }); +}); diff --git a/test/spec/modules/aaxBlockmeter_spec.js b/test/spec/modules/aaxBlockmeter_spec.js new file mode 100644 index 00000000000..f9704361976 --- /dev/null +++ b/test/spec/modules/aaxBlockmeter_spec.js @@ -0,0 +1,58 @@ +import {aaxBlockmeterRtdModule} from '../../../modules/aaxBlockmeterRtdProvider.js'; +import * as sinon from 'sinon'; +import {assert} from 'chai'; + +let sandbox; +let getTargetingDataSpy; + +const config = { + dataProviders: [{ + 'name': 'aaxBlockmeter', + 'params': { + 'pub': 'publisher_id', + } + }] +}; + +describe('aaxBlockmeter realtime module', function () { + beforeEach(function () { + sandbox = sinon.sandbox.create(); + window.aax = window.aax || {}; + window.aax.getTargetingData = getTargetingDataSpy = sandbox.spy(); + }); + + afterEach(function () { + sandbox.restore(); + window.aax = {}; + }); + + it('init should return false when config is empty', function () { + assert.equal(aaxBlockmeterRtdModule.init({}), false); + }); + + it('init should return false when config.params id is empty', function () { + assert.equal(aaxBlockmeterRtdModule.init({params: {}}), false); + }); + + it('init should return true when config.params.pub is not string', function () { + assert.equal(aaxBlockmeterRtdModule.init({params: {pub: 12345}}), false); + }); + + it('init should return true when config.params.pub id is passed and is string typed', function () { + assert.equal(aaxBlockmeterRtdModule.init(config.dataProviders[0]), true); + }); + + describe('getTargetingData should work correctly', function () { + it('should return ad unit codes when ad units are present', function () { + const codes = ['code1', 'code2']; + assert.deepEqual(aaxBlockmeterRtdModule.getTargetingData(codes), { + code1: {'atk': 'code1'}, + code2: {'atk': 'code2'}, + }); + }); + + it('should call aax.getTargetingData if loaded', function () { + aaxBlockmeterRtdModule.getTargetingData([], config.dataProviders[0], null); + }); + }); +}); diff --git a/test/spec/modules/adWMGAnalyticsAdapter_spec.js b/test/spec/modules/adWMGAnalyticsAdapter_spec.js index ab8336c7126..1e0da1bb3c8 100644 --- a/test/spec/modules/adWMGAnalyticsAdapter_spec.js +++ b/test/spec/modules/adWMGAnalyticsAdapter_spec.js @@ -1,6 +1,7 @@ import adWMGAnalyticsAdapter from 'modules/adWMGAnalyticsAdapter.js'; import { expect } from 'chai'; import { server } from 'test/mocks/xhr.js'; +import {expectEvents} from '../../helpers/analytics.js'; let adapterManager = require('src/adapterManager').default; let events = require('src/events'); let constants = require('src/constants.json'); @@ -140,14 +141,15 @@ describe('adWMG Analytics', function () { } }); - events.emit(constants.EVENTS.AUCTION_INIT, {timestamp, auctionId, timeout, adUnits}); - events.emit(constants.EVENTS.BID_REQUESTED, {}); - events.emit(constants.EVENTS.BID_RESPONSE, bidResponse); - events.emit(constants.EVENTS.NO_BID, {}); - events.emit(constants.EVENTS.BID_TIMEOUT, bidTimeoutArgs); - events.emit(constants.EVENTS.AUCTION_END, {}); - events.emit(constants.EVENTS.BID_WON, wonRequest); - sinon.assert.callCount(adWMGAnalyticsAdapter.track, 7); + expectEvents([ + [constants.EVENTS.AUCTION_INIT, {timestamp, auctionId, timeout, adUnits}], + [constants.EVENTS.BID_REQUESTED, {}], + [constants.EVENTS.BID_RESPONSE, bidResponse], + [constants.EVENTS.NO_BID, {}], + [constants.EVENTS.BID_TIMEOUT, bidTimeoutArgs], + [constants.EVENTS.AUCTION_END, {}], + [constants.EVENTS.BID_WON, wonRequest], + ]).to.beTrackedBy(adWMGAnalyticsAdapter.track); }); it('should be two xhr requests', function () { diff --git a/test/spec/modules/adagioAnalyticsAdapter_spec.js b/test/spec/modules/adagioAnalyticsAdapter_spec.js index aee85412104..581f3cb1b87 100644 --- a/test/spec/modules/adagioAnalyticsAdapter_spec.js +++ b/test/spec/modules/adagioAnalyticsAdapter_spec.js @@ -83,34 +83,27 @@ describe('adagio analytics adapter', () => { timeToRespond: 132, }; - // Step 1: Send bid requested event - events.emit(constants.EVENTS.BID_REQUESTED, bidRequest); + const testEvents = { + [constants.EVENTS.BID_REQUESTED]: bidRequest, + [constants.EVENTS.BID_RESPONSE]: bidResponse, + [constants.EVENTS.AUCTION_END]: {} + }; - // Step 2: Send bid response event - events.emit(constants.EVENTS.BID_RESPONSE, bidResponse); + // Step 1-3: Send events + Object.entries(testEvents).forEach(([ev, payload]) => events.emit(ev, payload)); - // Step 3: Send auction end event - events.emit(constants.EVENTS.AUCTION_END, {}); + function eventItem(eventName, args) { + return sinon.match({ + action: 'pb-analytics-event', + ts: sinon.match((val) => val !== undefined), + data: { + eventName, + args + } + }) + } - sandbox.assert.callCount(adagioQueuePushSpy, 3); - - const call0 = adagioQueuePushSpy.getCall(0); - expect(call0.args[0].action).to.equal('pb-analytics-event'); - expect(call0.args[0].ts).to.not.be.undefined; - expect(call0.args[0].data).to.not.be.undefined; - expect(call0.args[0].data).to.deep.equal({eventName: constants.EVENTS.BID_REQUESTED, args: bidRequest}); - - const call1 = adagioQueuePushSpy.getCall(1); - expect(call1.args[0].action).to.equal('pb-analytics-event'); - expect(call1.args[0].ts).to.not.be.undefined; - expect(call1.args[0].data).to.not.be.undefined; - expect(call1.args[0].data).to.deep.equal({eventName: constants.EVENTS.BID_RESPONSE, args: bidResponse}); - - const call2 = adagioQueuePushSpy.getCall(2); - expect(call2.args[0].action).to.equal('pb-analytics-event'); - expect(call2.args[0].ts).to.not.be.undefined; - expect(call2.args[0].data).to.not.be.undefined; - expect(call2.args[0].data).to.deep.equal({eventName: constants.EVENTS.AUCTION_END, args: {}}); + Object.entries(testEvents).forEach(([ev, payload]) => sinon.assert.calledWith(adagioQueuePushSpy, eventItem(ev, payload))); }); }); diff --git a/test/spec/modules/adagioBidAdapter_spec.js b/test/spec/modules/adagioBidAdapter_spec.js index e2fde8ff2e3..899ef392357 100644 --- a/test/spec/modules/adagioBidAdapter_spec.js +++ b/test/spec/modules/adagioBidAdapter_spec.js @@ -17,6 +17,7 @@ import * as utils from '../../../src/utils.js'; import { config } from '../../../src/config.js'; import { NATIVE } from '../../../src/mediaTypes.js'; import { executeRenderer } from '../../../src/Renderer.js'; +import { userSync } from '../../../src/userSync.js'; const BidRequestBuilder = function BidRequestBuilder(options) { const defaults = { @@ -149,10 +150,8 @@ describe('Adagio bid adapter', () => { site: { ext: { data: { - environment: 'desktop', pagetype: 'abc', - category: ['cat1', 'cat2', 'cat3'], - subcategory: [] + category: ['cat1', 'cat2', 'cat3'] } } } @@ -167,17 +166,11 @@ describe('Adagio bid adapter', () => { return utils.deepAccess(config, key); }); - setExtraParam(bid, 'environment'); - expect(bid.params.environment).to.equal('desktop'); - setExtraParam(bid, 'pagetype') expect(bid.params.pagetype).to.equal('article'); setExtraParam(bid, 'category'); expect(bid.params.category).to.equal('cat1'); // Only the first value is kept - - setExtraParam(bid, 'subcategory'); - expect(bid.params.subcategory).to.be.undefined; }); it('should use the adUnit param unit if defined', function() { @@ -274,7 +267,8 @@ describe('Adagio bid adapter', () => { 'schain', 'prebidVersion', 'featuresVersion', - 'data' + 'data', + 'usIfr' ]; it('groups requests by organizationId', function() { @@ -389,8 +383,8 @@ describe('Adagio bid adapter', () => { context: 'outstream', playerSize: [[300, 250]], mimes: ['video/mp4'], - api: 5, // will be removed because invalid - playbackmethod: [7], // will be removed because invalid + api: 'val', // will be removed because invalid + playbackmethod: ['val'], // will be removed because invalid } }, }).withParams({ @@ -400,7 +394,7 @@ describe('Adagio bid adapter', () => { skipafter: 4, minduration: 10, maxduration: 30, - placement: [3], + placement: 3, protocols: [8] } }).build(); @@ -415,7 +409,7 @@ describe('Adagio bid adapter', () => { skipafter: 4, minduration: 10, maxduration: 30, - placement: [3], + placement: 3, protocols: [8], w: 300, h: 250 @@ -569,15 +563,13 @@ describe('Adagio bid adapter', () => { it('should send the Coppa "required" flag set to "1" in the request', function () { const bidderRequest = new BidderRequestBuilder().build(); - sinon.stub(config, 'getConfig') - .withArgs('coppa') - .returns(true); + sandbox.stub(config, 'getConfig') + .withArgs('userSync').returns({ syncEnabled: true }) + .withArgs('coppa').returns(true); const requests = spec.buildRequests([bid01], bidderRequest); expect(requests[0].data.regs.coppa.required).to.equal(1); - - config.getConfig.restore(); }); }); @@ -744,6 +736,46 @@ describe('Adagio bid adapter', () => { expect(requests[0].data.adUnits[0].mediaTypes.video.floor).to.be.undefined; }); }); + + describe('with user-sync iframe enabled', function () { + const bid01 = new BidRequestBuilder().withParams().build(); + + it('should send the UsIfr flag set to "true" in the request', function () { + const bidderRequest = new BidderRequestBuilder().build(); + + sandbox.stub(config, 'getConfig') + .withArgs('userSync') + .returns({ syncEnabled: true }); + + sandbox.stub(userSync, 'canBidderRegisterSync') + .withArgs('iframe', 'adagio') + .returns(true); + + const requests = spec.buildRequests([bid01], bidderRequest); + + expect(requests[0].data.usIfr).to.equal(true); + }); + }); + + describe('with user-sync iframe disabled', function () { + const bid01 = new BidRequestBuilder().withParams().build(); + + it('should send the UsIfr flag set to "false" in the request', function () { + const bidderRequest = new BidderRequestBuilder().build(); + + sandbox.stub(config, 'getConfig') + .withArgs('userSync') + .returns({ syncEnabled: true }); + + sandbox.stub(userSync, 'canBidderRegisterSync') + .withArgs('iframe', 'adagio') + .returns(false); + + const requests = spec.buildRequests([bid01], bidderRequest); + + expect(requests[0].data.usIfr).to.equal(false); + }); + }); }); describe('interpretResponse()', function() { @@ -784,8 +816,6 @@ describe('Adagio bid adapter', () => { adUnitElementId: 'gpt-adunit-code', pagetype: 'ARTICLE', category: 'NEWS', - subcategory: 'SPORT', - environment: 'desktop', supportIObs: true }, adUnitCode: 'adunit-code', @@ -833,8 +863,6 @@ describe('Adagio bid adapter', () => { site: 'SITE-NAME', pagetype: 'ARTICLE', category: 'NEWS', - subcategory: 'SPORT', - environment: 'desktop', aDomain: ['advertiser.com'], mediaType: 'banner', meta: { @@ -868,8 +896,6 @@ describe('Adagio bid adapter', () => { site: 'SITE-NAME', pagetype: 'ARTICLE', category: 'NEWS', - subcategory: 'SPORT', - environment: 'desktop', aDomain: ['advertiser.com'], mediaType: 'banner', meta: { @@ -1392,19 +1418,6 @@ describe('Adagio bid adapter', () => { }); describe.skip('optional params auto detection', function() { - it('should auto detect environment', function() { - const getDeviceStub = sandbox.stub(_features, 'getDevice'); - - getDeviceStub.returns(5); - expect(adagio.autoDetectEnvironment()).to.eq('tablet'); - - getDeviceStub.returns(4); - expect(adagio.autoDetectEnvironment()).to.eq('mobile'); - - getDeviceStub.returns(2); - expect(adagio.autoDetectEnvironment()).to.eq('desktop'); - }); - it('should auto detect adUnitElementId when GPT is used', function() { sandbox.stub(utils, 'getGptSlotInfoForAdUnitCode').withArgs('banner').returns({divId: 'gpt-banner'}); expect(adagio.autoDetectAdUnitElementId('banner')).to.eq('gpt-banner'); diff --git a/test/spec/modules/adhashBidAdapter_spec.js b/test/spec/modules/adhashBidAdapter_spec.js index 40bf354c4d9..4ea525c59d5 100644 --- a/test/spec/modules/adhashBidAdapter_spec.js +++ b/test/spec/modules/adhashBidAdapter_spec.js @@ -60,6 +60,12 @@ describe('adhashBidAdapter', function () { bid.params.platformURL = 'https://'; expect(spec.isBidRequestValid(bid)).to.equal(false); }); + + it('should return false when bidderURL is present but not https://', function () { + const bid = { ...validBid }; + bid.params.bidderURL = 'http://example.com/'; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); }); describe('buildRequests', function () { @@ -73,11 +79,11 @@ describe('adhashBidAdapter', function () { it('should build the request correctly', function () { const result = spec.buildRequests( [ bidRequest ], - { gdprConsent: { gdprApplies: true, consentString: 'example' }, refererInfo: { referer: 'http://example.com/' } } + { gdprConsent: { gdprApplies: true, consentString: 'example' }, refererInfo: { topmostLocation: 'https://example.com/path.html' } } ); expect(result.length).to.equal(1); expect(result[0].method).to.equal('POST'); - expect(result[0].url).to.equal('https://bidder.adhash.com/rtb?version=1.0&prebid=true&publisher=0xc3b09b27e9c6ef73957901aa729b9e69e5bbfbfb'); + expect(result[0].url).to.equal('https://bidder.adhash.com/rtb?version=3.2&prebid=true&publisher=0xc3b09b27e9c6ef73957901aa729b9e69e5bbfbfb'); expect(result[0].bidRequest).to.equal(bidRequest); expect(result[0].data).to.have.property('timezone'); expect(result[0].data).to.have.property('location'); @@ -93,7 +99,7 @@ describe('adhashBidAdapter', function () { const result = spec.buildRequests([ bidRequest ], { gdprConsent: { gdprApplies: true, consentString: 'example' } }); expect(result.length).to.equal(1); expect(result[0].method).to.equal('POST'); - expect(result[0].url).to.equal('https://bidder.adhash.com/rtb?version=1.0&prebid=true&publisher=0xc3b09b27e9c6ef73957901aa729b9e69e5bbfbfb'); + expect(result[0].url).to.equal('https://bidder.adhash.com/rtb?version=3.2&prebid=true&publisher=0xc3b09b27e9c6ef73957901aa729b9e69e5bbfbfb'); expect(result[0].bidRequest).to.equal(bidRequest); expect(result[0].data).to.have.property('timezone'); expect(result[0].data).to.have.property('location'); @@ -127,9 +133,15 @@ describe('adhashBidAdapter', function () { creatives: [{ costEUR: 1.234 }], advertiserDomains: 'adhash.com', badWords: [ - ['onqjbeq1', 'full', 1], - ['onqjbeq2', 'partial', 1], + ['onqjbeq', 'full', 1], + ['onqjbeqo', 'partial', 1], ['tbbqjbeq', 'full', -1], + ['fgnegf', 'starts', 1], + ['raqf', 'ends', 1], + ['kkk[no]lll', 'regexp', 1], + ['дума', 'full', 1], + ['старт', 'starts', 1], + ['край', 'ends', 1], ], maxScore: 2 } @@ -155,42 +167,84 @@ describe('adhashBidAdapter', function () { it('should return empty array when there are bad words (full)', function () { bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() { - return 'example text badWord1 badWord1 example badWord1 text' + ' word'.repeat(493); + return 'example text badword badword example badword text' + ' word'.repeat(993); + }); + expect(spec.interpretResponse(serverResponse, request).length).to.equal(0); + }); + + it('should return empty array when there are bad words (full cyrillic)', function () { + bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() { + return 'example text дума дума example дума text' + ' текст'.repeat(993); }); expect(spec.interpretResponse(serverResponse, request).length).to.equal(0); }); it('should return empty array when there are bad words (partial)', function () { bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() { - return 'example text partialBadWord2 badword2 example BadWord2text' + ' word'.repeat(494); + return 'example text partialbadwordb badwordb example badwordbtext' + ' word'.repeat(994); + }); + expect(spec.interpretResponse(serverResponse, request).length).to.equal(0); + }); + + it('should return empty array when there are bad words (starts)', function () { + bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() { + return 'example text startsWith starts text startsAgain' + ' word'.repeat(994); + }); + expect(spec.interpretResponse(serverResponse, request).length).to.equal(0); + }); + + it('should return empty array when there are bad words (starts cyrillic)', function () { + bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() { + return 'example text стартТекст старт text стартТекст' + ' дума'.repeat(994); + }); + expect(spec.interpretResponse(serverResponse, request).length).to.equal(0); + }); + + it('should return empty array when there are bad words (ends)', function () { + bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() { + return 'example text wordEnds ends text anotherends' + ' word'.repeat(994); + }); + expect(spec.interpretResponse(serverResponse, request).length).to.equal(0); + }); + + it('should return empty array when there are bad words (ends cyrillic)', function () { + bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() { + return 'example text ДругКрай край text ощеединкрай' + ' дума'.repeat(994); + }); + expect(spec.interpretResponse(serverResponse, request).length).to.equal(0); + }); + + it('should return empty array when there are bad words (regexp)', function () { + bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() { + return 'example text xxxayyy zzxxxAyyyzz text xxxbyyy' + ' word'.repeat(994); }); expect(spec.interpretResponse(serverResponse, request).length).to.equal(0); }); it('should return non-empty array when there are not enough bad words (full)', function () { bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() { - return 'example text badWord1 badWord1 example text' + ' word'.repeat(494); + return 'example text badword badword example text' + ' word'.repeat(994); }); expect(spec.interpretResponse(serverResponse, request).length).to.equal(1); }); it('should return non-empty array when there are not enough bad words (partial)', function () { bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() { - return 'example text partialBadWord2 example' + ' word'.repeat(496); + return 'example text partialbadwordb example' + ' word'.repeat(996); }); expect(spec.interpretResponse(serverResponse, request).length).to.equal(1); }); it('should return non-empty array when there are no-bad word matches', function () { bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() { - return 'example text partialBadWord1 example text' + ' word'.repeat(495); + return 'example text partialbadword example text' + ' word'.repeat(995); }); expect(spec.interpretResponse(serverResponse, request).length).to.equal(1); }); it('should return non-empty array when there are bad words and good words', function () { bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() { - return 'example text badWord1 badWord1 example badWord1 goodWord goodWord ' + ' word'.repeat(492); + return 'example text badword badword example badword goodWord goodWord ' + ' word'.repeat(992); }); expect(spec.interpretResponse(serverResponse, request).length).to.equal(1); }); diff --git a/test/spec/modules/adlooxRtdProvider_spec.js b/test/spec/modules/adlooxRtdProvider_spec.js index 236e053e58c..5b99789981f 100644 --- a/test/spec/modules/adlooxRtdProvider_spec.js +++ b/test/spec/modules/adlooxRtdProvider_spec.js @@ -1,5 +1,6 @@ import adapterManager from 'src/adapterManager.js'; import analyticsAdapter from 'modules/adlooxAnalyticsAdapter.js'; +import {auctionManager} from 'src/auctionManager.js'; import { config as _config } from 'src/config.js'; import { expect } from 'chai'; import * as events from 'src/events.js'; @@ -75,14 +76,6 @@ describe('Adloox RTD Provider', function () { done(); }); - it('should reject non-string config.params.api_origin', function (done) { - const ret = rtdProvider.init({ params: { api_origin: null } }); - - expect(ret).is.false; - - done(); - }); - it('should reject less than one config.params.imps', function (done) { const ret = rtdProvider.init({ params: { imps: 0 } }); @@ -147,31 +140,37 @@ describe('Adloox RTD Provider', function () { }); let server = null; - let __config = null, CONFIG = null; - let getConfigStub, setConfigStub; + let CONFIG = null; beforeEach(function () { server = sinon.createFakeServer(); - __config = {}; CONFIG = utils.deepClone(config); - getConfigStub = sinon.stub(_config, 'getConfig').callsFake(function (path) { - return utils.deepAccess(__config, path); - }); - setConfigStub = sinon.stub(_config, 'setConfig').callsFake(function (obj) { - utils.mergeDeep(__config, obj); - }); }); afterEach(function () { - setConfigStub.restore(); - getConfigStub.restore(); - getConfigStub = setConfigStub = undefined; CONFIG = null; - __config = null; server.restore(); server = null; }); it('should fetch segments', function (done) { - const req = {}; + const req = { + adUnitCodes: [ adUnit.code ], + ortb2Fragments: { + global: { + site: { + ext: { + data: { + } + } + }, + user: { + ext: { + data: { + } + } + } + } + } + }; const adUnitWithSegments = utils.deepClone(adUnit); const getGlobalStub = sinon.stub(prebidGlobal, 'getGlobal').returns({ adUnits: [ adUnitWithSegments ] @@ -201,119 +200,28 @@ describe('Adloox RTD Provider', function () { }); it('should set ad server targeting', function (done) { - utils.deepSetValue(__config, 'ortb2.site.ext.data.adloox_rtd.ok', true); - const adUnitWithSegments = utils.deepClone(adUnit); utils.deepSetValue(adUnitWithSegments, 'ortb2Imp.ext.data.adloox_rtd.dis', [ 50, 60 ]); const getGlobalStub = sinon.stub(prebidGlobal, 'getGlobal').returns({ adUnits: [ adUnitWithSegments ] }); - const targetingData = rtdProvider.getTargetingData([ adUnitWithSegments.code ], CONFIG, null, { - getFPD: () => ({ - global: __config.ortb2 - }) + const auction = { adUnits: [ adUnitWithSegments ] }; + const getAuctionStub = sinon.stub(auctionManager.index, 'getAuction').returns({ + adUnits: [ adUnitWithSegments ], + getFPD: () => { return { global: { site: { ext: { data: { adloox_rtd: { ok: true } } } } } } } }); + + const targetingData = rtdProvider.getTargetingData([ adUnitWithSegments.code ], CONFIG, null, auction); expect(Object.keys(targetingData).length).is.equal(1); expect(Object.keys(targetingData[adUnit.code]).length).is.equal(2); expect(targetingData[adUnit.code].adl_ok).is.equal(1); expect(targetingData[adUnit.code].adl_dis.length).is.equal(2); + getAuctionStub.restore(); getGlobalStub.restore(); done(); }); }); - - describe('measure atf', function () { - const adUnitCopy = utils.deepClone(adUnit); - - const ratio = 0.38; - const [ [width, height] ] = utils.getAdUnitSizes(adUnitCopy); - - before(function () { - adapterManager.enableAnalytics({ - provider: analyticsAdapterName, - options: analyticsOptions - }); - expect(analyticsAdapter.context).is.not.null; - }); - - after(function () { - analyticsAdapter.disableAnalytics(); - expect(analyticsAdapter.context).is.null; - }); - - it(`should return ${ratio} for same-origin`, function (done) { - const el = document.createElement('div'); - el.setAttribute('id', adUnitCopy.code); - - const offset = height * ratio; - const elStub = sinon.stub(el, 'getBoundingClientRect').returns({ - top: 0 - (height - offset), - bottom: height - offset, - left: 0, - right: width - }); - - const querySelectorStub = sinon.stub(document, 'querySelector'); - querySelectorStub.withArgs(`#${adUnitCopy.code}`).returns(el); - - rtdProvider.atf(adUnitCopy, function(x) { - expect(x).is.equal(ratio); - - querySelectorStub.restore(); - elStub.restore(); - - done(); - }); - }); - - ('IntersectionObserver' in window ? it : it.skip)(`should return ${ratio} for cross-origin`, function (done) { - const frameElementStub = sinon.stub(window, 'frameElement').value(null); - - const el = document.createElement('div'); - el.setAttribute('id', adUnitCopy.code); - - const elStub = sinon.stub(el, 'getBoundingClientRect').returns({ - top: 0, - bottom: height, - left: 0, - right: width - }); - - const querySelectorStub = sinon.stub(document, 'querySelector'); - querySelectorStub.withArgs(`#${adUnitCopy.code}`).returns(el); - - let intersectionObserverStubFn = null; - const intersectionObserverStub = sinon.stub(window, 'IntersectionObserver').callsFake((fn) => { - intersectionObserverStubFn = fn; - return { - observe: (element) => { - expect(element).is.equal(el); - - intersectionObserverStubFn([{ - target: element, - intersectionRect: { width, height }, - intersectionRatio: ratio - }]); - }, - unobserve: (element) => { - expect(element).is.equal(el); - } - } - }); - - rtdProvider.atf(adUnitCopy, function(x) { - expect(x).is.equal(ratio); - - intersectionObserverStub.restore(); - querySelectorStub.restore(); - elStub.restore(); - frameElementStub.restore(); - - done(); - }); - }); - }); }); diff --git a/test/spec/modules/admaruBidAdapter_spec.js b/test/spec/modules/admaruBidAdapter_spec.js index a45ddae108f..813a4ed8b29 100644 --- a/test/spec/modules/admaruBidAdapter_spec.js +++ b/test/spec/modules/admaruBidAdapter_spec.js @@ -121,4 +121,52 @@ describe('Admaru Adapter', function () { expect(result.length).to.equal(0); }); }); + + describe('getUserSyncs()', () => { + it('should return iframe user sync if iframe sync is enabled', () => { + const syncs = spec.getUserSyncs( + { + pixelEnabled: true, + iframeEnabled: true, + }, + null + ); + + expect(syncs).to.deep.equal([ + { + type: 'iframe', + url: 'https://p2.admaru.net/UserSync/sync', + }, + ]); + }); + + it('should return image syncs if they are enabled and iframe is disabled', () => { + const syncs = spec.getUserSyncs( + { + pixelEnabled: true, + iframeEnabled: false, + }, + null + ); + + expect(syncs).to.deep.equal([ + { + type: 'image', + url: 'https://p2.admaru.net/UserSync/sync', + }, + ]); + }); + + it('should not return user syncs if syncs are disabled', () => { + const syncs = spec.getUserSyncs( + { + pixelEnabled: false, + iframeEnabled: false, + }, + null + ); + + expect(syncs).to.deep.equal([]); + }); + }); }); diff --git a/test/spec/modules/admaticBidAdapter_spec.js b/test/spec/modules/admaticBidAdapter_spec.js new file mode 100644 index 00000000000..65a7b4111b7 --- /dev/null +++ b/test/spec/modules/admaticBidAdapter_spec.js @@ -0,0 +1,305 @@ +import {expect} from 'chai'; +import {spec, storage} from 'modules/admaticBidAdapter.js'; +import {newBidder} from 'src/adapters/bidderFactory.js'; +import {getStorageManager} from 'src/storageManager'; + +const ENDPOINT = 'https://layer.serve.admatic.com.tr/pb?bidder=admatic'; + +describe('admaticBidAdapter', () => { + const adapter = newBidder(spec); + + describe('inherited functions', () => { + it('exists and is a function', () => { + expect(adapter.callBids).to.exist.and.to.be.a('function'); + }); + }); + + describe('isBidRequestValid', function() { + let bid = { + 'bidder': 'admatic', + 'params': { + 'networkId': 10433394, + 'host': 'layer.serve.admatic.com.tr' + }, + 'adUnitCode': 'adunit-code', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + 'creativeId': 'er2ee' + }; + + it('should return true when required params found', function() { + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('should return false when required params are not passed', function() { + let bid = Object.assign({}, bid); + delete bid.params; + + bid.params = { + 'networkId': 0, + 'host': 'layer.serve.admatic.com.tr' + }; + + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + }); + + describe('buildRequests', function () { + it('sends bid request to ENDPOINT via POST', function () { + let validRequest = [ { + 'bidder': 'admatic', + 'params': { + 'networkId': 10433394, + 'host': 'layer.serve.admatic.com.tr' + }, + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250], [728, 90]] + } + }, + getFloor: inputParams => { + if (inputParams.mediaType === BANNER && inputParams.size[0] === 300 && inputParams.size[1] === 250) { + return { + currency: 'USD', + floor: 1.0 + }; + } else if (inputParams.mediaType === BANNER && inputParams.size[0] === 728 && inputParams.size[1] === 90) { + return { + currency: 'USD', + floor: 2.0 + }; + } else { + return {} + } + }, + 'user': { + 'ua': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36' + }, + 'blacklist': [], + 'site': { + 'page': 'http://localhost:8888/admatic.html', + 'ref': 'http://localhost:8888', + 'publisher': { + 'name': 'localhost', + 'publisherId': 12321312 + } + }, + 'imp': [ + { + 'size': [ + { + 'w': 300, + 'h': 250 + }, + { + 'w': 728, + 'h': 90 + } + ], + 'id': '2205da7a81846b', + 'floors': { + 'banner': { + '300x250': { 'currency': 'USD', 'floor': 1 }, + '728x90': { 'currency': 'USD', 'floor': 2 } + } + } + } + ], + 'ext': { + 'cur': 'USD', + 'bidder': 'admatic' + } + } ]; + let bidderRequest = { + 'bidder': 'admatic', + 'params': { + 'networkId': 10433394, + 'host': 'layer.serve.admatic.com.tr' + }, + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250], [728, 90]] + } + }, + getFloor: inputParams => { + if (inputParams.mediaType === BANNER && inputParams.size[0] === 300 && inputParams.size[1] === 250) { + return { + currency: 'USD', + floor: 1.0 + }; + } else if (inputParams.mediaType === BANNER && inputParams.size[0] === 728 && inputParams.size[1] === 90) { + return { + currency: 'USD', + floor: 2.0 + }; + } else { + return {} + } + }, + 'user': { + 'ua': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36' + }, + 'blacklist': [], + 'site': { + 'page': 'http://localhost:8888/admatic.html', + 'ref': 'http://localhost:8888', + 'publisher': { + 'name': 'localhost', + 'publisherId': 12321312 + } + }, + 'imp': [ + { + 'size': [ + { + 'w': 300, + 'h': 250 + }, + { + 'w': 728, + 'h': 90 + } + ], + 'id': '2205da7a81846b', + 'floors': { + 'banner': { + '300x250': { 'currency': 'USD', 'floor': 1 }, + '728x90': { 'currency': 'USD', 'floor': 2 } + } + } + } + ], + 'ext': { + 'cur': 'USD', + 'bidder': 'admatic' + } + }; + const request = spec.buildRequests(validRequest, bidderRequest); + expect(request.url).to.equal(ENDPOINT); + expect(request.method).to.equal('POST'); + }); + + it('should properly build a banner request with floors', function () { + let bidRequests = [ + { + 'bidder': 'admatic', + 'params': { + 'networkId': 10433394, + 'host': 'layer.serve.admatic.com.tr' + }, + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250], [728, 90]] + } + }, + getFloor: inputParams => { + if (inputParams.mediaType === BANNER && inputParams.size[0] === 300 && inputParams.size[1] === 250) { + return { + currency: 'USD', + floor: 1.0 + }; + } else if (inputParams.mediaType === BANNER && inputParams.size[0] === 728 && inputParams.size[1] === 90) { + return { + currency: 'USD', + floor: 2.0 + }; + } else { + return {} + } + } + }, + ]; + let bidderRequest = { + 'bidder': 'admatic', + 'params': { + 'networkId': 10433394, + 'host': 'layer.serve.admatic.com.tr' + }, + 'adUnitCode': 'adunit-code', + 'sizes': [[300, 250], [728, 90]], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + 'creativeId': 'er2ee', + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250], [728, 90]] + } + } + }; + const request = spec.buildRequests(bidRequests, bidderRequest); + request.data.imp[0].floors = { + 'banner': { + '300x250': { 'currency': 'USD', 'floor': 1 }, + '728x90': { 'currency': 'USD', 'floor': 2 } + } + }; + }); + }); + + describe('interpretResponse', function () { + it('should get correct bid responses', function() { + let bids = { body: { + data: [ + { + 'id': 1, + 'creative_id': '374', + 'width': 300, + 'height': 250, + 'price': 0.01, + 'bidder': 'admatic', + 'adomain': ['admatic.com.tr'], + 'party_tag': '
' + } + ], + 'queryId': 'cdnbh24rlv0hhkpfpln0', + 'status': true + }}; + + let expectedResponse = [ + { + requestId: 1, + cpm: 0.01, + width: 300, + height: 250, + currency: 'TRY', + netRevenue: true, + ad: '
', + creativeId: '374', + meta: { + advertiserDomains: ['admatic.com.tr'] + }, + ttl: 360, + bidder: 'admatic' + } + ]; + const request = { + ext: { + 'cur': 'TRY', + 'type': 'admatic' + } + }; + let result = spec.interpretResponse(bids, {data: request}); + expect(result).to.eql(expectedResponse); + }); + + it('handles nobid responses', function () { + let request = { + ext: { + 'cur': 'TRY', + 'type': 'admatic' + } + }; + let bids = { body: { + data: [], + 'queryId': 'cdnbh24rlv0hhkpfpln0', + 'status': true + }}; + + let result = spec.interpretResponse(bids, {data: request}); + expect(result.length).to.equal(0); + }); + }); +}); diff --git a/test/spec/modules/admediaBidAdapter_spec.js b/test/spec/modules/admediaBidAdapter_spec.js new file mode 100644 index 00000000000..a04e288311a --- /dev/null +++ b/test/spec/modules/admediaBidAdapter_spec.js @@ -0,0 +1,130 @@ +import {assert, expect} from 'chai'; +import {spec} from 'modules/admediaBidAdapter.js'; +import {newBidder} from 'src/adapters/bidderFactory.js'; +import * as utils from 'src/utils.js'; + +const ENDPOINT_URL = 'https://prebid.admedia.com/bidder/'; + +describe('admediaBidAdapter', function () { + const adapter = newBidder(spec); + describe('isBidRequestValid', function () { + let bid = { + adUnitCode: 'adunit-code', + bidder: 'admedia', + bidId: 'g7ghhs78', + mediaTypes: {banner: {sizes: [[300, 250]]}}, + params: { + placementId: '782332', + aid: '86858', + }, + refererInfo: { + page: 'https://test.com' + } + }; + it('should return true where required params found', function () { + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + }); + describe('buildRequests', function () { + let bidRequests = [ + { + adUnitCode: 'adunit-code', + bidder: 'admedia', + bidId: 'g7ghhs78', + mediaTypes: {banner: {sizes: [[300, 250]]}}, + params: { + placementId: '782332', + aid: '86858' + }, + refererInfo: { + page: 'https://test.com' + } + } + ]; + + let bidderRequests = { + refererInfo: { + page: 'https://test.com', + } + }; + + const request = spec.buildRequests(bidRequests, bidderRequests); + it('sends bid request via POST', function () { + expect(request[0].method).to.equal('POST'); + }); + }); + + describe('interpretResponse', function () { + let bidRequest = { + method: 'POST', + url: ENDPOINT_URL, + data: { + 'id': '782332', + 'aid': '86858', + 'tags': [ + { + 'sizes': [ + '300x250' + ], + 'id': '782332', + 'aid': '86858' + } + ], + 'bidId': '2556388472b168', + 'referer': 'https%3A%2F%test.com' + } + }; + let serverResponse = { + body: + { + 'tags': [ + { + 'requestId': '2b8bf2ac497ae', + 'ad': "", + 'width': 300, + 'height': 250, + 'cpm': 0.71, + 'currency': 'USD', + 'ttl': 200, + 'creativeId': 128, + 'netRevenue': true, + 'meta': { + 'advertiserDomains': [ + 'https://www.test.com' + ] + } + } + ] + } + + }; + it('should get the correct bid response', function () { + let expectedResponse = + { + 'tags': [ + { + 'requestId': '2b8bf2ac497ae', + 'ad': "", + 'width': 300, + 'height': 250, + 'cpm': 0.71, + 'currency': 'USD', + 'ttl': 200, + 'creativeId': 128, + 'netRevenue': true, + 'meta': { + 'advertiserDomains': [ + 'https://www.test.com' + ] + } + } + ] + } + let result = spec.interpretResponse(serverResponse, bidRequest); + expect(result).to.be.an('array').that.is.not.empty; + expect(Object.keys(result[0])).to.have.members( + Object.keys(expectedResponse.tags[0]) + ); + }); + }); +}); diff --git a/test/spec/modules/admixerBidAdapter_spec.js b/test/spec/modules/admixerBidAdapter_spec.js index 228b87ae4d5..26caaf5b70f 100644 --- a/test/spec/modules/admixerBidAdapter_spec.js +++ b/test/spec/modules/admixerBidAdapter_spec.js @@ -4,8 +4,10 @@ import {newBidder} from 'src/adapters/bidderFactory.js'; import {config} from '../../../src/config.js'; const BIDDER_CODE = 'admixer'; +const BIDDER_CODE_ADX = 'admixeradx'; const ENDPOINT_URL = 'https://inv-nets.admixer.net/prebid.1.2.aspx'; const ENDPOINT_URL_CUSTOM = 'https://custom.admixer.net/prebid.aspx'; +const ENDPOINT_URL_ADX = 'https://inv-nets.admixer.net/adxprebid.1.2.aspx'; const ZONE_ID = '2eb6bd58-865c-47ce-af7f-a918108c3fd2'; describe('AdmixerAdapter', function () { @@ -16,18 +18,22 @@ describe('AdmixerAdapter', function () { expect(adapter.callBids).to.be.exist.and.to.be.a('function'); }); }); + // inv-nets.admixer.net/adxprebid.1.2.aspx describe('isBidRequestValid', function () { let bid = { - 'bidder': BIDDER_CODE, - 'params': { - 'zone': ZONE_ID + bidder: BIDDER_CODE, + params: { + zone: ZONE_ID, }, - 'adUnitCode': 'adunit-code', - 'sizes': [[300, 250], [300, 600]], - 'bidId': '30b31c1838de1e', - 'bidderRequestId': '22edbae2733bf6', - 'auctionId': '1d1a030790a475', + adUnitCode: 'adunit-code', + sizes: [ + [300, 250], + [300, 600], + ], + bidId: '30b31c1838de1e', + bidderRequestId: '22edbae2733bf6', + auctionId: '1d1a030790a475', }; it('should return true when required params found', function () { @@ -38,7 +44,7 @@ describe('AdmixerAdapter', function () { let bid = Object.assign({}, bid); delete bid.params; bid.params = { - 'placementId': 0 + placementId: 0, }; expect(spec.isBidRequestValid(bid)).to.equal(false); }); @@ -47,22 +53,25 @@ describe('AdmixerAdapter', function () { describe('buildRequests', function () { let validRequest = [ { - 'bidder': BIDDER_CODE, - 'params': { - 'zone': ZONE_ID + bidder: BIDDER_CODE, + params: { + zone: ZONE_ID, }, - 'adUnitCode': 'adunit-code', - 'sizes': [[300, 250], [300, 600]], - 'bidId': '30b31c1838de1e', - 'bidderRequestId': '22edbae2733bf6', - 'auctionId': '1d1a030790a475', - } + adUnitCode: 'adunit-code', + sizes: [ + [300, 250], + [300, 600], + ], + bidId: '30b31c1838de1e', + bidderRequestId: '22edbae2733bf6', + auctionId: '1d1a030790a475', + }, ]; let bidderRequest = { bidderCode: BIDDER_CODE, refererInfo: { - page: 'https://example.com' - } + page: 'https://example.com', + }, }; it('should add referrer and imp to be equal bidRequest', function () { @@ -81,49 +90,122 @@ describe('AdmixerAdapter', function () { it('sends bid request to CUSTOM_ENDPOINT via GET', function () { config.setBidderConfig({ bidders: [BIDDER_CODE], // one or more bidders - config: {[BIDDER_CODE]: {endpoint_url: ENDPOINT_URL_CUSTOM}} + config: { [BIDDER_CODE]: { endpoint_url: ENDPOINT_URL_CUSTOM } }, }); - const request = config.runWithBidder(BIDDER_CODE, () => spec.buildRequests(validRequest, bidderRequest)); + const request = config.runWithBidder(BIDDER_CODE, () => + spec.buildRequests(validRequest, bidderRequest) + ); expect(request.url).to.equal(ENDPOINT_URL_CUSTOM); expect(request.method).to.equal('POST'); }); }); + describe('buildRequestsAdmixerADX', function () { + let validRequest = [ + { + bidder: BIDDER_CODE_ADX, + params: { + zone: ZONE_ID, + }, + adUnitCode: 'adunit-code', + sizes: [ + [300, 250], + [300, 600], + ], + bidId: '30b31c1838de1e', + bidderRequestId: '22edbae2733bf6', + auctionId: '1d1a030790a475', + }, + ]; + let bidderRequest = { + bidderCode: BIDDER_CODE_ADX, + refererInfo: { + page: 'https://example.com', + }, + }; + + it('sends bid request to ADX ENDPOINT', function () { + const request = spec.buildRequests(validRequest, bidderRequest); + expect(request.url).to.equal(ENDPOINT_URL_ADX); + expect(request.method).to.equal('POST'); + }); + }); + + describe('checkFloorGetting', function () { + let validRequest = [ + { + bidder: BIDDER_CODE, + params: { + zone: ZONE_ID, + }, + adUnitCode: 'adunit-code', + sizes: [[300, 250]], + bidId: '30b31c1838de1e', + bidderRequestId: '22edbae2733bf6', + auctionId: '1d1a030790a475', + }, + ]; + let bidderRequest = { + bidderCode: BIDDER_CODE, + refererInfo: { + page: 'https://example.com', + }, + }; + it('gets floor', function () { + bidderRequest.getFloor = () => { + return { floor: 0.6 }; + }; + const request = spec.buildRequests(validRequest, bidderRequest); + const payload = request.data; + expect(payload.bidFloor).to.deep.equal(0.6); + }); + }); + describe('interpretResponse', function () { let response = { body: { - ads: [{ - 'currency': 'USD', - 'cpm': 6.210000, - 'ad': '
ad
', - 'width': 300, - 'height': 600, - 'creativeId': 'ccca3e5e-0c54-4761-9667-771322fbdffc', - 'ttl': 360, - 'netRevenue': false, - 'requestId': '5e4e763b6bc60b', - 'dealId': 'asd123', - 'meta': {'advertiserId': 123, 'networkId': 123, 'advertiserDomains': ['test.com']} - }] - } + ads: [ + { + currency: 'USD', + cpm: 6.21, + ad: '
ad
', + width: 300, + height: 600, + creativeId: 'ccca3e5e-0c54-4761-9667-771322fbdffc', + ttl: 360, + netRevenue: false, + requestId: '5e4e763b6bc60b', + dealId: 'asd123', + meta: { + advertiserId: 123, + networkId: 123, + advertiserDomains: ['test.com'], + }, + }, + ], + }, }; it('should get correct bid response', function () { const ads = response.body.ads; let expectedResponse = [ { - 'requestId': ads[0].requestId, - 'cpm': ads[0].cpm, - 'creativeId': ads[0].creativeId, - 'width': ads[0].width, - 'height': ads[0].height, - 'ad': ads[0].ad, - 'currency': ads[0].currency, - 'netRevenue': ads[0].netRevenue, - 'ttl': ads[0].ttl, - 'dealId': ads[0].dealId, - 'meta': {'advertiserId': 123, 'networkId': 123, 'advertiserDomains': ['test.com']} - } + requestId: ads[0].requestId, + cpm: ads[0].cpm, + creativeId: ads[0].creativeId, + width: ads[0].width, + height: ads[0].height, + ad: ads[0].ad, + currency: ads[0].currency, + netRevenue: ads[0].netRevenue, + ttl: ads[0].ttl, + dealId: ads[0].dealId, + meta: { + advertiserId: 123, + networkId: 123, + advertiserDomains: ['test.com'], + }, + }, ]; let result = spec.interpretResponse(response); @@ -141,18 +223,16 @@ describe('AdmixerAdapter', function () { describe('getUserSyncs', function () { let imgUrl = 'https://example.com/img1'; let frmUrl = 'https://example.com/frm2'; - let responses = [{ - body: { - cm: { - pixels: [ - imgUrl - ], - iframes: [ - frmUrl - ], - } - } - }]; + let responses = [ + { + body: { + cm: { + pixels: [imgUrl], + iframes: [frmUrl], + }, + }, + }, + ]; it('Returns valid values', function () { let userSyncAll = spec.getUserSyncs({pixelEnabled: true, iframeEnabled: true}, responses); diff --git a/test/spec/modules/adnuntiusBidAdapter_spec.js b/test/spec/modules/adnuntiusBidAdapter_spec.js index 2d5ea630f0f..b787a52d6f2 100644 --- a/test/spec/modules/adnuntiusBidAdapter_spec.js +++ b/test/spec/modules/adnuntiusBidAdapter_spec.js @@ -71,6 +71,30 @@ describe('adnuntiusBidAdapter', function () { } ] + // const nativeBidderRequest = [ + // { + // bidId: '123', + // bidder: 'adnuntius', + // params: { + // auId: '8b6bc', + // network: 'adnuntius', + // }, + // mediaTypes: { + // native: { + // title: { + // required: true + // }, + // image: { + // required: true + // }, + // body: { + // required: true + // } + // } + // }, + // } + // ] + const singleBidRequest = { bid: [ { @@ -83,6 +107,10 @@ describe('adnuntiusBidAdapter', function () { bid: videoBidderRequest } + // const nativeBidRequest = { + // bid: nativeBidderRequest + // } + const serverResponse = { body: { 'adUnits': [ @@ -209,6 +237,83 @@ describe('adnuntiusBidAdapter', function () { ] } } + // const serverNativeResponse = { + // body: { + // 'adUnits': [ + // { + // 'auId': '000000000008b6bc', + // 'targetId': '123', + // 'html': '

hi!

', + // 'matchedAdCount': 1, + // 'responseId': 'adn-rsp-1460129238', + // 'ads': [ + // { + // 'destinationUrlEsc': 'https%3A%2F%2Fdelivery.adnuntius.com%2Fc%2F52AHNuxCqxB_Y9ZP9ERWkMBPCOha4zuV3aKn5cog5jsAAAAQCtjQz9kbGWD4nuZy3q6HaHGLB4-k_fySWECIOOmHKY6iokgHNFH-U57ew_-1QHlKnFr2NT8y4QK1oU5HxnDLbYPz-GmQ3C2JyxLGpKmIb-P-3bm7HYPEreNjPdhjRG51A8NGuc4huUhns7nEUejHuOjOHE5sV1zfYxCRWRx9wPDN9EUCC7KN%3Fct%3D2501%26r%3Dhttp%253A%252F%252Fgoogle.com', + // 'assets': { + // 'image': { + // 'cdnId': 'https://assets.adnuntius.com/K9rfXC6wJvgVuy4Fbt5P8oEEGXme9ZaP8BNDzz3OMGQ.jpg', + // 'width': '300', + // 'height': '250' + // } + // }, + // 'text': { + // 'body': { + // 'content': 'Testing Native ad from Adnuntius', + // 'length': '32', + // 'minLength': '0', + // 'maxLength': '100' + // }, + // 'title': { + // 'content': 'Native Ad', + // 'length': '9', + // 'minLength': '5', + // 'maxLength': '100' + // } + // }, + // 'clickUrl': 'https://delivery.adnuntius.com/c/52AHNuxCqxB_Y9ZP9ERWkMBPCOha4zuV3aKn5cog5jsAAAAQCtjQz9kbGWD4nuZy3q6HaHGLB4-k_fySWECIOOmHKY6iokgHNFH-U57ew_-1QHlKnFr2NT8y4QK1oU5HxnDLbYPz-GmQ3C2JyxLGpKmIb-P-3bm7HYPEreNjPdhjRG51A8NGuc4huUhns7nEUejHuOjOHE5sV1zfYxCRWRx9wPDN9EUCC7KN', + // 'urls': { + // 'destination': 'https://delivery.adnuntius.com/c/52AHNuxCqxB_Y9ZP9ERWkMBPCOha4zuV3aKn5cog5jsAAAAQCtjQz9kbGWD4nuZy3q6HaHGLB4-k_fySWECIOOmHKY6iokgHNFH-U57ew_-1QHlKnFr2NT8y4QK1oU5HxnDLbYPz-GmQ3C2JyxLGpKmIb-P-3bm7HYPEreNjPdhjRG51A8NGuc4huUhns7nEUejHuOjOHE5sV1zfYxCRWRx9wPDN9EUCC7KN?ct=2501&r=http%3A%2F%2Fgoogle.com' + // }, + // 'urlsEsc': { + // 'destination': 'https%3A%2F%2Fdelivery.adnuntius.com%2Fc%2F52AHNuxCqxB_Y9ZP9ERWkMBPCOha4zuV3aKn5cog5jsAAAAQCtjQz9kbGWD4nuZy3q6HaHGLB4-k_fySWECIOOmHKY6iokgHNFH-U57ew_-1QHlKnFr2NT8y4QK1oU5HxnDLbYPz-GmQ3C2JyxLGpKmIb-P-3bm7HYPEreNjPdhjRG51A8NGuc4huUhns7nEUejHuOjOHE5sV1zfYxCRWRx9wPDN9EUCC7KN%3Fct%3D2501%26r%3Dhttp%253A%252F%252Fgoogle.com' + // }, + // 'destinationUrls': { + // 'destination': 'http://google.com' + // }, + // 'cpm': { 'amount': 5.0, 'currency': 'NOK' }, + // 'bid': { 'amount': 0.005, 'currency': 'NOK' }, + // 'cost': { 'amount': 0.005, 'currency': 'NOK' }, + // 'impressionTrackingUrls': [], + // 'impressionTrackingUrlsEsc': [], + // 'adId': 'adn-id-1347343135', + // 'selectedColumn': '0', + // 'selectedColumnPosition': '0', + // 'renderedPixel': 'https://delivery.adnuntius.com/b/52AHNuxCqxB_Y9ZP9ERWkMBPCOha4zuV3aKn5cog5jsAAAAQCtjQz9kbGWD4nuZy3q6HaHGLB4-k_fySWECIOOmHKY6iokgHNFH-U57ew_-1QHlKnFr2NT8y4QK1oU5HxnDLbYPz-GmQ3C2JyxLGpKmIb-P-3bm7HYPEreNjPdhjRG51A8NGuc4huUhns7nEUejHuOjOHE5sV1zfYxCRWRx9wPDN9EUCC7KN.html', + // 'renderedPixelEsc': 'https%3A%2F%2Fdelivery.adnuntius.com%2Fb%2F52AHNuxCqxB_Y9ZP9ERWkMBPCOha4zuV3aKn5cog5jsAAAAQCtjQz9kbGWD4nuZy3q6HaHGLB4-k_fySWECIOOmHKY6iokgHNFH-U57ew_-1QHlKnFr2NT8y4QK1oU5HxnDLbYPz-GmQ3C2JyxLGpKmIb-P-3bm7HYPEreNjPdhjRG51A8NGuc4huUhns7nEUejHuOjOHE5sV1zfYxCRWRx9wPDN9EUCC7KN.html', + // 'visibleUrl': 'https://delivery.adnuntius.com/s?rt=52AHNuxCqxB_Y9ZP9ERWkMBPCOha4zuV3aKn5cog5jsAAAAQCtjQz9kbGWD4nuZy3q6HaHGLB4-k_fySWECIOOmHKY6iokgHNFH-U57ew_-1QHlKnFr2NT8y4QK1oU5HxnDLbYPz-GmQ3C2JyxLGpKmIb-P-3bm7HYPEreNjPdhjRG51A8NGuc4huUhns7nEUejHuOjOHE5sV1zfYxCRWRx9wPDN9EUCC7KN', + // 'visibleUrlEsc': 'https%3A%2F%2Fdelivery.adnuntius.com%2Fs%3Frt%3D52AHNuxCqxB_Y9ZP9ERWkMBPCOha4zuV3aKn5cog5jsAAAAQCtjQz9kbGWD4nuZy3q6HaHGLB4-k_fySWECIOOmHKY6iokgHNFH-U57ew_-1QHlKnFr2NT8y4QK1oU5HxnDLbYPz-GmQ3C2JyxLGpKmIb-P-3bm7HYPEreNjPdhjRG51A8NGuc4huUhns7nEUejHuOjOHE5sV1zfYxCRWRx9wPDN9EUCC7KN', + // 'viewUrl': 'https://delivery.adnuntius.com/v?rt=52AHNuxCqxB_Y9ZP9ERWkMBPCOha4zuV3aKn5cog5jsAAAAQCtjQz9kbGWD4nuZy3q6HaHGLB4-k_fySWECIOOmHKY6iokgHNFH-U57ew_-1QHlKnFr2NT8y4QK1oU5HxnDLbYPz-GmQ3C2JyxLGpKmIb-P-3bm7HYPEreNjPdhjRG51A8NGuc4huUhns7nEUejHuOjOHE5sV1zfYxCRWRx9wPDN9EUCC7KN', + // 'viewUrlEsc': 'https%3A%2F%2Fdelivery.adnuntius.com%2Fv%3Frt%3D52AHNuxCqxB_Y9ZP9ERWkMBPCOha4zuV3aKn5cog5jsAAAAQCtjQz9kbGWD4nuZy3q6HaHGLB4-k_fySWECIOOmHKY6iokgHNFH-U57ew_-1QHlKnFr2NT8y4QK1oU5HxnDLbYPz-GmQ3C2JyxLGpKmIb-P-3bm7HYPEreNjPdhjRG51A8NGuc4huUhns7nEUejHuOjOHE5sV1zfYxCRWRx9wPDN9EUCC7KN', + // 'rt': '52AHNuxCqxB_Y9ZP9ERWkMBPCOha4zuV3aKn5cog5jsAAAAQCtjQz9kbGWD4nuZy3q6HaHGLB4-k_fySWECIOOmHKY6iokgHNFH-U57ew_-1QHlKnFr2NT8y4QK1oU5HxnDLbYPz-GmQ3C2JyxLGpKmIb-P-3bm7HYPEreNjPdhjRG51A8NGuc4huUhns7nEUejHuOjOHE5sV1zfYxCRWRx9wPDN9EUCC7KN', + // 'creativeWidth': '980', + // 'creativeHeight': '120', + // 'creativeId': 'wgkq587vgtpchsx1', + // 'lineItemId': 'scyjdyv3mzgdsnpf', + // 'layoutId': 'sw6gtws2rdj1kwby', + // 'layoutName': 'Responsive image' + // }, + + // ] + // }, + // { + // 'auId': '000000000008b6bc', + // 'targetId': '456', + // 'matchedAdCount': 0, + // 'responseId': 'adn-rsp-1460129238', + // } + // ] + // } + // } describe('inherited functions', function () { it('exists and is a function', function () { @@ -426,4 +531,21 @@ describe('adnuntiusBidAdapter', function () { expect(interpretedResponse[0].vastXml).to.equal(serverVideoResponse.body.adUnits[0].vastXml); }); }); + // describe('interpretNativeResponse', function () { + // it('should return valid response when passed valid server response', function () { + // const interpretedResponse = spec.interpretResponse(serverNativeResponse, nativeBidRequest); + // const ad = serverNativeResponse.body.adUnits[0].ads[0] + // expect(interpretedResponse).to.have.lengthOf(1); + // expect(interpretedResponse[0].cpm).to.equal(ad.cpm.amount); + // expect(interpretedResponse[0].width).to.equal(Number(ad.creativeWidth)); + // expect(interpretedResponse[0].height).to.equal(Number(ad.creativeHeight)); + // expect(interpretedResponse[0].creativeId).to.equal(ad.creativeId); + // expect(interpretedResponse[0].currency).to.equal(ad.bid.currency); + // expect(interpretedResponse[0].netRevenue).to.equal(false); + // expect(interpretedResponse[0].meta).to.have.property('advertiserDomains'); + // expect(interpretedResponse[0].meta.advertiserDomains).to.have.lengthOf(1); + // expect(interpretedResponse[0].meta.advertiserDomains[0]).to.equal('google.com'); + // expect(interpretedResponse[0].native.body).to.equal(serverNativeResponse.body.adUnits[0].ads[0].text.body.content); + // }); + // }); }); diff --git a/test/spec/modules/aduptechBidAdapter_spec.js b/test/spec/modules/aduptechBidAdapter_spec.js index bbc4e554f7e..8dbdbbfeab5 100644 --- a/test/spec/modules/aduptechBidAdapter_spec.js +++ b/test/spec/modules/aduptechBidAdapter_spec.js @@ -182,6 +182,54 @@ describe('AduptechBidAdapter', () => { }); }); + describe('getFloor', () => { + let bidRequest; + + beforeEach(() => { + bidRequest = { + getFloor: sinon.stub() + }; + }); + + it('should handle empty or invalid bidRequest', () => { + expect(internal.getFloor(null)).to.be.null; + expect(internal.getFloor({})).to.be.null; + expect(internal.getFloor({ getFloor: 'foo' })).to.be.null; + }); + + it('should detect floor via getFloor()', () => { + const result = { + floor: 1.11, + currency: 'USD' + }; + + const options = { + mediaType: BANNER, + size: '*' + } + + bidRequest.getFloor.returns(result); + + expect(internal.getFloor(bidRequest, options)).to.deep.equal(result); + expect(bidRequest.getFloor.calledOnceWith(options)).to.be.true; + }); + + it('should handle empty, invalid or faulty getFloor() results', () => { + bidRequest.getFloor + .onCall(0).returns({}) + .onCall(1).returns({ floor: 'foo' }) + .onCall(2).returns('bar') + .onCall(3).throws(new Error('baz')); + + expect(internal.getFloor(bidRequest, {})).to.be.null; + expect(internal.getFloor(bidRequest, {})).to.be.null; + expect(internal.getFloor(bidRequest, {})).to.be.null; + expect(internal.getFloor(bidRequest, {})).to.be.null; + + expect(bidRequest.getFloor.callCount).to.equal(4); + }); + }); + describe('groupBidRequestsByPublisher', () => { it('should handle empty bidRequests', () => { expect(internal.groupBidRequestsByPublisher(null)).to.deep.equal({}); @@ -541,34 +589,35 @@ describe('AduptechBidAdapter', () => { } }; - const getFloorResponse = { - currency: 'USD', - floor: '1.23' - }; - - const validBidRequests = [ - { - bidId: 'bidId1', - adUnitCode: 'adUnitCode1', - transactionId: 'transactionId1', - mediaTypes: { - banner: { - sizes: [[100, 200], [300, 400]] - } - }, - params: { - publisher: 'publisher1', - placement: 'placement1' + const bidRequest = { + bidId: 'bidId1', + adUnitCode: 'adUnitCode1', + transactionId: 'transactionId1', + mediaTypes: { + banner: { + sizes: [[100, 200], [300, 400]] }, - getFloor: () => { - return getFloorResponse + native: { + image: { + required: true + }, } - } - ]; + }, + params: { + publisher: 'publisher1', + placement: 'placement1' + }, + getFloor: sinon.stub() + .onCall(0).returns({ floor: 1.11, currency: 'USD' }) + .onCall(1).returns({ floor: 2.22, currency: 'EUR' }) + .onCall(2).returns({ floor: 3.33, currency: 'USD' }) + .onCall(3).returns({ floor: 4.44, currency: 'GBP' }) + .onCall(4).returns({ floor: 5.55, currency: 'EUR' }) + }; - expect(spec.buildRequests(validBidRequests, bidderRequest)).to.deep.equal([ + expect(spec.buildRequests([bidRequest], bidderRequest)).to.deep.equal([ { - url: internal.buildEndpointUrl(validBidRequests[0].params.publisher), + url: internal.buildEndpointUrl(bidRequest.params.publisher), method: ENDPOINT_METHOD, data: { auctionId: bidderRequest.auctionId, @@ -580,17 +629,39 @@ describe('AduptechBidAdapter', () => { }, imp: [ { - bidId: validBidRequests[0].bidId, - transactionId: validBidRequests[0].transactionId, - adUnitCode: validBidRequests[0].adUnitCode, - params: validBidRequests[0].params, - banner: validBidRequests[0].mediaTypes.banner, - floorPrice: getFloorResponse.floor + bidId: bidRequest.bidId, + transactionId: bidRequest.transactionId, + adUnitCode: bidRequest.adUnitCode, + params: bidRequest.params, + banner: { + sizes: [ + [100, 200, 1.11, 'USD'], + [300, 400, 2.22, 'EUR'], + ], + floorPrice: 3.33, + floorCurrency: 'USD' + }, + native: { + image: { + required: true + }, + floorPrice: 4.44, + floorCurrency: 'GBP' + }, + floorPrice: 5.55, + floorCurrency: 'EUR' } ] } } ]); + + expect(bidRequest.getFloor.callCount).to.equal(5); + expect(bidRequest.getFloor.getCall(0).calledWith({ mediaType: BANNER, size: bidRequest.mediaTypes.banner.sizes[0] })).to.be.true; + expect(bidRequest.getFloor.getCall(1).calledWith({ mediaType: BANNER, size: bidRequest.mediaTypes.banner.sizes[1] })).to.be.true; + expect(bidRequest.getFloor.getCall(2).calledWith({ mediaType: BANNER, size: '*' })).to.be.true; + expect(bidRequest.getFloor.getCall(3).calledWith({ mediaType: NATIVE, size: '*' })).to.be.true; + expect(bidRequest.getFloor.getCall(4).calledWith({ mediaType: '*', size: '*' })).to.be.true; }); }); diff --git a/test/spec/modules/adyoulikeBidAdapter_spec.js b/test/spec/modules/adyoulikeBidAdapter_spec.js index e6a153d501a..24cede20352 100644 --- a/test/spec/modules/adyoulikeBidAdapter_spec.js +++ b/test/spec/modules/adyoulikeBidAdapter_spec.js @@ -722,6 +722,7 @@ describe('Adyoulike Adapter', function () { expect(payload.Version).to.equal('1.0'); expect(payload.Bids['bid_id_0'].PlacementID).to.be.equal('placement_0'); expect(payload.PageRefreshed).to.equal(false); + expect(payload.pbjs_version).to.equal('$prebid.version$'); expect(payload.Bids['bid_id_0'].TransactionID).to.be.equal('bid_id_0_transaction_id'); }); @@ -736,6 +737,7 @@ describe('Adyoulike Adapter', function () { expect(payload.Version).to.equal('1.0'); expect(payload.Bids['bid_id_0'].PlacementID).to.be.equal('placement_0'); expect(payload.PageRefreshed).to.equal(false); + expect(payload.pbjs_version).to.equal('$prebid.version$'); expect(payload.Bids['bid_id_0'].TransactionID).to.be.equal('bid_id_0_transaction_id'); }); @@ -758,6 +760,7 @@ describe('Adyoulike Adapter', function () { expect(payload.Bids['bid_id_1'].TransactionID).to.be.equal('bid_id_1_transaction_id'); expect(payload.Bids['bid_id_3'].TransactionID).to.be.equal('bid_id_3_transaction_id'); expect(payload.PageRefreshed).to.equal(false); + expect(payload.pbjs_version).to.equal('$prebid.version$'); }); it('sends bid request to endpoint setted by parameters', function () { diff --git a/test/spec/modules/aidemBidAdapter_spec.js b/test/spec/modules/aidemBidAdapter_spec.js new file mode 100644 index 00000000000..f58e49eb364 --- /dev/null +++ b/test/spec/modules/aidemBidAdapter_spec.js @@ -0,0 +1,739 @@ +import {expect} from 'chai'; +import {setEndPoints, spec} from 'modules/aidemBidAdapter.js'; +import * as utils from '../../../src/utils'; +import {deepSetValue} from '../../../src/utils'; +import {server} from '../../mocks/xhr'; +import {config} from '../../../src/config'; +import {NATIVE} from '../../../src/mediaTypes.js'; + +// Full banner + Full Video + Basic Banner + Basic Video +const VALID_BIDS = [ + { + bidder: 'aidem', + params: { + siteId: '301491', + publisherId: '3021491', + placementId: '13144370', + }, + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]], + } + }, + }, + { + bidder: 'aidem', + params: { + siteId: '301491', + publisherId: '3021491', + placementId: '13144370', + }, + mediaTypes: { + video: { + context: 'instream', + minduration: 7, + maxduration: 30, + playerSize: [640, 480], + mimes: ['video/mp4'], + protocols: [2] + } + }, + }, +] + +const INVALID_BIDS = [ + { + bidder: 'aidem', + params: { + siteId: '3014912' + } + }, + { + bidder: 'aidem', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]], + } + }, + params: { + siteId: '3014912', + } + }, + { + bidder: 'aidem', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]], + } + }, + params: { + publisherId: '3014912', + } + }, + { + bidder: 'aidem', + params: { + siteId: '3014912', + member: '301e4912' + } + }, + { + bidder: 'aidem', + params: { + siteId: '3014912', + invCode: '3014912' + } + }, + { + bidder: 'aidem', + mediaType: NATIVE, + params: { + siteId: '3014912' + } + }, + { + bidder: 'aidem', + mediaTypes: { + banner: {} + }, + }, + { + bidder: 'aidem', + mediaTypes: { + video: { + placement: 1, + minduration: 7, + maxduration: 30, + mimes: ['video/mp4'], + protocols: [2] + } + }, + params: { + siteId: '301491', + placementId: '13144370', + }, + }, + { + bidder: 'aidem', + mediaTypes: { + video: { + minduration: 7, + maxduration: 30, + playerSize: [640, 480], + mimes: ['video/mp4'], + protocols: [2] + } + }, + params: { + siteId: '301491', + placementId: '13144370', + }, + }, + { + bidder: 'aidem', + mediaTypes: { + video: { + minduration: 7, + maxduration: 30, + playerSize: [640, 480], + mimes: ['video/mp4'], + protocols: [2], + placement: 1 + } + }, + params: { + siteId: '301491', + placementId: '13144370', + video: { + size: [480, 40] + } + }, + }, +] + +const DEFAULT_VALID_BANNER_REQUESTS = [ + { + adUnitCode: 'test-div', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '22c4871113f461', + bidder: 'aidem', + bidderRequestId: '15246a574e859f', + mediaTypes: { + banner: { + sizes: [ + [ 300, 250 ], + [ 300, 600 ] + ] + } + }, + params: { + siteId: '1', + placementId: '13144370' + }, + src: 'client', + transactionId: '54a58774-7a41-494e-9aaf-fa7b79164f0c' + } +]; + +const DEFAULT_VALID_VIDEO_REQUESTS = [ + { + adUnitCode: 'test-div', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '22c4871113f461', + bidder: 'aidem', + bidderRequestId: '15246a574e859f', + mediaTypes: { + video: { + minduration: 7, + maxduration: 30, + playerSize: [640, 480], + mimes: ['video/mp4'], + protocols: [2] + } + }, + params: { + siteId: '1', + placementId: '13144370' + }, + src: 'client', + transactionId: '54a58774-7a41-494e-9aaf-fa7b79164f0c' + } +]; + +const VALID_BIDDER_REQUEST = { + auctionId: '6e9b46c3-65a8-46ea-89f4-c5071110c85c', + bidderCode: 'aidem', + bidderRequestId: '170ea5d2b1d073', + refererInfo: { + page: 'test-page', + domain: 'test-domain', + ref: 'test-referer' + }, +} + +// Add mediatype +const SERVER_RESPONSE_BANNER = { + body: { + id: 'efa1930a-bc3e-4fd0-8368-08bc40236b4f', + bid: [ + // BANNER + { + 'id': '2e614be960ee1d', + 'impid': '2e614be960ee1d', + 'price': 7.91, + 'mediatype': 'banner', + 'adid': '24277955', + 'adm': 'creativity_banner', + 'adomain': [ + 'aidem.com' + ], + 'iurl': 'http://www.aidem.com', + 'cat': [], + 'cid': '4193561', + 'crid': '24277955', + 'w': 300, + 'h': 250, + 'ext': { + 'dspid': 85, + 'advbrandid': 1246, + 'advbrand': 'AIDEM' + } + }, + ], + cur: 'USD' + }, +} + +const SERVER_RESPONSE_VIDEO = { + body: { + id: 'efa1930a-bc3e-4fd0-8368-08bc40236b4f', + bid: [ + // VIDEO + { + 'id': '2876a29392a47c', + 'impid': '2876a29392a47c', + 'price': 7.93, + 'mediatype': 'video', + 'adid': '24277955', + 'adm': 'https://hermes.aidemsrv.com/vast-tag/cl9mzhhd502uq09l720uegb02?auction_id={{AUCTION_ID}}&cachebuster={{CACHEBUSTER}}', + 'adomain': [ + 'aidem.com' + ], + 'iurl': 'http://www.aidem.com', + 'cat': [], + 'cid': '4193561', + 'crid': '24277955', + 'w': 640, + 'h': 480, + 'ext': { + 'dspid': 85, + 'advbrandid': 1246, + 'advbrand': 'AIDEM' + } + } + ], + cur: 'USD' + }, +} + +const WIN_NOTICE = { + 'adId': '3a20ee5dc78c1e', + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'creativeId': '24277955', + 'cpm': 1, + 'netRevenue': false, + 'adserverTargeting': { + 'hb_bidder': 'aidem', + 'hb_adid': '3a20ee5dc78c1e', + 'hb_pb': '1.00', + 'hb_size': '300x250', + 'hb_source': 'client', + 'hb_format': 'banner', + 'hb_adomain': 'example.com' + }, + + 'auctionId': '85864730-6cbc-4e56-bc3c-a4a6596dca5b', + 'currency': [ + 'USD' + ], + 'mediaType': 'banner', + 'advertiserDomains': [ + 'abc.com' + ], + 'size': '300x250', + 'params': [ + { + 'placementId': '13144370', + 'siteId': '23434', + 'publisherId': '7689670753' + } + ], + 'width': 300, + 'height': 250, + 'status': 'rendered', + 'transactionId': 'ce089116-4251-45c3-bdbb-3a03cb13816b', + 'ttl': 300, + 'requestTimestamp': 1666796241007, + 'responseTimestamp': 1666796241021, + metrics: { + getMetrics() { + return { + + } + } + } +} + +const ERROR_NOTICE = { + 'message': 'Prebid.js: Server call for aidem failed.', + 'url': 'http%3A%2F%2Flocalhost%3A9999%2FintegrationExamples%2Fgpt%2Fhello_world.html%3Fpbjs_debug%3Dtrue', + 'auctionId': 'b57faab7-23f7-4b63-90db-67b259d20db7', + 'bidderRequestId': '1c53857d1ce616', + 'timeout': 1000, + 'bidderCode': 'aidem', + metrics: { + getMetrics() { + return { + + } + } + } +} + +describe('Aidem adapter', () => { + describe('isBidRequestValid', () => { + it('should return true for each valid bid requests', function () { + // spec.isBidRequestValid() + VALID_BIDS.forEach((value, index) => { + expect(spec.isBidRequestValid(value)).to.be.true + }) + }); + + it('should return false for each invalid bid requests', function () { + // spec.isBidRequestValid() + INVALID_BIDS.forEach((value, index) => { + expect(spec.isBidRequestValid(value)).to.be.false + }) + }); + + it('should return true if valid banner sizes are specified in params as single array', function () { + // spec.isBidRequestValid() + const validBannerRequest = utils.deepClone(VALID_BIDS[0]) + deepSetValue(validBannerRequest.params, 'banner.size', [300, 250]) + expect(spec.isBidRequestValid(validBannerRequest)).to.be.true + }); + + it('should return true if valid banner sizes are specified in params as array of array', function () { + // spec.isBidRequestValid() + const validBannerRequest = utils.deepClone(VALID_BIDS[0]) + deepSetValue(validBannerRequest.params, 'banner.size', [[300, 600]]) + expect(spec.isBidRequestValid(validBannerRequest)).to.be.true + }); + + it('should return true if valid video sizes are specified in params as single array', function () { + // spec.isBidRequestValid() + const validVideoRequest = utils.deepClone(VALID_BIDS[1]) + deepSetValue(validVideoRequest.params, 'video.size', [640, 480]) + expect(spec.isBidRequestValid(validVideoRequest)).to.be.true + }); + + it('BANNER: should return true if rateLimit is 1', function () { + // spec.isBidRequestValid() + const validBannerRequest = utils.deepClone(VALID_BIDS[0]) + deepSetValue(validBannerRequest.params, 'rateLimit', 1) + expect(spec.isBidRequestValid(validBannerRequest)).to.be.true + }); + + it('BANNER: should return false if rateLimit is 0', function () { + // spec.isBidRequestValid() + const validBannerRequest = utils.deepClone(VALID_BIDS[0]) + deepSetValue(validBannerRequest.params, 'rateLimit', 0) + expect(spec.isBidRequestValid(validBannerRequest)).to.be.false + }); + + it('BANNER: should return false if rateLimit is not between 0 and 1', function () { + // spec.isBidRequestValid() + const validBannerRequest = utils.deepClone(VALID_BIDS[0]) + deepSetValue(validBannerRequest.params, 'rateLimit', 1.2) + expect(spec.isBidRequestValid(validBannerRequest)).to.be.false + }); + + it('BANNER: should return false if rateLimit is not a number', function () { + // spec.isBidRequestValid() + const validBannerRequest = utils.deepClone(VALID_BIDS[0]) + deepSetValue(validBannerRequest.params, 'rateLimit', '0.5') + expect(spec.isBidRequestValid(validBannerRequest)).to.be.false + }); + + it('VIDEO: should return true if rateLimit is 1', function () { + // spec.isBidRequestValid() + const validVideoRequest = utils.deepClone(VALID_BIDS[1]) + deepSetValue(validVideoRequest.params, 'rateLimit', 1) + expect(spec.isBidRequestValid(validVideoRequest)).to.be.true + }); + + it('VIDEO: should return false if rateLimit is 0', function () { + // spec.isBidRequestValid() + const validVideoRequest = utils.deepClone(VALID_BIDS[1]) + deepSetValue(validVideoRequest.params, 'rateLimit', 0) + expect(spec.isBidRequestValid(validVideoRequest)).to.be.false + }); + + it('VIDEO: should return false if rateLimit is not between 0 and 1', function () { + // spec.isBidRequestValid() + const validBannerRequest = utils.deepClone(VALID_BIDS[1]) + deepSetValue(validBannerRequest.params, 'rateLimit', 1.2) + expect(spec.isBidRequestValid(validBannerRequest)).to.be.false + }); + + it('VIDEO: should return false if rateLimit is not a number', function () { + // spec.isBidRequestValid() + const validBannerRequest = utils.deepClone(VALID_BIDS[1]) + deepSetValue(validBannerRequest.params, 'rateLimit', '0.5') + expect(spec.isBidRequestValid(validBannerRequest)).to.be.false + }); + }); + + describe('buildRequests', () => { + it('should match server requirements', () => { + const requests = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + expect(requests).to.be.an('object'); + expect(requests.method).to.be.a('string') + expect(requests.data).to.be.a('string') + expect(requests.options).to.be.an('object').that.have.a.property('withCredentials') + }); + + it('should have a well formatted banner payload', () => { + const requests = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + const payload = JSON.parse(requests.data) + expect(payload).to.be.a('object').that.has.all.keys( + 'id', 'imp', 'device', 'cur', 'tz', 'regs', 'site', 'environment', 'at' + ) + expect(payload.imp).to.be.a('array').that.has.lengthOf(DEFAULT_VALID_BANNER_REQUESTS.length) + + expect(payload.imp[0]).to.be.a('object').that.has.all.keys( + 'banner', 'id', 'mediatype', 'imp_ext', 'tid', 'tagid' + ) + expect(payload.imp[0].banner).to.be.a('object').that.has.all.keys( + 'format', 'topframe' + ) + }); + + it('should have a well formatted video payload', () => { + const requests = spec.buildRequests(DEFAULT_VALID_VIDEO_REQUESTS, VALID_BIDDER_REQUEST); + const payload = JSON.parse(requests.data) + expect(payload).to.be.a('object').that.has.all.keys( + 'id', 'imp', 'device', 'cur', 'tz', 'regs', 'site', 'environment', 'at' + ) + expect(payload.imp).to.be.a('array').that.has.lengthOf(DEFAULT_VALID_VIDEO_REQUESTS.length) + + expect(payload.imp[0]).to.be.a('object').that.has.all.keys( + 'video', 'id', 'mediatype', 'imp_ext', 'tid', 'tagid' + ) + expect(payload.imp[0].video).to.be.a('object').that.has.all.keys( + 'format', 'mimes', 'minDuration', 'maxDuration', 'protocols' + ) + }); + + it('should have a well formatted bid floor payload if configured', () => { + const validBannerRequests = utils.deepClone(DEFAULT_VALID_BANNER_REQUESTS) + validBannerRequests[0].params.floor = { + value: 1.98, + currency: 'USD' + } + const requests = spec.buildRequests(validBannerRequests, VALID_BIDDER_REQUEST); + const payload = JSON.parse(requests.data) + const { floor } = payload.imp[0] + expect(floor).to.be.a('object').that.has.all.keys( + 'value', 'currency' + ) + }); + + it('should hav wpar keys in environment object', function () { + const requests = spec.buildRequests(DEFAULT_VALID_VIDEO_REQUESTS, VALID_BIDDER_REQUEST); + const payload = JSON.parse(requests.data) + expect(payload).to.have.property('environment') + expect(payload.environment).to.be.a('object').that.have.property('wpar') + expect(payload.environment.wpar).to.be.a('object').that.has.keys('innerWidth', 'innerHeight') + }); + }) + + describe('interpretResponse', () => { + it('should return a valid bid array with a banner bid', () => { + const response = utils.deepClone(SERVER_RESPONSE_BANNER) + const interpreted = spec.interpretResponse(response) + expect(interpreted).to.be.a('array').that.has.lengthOf(1) + interpreted.forEach(value => { + expect(value).to.be.a('object').that.has.all.keys( + 'ad', 'cpm', 'creativeId', 'currency', 'height', 'mediaType', 'meta', 'netRevenue', 'requestId', 'ttl', 'width', 'dealId' + ) + }) + }); + + it('should return a valid bid array with a banner bid', () => { + const response = utils.deepClone(SERVER_RESPONSE_VIDEO) + const interpreted = spec.interpretResponse(response) + expect(interpreted).to.be.a('array').that.has.lengthOf(1) + interpreted.forEach(value => { + expect(value).to.be.a('object').that.has.all.keys( + 'vastUrl', 'cpm', 'creativeId', 'currency', 'height', 'mediaType', 'meta', 'netRevenue', 'requestId', 'ttl', 'width', 'dealId' + ) + }) + }); + + it('should return a valid bid array with netRevenue', () => { + const response = utils.deepClone(SERVER_RESPONSE_BANNER) + response.body.bid[0].isNet = true + const interpreted = spec.interpretResponse(response) + expect(interpreted).to.be.a('array').that.has.lengthOf(1) + expect(interpreted[0].netRevenue).to.be.true + }); + + it('should return an empty bid array if one of seatbid entry is missing price property', () => { + const response = utils.deepClone(SERVER_RESPONSE_BANNER) + delete response.body.bid[0].price + const interpreted = spec.interpretResponse(response) + expect(interpreted).to.be.a('array').that.has.lengthOf(0) + }); + + it('should return an empty bid array if one of seatbid entry is missing adm property', () => { + const response = utils.deepClone(SERVER_RESPONSE_BANNER) + delete response.body.bid[0].adm + const interpreted = spec.interpretResponse(response) + expect(interpreted).to.be.a('array').that.has.lengthOf(0) + }); + }) + + describe('onBidWon', () => { + it(`should exists and type function`, function () { + expect(spec.onBidWon).to.exist.and.to.be.a('function') + }); + + it(`should send a valid bid won notice`, function () { + spec.onBidWon(WIN_NOTICE); + // server.respondWith('POST', WIN_EVENT_URL, [ + // 400, {'Content-Type': 'application/json'}, ) + // ]); + expect(server.requests.length).to.equal(1); + }); + }); + + describe('onBidderError', () => { + it(`should exists and type function`, function () { + expect(spec.onBidderError).to.exist.and.to.be.a('function') + }); + + it(`should send a valid error notice`, function () { + spec.onBidderError({ bidderRequest: ERROR_NOTICE }) + expect(server.requests.length).to.equal(1); + const body = JSON.parse(server.requests[0].requestBody) + expect(body).to.be.a('object').that.has.all.keys('message', 'auctionId', 'bidderRequestId', 'url', 'metrics') + // const { bids } = JSON.parse(server.requests[0].requestBody) + // expect(bids).to.be.a('array').that.has.lengthOf(1) + // _each(bids, (bid) => { + // expect(bid).to.be.a('object').that.has.all.keys('adUnitCode', 'auctionId', 'bidId', 'bidderRequestId', 'transactionId', 'metrics') + // }) + }); + }); + + describe('setEndPoints', () => { + it(`should exists and type function`, function () { + expect(setEndPoints).to.exist.and.to.be.a('function') + }); + + it(`should not modify default endpoints`, function () { + const endpoints = setEndPoints() + const requestURL = new URL(endpoints.request) + const winNoticeURL = new URL(endpoints.notice.win) + const timeoutNoticeURL = new URL(endpoints.notice.timeout) + const errorNoticeURL = new URL(endpoints.notice.error) + + expect(requestURL.host).to.equal('zero.aidemsrv.com') + expect(winNoticeURL.host).to.equal('zero.aidemsrv.com') + expect(timeoutNoticeURL.host).to.equal('zero.aidemsrv.com') + expect(errorNoticeURL.host).to.equal('zero.aidemsrv.com') + + expect(decodeURIComponent(requestURL.pathname)).to.equal('/bid/request') + expect(decodeURIComponent(winNoticeURL.pathname)).to.equal('/notice/win') + expect(decodeURIComponent(timeoutNoticeURL.pathname)).to.equal('/notice/timeout') + expect(decodeURIComponent(errorNoticeURL.pathname)).to.equal('/notice/error') + }); + + it(`should not change request endpoint`, function () { + const endpoints = setEndPoints('default') + const requestURL = new URL(endpoints.request) + expect(decodeURIComponent(requestURL.pathname)).to.equal('/bid/request') + }); + + it(`should change to local env`, function () { + const endpoints = setEndPoints('local') + const requestURL = new URL(endpoints.request) + const winNoticeURL = new URL(endpoints.notice.win) + const timeoutNoticeURL = new URL(endpoints.notice.timeout) + const errorNoticeURL = new URL(endpoints.notice.error) + + expect(requestURL.host).to.equal('127.0.0.1:8787') + expect(winNoticeURL.host).to.equal('127.0.0.1:8787') + expect(timeoutNoticeURL.host).to.equal('127.0.0.1:8787') + expect(errorNoticeURL.host).to.equal('127.0.0.1:8787') + }); + + it(`should add a path prefix`, function () { + const endpoints = setEndPoints('local', '/path') + const requestURL = new URL(endpoints.request) + const winNoticeURL = new URL(endpoints.notice.win) + const timeoutNoticeURL = new URL(endpoints.notice.timeout) + const errorNoticeURL = new URL(endpoints.notice.error) + + expect(decodeURIComponent(requestURL.pathname)).to.equal('/path/bid/request') + expect(decodeURIComponent(winNoticeURL.pathname)).to.equal('/path/notice/win') + expect(decodeURIComponent(timeoutNoticeURL.pathname)).to.equal('/path/notice/timeout') + expect(decodeURIComponent(errorNoticeURL.pathname)).to.equal('/path/notice/error') + }); + + it(`should add a path prefix and change request endpoint`, function () { + const endpoints = setEndPoints('local', '/path') + const requestURL = new URL(endpoints.request) + const winNoticeURL = new URL(endpoints.notice.win) + const timeoutNoticeURL = new URL(endpoints.notice.timeout) + const errorNoticeURL = new URL(endpoints.notice.error) + + expect(decodeURIComponent(requestURL.pathname)).to.equal('/path/bid/request') + expect(decodeURIComponent(winNoticeURL.pathname)).to.equal('/path/notice/win') + expect(decodeURIComponent(timeoutNoticeURL.pathname)).to.equal('/path/notice/timeout') + expect(decodeURIComponent(errorNoticeURL.pathname)).to.equal('/path/notice/error') + }); + }); + + describe('config', () => { + beforeEach(() => { + config.setConfig({ + aidem: { + env: 'main' + } + }); + }) + + it(`should not override default endpoints`, function () { + config.setConfig({ + aidem: { + env: 'unknown', + path: '/test' + } + }); + const { url } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + const requestURL = new URL(url) + expect(requestURL.host).to.equal('zero.aidemsrv.com') + }); + + it(`should set local endpoints`, function () { + config.setConfig({ + aidem: { + env: 'local', + path: '/test' + } + }); + const { url } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + const requestURL = new URL(url) + expect(requestURL.host).to.equal('127.0.0.1:8787') + }); + + it(`should set coppa`, function () { + config.setConfig({ + coppa: true + }); + const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + const request = JSON.parse(data) + expect(request.regs.coppa_applies).to.equal(true) + }); + + it(`should set gdpr to true`, function () { + config.setConfig({ + consentManagement: { + gdpr: { + // any data here set gdpr to true + }, + } + }); + const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + const request = JSON.parse(data) + expect(request.regs.gdpr_applies).to.equal(true) + }); + + it(`should set usp_consent string`, function () { + config.setConfig({ + consentManagement: { + usp: { + cmpApi: 'static', + consentData: { + getUSPData: { + uspString: '1YYY' + } + } + } + } + }); + const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + const request = JSON.parse(data) + expect(request.regs.us_privacy).to.equal('1YYY') + }); + + it(`should not set usp_consent string`, function () { + config.setConfig({ + consentManagement: { + usp: { + cmpApi: 'iab', + consentData: { + getUSPData: { + uspString: '1YYY' + } + } + } + } + }); + const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + const request = JSON.parse(data) + expect(request.regs.us_privacy).to.undefined + }); + }); +}); diff --git a/test/spec/modules/ajaBidAdapter_spec.js b/test/spec/modules/ajaBidAdapter_spec.js index a2095d52857..7cf5698f7d4 100644 --- a/test/spec/modules/ajaBidAdapter_spec.js +++ b/test/spec/modules/ajaBidAdapter_spec.js @@ -45,6 +45,26 @@ describe('AjaAdapter', function () { bidId: '30b31c1838de1e', bidderRequestId: '22edbae2733bf6', auctionId: '1d1a030790a475', + ortb2: { + device: { + sua: { + source: 2, + platform: { + brand: 'Android', + version: ['8', '0', '0'] + }, + browsers: [ + {brand: 'Not_A Brand', version: ['99', '0', '0', '0']}, + {brand: 'Google Chrome', version: ['109', '0', '5414', '119']}, + {brand: 'Chromium', version: ['109', '0', '5414', '119']} + ], + mobile: 1, + model: 'SM-G955U', + bitness: '64', + architecture: '' + } + } + } } ]; @@ -58,7 +78,7 @@ describe('AjaAdapter', function () { const requests = spec.buildRequests(bidRequests, bidderRequest); expect(requests[0].url).to.equal(ENDPOINT); expect(requests[0].method).to.equal('GET'); - expect(requests[0].data).to.equal('asi=123456&skt=5&prebid_id=30b31c1838de1e&prebid_ver=$prebid.version$&page_url=https%3A%2F%2Fhoge.com&'); + expect(requests[0].data).to.equal('asi=123456&skt=5&prebid_id=30b31c1838de1e&prebid_ver=$prebid.version$&page_url=https%3A%2F%2Fhoge.com&sua=%7B%22source%22%3A2%2C%22platform%22%3A%7B%22brand%22%3A%22Android%22%2C%22version%22%3A%5B%228%22%2C%220%22%2C%220%22%5D%7D%2C%22browsers%22%3A%5B%7B%22brand%22%3A%22Not_A%20Brand%22%2C%22version%22%3A%5B%2299%22%2C%220%22%2C%220%22%2C%220%22%5D%7D%2C%7B%22brand%22%3A%22Google%20Chrome%22%2C%22version%22%3A%5B%22109%22%2C%220%22%2C%225414%22%2C%22119%22%5D%7D%2C%7B%22brand%22%3A%22Chromium%22%2C%22version%22%3A%5B%22109%22%2C%220%22%2C%225414%22%2C%22119%22%5D%7D%5D%2C%22mobile%22%3A1%2C%22model%22%3A%22SM-G955U%22%2C%22bitness%22%3A%2264%22%2C%22architecture%22%3A%22%22%7D&'); }); }); diff --git a/test/spec/modules/alkimiBidAdapter_spec.js b/test/spec/modules/alkimiBidAdapter_spec.js index 1ae9bb56df4..a396e5b8139 100644 --- a/test/spec/modules/alkimiBidAdapter_spec.js +++ b/test/spec/modules/alkimiBidAdapter_spec.js @@ -108,7 +108,7 @@ describe('alkimiBidAdapter', function () { describe('buildRequests', function () { let bidRequests = [REQUEST] - const bidderRequest = spec.buildRequests(bidRequests, { + let requestData = { auctionId: '123', refererInfo: { page: 'http://test.com/path.html' @@ -119,7 +119,8 @@ describe('alkimiBidAdapter', function () { gdprApplies: true }, uspConsent: 'uspConsent' - }) + } + const bidderRequest = spec.buildRequests(bidRequests, requestData) it('should return a properly formatted request with eids defined', function () { expect(bidderRequest.data.eids).to.deep.equal(REQUEST.userIdAsEids) @@ -138,8 +139,8 @@ describe('alkimiBidAdapter', function () { expect(bidderRequest.method).to.equal('POST') expect(bidderRequest.data.requestId).to.equal('123') expect(bidderRequest.data.referer).to.equal('http://test.com/path.html') - expect(bidderRequest.data.schain).to.deep.contains({ver: '1.0', complete: 1, nodes: [{asi: 'alkimi-onboarding.com', sid: '00001', hp: 1}]}) - expect(bidderRequest.data.signRequest.bids).to.deep.contains({ token: 'e64782a4-8e68-4c38-965b-80ccf115d46f', pos: 7, bidFloor: 0.1, width: 300, height: 250, impMediaType: 'Banner', adUnitCode: 'bannerAdUnitCode' }) + expect(bidderRequest.data.schain).to.deep.contains({ ver: '1.0', complete: 1, nodes: [{ asi: 'alkimi-onboarding.com', sid: '00001', hp: 1 }] }) + expect(bidderRequest.data.signRequest.bids).to.deep.contains({ token: 'e64782a4-8e68-4c38-965b-80ccf115d46f', pos: 7, bidFloor: 0.1, sizes: [{width: 300, height: 250}], playerSizes: [], impMediaTypes: ['Banner'], adUnitCode: 'bannerAdUnitCode' }) expect(bidderRequest.data.signRequest.randomUUID).to.equal(undefined) expect(bidderRequest.data.bidIds).to.deep.contains('456') expect(bidderRequest.data.signature).to.equal(undefined) @@ -147,6 +148,17 @@ describe('alkimiBidAdapter', function () { expect(bidderRequest.options.contentType).to.equal('application/json') expect(bidderRequest.url).to.equal(ENDPOINT) }) + + it('sends bidFloor when configured', () => { + const requestWithFloor = Object.assign({}, REQUEST); + requestWithFloor.getFloor = function (arg) { + if (arg.currency === 'USD' && arg.mediaType === 'banner' && JSON.stringify(arg.size) === JSON.stringify([300, 250])) { + return { currency: 'USD', floor: 0.3 } + } + } + const bidderRequestFloor = spec.buildRequests([requestWithFloor], requestData); + expect(bidderRequestFloor.data.signRequest.bids[0].bidFloor).to.be.equal(0.3); + }); }) describe('interpretResponse', function () { diff --git a/test/spec/modules/aolBidAdapter_spec.js b/test/spec/modules/aolBidAdapter_spec.js index 57ce37145f4..92246f76c7a 100644 --- a/test/spec/modules/aolBidAdapter_spec.js +++ b/test/spec/modules/aolBidAdapter_spec.js @@ -84,7 +84,7 @@ describe('AolAdapter', function () { 'admixer.net': '100', 'adserver.org': '200', 'adtelligent.com': '300', - 'amxrtb.com': '500', + 'amxdt.net': '500', 'audigent.com': '600', 'britepool.com': '700', 'criteo.com': '800', @@ -110,7 +110,7 @@ describe('AolAdapter', function () { const USER_ID_DATA = { admixerId: SUPPORTED_USER_ID_SOURCES['admixer.net'], adtelligentId: SUPPORTED_USER_ID_SOURCES['adtelligent.com'], - amxId: SUPPORTED_USER_ID_SOURCES['amxrtb.com'], + amxId: SUPPORTED_USER_ID_SOURCES['amxdt.net'], britepoolid: SUPPORTED_USER_ID_SOURCES['britepool.com'], criteoId: SUPPORTED_USER_ID_SOURCES['criteo.com'], connectid: SUPPORTED_USER_ID_SOURCES['verizonmedia.com'], @@ -488,6 +488,20 @@ describe('AolAdapter', function () { expect(request.url).to.contain(NEXAGE_URL + 'dcn=2c9d2b50015c5ce9db6aeeed8b9500d6&pos=header'); }); + it('should return One Mobile url with configured GPP data', function () { + let bidRequest = createCustomBidRequest({ + params: getNexageGetBidParams() + }); + bidRequest.ortb2 = { + regs: { + gpp: 'testgpp', + gpp_sid: [8] + } + } + let [request] = spec.buildRequests(bidRequest.bids, bidRequest); + expect(request.url).to.contain('gpp=testgpp&gpp_sid=8'); + }); + it('should return One Mobile url with cmd=bid option', function () { let bidRequest = createCustomBidRequest({ params: getNexageGetBidParams() @@ -794,6 +808,14 @@ describe('AolAdapter', function () { 'euconsent=test-consent;gdpr=1;us_privacy=test-usp-consent;'); }); + it('should return formatted gpp privacy params when formatConsentData returns GPP data', function () { + formatConsentDataStub.returns({ + gpp: 'gppstring', + gpp_sid: [6, 7] + }); + expect(spec.formatMarketplaceDynamicParams()).to.be.equal('gpp=gppstring;gpp_sid=6%2C7;'); + }); + it('should return formatted params when formatKeyValues returns data', function () { formatKeyValuesStub.returns({ param1: 'val1', diff --git a/test/spec/modules/appnexusBidAdapter_spec.js b/test/spec/modules/appnexusBidAdapter_spec.js index 5cd189da9a1..9e88e2875c7 100644 --- a/test/spec/modules/appnexusBidAdapter_spec.js +++ b/test/spec/modules/appnexusBidAdapter_spec.js @@ -36,14 +36,31 @@ describe('AppNexusAdapter', function () { }); it('should return true when required params found', function () { - let bid = Object.assign({}, bid); - delete bid.params; - bid.params = { + let bid1 = deepClone(bid); + bid1.params = { + 'placement_id': 123423 + } + expect(spec.isBidRequestValid(bid1)).to.equal(true); + }); + + it('should return true when required params found', function () { + let bid1 = deepClone(bid); + bid1.params = { 'member': '1234', 'invCode': 'ABCD' }; - expect(spec.isBidRequestValid(bid)).to.equal(true); + expect(spec.isBidRequestValid(bid1)).to.equal(true); + }); + + it('should return true when required params found', function () { + let bid1 = deepClone(bid); + bid1.params = { + 'member': '1234', + 'inv_code': 'ABCD' + }; + + expect(spec.isBidRequestValid(bid1)).to.equal(true); }); it('should return false when required params are not passed', function () { @@ -54,6 +71,15 @@ describe('AppNexusAdapter', function () { }; expect(spec.isBidRequestValid(bid)).to.equal(false); }); + + it('should return false when required params are not passed', function () { + let bid = Object.assign({}, bid); + delete bid.params; + bid.params = { + 'placement_id': 0 + }; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); }); describe('buildRequests', function () { @@ -101,6 +127,24 @@ describe('AppNexusAdapter', function () { expect(payload.tags[0].private_sizes).to.deep.equal([{ width: 300, height: 250 }]); }); + it('should parse out private sizes', function () { + let bidRequest = Object.assign({}, + bidRequests[0], + { + params: { + placementId: '10433394', + private_sizes: [300, 250] + } + } + ); + + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + + expect(payload.tags[0].private_sizes).to.exist; + expect(payload.tags[0].private_sizes).to.deep.equal([{ width: 300, height: 250 }]); + }); + it('should add position in request', function () { // set from bid.params let bidRequest = deepClone(bidRequests[0]); @@ -168,6 +212,24 @@ describe('AppNexusAdapter', function () { expect(payload.publisher_id).to.deep.equal(1231234); }); + it('should add publisher_id in request', function () { + let bidRequest = Object.assign({}, + bidRequests[0], + { + params: { + placement_id: '10433394', + publisher_id: '1231234' + } + }); + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + + expect(payload.tags[0].publisher_id).to.exist; + expect(payload.tags[0].publisher_id).to.deep.equal(1231234); + expect(payload.publisher_id).to.exist; + expect(payload.publisher_id).to.deep.equal(1231234); + }); + it('should add source and verison to the tag', function () { const request = spec.buildRequests(bidRequests); const payload = JSON.parse(request.data); @@ -189,7 +251,7 @@ describe('AppNexusAdapter', function () { bids: [{ bidder: 'appnexus', params: { - placementId: '10433394' + placement_id: '10433394' } }], transactionId: '04f2659e-c005-4eb1-a57c-fa93145e3843' @@ -351,7 +413,7 @@ describe('AppNexusAdapter', function () { bidRequests[0], { params: { - placementId: '10433394', + placement_id: '10433394', user: { externalUid: '123', segments: [123, { id: 987, value: 876 }], @@ -407,7 +469,7 @@ describe('AppNexusAdapter', function () { // 2 -> reserve is defined, getFloor not defined > reserve is used bidRequest.params = { - 'placementId': '10433394', + 'placement_id': '10433394', 'reserve': 0.5 }; request = spec.buildRequests([bidRequest]); @@ -428,7 +490,7 @@ describe('AppNexusAdapter', function () { let bidRequest = Object.assign({}, bidRequests[0], { - params: { placementId: '14542875' } + params: { placement_id: '14542875' } }, { mediaTypes: { @@ -461,7 +523,7 @@ describe('AppNexusAdapter', function () { let bidRequest = Object.assign({}, bidRequests[0], { - params: { placementId: '14542875' } + params: { placement_id: '14542875' } }, { mediaTypes: { @@ -484,7 +546,7 @@ describe('AppNexusAdapter', function () { let bidRequest = Object.assign({}, bidRequests[0], { - params: { placementId: '14542875' } + params: { placement_id: '14542875' } }, { mediaTypes: { @@ -526,7 +588,7 @@ describe('AppNexusAdapter', function () { let bidRequest = Object.assign({}, bidRequests[0], { - params: { placementId: '14542875' } + params: { placement_id: '14542875' } }, { mediaTypes: { @@ -557,7 +619,7 @@ describe('AppNexusAdapter', function () { let bidRequest = Object.assign({}, bidRequests[0], { - params: { placementId: '14542875' } + params: { placement_id: '14542875' } }, { mediaTypes: { @@ -585,7 +647,7 @@ describe('AppNexusAdapter', function () { let bidRequest = Object.assign({}, bidRequests[0], { - params: { placementId: '14542875' } + params: { placement_id: '14542875' } }, { mediaTypes: { @@ -610,7 +672,7 @@ describe('AppNexusAdapter', function () { mediaType: 'banner', params: { sizes: [[300, 250], [300, 600]], - placementId: 13144370 + placement_id: 13144370 } } ); @@ -786,7 +848,7 @@ describe('AppNexusAdapter', function () { bidRequests[0], { params: { - placementId: '10433394', + placement_id: '10433394', keywords: { single: 'val', singleArr: ['val'], @@ -931,6 +993,23 @@ describe('AppNexusAdapter', function () { expect(payload.tags[0].use_pmt_rule).to.equal(true); }); + it('should add payment rules to the request', function () { + let bidRequest = Object.assign({}, + bidRequests[0], + { + params: { + placement_id: '10433394', + use_payment_rule: true + } + } + ); + + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + + expect(payload.tags[0].use_pmt_rule).to.equal(true); + }); + it('should add gpid to the request', function () { let testGpid = '/12345/my-gpt-tag-0'; let bidRequest = deepClone(bidRequests[0]); @@ -985,6 +1064,52 @@ describe('AppNexusAdapter', function () { expect(payload.us_privacy).to.exist.and.to.equal(consentString); }); + it('should add gpp information to the request via bidderRequest.gppConsent', function () { + let consentString = 'abc1234'; + let bidderRequest = { + 'bidderCode': 'appnexus', + 'auctionId': '1d1a030790a475', + 'bidderRequestId': '22edbae2733bf6', + 'timeout': 3000, + 'gppConsent': { + 'gppString': consentString, + 'applicableSections': [8] + } + }; + bidderRequest.bids = bidRequests; + + const request = spec.buildRequests(bidRequests, bidderRequest); + const payload = JSON.parse(request.data); + + expect(payload.privacy).to.exist; + expect(payload.privacy.gpp).to.equal(consentString); + expect(payload.privacy.gpp_sid).to.deep.equal([8]); + }); + + it('should add gpp information to the request via bidderRequest.ortb2.regs', function () { + let consentString = 'abc1234'; + let bidderRequest = { + 'bidderCode': 'appnexus', + 'auctionId': '1d1a030790a475', + 'bidderRequestId': '22edbae2733bf6', + 'timeout': 3000, + 'ortb2': { + 'regs': { + 'gpp': consentString, + 'gpp_sid': [7] + } + } + }; + bidderRequest.bids = bidRequests; + + const request = spec.buildRequests(bidRequests, bidderRequest); + const payload = JSON.parse(request.data); + + expect(payload.privacy).to.exist; + expect(payload.privacy.gpp).to.equal(consentString); + expect(payload.privacy.gpp_sid).to.deep.equal([7]); + }); + it('supports sending hybrid mobile app parameters', function () { let appRequest = Object.assign({}, bidRequests[0], @@ -1193,9 +1318,33 @@ describe('AppNexusAdapter', function () { source: 'puburl2.com', uids: [{ id: 'pubid2' + }, { + id: 'pubid2-123' }] }] - } + }, + userIdAsEids: [{ + source: 'adserver.org', + uids: [{ id: 'sample-userid' }] + }, { + source: 'criteo.com', + uids: [{ id: 'sample-criteo-userid' }] + }, { + source: 'netid.de', + uids: [{ id: 'sample-netId-userid' }] + }, { + source: 'liveramp.com', + uids: [{ id: 'sample-idl-userid' }] + }, { + source: 'uidapi.com', + uids: [{ id: 'sample-uid2-value' }] + }, { + source: 'puburl.com', + uids: [{ id: 'pubid1' }] + }, { + source: 'puburl2.com', + uids: [{ id: 'pubid2' }, { id: 'pubid2-123' }] + }] }); const request = spec.buildRequests([bidRequest]); @@ -1236,6 +1385,10 @@ describe('AppNexusAdapter', function () { source: 'puburl2.com', id: 'pubid2' }); + expect(payload.eids).to.deep.include({ + source: 'puburl2.com', + id: 'pubid2-123' + }); }); it('should populate iab_support object at the root level if omid support is detected', function () { @@ -1584,7 +1737,10 @@ describe('AppNexusAdapter', function () { 'phone': '1234567890', 'address': '28 W 23rd St, New York, NY 10010', 'privacy_link': 'https://appnexus.com/?url=privacy_url', - 'javascriptTrackers': '' + 'javascriptTrackers': '', + 'video': { + 'content': '' + } }; let bidderRequest = { bids: [{ @@ -1598,6 +1754,7 @@ describe('AppNexusAdapter', function () { expect(result[0].native.body).to.equal('Cool description great stuff'); expect(result[0].native.cta).to.equal('Do it'); expect(result[0].native.image.url).to.equal('https://cdn.adnxs.com/img.png'); + expect(result[0].native.video.content).to.equal(''); }); } @@ -1685,7 +1842,7 @@ describe('AppNexusAdapter', function () { it('should add advertiserDomains', function () { let responseAdvertiserId = deepClone(response); - responseAdvertiserId.tags[0].ads[0].adomain = ['123']; + responseAdvertiserId.tags[0].ads[0].adomain = '123'; let bidderRequest = { bids: [{ @@ -1695,7 +1852,7 @@ describe('AppNexusAdapter', function () { } let result = spec.interpretResponse({ body: responseAdvertiserId }, { bidderRequest }); expect(Object.keys(result[0].meta)).to.include.members(['advertiserDomains']); - expect(Object.keys(result[0].meta.advertiserDomains)).to.deep.equal([]); + expect(result[0].meta.advertiserDomains).to.deep.equal(['123']); }); }); diff --git a/test/spec/modules/appushBidAdapter_spec.js b/test/spec/modules/appushBidAdapter_spec.js new file mode 100644 index 00000000000..91c50cc3dd0 --- /dev/null +++ b/test/spec/modules/appushBidAdapter_spec.js @@ -0,0 +1,372 @@ +import { expect } from 'chai'; +import { spec } from '../../../modules/appushBidAdapter.js'; +import { BANNER, VIDEO, NATIVE } from '../../../src/mediaTypes.js'; +import { getUniqueIdentifierStr } from '../../../src/utils.js'; + +const bidder = 'appush' + +describe('AppushBidAdapter', function () { + const bids = [ + { + bidId: getUniqueIdentifierStr(), + bidder: bidder, + mediaTypes: { + [BANNER]: { + sizes: [[300, 250]] + } + }, + params: { + placementId: 'testBanner', + } + }, + { + bidId: getUniqueIdentifierStr(), + bidder: bidder, + mediaTypes: { + [VIDEO]: { + playerSize: [[300, 300]], + minduration: 5, + maxduration: 60 + } + }, + params: { + placementId: 'testVideo', + } + }, + { + bidId: getUniqueIdentifierStr(), + bidder: bidder, + mediaTypes: { + [NATIVE]: { + native: { + title: { + required: true + }, + body: { + required: true + }, + icon: { + required: true, + size: [64, 64] + } + } + } + }, + params: { + placementId: 'testNative', + } + } + ]; + + const invalidBid = { + bidId: getUniqueIdentifierStr(), + bidder: bidder, + mediaTypes: { + [BANNER]: { + sizes: [[300, 250]] + } + }, + params: { + + } + } + + const bidderRequest = { + uspConsent: '1---', + gdprConsent: 'COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw', + refererInfo: { + referer: 'https://test.com' + } + }; + + describe('isBidRequestValid', function () { + it('Should return true if there are bidId, params and key parameters present', function () { + expect(spec.isBidRequestValid(bids[0])).to.be.true; + }); + it('Should return false if at least one of parameters is not present', function () { + expect(spec.isBidRequestValid(invalidBid)).to.be.false; + }); + }); + + describe('buildRequests', function () { + let serverRequest = spec.buildRequests(bids, bidderRequest); + + it('Creates a ServerRequest object with method, URL and data', function () { + expect(serverRequest).to.exist; + expect(serverRequest.method).to.exist; + expect(serverRequest.url).to.exist; + expect(serverRequest.data).to.exist; + }); + + it('Returns POST method', function () { + expect(serverRequest.method).to.equal('POST'); + }); + + it('Returns valid URL', function () { + expect(serverRequest.url).to.equal('https://hb.appush.com/pbjs'); + }); + + it('Returns general data valid', function () { + let data = serverRequest.data; + expect(data).to.be.an('object'); + expect(data).to.have.all.keys('deviceWidth', + 'deviceHeight', + 'language', + 'secure', + 'host', + 'page', + 'placements', + 'coppa', + 'ccpa', + 'gdpr', + 'tmax' + ); + expect(data.deviceWidth).to.be.a('number'); + expect(data.deviceHeight).to.be.a('number'); + expect(data.language).to.be.a('string'); + expect(data.secure).to.be.within(0, 1); + 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.ccpa).to.be.a('string'); + expect(data.tmax).to.be.a('number'); + expect(data.placements).to.have.lengthOf(3); + }); + + it('Returns valid placements', function () { + const { placements } = serverRequest.data; + for (let i = 0, len = placements.length; i < len; i++) { + const placement = placements[i]; + expect(placement.placementId).to.be.oneOf(['testBanner', 'testVideo', 'testNative']); + expect(placement.adFormat).to.be.oneOf([BANNER, VIDEO, NATIVE]); + expect(placement.bidId).to.be.a('string'); + expect(placement.schain).to.be.an('object'); + expect(placement.bidfloor).to.exist.and.to.equal(0); + expect(placement.type).to.exist.and.to.equal('publisher'); + + if (placement.adFormat === BANNER) { + expect(placement.sizes).to.be.an('array'); + } + switch (placement.adFormat) { + case BANNER: + expect(placement.sizes).to.be.an('array'); + break; + case VIDEO: + expect(placement.playerSize).to.be.an('array'); + expect(placement.minduration).to.be.an('number'); + expect(placement.maxduration).to.be.an('number'); + break; + case NATIVE: + expect(placement.native).to.be.an('object'); + break; + } + } + }); + + it('Returns data with gdprConsent and without uspConsent', function () { + delete bidderRequest.uspConsent; + serverRequest = spec.buildRequests(bids, bidderRequest); + let data = serverRequest.data; + expect(data.gdpr).to.exist; + expect(data.gdpr).to.be.a('string'); + expect(data.gdpr).to.equal(bidderRequest.gdprConsent); + expect(data.ccpa).to.not.exist; + delete bidderRequest.gdprConsent; + }); + + it('Returns data with uspConsent and without gdprConsent', function () { + bidderRequest.uspConsent = '1---'; + delete bidderRequest.gdprConsent; + serverRequest = spec.buildRequests(bids, bidderRequest); + let data = serverRequest.data; + expect(data.ccpa).to.exist; + expect(data.ccpa).to.be.a('string'); + expect(data.ccpa).to.equal(bidderRequest.uspConsent); + expect(data.gdpr).to.not.exist; + }); + + it('Returns empty data if no valid requests are passed', function () { + serverRequest = spec.buildRequests([], bidderRequest); + let data = serverRequest.data; + expect(data.placements).to.be.an('array').that.is.empty; + }); + }); + + describe('interpretResponse', function () { + it('Should interpret banner response', function () { + const banner = { + body: [{ + mediaType: 'banner', + width: 300, + height: 250, + cpm: 0.4, + ad: 'Test', + requestId: '23fhj33i987f', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1', + meta: { + advertiserDomains: ['google.com'], + advertiserId: 1234 + } + }] + }; + let bannerResponses = spec.interpretResponse(banner); + expect(bannerResponses).to.be.an('array').that.is.not.empty; + let dataItem = bannerResponses[0]; + expect(dataItem).to.have.all.keys('requestId', 'cpm', 'width', 'height', 'ad', 'ttl', 'creativeId', + 'netRevenue', 'currency', 'dealId', 'mediaType', 'meta'); + expect(dataItem.requestId).to.equal(banner.body[0].requestId); + expect(dataItem.cpm).to.equal(banner.body[0].cpm); + expect(dataItem.width).to.equal(banner.body[0].width); + expect(dataItem.height).to.equal(banner.body[0].height); + expect(dataItem.ad).to.equal(banner.body[0].ad); + expect(dataItem.ttl).to.equal(banner.body[0].ttl); + expect(dataItem.creativeId).to.equal(banner.body[0].creativeId); + expect(dataItem.netRevenue).to.be.true; + expect(dataItem.currency).to.equal(banner.body[0].currency); + expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains'); + }); + it('Should interpret video response', function () { + const video = { + body: [{ + vastUrl: 'test.com', + mediaType: 'video', + cpm: 0.5, + requestId: '23fhj33i987f', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1', + meta: { + advertiserDomains: ['google.com'], + advertiserId: 1234 + } + }] + }; + let videoResponses = spec.interpretResponse(video); + expect(videoResponses).to.be.an('array').that.is.not.empty; + + let dataItem = videoResponses[0]; + expect(dataItem).to.have.all.keys('requestId', 'cpm', 'vastUrl', 'ttl', 'creativeId', + 'netRevenue', 'currency', 'dealId', 'mediaType', 'meta'); + expect(dataItem.requestId).to.equal('23fhj33i987f'); + expect(dataItem.cpm).to.equal(0.5); + expect(dataItem.vastUrl).to.equal('test.com'); + expect(dataItem.ttl).to.equal(120); + expect(dataItem.creativeId).to.equal('2'); + expect(dataItem.netRevenue).to.be.true; + expect(dataItem.currency).to.equal('USD'); + expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains'); + }); + it('Should interpret native response', function () { + const native = { + body: [{ + mediaType: 'native', + native: { + clickUrl: 'test.com', + title: 'Test', + image: 'test.com', + impressionTrackers: ['test.com'], + }, + ttl: 120, + cpm: 0.4, + requestId: '23fhj33i987f', + creativeId: '2', + netRevenue: true, + currency: 'USD', + meta: { + advertiserDomains: ['google.com'], + advertiserId: 1234 + } + }] + }; + let nativeResponses = spec.interpretResponse(native); + expect(nativeResponses).to.be.an('array').that.is.not.empty; + + let dataItem = nativeResponses[0]; + expect(dataItem).to.have.keys('requestId', 'cpm', 'ttl', 'creativeId', 'netRevenue', 'currency', 'mediaType', 'native', 'meta'); + expect(dataItem.native).to.have.keys('clickUrl', 'impressionTrackers', 'title', 'image') + expect(dataItem.requestId).to.equal('23fhj33i987f'); + expect(dataItem.cpm).to.equal(0.4); + expect(dataItem.native.clickUrl).to.equal('test.com'); + expect(dataItem.native.title).to.equal('Test'); + expect(dataItem.native.image).to.equal('test.com'); + expect(dataItem.native.impressionTrackers).to.be.an('array').that.is.not.empty; + expect(dataItem.native.impressionTrackers[0]).to.equal('test.com'); + expect(dataItem.ttl).to.equal(120); + expect(dataItem.creativeId).to.equal('2'); + expect(dataItem.netRevenue).to.be.true; + expect(dataItem.currency).to.equal('USD'); + expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains'); + }); + it('Should return an empty array if invalid banner response is passed', function () { + const invBanner = { + body: [{ + width: 300, + cpm: 0.4, + ad: 'Test', + requestId: '23fhj33i987f', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1' + }] + }; + + let serverResponses = spec.interpretResponse(invBanner); + expect(serverResponses).to.be.an('array').that.is.empty; + }); + it('Should return an empty array if invalid video response is passed', function () { + const invVideo = { + body: [{ + mediaType: 'video', + cpm: 0.5, + requestId: '23fhj33i987f', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1' + }] + }; + let serverResponses = spec.interpretResponse(invVideo); + expect(serverResponses).to.be.an('array').that.is.empty; + }); + it('Should return an empty array if invalid native response is passed', function () { + const invNative = { + body: [{ + mediaType: 'native', + clickUrl: 'test.com', + title: 'Test', + impressionTrackers: ['test.com'], + ttl: 120, + requestId: '23fhj33i987f', + creativeId: '2', + netRevenue: true, + currency: 'USD', + }] + }; + let serverResponses = spec.interpretResponse(invNative); + expect(serverResponses).to.be.an('array').that.is.empty; + }); + it('Should return an empty array if invalid response is passed', function () { + const invalid = { + body: [{ + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1' + }] + }; + let serverResponses = spec.interpretResponse(invalid); + expect(serverResponses).to.be.an('array').that.is.empty; + }); + }); +}); diff --git a/test/spec/modules/arcspanRtdProvider_spec.js b/test/spec/modules/arcspanRtdProvider_spec.js new file mode 100644 index 00000000000..c75075d8e05 --- /dev/null +++ b/test/spec/modules/arcspanRtdProvider_spec.js @@ -0,0 +1,187 @@ +import { arcspanSubmodule } from 'modules/arcspanRtdProvider.js'; +import { expect } from 'chai'; +import { loadExternalScript } from 'src/adloader.js'; + +describe('arcspanRtdProvider', function () { + describe('init', function () { + afterEach(function () { + window.arcobj1 = undefined; + window.arcobj2 = undefined; + }); + + it('successfully initializes with a valid silo ID', function () { + expect(arcspanSubmodule.init(getGoodConfig())).to.equal(true); + expect(loadExternalScript.called).to.be.ok; + expect(loadExternalScript.args[0][0]).to.deep.equal('https://silo13.p7cloud.net/as.js'); + loadExternalScript.resetHistory(); + }); + + it('fails to initialize with a missing silo ID', function () { + expect(arcspanSubmodule.init(getBadConfig())).to.equal(false); + expect(loadExternalScript.called).to.be.not.ok; + loadExternalScript.resetHistory(); + }); + + it('drops localhost script for test silo', function () { + expect(arcspanSubmodule.init(getTestConfig())).to.equal(true); + expect(loadExternalScript.called).to.be.ok; + expect(loadExternalScript.args[0][0]).to.deep.equal('https://localhost:8080/as.js'); + loadExternalScript.resetHistory(); + }); + }); + + describe('alterBidRequests', function () { + afterEach(function () { + window.arcobj1 = undefined; + window.arcobj2 = undefined; + }); + + it('alters the bid request 1', function () { + setIAB({ + raw: { + images: [ + 'Religion & Spirituality', + 'Medical Health>Substance Abuse', + 'Religion & Spirituality>Astrology', + 'Medical Health', + 'Events & Attractions', + ], + }, + codes: { + images: ['IAB23-10', 'IAB7', 'IAB7-42', 'IAB15-1'], + }, + newcodes: { + images: ['150', '453', '311', '456', '286'], + }, + }); + + var reqBidsConfigObj = {}; + reqBidsConfigObj.ortb2Fragments = {}; + reqBidsConfigObj.ortb2Fragments.global = {}; + arcspanSubmodule.getBidRequestData(reqBidsConfigObj, function () { + expect(reqBidsConfigObj.ortb2Fragments.global.site.name).to.equal( + 'arcspan' + ); + expect(reqBidsConfigObj.ortb2Fragments.global.site.keywords).to.equal( + 'Religion & Spirituality,Medical Health>Substance Abuse,Religion & Spirituality>Astrology,Medical Health,Events & Attractions' + ); + expect(reqBidsConfigObj.ortb2Fragments.global.site.content.data[0].ext.segtax).to.equal(6); + expect(reqBidsConfigObj.ortb2Fragments.global.site.cat).to.eql([ + 'IAB23_10', + 'IAB7', + 'IAB7_42', + 'IAB15_1', + ]); + expect(reqBidsConfigObj.ortb2Fragments.global.site.sectioncat).to.eql([ + 'IAB23_10', + 'IAB7', + 'IAB7_42', + 'IAB15_1' + ]); + expect(reqBidsConfigObj.ortb2Fragments.global.site.pagecat).to.eql([ + 'IAB23_10', + 'IAB7', + 'IAB7_42', + 'IAB15_1', + ]); + expect(reqBidsConfigObj.ortb2Fragments.global.site.content.data[0].segment).to.eql([ + { id: '150' }, + { id: '453' }, + { id: '311' }, + { id: '456' }, + { id: '286' } + ]); + }); + }); + + it('alters the bid request 2', function () { + setIAB({ + raw: { text: ['Sports', 'Sports>Soccer'] }, + codes: { text: ['IAB17', 'IAB17-44'] }, + newcodes: { text: ['483', '533'] }, + }); + + var reqBidsConfigObj = {}; + reqBidsConfigObj.ortb2Fragments = {}; + reqBidsConfigObj.ortb2Fragments.global = {}; + arcspanSubmodule.getBidRequestData(reqBidsConfigObj, function () { + expect(reqBidsConfigObj.ortb2Fragments.global.site.name).to.equal( + 'arcspan' + ); + expect(reqBidsConfigObj.ortb2Fragments.global.site.keywords).to.equal( + 'Sports,Sports>Soccer' + ); + expect(reqBidsConfigObj.ortb2Fragments.global.site.content.data[0].ext.segtax).to.equal(6); + expect(reqBidsConfigObj.ortb2Fragments.global.site.cat).to.eql([ + 'IAB17', + 'IAB17_44', + ]); + expect(reqBidsConfigObj.ortb2Fragments.global.site.sectioncat).to.eql([ + 'IAB17', + 'IAB17_44' + ]); + expect(reqBidsConfigObj.ortb2Fragments.global.site.pagecat).to.eql([ + 'IAB17', + 'IAB17_44', + ]); + expect(reqBidsConfigObj.ortb2Fragments.global.site.content.data[0].segment).to.eql([ + { id: '483' }, + { id: '533' } + ]); + }); + }); + }); +}); + +function getGoodConfig() { + return { + name: 'arcspan', + waitForIt: true, + params: { + silo: 13, + }, + }; +} + +function getBadConfig() { + return { + name: 'arcspan', + waitForIt: true, + params: { + notasilo: 1, + }, + }; +} + +function getTestConfig() { + return { + name: 'arcspan', + waitForIt: true, + params: { + silo: 'test', + }, + }; +} + +function setIAB(vjson) { + window.arcobj2 = {}; + window.arcobj2.cat = 0; + if (typeof vjson.codes != 'undefined') { + window.arcobj2.cat = 1; + if (typeof vjson.codes.images != 'undefined') { + vjson.codes.images.forEach(function f(e, i) { + vjson.codes.images[i] = e.replace('-', '_'); + }); + } + if (typeof vjson.codes.text != 'undefined') { + vjson.codes.text.forEach(function f(e, i) { + vjson.codes.text[i] = e.replace('-', '_'); + }); + } + window.arcobj2.sampled = 1; + window.arcobj1 = {}; + window.arcobj1.page_iab_codes = vjson.codes; + window.arcobj1.page_iab = vjson.raw; + window.arcobj1.page_iab_newcodes = vjson.newcodes; + } +} diff --git a/test/spec/modules/beopBidAdapter_spec.js b/test/spec/modules/beopBidAdapter_spec.js index c6001c3ba2e..ad096fd6526 100644 --- a/test/spec/modules/beopBidAdapter_spec.js +++ b/test/spec/modules/beopBidAdapter_spec.js @@ -216,4 +216,56 @@ describe('BeOp Bid Adapter tests', () => { expect(triggerPixelStub.getCall(0).args[0]).to.exist.and.to.include('pid=5a8af500c9e77c00017e4cad'); }); }); + + describe('Ensure keywords is always array of string', function () { + let bidRequests = []; + afterEach(function () { + bidRequests = []; + }); + + it('should work with keywords as an array', function () { + let bid = Object.assign({}, validBid); + bid.params.keywords = ['a', 'b']; + bidRequests.push(bid); + config.setConfig({ + currency: { adServerCurrency: 'USD' } + }); + const request = spec.buildRequests(bidRequests, {}); + const payload = JSON.parse(request.data); + const url = request.url; + expect(payload.kwds).to.exist; + expect(payload.kwds).to.include('a'); + expect(payload.kwds).to.include('b'); + }); + + it('should work with keywords as a string', function () { + let bid = Object.assign({}, validBid); + bid.params.keywords = 'list of keywords'; + bidRequests.push(bid); + config.setConfig({ + currency: { adServerCurrency: 'USD' } + }); + const request = spec.buildRequests(bidRequests, {}); + const payload = JSON.parse(request.data); + const url = request.url; + expect(payload.kwds).to.exist; + expect(payload.kwds).to.include('list of keywords'); + }); + + it('should work with keywords as a string containing a comma', function () { + let bid = Object.assign({}, validBid); + bid.params.keywords = 'list, of, keywords'; + bidRequests.push(bid); + config.setConfig({ + currency: { adServerCurrency: 'USD' } + }); + const request = spec.buildRequests(bidRequests, {}); + const payload = JSON.parse(request.data); + const url = request.url; + expect(payload.kwds).to.exist; + expect(payload.kwds).to.include('list'); + expect(payload.kwds).to.include('of'); + expect(payload.kwds).to.include('keywords'); + }) + }) }); diff --git a/test/spec/modules/bidwatchAnalyticsAdapter_spec.js b/test/spec/modules/bidwatchAnalyticsAdapter_spec.js index 9e9d7dbe156..a72bb012fa1 100644 --- a/test/spec/modules/bidwatchAnalyticsAdapter_spec.js +++ b/test/spec/modules/bidwatchAnalyticsAdapter_spec.js @@ -297,7 +297,6 @@ describe('BidWatch Analytics', function () { expect(message.auctionEnd[0]).to.have.property('bidderRequests').and.to.have.lengthOf(1); expect(message.auctionEnd[0].bidderRequests[0]).to.have.property('gdprConsent'); expect(message.auctionEnd[0].bidderRequests[0].gdprConsent).not.to.have.property('vendorData'); - sinon.assert.callCount(bidwatchAnalytics.track, 4); }); it('test bidWon', function() { @@ -318,7 +317,6 @@ describe('BidWatch Analytics', function () { expect(message).not.to.have.property('ad'); expect(message).to.have.property('adId') expect(message).to.have.property('cpmIncrement').and.to.equal(27.4276); - sinon.assert.callCount(bidwatchAnalytics.track, 1); }); }); }); diff --git a/test/spec/modules/bliinkBidAdapter_spec.js b/test/spec/modules/bliinkBidAdapter_spec.js index b8994b86847..8e96bd76940 100644 --- a/test/spec/modules/bliinkBidAdapter_spec.js +++ b/test/spec/modules/bliinkBidAdapter_spec.js @@ -130,7 +130,7 @@ const getConfigCreative = () => { creativeId: '34567erty', width: 300, height: 250, - ttl: 3600, + ttl: 300, netRevenue: true, } } @@ -145,7 +145,7 @@ const getConfigCreativeVideo = (isNoVast) => { requestId: '6a204ce130280d', width: 300, height: 250, - ttl: 3600, + ttl: 300, netRevenue: true, } } @@ -395,7 +395,7 @@ const testsInterpretResponse = [ mediaType: 'video', netRevenue: true, requestId: '2def0c5b2a7f6e', - ttl: 3600, + ttl: 300, vastXml, vastUrl: 'data:text/xml;charset=utf-8;base64,' + btoa(vastXml.replace(/\\"/g, '"')) }] @@ -421,7 +421,7 @@ const testsInterpretResponse = [ mediaType: 'banner', netRevenue: true, requestId: '2def0c5b2a7f6e', - ttl: 3600, + ttl: 300, width: 300 }] }, @@ -505,7 +505,7 @@ const testsBuildBid = [ netRevenue: true, vastXml: getConfigCreativeVideo().vastXml, vastUrl: 'data:text/xml;charset=utf-8;base64,' + btoa(getConfigCreativeVideo().vastXml.replace(/\\"/g, '"')), - ttl: 3600, + ttl: 300, } }, { @@ -535,7 +535,7 @@ const testsBuildBid = [ netRevenue: true, vastXml: getConfigCreativeVideo().vastXml, vastUrl: 'data:text/xml;charset=utf-8;base64,' + btoa(getConfigCreativeVideo().vastXml.replace(/\\"/g, '"')), - ttl: 3600, + ttl: 300, } }, { @@ -552,7 +552,7 @@ const testsBuildBid = [ height: 250, creativeId: getConfigCreative().creativeId, ad: getConfigBannerBid().creative.banner.adm, - ttl: 3600, + ttl: 300, netRevenue: true, } } diff --git a/test/spec/modules/brightcomSSPBidAdapter_spec.js b/test/spec/modules/brightcomSSPBidAdapter_spec.js new file mode 100644 index 00000000000..6f35a7a290b --- /dev/null +++ b/test/spec/modules/brightcomSSPBidAdapter_spec.js @@ -0,0 +1,411 @@ +import { expect } from 'chai'; +import * as utils from 'src/utils.js'; +import { spec } from 'modules/brightcomSSPBidAdapter'; +import { newBidder } from 'src/adapters/bidderFactory.js'; +import {config} from '../../../src/config'; + +const URL = 'https://rt.marphezis.com/hb'; + +describe('brightcomSSPBidAdapter', function() { + const adapter = newBidder(spec); + let element, win; + let bidRequests; + let sandbox; + + beforeEach(function() { + element = { + x: 0, + y: 0, + + width: 0, + height: 0, + + getBoundingClientRect: () => { + return { + width: element.width, + height: element.height, + + left: element.x, + top: element.y, + right: element.x + element.width, + bottom: element.y + element.height + }; + } + }; + win = { + document: { + visibilityState: 'visible' + }, + + innerWidth: 800, + innerHeight: 600 + }; + bidRequests = [{ + 'bidder': 'bcmssp', + 'params': { + 'publisherId': 1234567 + }, + 'adUnitCode': 'adunit-code', + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250], [300, 600]] + } + }, + 'bidId': '5fb26ac22bde4', + 'bidderRequestId': '4bf93aeb730cb9', + 'auctionId': 'ffe9a1f7-7b67-4bda-a8e0-9ee5dc9f442e', + 'schain': { + 'ver': '1.0', + 'complete': 1, + 'nodes': [ + { + 'asi': 'exchange1.com', + 'sid': '1234', + 'hp': 1, + 'rid': 'bid-request-1', + 'name': 'publisher', + 'domain': 'publisher.com' + } + ] + }, + }]; + + sandbox = sinon.sandbox.create(); + sandbox.stub(document, 'getElementById').withArgs('adunit-code').returns(element); + sandbox.stub(utils, 'getWindowTop').returns(win); + sandbox.stub(utils, 'getWindowSelf').returns(win); + }); + + afterEach(function() { + sandbox.restore(); + }); + + describe('isBidRequestValid', function () { + let bid = { + 'bidder': 'bcmssp', + 'params': { + 'publisherId': 1234567 + }, + 'adUnitCode': 'adunit-code', + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250], [300, 600]] + } + }, + 'bidId': '5fb26ac22bde4', + 'bidderRequestId': '4bf93aeb730cb9', + 'auctionId': 'ffe9a1f7-7b67-4bda-a8e0-9ee5dc9f442e', + }; + + it('should return true when required params found', function () { + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('should return false when publisherId not passed correctly', function () { + bid.params.publisherId = undefined; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should return false when require params are not passed', function () { + let bid = Object.assign({}, bid); + bid.params = {}; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + }); + + describe('buildRequests', function () { + it('sends bid request to our endpoint via POST', function () { + const request = spec.buildRequests(bidRequests); + expect(request.method).to.equal('POST'); + }); + + it('request url should match our endpoint url', function () { + const request = spec.buildRequests(bidRequests); + expect(request.url).to.equal(URL); + }); + + it('sets the proper banner object', function() { + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + expect(payload.imp[0].banner.format).to.deep.equal([{w: 300, h: 250}, {w: 300, h: 600}]); + }); + + it('accepts a single array as a size', function() { + bidRequests[0].mediaTypes.banner.sizes = [300, 250]; + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + expect(payload.imp[0].banner.format).to.deep.equal([{w: 300, h: 250}]); + }); + + it('sends bidfloor param if present', function () { + bidRequests[0].params.bidFloor = 0.05; + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + expect(payload.imp[0].bidfloor).to.equal(0.05); + }); + + it('sends tagid', function () { + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + expect(payload.imp[0].tagid).to.equal('adunit-code'); + }); + + it('sends publisher id', function () { + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + expect(payload.site.publisher.id).to.equal(1234567); + }); + + it('sends gdpr info if exists', function () { + const consentString = 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A=='; + const bidderRequest = { + 'bidderCode': 'bcmssp', + 'auctionId': '1d1a030790a437', + 'bidderRequestId': '22edbae2744bf5', + 'timeout': 3000, + gdprConsent: { + consentString: consentString, + gdprApplies: true + }, + refererInfo: { + page: 'http://example.com/page.html', + domain: 'example.com', + } + }; + bidderRequest.bids = bidRequests; + + const data = JSON.parse(spec.buildRequests(bidRequests, bidderRequest).data); + + expect(data.regs.ext.gdpr).to.exist.and.to.be.a('number'); + expect(data.regs.ext.gdpr).to.equal(1); + expect(data.user.ext.consent).to.exist.and.to.be.a('string'); + expect(data.user.ext.consent).to.equal(consentString); + }); + + it('sends us_privacy', function () { + const bidderRequest = { + uspConsent: '1YYY' + }; + const data = JSON.parse(spec.buildRequests(bidRequests, bidderRequest).data) + + expect(data.regs).to.not.equal(null); + expect(data.regs.ext).to.not.equal(null); + expect(data.regs.ext.us_privacy).to.equal('1YYY'); + }); + + it('sends coppa', function () { + sandbox.stub(config, 'getConfig').withArgs('coppa').returns(true); + + const data = JSON.parse(spec.buildRequests(bidRequests).data) + expect(data.regs).to.not.be.undefined; + expect(data.regs.coppa).to.equal(1); + }); + + it('sends schain', function () { + const data = JSON.parse(spec.buildRequests(bidRequests).data); + expect(data).to.not.be.undefined; + expect(data.source).to.not.be.undefined; + expect(data.source.ext).to.not.be.undefined; + expect(data.source.ext.schain).to.not.be.undefined; + expect(data.source.ext.schain.complete).to.equal(1); + expect(data.source.ext.schain.ver).to.equal('1.0'); + expect(data.source.ext.schain.nodes).to.not.be.undefined; + expect(data.source.ext.schain.nodes).to.lengthOf(1); + expect(data.source.ext.schain.nodes[0].asi).to.equal('exchange1.com'); + expect(data.source.ext.schain.nodes[0].sid).to.equal('1234'); + expect(data.source.ext.schain.nodes[0].hp).to.equal(1); + expect(data.source.ext.schain.nodes[0].rid).to.equal('bid-request-1'); + expect(data.source.ext.schain.nodes[0].name).to.equal('publisher'); + expect(data.source.ext.schain.nodes[0].domain).to.equal('publisher.com'); + }); + + it('sends user eid parameters', function () { + bidRequests[0].userIdAsEids = [{ + source: 'pubcid.org', + uids: [{ + id: 'userid_pubcid' + }] + }, { + source: 'adserver.org', + uids: [{ + id: 'userid_ttd', + ext: { + rtiPartner: 'TDID' + } + }] + } + ]; + + const data = JSON.parse(spec.buildRequests(bidRequests).data); + + expect(data.user).to.not.be.undefined; + expect(data.user.ext).to.not.be.undefined; + expect(data.user.ext.eids).to.not.be.undefined; + expect(data.user.ext.eids).to.deep.equal(bidRequests[0].userIdAsEids); + }); + + it('sends user id parameters', function () { + const userId = { + sharedid: { + id: '01*******', + third: '01E*******' + } + }; + + bidRequests[0].userId = userId; + + const data = JSON.parse(spec.buildRequests(bidRequests).data); + expect(data.user).to.not.be.undefined; + expect(data.user.ext).to.not.be.undefined; + expect(data.user.ext.ids).is.deep.equal(userId); + }); + + context('when element is fully in view', function() { + it('returns 100', function() { + Object.assign(element, { width: 600, height: 400 }); + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + expect(payload.imp[0].banner.ext.viewability).to.equal(100); + }); + }); + + context('when element is out of view', function() { + it('returns 0', function() { + Object.assign(element, { x: -300, y: 0, width: 207, height: 320 }); + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + expect(payload.imp[0].banner.ext.viewability).to.equal(0); + }); + }); + + context('when element is partially in view', function() { + it('returns percentage', function() { + Object.assign(element, { width: 800, height: 800 }); + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + expect(payload.imp[0].banner.ext.viewability).to.equal(75); + }); + }); + + context('when width or height of the element is zero', function() { + it('try to use alternative values', function() { + Object.assign(element, { width: 0, height: 0 }); + bidRequests[0].mediaTypes.banner.sizes = [[800, 2400]]; + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + expect(payload.imp[0].banner.ext.viewability).to.equal(25); + }); + }); + + context('when nested iframes', function() { + it('returns \'na\'', function() { + Object.assign(element, { width: 600, height: 400 }); + + utils.getWindowTop.restore(); + utils.getWindowSelf.restore(); + sandbox.stub(utils, 'getWindowTop').returns(win); + sandbox.stub(utils, 'getWindowSelf').returns({}); + + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + expect(payload.imp[0].banner.ext.viewability).to.equal('na'); + }); + }); + + context('when tab is inactive', function() { + it('returns 0', function() { + Object.assign(element, { width: 600, height: 400 }); + + utils.getWindowTop.restore(); + win.document.visibilityState = 'hidden'; + sandbox.stub(utils, 'getWindowTop').returns(win); + + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + expect(payload.imp[0].banner.ext.viewability).to.equal(0); + }); + }); + }); + + describe('interpretResponse', function () { + let response; + beforeEach(function () { + response = { + body: { + 'id': '37386aade21a71', + 'seatbid': [{ + 'bid': [{ + 'id': '376874781', + 'impid': '283a9f4cd2415d', + 'price': 0.35743275, + 'nurl': '', + 'adm': '', + 'w': 300, + 'h': 250, + 'adomain': ['example.com'] + }] + }] + } + }; + }); + + it('should get the correct bid response', function () { + let expectedResponse = [{ + 'requestId': '283a9f4cd2415d', + 'cpm': 0.35743275, + 'width': 300, + 'height': 250, + 'creativeId': '376874781', + 'currency': 'USD', + 'netRevenue': true, + 'mediaType': 'banner', + 'ad': `
`, + 'ttl': 60, + 'meta': { + 'advertiserDomains': ['example.com'] + } + }]; + + let result = spec.interpretResponse(response); + expect(result[0]).to.deep.equal(expectedResponse[0]); + }); + + it('crid should default to the bid id if not on the response', function () { + let expectedResponse = [{ + 'requestId': '283a9f4cd2415d', + 'cpm': 0.35743275, + 'width': 300, + 'height': 250, + 'creativeId': response.body.seatbid[0].bid[0].id, + 'currency': 'USD', + 'netRevenue': true, + 'mediaType': 'banner', + 'ad': `
`, + 'ttl': 60, + 'meta': { + 'advertiserDomains': ['example.com'] + } + }]; + + let result = spec.interpretResponse(response); + expect(result[0]).to.deep.equal(expectedResponse[0]); + }); + + it('handles empty bid response', function () { + let response = { + body: '' + }; + let result = spec.interpretResponse(response); + expect(result.length).to.equal(0); + }); + }); + + describe('getUserSyncs ', () => { + let syncOptions = {iframeEnabled: true, pixelEnabled: true}; + + it('should not return', () => { + let returnStatement = spec.getUserSyncs(syncOptions, []); + expect(returnStatement).to.be.empty; + }); + }); +}); diff --git a/test/spec/modules/browsiRtdProvider_spec.js b/test/spec/modules/browsiRtdProvider_spec.js index 19483047827..75120aa7505 100644 --- a/test/spec/modules/browsiRtdProvider_spec.js +++ b/test/spec/modules/browsiRtdProvider_spec.js @@ -252,7 +252,8 @@ describe('browsi Real time data sub module', function () { }) it('should send event if type is correct', function () { sendPageviewEvent('PAGEVIEW') - + const pageViewEvent = new CustomEvent('browsi_pageview', {}); + window.dispatchEvent(pageViewEvent); const expectedCall = { vendor: 'browsi', type: 'pageview', diff --git a/test/spec/modules/captifyRtdProvider_spec.js b/test/spec/modules/captifyRtdProvider_spec.js new file mode 100644 index 00000000000..2e1052e000f --- /dev/null +++ b/test/spec/modules/captifyRtdProvider_spec.js @@ -0,0 +1,253 @@ +import {addSegmentData, captifySubmodule, getMatchingBidders, setCaptifyTargeting} from 'modules/captifyRtdProvider.js'; +import {server} from 'test/mocks/xhr.js'; +import {config} from 'src/config.js'; +import {deepAccess} from '../../../src/utils'; + +const responseHeader = {'Content-Type': 'application/json'}; +const defaultRequestUrl = 'https://live-classification.cpx.to/prebid-segments'; + +describe('captifyRtdProvider', function () { + describe('init function', function () { + it('successfully instantiates, when configured properly', function () { + const config = { + params: { + pubId: 123456, + bidders: ['appnexus'], + } + }; + expect(captifySubmodule.init(config, null)).to.equal(true); + }); + + it('return false on init, when config is invalid', function () { + const config = { + params: {} + }; + expect(captifySubmodule.init(config, null)).to.equal(false); + expect(captifySubmodule.init(null, null)).to.equal(false); + }); + + it('return false on init, when pubId is absent', function () { + const config = { + params: { + bidders: ['appnexus'], + } + }; + expect(captifySubmodule.init(config, null)).to.equal(false); + expect(captifySubmodule.init(null, null)).to.equal(false); + }); + + it('return false on init, when bidders is empty array', function () { + const config = { + params: { + bidders: [], + pubId: 123, + } + }; + expect(captifySubmodule.init(config, null)).to.equal(false); + expect(captifySubmodule.init(null, null)).to.equal(false); + }); + }); + + describe('addSegmentData function', function () { + it('adds segment data', function () { + config.resetConfig(); + + let data = { + xandr: [111111, 222222], + }; + + addSegmentData(['appnexus'], data); + expect(deepAccess(config.getConfig(), 'appnexusAuctionKeywords.captify_segments')).to.eql(data['xandr']); + }); + }); + + describe('getMatchingBidders function', function () { + it('returns only bidders that used within adUnits', function () { + const moduleConfig = { + params: { + pubId: 123, + bidders: ['appnexus', 'pubmatic'], + } + }; + let reqBidsConfigObj = { + adUnits: [{ + bids: [{ + bidder: 'appnexus', + params: { + placementId: 13144370 + } + }] + }] + }; + + let matchedBidders = getMatchingBidders(moduleConfig, reqBidsConfigObj); + expect(matchedBidders).to.eql(['appnexus']); + }); + + it('return empty result, when there are no bidders configured for adUnits', function () { + const moduleConfig = { + params: { + pubId: 123, + bidders: ['pubmatic'], + } + }; + let reqBidsConfigObj = { + adUnits: [{ + bids: [] + }] + }; + expect(getMatchingBidders(moduleConfig, reqBidsConfigObj)).to.be.empty; + }); + + it('return empty result, when there are no bidders matched', function () { + const moduleConfig = { + params: { + pubId: 123, + bidders: ['pubmatic'], + } + }; + let reqBidsConfigObj = { + adUnits: [{ + bids: [{ + params: { + bidder: 'appnexus', + placementId: 13144370, + } + }] + }] + }; + expect(getMatchingBidders(moduleConfig, reqBidsConfigObj)).to.be.empty; + }); + + it('return empty result, when there are no adUnits with bidders', function () { + const moduleConfig = { + params: { + pubId: 123, + bidders: ['pubmatic'], + } + }; + let reqBidsConfigObj = { + adUnits: [{ + bids: [{ + params: { + placementId: 13144370, + } + }] + }] + }; + expect(getMatchingBidders(moduleConfig, reqBidsConfigObj)).to.be.empty; + }); + }); + + describe('integration test with mock live-classification response', function () { + const moduleConfig = { + params: { + pubId: 123456, + bidders: ['appnexus'], + } + }; + + const reqBidsConfigObj = { + adUnits: [{ + bids: [{ + bidder: 'appnexus', + params: { + placementId: 13144370 + } + }, { + bidder: 'other' + }] + }] + }; + + const expectedUrlParam = 'http://localhost:9876/context.html'; + + it('gets data from async request and adds segment data', function () { + config.resetConfig(); + let data = {xandr: [111111, 222222]}; + const callbackSpy = sinon.spy(); + setCaptifyTargeting(reqBidsConfigObj, callbackSpy, moduleConfig, {}); + let request = server.requests[0]; + let requestBody = JSON.parse(server.requests[0].requestBody); + expect(request.url).to.be.eq(defaultRequestUrl); + expect(requestBody['pubId']).to.eq(moduleConfig.params.pubId); + expect(requestBody['url']).to.eq(expectedUrlParam); + request.respond(200, responseHeader, JSON.stringify(data)); + expect(deepAccess(config.getConfig(), 'appnexusAuctionKeywords.captify_segments')).to.eql(data['xandr']); + expect(callbackSpy.calledOnce).to.be.true; + }); + + it('do not send classification request, if no matching adUnits on page', function () { + config.resetConfig(); + let reqBidsConfigObj = { + adUnits: [{ + bids: [ + {bidder: 'pubmatic'} + ] + }] + }; + const callbackSpy = sinon.spy(); + setCaptifyTargeting(reqBidsConfigObj, callbackSpy, moduleConfig, {}); + expect(server.requests).to.be.empty; + }); + + it('gets data from async request and adds segment data, using URL from config', function () { + config.resetConfig(); + let data = {xandr: [111111, 222222]}; + const callbackSpy = sinon.spy(); + const testUrl = 'http://my-test-server.com/path'; + const conf = { + params: { + url: testUrl, + pubId: 123456, + bidders: ['appnexus'], + } + }; + setCaptifyTargeting(reqBidsConfigObj, callbackSpy, conf, {}); + let request = server.requests[0]; + let requestBody = JSON.parse(server.requests[0].requestBody); + expect(request.url).to.be.eq(testUrl); + expect(requestBody['pubId']).to.eq(conf.params.pubId); + expect(requestBody['url']).to.eq(expectedUrlParam); + request.respond(200, responseHeader, JSON.stringify(data)); + expect(deepAccess(config.getConfig(), 'appnexusAuctionKeywords.captify_segments')).to.eql(data['xandr']); + expect(callbackSpy.calledOnce).to.be.true; + }); + + it('do not set anything, in case server responded with 202', function () { + config.resetConfig(); + const callbackSpy = sinon.spy(); + setCaptifyTargeting(reqBidsConfigObj, callbackSpy, moduleConfig, {}); + let request = server.requests[0]; + let requestBody = JSON.parse(server.requests[0].requestBody); + expect(request.url).to.be.eq(defaultRequestUrl); + expect(requestBody['pubId']).to.eq(moduleConfig.params.pubId); + expect(requestBody['url']).to.eq(expectedUrlParam); + request.respond(202, responseHeader, ''); + expect(deepAccess(config.getConfig(), 'appnexusAuctionKeywords.captify_segments')).to.be.undefined; + expect(callbackSpy.calledOnce).to.be.true; + }); + + it('do not set anything, in case server responded with error', function () { + config.resetConfig(); + const callbackSpy = sinon.spy(); + setCaptifyTargeting(reqBidsConfigObj, callbackSpy, moduleConfig, {}); + let request = server.requests[0]; + expect(request.url).to.be.eq(defaultRequestUrl); + request.respond(500, null, ''); + expect(deepAccess(config.getConfig(), 'appnexusAuctionKeywords.captify_segments')).to.be.undefined; + expect(callbackSpy.calledOnce).to.be.true; + }); + + it('do not set anything, in case request error', function () { + config.resetConfig(); + const callbackSpy = sinon.spy(); + setCaptifyTargeting(reqBidsConfigObj, callbackSpy, moduleConfig, {}); + let request = server.requests[0]; + expect(request.url).to.be.eq(defaultRequestUrl); + request.abort('test error'); + expect(deepAccess(config.getConfig(), 'appnexusAuctionKeywords.captify_segments')).to.be.undefined; + expect(callbackSpy.calledOnce).to.be.true; + }); + }); +}); diff --git a/test/spec/modules/cointrafficBidAdapter_spec.js b/test/spec/modules/cointrafficBidAdapter_spec.js index 24570de5083..79775f7b135 100644 --- a/test/spec/modules/cointrafficBidAdapter_spec.js +++ b/test/spec/modules/cointrafficBidAdapter_spec.js @@ -1,13 +1,15 @@ +import sinon from 'sinon' import { expect } from 'chai'; import { spec } from 'modules/cointrafficBidAdapter.js'; import { config } from 'src/config.js' import * as utils from 'src/utils.js' -const ENDPOINT_URL = 'https://apps-pbd.ctengine.io/pb/tmp'; +const ENDPOINT_URL = 'https://apps-pbd.ctraffic.io/pb/tmp'; describe('cointrafficBidAdapter', function () { describe('isBidRequestValid', function () { - let bid = { + /** @type {BidRequest} */ + let bidRequest = { bidder: 'cointraffic', params: { placementId: 'testPlacementId' @@ -22,11 +24,12 @@ describe('cointrafficBidAdapter', function () { }; it('should return true where required params found', function () { - expect(spec.isBidRequestValid(bid)).to.equal(true); + expect(spec.isBidRequestValid(bidRequest)).to.equal(true); }); }); describe('buildRequests', function () { + /** @type {BidRequest[]} */ let bidRequests = [ { bidder: 'cointraffic', @@ -56,7 +59,8 @@ describe('cointrafficBidAdapter', function () { } ]; - let bidderRequests = { + /** @type {BidderRequest} */ + let bidderRequest = { refererInfo: { numIframes: 0, reachedTop: true, @@ -68,7 +72,7 @@ describe('cointrafficBidAdapter', function () { }; it('replaces currency with EUR if there is no currency provided', function () { - const request = spec.buildRequests(bidRequests, bidderRequests); + const request = spec.buildRequests(bidRequests, bidderRequest); expect(request[0].data.currency).to.equal('EUR'); expect(request[1].data.currency).to.equal('EUR'); @@ -79,7 +83,7 @@ describe('cointrafficBidAdapter', function () { arg => arg === 'currency.bidderCurrencyDefault.cointraffic' ? 'USD' : 'EUR' ); - const request = spec.buildRequests(bidRequests, bidderRequests); + const request = spec.buildRequests(bidRequests, bidderRequest); expect(request[0].data.currency).to.equal('USD'); expect(request[1].data.currency).to.equal('USD'); @@ -93,7 +97,7 @@ describe('cointrafficBidAdapter', function () { arg => arg === 'currency.bidderCurrencyDefault.cointraffic' ? 'BTC' : 'EUR' ); - const request = spec.buildRequests(bidRequests, bidderRequests); + const request = spec.buildRequests(bidRequests, bidderRequest); expect(request[0]).to.undefined; expect(request[1]).to.undefined; @@ -103,14 +107,14 @@ describe('cointrafficBidAdapter', function () { }); it('sends bid request to our endpoint via POST', function () { - const request = spec.buildRequests(bidRequests, bidderRequests); + const request = spec.buildRequests(bidRequests, bidderRequest); expect(request[0].method).to.equal('POST'); expect(request[1].method).to.equal('POST'); }); it('attaches source and version to endpoint URL as query params', function () { - const request = spec.buildRequests(bidRequests, bidderRequests); + const request = spec.buildRequests(bidRequests, bidderRequest); expect(request[0].url).to.equal(ENDPOINT_URL); expect(request[1].url).to.equal(ENDPOINT_URL); @@ -119,6 +123,7 @@ describe('cointrafficBidAdapter', function () { describe('interpretResponse', function () { it('should get the correct bid response', function () { + /** @type {BidRequest[]} */ let bidRequest = [{ method: 'POST', url: ENDPOINT_URL, @@ -142,7 +147,7 @@ describe('cointrafficBidAdapter', function () { height: 250, creativeId: 'creativeId12345', ttl: 90, - ad: '

I am an ad

', + ad: '

I am an ad

', mediaType: 'banner', adomain: ['test.com'] } @@ -157,7 +162,7 @@ describe('cointrafficBidAdapter', function () { height: 250, creativeId: 'creativeId12345', ttl: 90, - ad: '

I am an ad

', + ad: '

I am an ad

', meta: { mediaType: 'banner', advertiserDomains: [ @@ -170,7 +175,58 @@ describe('cointrafficBidAdapter', function () { expect(Object.keys(result)).to.deep.equal(Object.keys(expectedResponse)); }); + it('should get the correct bid response without advertiser domains specified', function () { + /** @type {BidRequest[]} */ + let bidRequest = [{ + method: 'POST', + url: ENDPOINT_URL, + data: { + placementId: 'testPlacementId', + device: 'desktop', + currency: 'EUR', + sizes: ['300x250'], + bidId: 'bidId12345', + referer: 'www.example.com' + } + }]; + + let serverResponse = { + body: { + requestId: 'bidId12345', + cpm: 3.9, + currency: 'EUR', + netRevenue: true, + width: 300, + height: 250, + creativeId: 'creativeId12345', + ttl: 90, + ad: '

I am an ad

', + mediaType: 'banner', + } + }; + + let expectedResponse = [{ + requestId: 'bidId12345', + cpm: 3.9, + currency: 'EUR', + netRevenue: true, + width: 300, + height: 250, + creativeId: 'creativeId12345', + ttl: 90, + ad: '

I am an ad

', + meta: { + mediaType: 'banner', + advertiserDomains: [] + } + }]; + + let result = spec.interpretResponse(serverResponse, bidRequest[0]); + expect(Object.keys(result)).to.deep.equal(Object.keys(expectedResponse)); + }); + it('should get the correct bid response with different currency', function () { + /** @type {BidRequest[]} */ let bidRequest = [{ method: 'POST', url: ENDPOINT_URL, @@ -194,7 +250,7 @@ describe('cointrafficBidAdapter', function () { height: 250, creativeId: 'creativeId12345', ttl: 90, - ad: '

I am an ad

', + ad: '

I am an ad

', mediaType: 'banner', adomain: ['test.com'] } @@ -209,7 +265,7 @@ describe('cointrafficBidAdapter', function () { height: 250, creativeId: 'creativeId12345', ttl: 90, - ad: '

I am an ad

', + ad: '

I am an ad

', meta: { mediaType: 'banner', advertiserDomains: [ @@ -227,6 +283,7 @@ describe('cointrafficBidAdapter', function () { }); it('should get empty bid response requested currency is not available', function () { + /** @type {BidRequest[]} */ let bidRequest = [{ method: 'POST', url: ENDPOINT_URL, @@ -253,6 +310,7 @@ describe('cointrafficBidAdapter', function () { }); it('should get empty bid response if no server response', function () { + /** @type {BidRequest[]} */ let bidRequest = [{ method: 'POST', url: ENDPOINT_URL, diff --git a/test/spec/modules/colossussspBidAdapter_spec.js b/test/spec/modules/colossussspBidAdapter_spec.js index 8b06868390a..adb9137d892 100644 --- a/test/spec/modules/colossussspBidAdapter_spec.js +++ b/test/spec/modules/colossussspBidAdapter_spec.js @@ -56,6 +56,93 @@ describe('ColossussspAdapter', function () { referer: 'http://www.example.com', reachedTop: true, }, + ortb2: { + app: { + name: 'myappname', + keywords: 'power tools, drills', + content: { + data: [ + { + name: 'www.dataprovider1.com', + ext: { + segtax: 6 + }, + segment: [ + { + id: '687' + }, + { + id: '123' + } + ] + }, + { + name: 'www.dataprovider1.com', + ext: { + segtax: 7 + }, + segment: [ + { + id: '456' + }, + { + id: '789' + } + ] + } + ] + } + }, + site: { + name: 'example', + domain: 'page.example.com', + cat: ['IAB2'], + sectioncat: ['IAB2-2'], + pagecat: ['IAB2-2'], + page: 'https://page.example.com/here.html', + ref: 'https://ref.example.com', + keywords: 'power tools, drills', + search: 'drill', + content: { + userrating: '4', + data: [{ + name: 'www.dataprovider1.com', + ext: { + segtax: 7, + cids: ['iris_c73g5jq96mwso4d8'] + }, + segment: [ + { id: '687' }, + { id: '123' } + ] + }] + }, + ext: { + data: { + pageType: 'article', + category: 'repair' + } + } + }, + user: { + yob: 1985, + gender: 'm', + keywords: 'a,b', + data: [{ + name: 'dataprovider.com', + ext: { segtax: 4 }, + segment: [ + { id: '1' } + ] + }], + ext: { + data: { + registered: true, + interests: ['cars'] + } + } + } + }, bids: [bid] } @@ -91,7 +178,7 @@ describe('ColossussspAdapter', function () { it('Returns valid data if array of bids is valid', function () { let data = serverRequest.data; expect(data).to.be.an('object'); - expect(data).to.have.all.keys('deviceWidth', 'deviceHeight', 'language', 'secure', 'host', 'page', 'placements', 'ccpa', 'gdpr_consent', 'gdpr_require'); + expect(data).to.have.all.keys('deviceWidth', 'deviceHeight', 'language', 'secure', 'host', 'page', 'placements', 'ccpa', 'gdpr_consent', 'gdpr_require', 'userObj', 'siteObj', 'appObj'); expect(data.deviceWidth).to.be.a('number'); expect(data.deviceHeight).to.be.a('number'); expect(data.language).to.be.a('string'); @@ -132,7 +219,7 @@ describe('ColossussspAdapter', function () { let data = serverRequest.data; expect(data).to.be.an('object'); - expect(data).to.have.all.keys('deviceWidth', 'deviceHeight', 'language', 'secure', 'host', 'page', 'placements', 'ccpa', 'gdpr_consent', 'gdpr_require'); + expect(data).to.have.all.keys('deviceWidth', 'deviceHeight', 'language', 'secure', 'host', 'page', 'placements', 'ccpa', 'gdpr_consent', 'gdpr_require', 'userObj', 'siteObj', 'appObj'); expect(data.deviceWidth).to.be.a('number'); expect(data.deviceHeight).to.be.a('number'); expect(data.language).to.be.a('string'); @@ -299,8 +386,8 @@ describe('ColossussspAdapter', function () { expect(userSync).to.be.an('array').with.lengthOf(1); expect(userSync[0].type).to.exist; expect(userSync[0].url).to.exist; - expect(userSync[0].type).to.be.equal('hms.gif'); - expect(userSync[0].url).to.be.equal('https://sync.colossusssp.com/hms.gif?pbjs=1&gdpr=0&gdpr_consent=xxx&ccpa_consent=1YN-&coppa=0'); + expect(userSync[0].type).to.be.equal('image'); + expect(userSync[0].url).to.be.equal('https://sync.colossusssp.com/image?pbjs=1&gdpr=0&gdpr_consent=xxx&ccpa_consent=1YN-&coppa=0'); }); }); }); diff --git a/test/spec/modules/concertAnalyticsAdapter_spec.js b/test/spec/modules/concertAnalyticsAdapter_spec.js index d130aea6043..1df73ae04fe 100644 --- a/test/spec/modules/concertAnalyticsAdapter_spec.js +++ b/test/spec/modules/concertAnalyticsAdapter_spec.js @@ -1,5 +1,6 @@ import concertAnalytics from 'modules/concertAnalyticsAdapter.js'; import { expect } from 'chai'; +import {expectEvents} from '../../helpers/analytics.js'; const sinon = require('sinon'); let adapterManager = require('src/adapterManager').default; let events = require('src/events'); @@ -46,10 +47,7 @@ describe('ConcertAnalyticsAdapter', function() { it('should catch all events', function() { sandbox.spy(concertAnalytics, 'track'); - - fireBidEvents(events); - // 5 Concert events + 1 Clean.io event - sandbox.assert.callCount(concertAnalytics.track, 6); + expectEvents().to.beTrackedBy(concertAnalytics.track); }); it('should report data for BID_RESPONSE, BID_WON events', function() { diff --git a/test/spec/modules/concertBidAdapter_spec.js b/test/spec/modules/concertBidAdapter_spec.js index 2f9eda0ca7c..00626472ecb 100644 --- a/test/spec/modules/concertBidAdapter_spec.js +++ b/test/spec/modules/concertBidAdapter_spec.js @@ -1,22 +1,44 @@ import { expect } from 'chai'; import sinon from 'sinon'; -import { spec } from 'modules/concertBidAdapter.js'; -import { getStorageManager } from '../../../src/storageManager.js' +import { spec, storage } from 'modules/concertBidAdapter.js'; +import { hook } from 'src/hook.js'; describe('ConcertAdapter', function () { let bidRequests; let bidRequest; let bidResponse; + let element; + let sandbox; - afterEach(function () { - $$PREBID_GLOBAL$$.bidderSettings = {}; + before(function () { + hook.ready(); }); + beforeEach(function () { + element = { + x: 0, + y: 0, + width: 0, + height: 0, + getBoundingClientRect: () => { + return { + width: element.width, + height: element.height, + + left: element.x, + top: element.y, + right: element.x + element.width, + bottom: element.y + element.height + }; + } + }; + $$PREBID_GLOBAL$$.bidderSettings = { concert: { storageAllowed: true } }; + bidRequests = [ { bidder: 'concert', @@ -56,6 +78,14 @@ describe('ConcertAdapter', function () { ] } } + + sandbox = sinon.sandbox.create(); + sandbox.stub(document, 'getElementById').withArgs('desktop_leaderboard_variable').returns(element) + }); + + afterEach(function () { + $$PREBID_GLOBAL$$.bidderSettings = {}; + sandbox.restore(); }); describe('spec.isBidRequestValid', function() { @@ -93,7 +123,6 @@ describe('ConcertAdapter', function () { }); it('should not generate uid if the user has opted out', function() { - const storage = getStorageManager(); storage.setDataInLocalStorage('c_nap', 'true'); const request = spec.buildRequests(bidRequests, bidRequest); const payload = JSON.parse(request.data); @@ -102,7 +131,6 @@ describe('ConcertAdapter', function () { }); it('should generate uid if the user has not opted out', function() { - const storage = getStorageManager(); storage.removeDataFromLocalStorage('c_nap'); const request = spec.buildRequests(bidRequests, bidRequest); const payload = JSON.parse(request.data); @@ -110,15 +138,59 @@ describe('ConcertAdapter', function () { expect(payload.meta.uid).to.not.equal(false); }); - it('should grab uid from local storage if it exists', function() { - const storage = getStorageManager(); - storage.setDataInLocalStorage('c_uid', 'foo'); + it('should use sharedid if it exists', function() { + storage.removeDataFromLocalStorage('c_nap'); + const request = spec.buildRequests(bidRequests, { + ...bidRequest, + userId: { + _sharedid: { + id: '123abc' + } + } + }); + const payload = JSON.parse(request.data); + expect(payload.meta.uid).to.equal('123abc'); + }) + + it('should grab uid from local storage if it exists and sharedid does not', function() { + storage.setDataInLocalStorage('vmconcert_uid', 'foo'); storage.removeDataFromLocalStorage('c_nap'); const request = spec.buildRequests(bidRequests, bidRequest); const payload = JSON.parse(request.data); expect(payload.meta.uid).to.equal('foo'); }); + + it('should add uid2 to eids list if available', function() { + bidRequests[0].userId = { uid2: { id: 'uid123' } } + + const request = spec.buildRequests(bidRequests, bidRequest); + const payload = JSON.parse(request.data); + const meta = payload.meta + + expect(meta.eids.length).to.equal(1); + expect(meta.eids[0].uids[0].id).to.equal('uid123') + expect(meta.eids[0].uids[0].atype).to.equal(3) + }) + + it('should return empty eids list if none are available', function() { + bidRequests[0].userId = { testId: { id: 'uid123' } } + const request = spec.buildRequests(bidRequests, bidRequest); + const payload = JSON.parse(request.data); + const meta = payload.meta + + expect(meta.eids.length).to.equal(0); + }); + + it('should return x/y offset coordiantes when element is present', function() { + Object.assign(element, { x: 100, y: 0, width: 400, height: 400 }) + const request = spec.buildRequests(bidRequests, bidRequest); + const payload = JSON.parse(request.data); + const slot = payload.slots[0]; + + expect(slot.offsetCoordinates.x).to.equal(100) + expect(slot.offsetCoordinates.y).to.equal(0) + }) }); describe('spec.interpretResponse', function() { @@ -155,7 +227,6 @@ describe('ConcertAdapter', function () { const opts = { iframeEnabled: true }; - const storage = getStorageManager(); storage.setDataInLocalStorage('c_nap', 'true'); const sync = spec.getUserSyncs(opts, [], bidRequest.gdprConsent, bidRequest.uspConsent); @@ -166,7 +237,6 @@ describe('ConcertAdapter', function () { const opts = { iframeEnabled: true }; - const storage = getStorageManager(); storage.removeDataFromLocalStorage('c_nap'); bidRequest.gdprConsent = { @@ -181,7 +251,6 @@ describe('ConcertAdapter', function () { const opts = { iframeEnabled: true }; - const storage = getStorageManager(); storage.removeDataFromLocalStorage('c_nap'); bidRequest.gdprConsent = { @@ -196,7 +265,6 @@ describe('ConcertAdapter', function () { const opts = { iframeEnabled: true }; - const storage = getStorageManager(); storage.removeDataFromLocalStorage('c_nap'); bidRequest.gdprConsent = { @@ -212,7 +280,6 @@ describe('ConcertAdapter', function () { const opts = { iframeEnabled: true }; - const storage = getStorageManager(); storage.removeDataFromLocalStorage('c_nap'); bidRequest.gdprConsent = { diff --git a/test/spec/modules/confiantRtdProvider_spec.js b/test/spec/modules/confiantRtdProvider_spec.js new file mode 100644 index 00000000000..987aca2e020 --- /dev/null +++ b/test/spec/modules/confiantRtdProvider_spec.js @@ -0,0 +1,107 @@ +import * as utils from '../../../src/utils.js'; +import * as hook from '../../../src/hook.js' +import * as events from '../../../src/events.js'; +import CONSTANTS from '../../../src/constants.json'; + +import confiantModule from '../../../modules/confiantRtdProvider.js'; + +const { + injectConfigScript, + setupPage, + subscribeToConfiantCommFrame, + registerConfiantSubmodule +} = confiantModule; + +describe('Confiant RTD module', function () { + describe('setupPage()', function() { + it('should return false if propertId is not present in config', function() { + expect(setupPage({})).to.be.false; + expect(setupPage({ params: {} })).to.be.false; + expect(setupPage({ params: { propertyId: '' } })).to.be.false; + }); + + it('should return true if expected parameters are present', function() { + expect(setupPage({ params: { propertyId: 'clientId' } })).to.be.true; + }); + }); + + describe('Module initialization', function() { + let insertElementStub; + beforeEach(function() { + insertElementStub = sinon.stub(utils, 'insertElement'); + }); + afterEach(function() { + utils.insertElement.restore(); + }); + + it('should subscribe to rovided Window object', function () { + const mockWindow = { addEventListener: sinon.spy() }; + + subscribeToConfiantCommFrame(mockWindow); + + sinon.assert.calledOnce(mockWindow.addEventListener); + }); + + it('should fire BillableEvent as a result for message in comm window', function() { + let listenerCallback; + const mockWindow = { addEventListener: (a, cb) => (listenerCallback = cb) }; + let billableEventsCounter = 0; + + events.on(CONSTANTS.EVENTS.BILLABLE_EVENT, (e) => { + if (e.vendor === 'confiant') { + billableEventsCounter++; + expect(e.type).to.equal('impression'); + expect(e.billingId).to.be.a('number'); + expect(e.auctionId).to.equal('auctionId'); + expect(e.transactionId).to.equal('transactionId'); + } + }); + + subscribeToConfiantCommFrame(mockWindow); + listenerCallback({ + data: { + auctionId: 'auctionId', + transactionId: 'transactionId' + } + }); + listenerCallback({ + data: { + auctionId: 'auctionId', + transactionId: 'transactionId' + } + }); + + expect(billableEventsCounter).to.equal(2); + }); + }); + + describe('Sumbodule execution', function() { + let submoduleStub; + let insertElementStub; + beforeEach(function () { + submoduleStub = sinon.stub(hook, 'submodule'); + insertElementStub = sinon.stub(utils, 'insertElement'); + }); + afterEach(function () { + utils.insertElement.restore(); + submoduleStub.restore(); + }); + + function initModule() { + registerConfiantSubmodule(); + + expect(submoduleStub.calledOnceWith('realTimeData')).to.equal(true); + + const registeredSubmoduleDefinition = submoduleStub.getCall(0).args[1]; + expect(registeredSubmoduleDefinition).to.be.an('object'); + expect(registeredSubmoduleDefinition).to.have.own.property('name', 'confiant'); + expect(registeredSubmoduleDefinition).to.have.own.property('init').that.is.a('function'); + + return registeredSubmoduleDefinition; + } + + it('should register Confiant submodule', function () { + initModule(); + }); + }); +}); diff --git a/test/spec/modules/connectIdSystem_spec.js b/test/spec/modules/connectIdSystem_spec.js index fe3cb81c2ea..52639c39baf 100644 --- a/test/spec/modules/connectIdSystem_spec.js +++ b/test/spec/modules/connectIdSystem_spec.js @@ -4,6 +4,7 @@ import {connectIdSubmodule} from 'modules/connectIdSystem.js'; describe('Yahoo ConnectID Submodule', () => { const HASHED_EMAIL = '6bda6f2fa268bf0438b5423a9861a2cedaa5dec163c03f743cfe05c08a8397b2'; + const PUBLISHER_USER_ID = '975484817'; const PIXEL_ID = '1234'; const PROD_ENDPOINT = `https://ups.analytics.yahoo.com/ups/${PIXEL_ID}/fed`; const OVERRIDE_ENDPOINT = 'https://foo/bar'; @@ -30,7 +31,11 @@ describe('Yahoo ConnectID Submodule', () => { gdprApplies: 1, consentString: 'GDPR_CONSENT_STRING' }, - uspConsent: 'USP_CONSENT_STRING' + uspConsent: 'USP_CONSENT_STRING', + gppConsent: { + gppString: 'header~section6~section7', + applicableSections: [6, 7] + } }; }); @@ -48,28 +53,76 @@ describe('Yahoo ConnectID Submodule', () => { return result; } - it('returns undefined if he and pixelId params are not passed', () => { + it('returns undefined if he, pixelId and puid params are not passed', () => { expect(invokeGetIdAPI({}, consentData)).to.be.undefined; expect(ajaxStub.callCount).to.equal(0); }); it('returns undefined if the pixelId param is not passed', () => { expect(invokeGetIdAPI({ - he: HASHED_EMAIL + he: HASHED_EMAIL, + puid: PUBLISHER_USER_ID }, consentData)).to.be.undefined; expect(ajaxStub.callCount).to.equal(0); }); - it('returns undefined if the he param is not passed', () => { + it('returns undefined if the pixelId param is passed, but the he and puid param are not passed', () => { expect(invokeGetIdAPI({ pixelId: PIXEL_ID }, consentData)).to.be.undefined; expect(ajaxStub.callCount).to.equal(0); }); - it('returns an object with the callback function if the correct params are passed', () => { + it('returns an object with the callback function if the endpoint override param and the he params are passed', () => { + let result = invokeGetIdAPI({ + he: HASHED_EMAIL, + endpoint: OVERRIDE_ENDPOINT + }, consentData); + expect(result).to.be.an('object').that.has.all.keys('callback'); + expect(result.callback).to.be.a('function'); + }); + + it('returns an object with the callback function if the endpoint override param and the puid params are passed', () => { + let result = invokeGetIdAPI({ + puid: PUBLISHER_USER_ID, + endpoint: OVERRIDE_ENDPOINT + }, consentData); + expect(result).to.be.an('object').that.has.all.keys('callback'); + expect(result.callback).to.be.a('function'); + }); + + it('returns an object with the callback function if the endpoint override param and the puid and he params are passed', () => { + let result = invokeGetIdAPI({ + he: HASHED_EMAIL, + puid: PUBLISHER_USER_ID, + endpoint: OVERRIDE_ENDPOINT + }, consentData); + expect(result).to.be.an('object').that.has.all.keys('callback'); + expect(result.callback).to.be.a('function'); + }); + + it('returns an object with the callback function if the pixelId and he params are passed', () => { + 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'); + }); + + it('returns an object with the callback function if the pixelId and puid params are passed', () => { + let result = invokeGetIdAPI({ + puid: PUBLISHER_USER_ID, + pixelId: PIXEL_ID + }, consentData); + expect(result).to.be.an('object').that.has.all.keys('callback'); + expect(result.callback).to.be.a('function'); + }); + + it('returns an object with the callback function if the pixelId, he and puid params are passed', () => { let result = invokeGetIdAPI({ he: HASHED_EMAIL, + puid: PUBLISHER_USER_ID, pixelId: PIXEL_ID }, consentData); expect(result).to.be.an('object').that.has.all.keys('callback'); @@ -96,19 +149,69 @@ describe('Yahoo ConnectID Submodule', () => { localStorage.removeItem('connectIdOptOut'); }); - it('Makes an ajax GET request to the production API endpoint with query params', () => { + it('Makes an ajax GET request to the production API endpoint with pixelId and he query params', () => { + invokeGetIdAPI({ + he: HASHED_EMAIL, + pixelId: PIXEL_ID + }, consentData); + + const expectedParams = { + he: HASHED_EMAIL, + pixelId: PIXEL_ID, + '1p': '0', + gdpr: '1', + gdpr_consent: consentData.gdpr.consentString, + us_privacy: consentData.uspConsent, + gpp: consentData.gppConsent.gppString, + gpp_sid: '6%2C7' + }; + const requestQueryParams = parseQS(ajaxStub.firstCall.args[0].split('?')[1]); + + expect(ajaxStub.firstCall.args[0].indexOf(`${PROD_ENDPOINT}?`)).to.equal(0); + expect(requestQueryParams).to.deep.equal(expectedParams); + expect(ajaxStub.firstCall.args[3]).to.deep.equal({method: 'GET', withCredentials: true}); + }); + + it('Makes an ajax GET request to the production API endpoint with pixelId and puid query params', () => { + invokeGetIdAPI({ + puid: PUBLISHER_USER_ID, + pixelId: PIXEL_ID + }, consentData); + + const expectedParams = { + puid: PUBLISHER_USER_ID, + pixelId: PIXEL_ID, + '1p': '0', + gdpr: '1', + gdpr_consent: consentData.gdpr.consentString, + us_privacy: consentData.uspConsent, + gpp: consentData.gppConsent.gppString, + gpp_sid: '6%2C7' + }; + const requestQueryParams = parseQS(ajaxStub.firstCall.args[0].split('?')[1]); + + expect(ajaxStub.firstCall.args[0].indexOf(`${PROD_ENDPOINT}?`)).to.equal(0); + expect(requestQueryParams).to.deep.equal(expectedParams); + expect(ajaxStub.firstCall.args[3]).to.deep.equal({method: 'GET', withCredentials: true}); + }); + + it('Makes an ajax GET request to the production API endpoint with pixelId, puid and he query params', () => { invokeGetIdAPI({ + puid: PUBLISHER_USER_ID, he: HASHED_EMAIL, pixelId: PIXEL_ID }, consentData); const expectedParams = { + puid: PUBLISHER_USER_ID, he: HASHED_EMAIL, pixelId: PIXEL_ID, '1p': '0', gdpr: '1', gdpr_consent: consentData.gdpr.consentString, - us_privacy: consentData.uspConsent + us_privacy: consentData.uspConsent, + gpp: consentData.gppConsent.gppString, + gpp_sid: '6%2C7' }; const requestQueryParams = parseQS(ajaxStub.firstCall.args[0].split('?')[1]); @@ -128,7 +231,9 @@ describe('Yahoo ConnectID Submodule', () => { '1p': '0', gdpr: '1', gdpr_consent: consentData.gdpr.consentString, - us_privacy: consentData.uspConsent + us_privacy: consentData.uspConsent, + gpp: consentData.gppConsent.gppString, + gpp_sid: '6%2C7' }; const requestQueryParams = parseQS(ajaxStub.firstCall.args[0].split('?')[1]); @@ -185,6 +290,16 @@ describe('Yahoo ConnectID Submodule', () => { }); describe('decode()', () => { + let userHasOptedOutStub; + beforeEach(() => { + userHasOptedOutStub = sinon.stub(connectIdSubmodule, 'userHasOptedOut'); + userHasOptedOutStub.returns(false); + }); + + afterEach(() => { + userHasOptedOutStub.restore() + }); + const VALID_API_RESPONSES = [{ key: 'connectid', expected: '4567', @@ -205,5 +320,72 @@ describe('Yahoo ConnectID Submodule', () => { expect(connectIdSubmodule.decode(response)).to.be.undefined; }); }); + + it('should return undefined if user has utilised the easy opt-out mechanism', () => { + userHasOptedOutStub.returns(true); + expect(connectIdSubmodule.decode(VALID_API_RESPONSES[0].payload)).to.be.undefined; + }) + }); + + describe('getAjaxFn()', () => { + it('should return a function', () => { + expect(connectIdSubmodule.getAjaxFn()).to.be.a('function'); + }); + }); + + describe('isEUConsentRequired()', () => { + it('should return a function', () => { + expect(connectIdSubmodule.isEUConsentRequired).to.be.a('function'); + }); + + it('should be false if consent data is empty', () => { + expect(connectIdSubmodule.isEUConsentRequired({})).to.be.false; + }); + + it('should be false if consent data.gdpr object is empty', () => { + expect(connectIdSubmodule.isEUConsentRequired({ + gdpr: {} + })).to.be.false; + }); + + it('should return false if consent data.gdpr.applies is false', () => { + expect(connectIdSubmodule.isEUConsentRequired({ + gdpr: { + gdprApplies: false + } + })).to.be.false; + }); + + it('should return true if consent data.gdpr.applies is true', () => { + expect(connectIdSubmodule.isEUConsentRequired({ + gdpr: { + gdprApplies: true + } + })).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/consentManagementGpp_spec.js b/test/spec/modules/consentManagementGpp_spec.js new file mode 100644 index 00000000000..1170f418caf --- /dev/null +++ b/test/spec/modules/consentManagementGpp_spec.js @@ -0,0 +1,577 @@ +import { setConsentConfig, requestBidsHook, resetConsentData, userCMP, consentTimeout, staticConsentData } from 'modules/consentManagementGpp.js'; +import { gppDataHandler } from 'src/adapterManager.js'; +import * as utils from 'src/utils.js'; +import { config } from 'src/config.js'; +import 'src/prebid.js'; + +let expect = require('chai').expect; + +describe('consentManagementGpp', function () { + describe('setConsentConfig tests:', function () { + describe('empty setConsentConfig value', function () { + beforeEach(function () { + sinon.stub(utils, 'logInfo'); + sinon.stub(utils, 'logWarn'); + }); + + afterEach(function () { + utils.logInfo.restore(); + utils.logWarn.restore(); + config.resetConfig(); + resetConsentData(); + }); + + it('should use system default values', function () { + setConsentConfig({ + gpp: {} + }); + expect(userCMP).to.be.equal('iab'); + expect(consentTimeout).to.be.equal(10000); + sinon.assert.callCount(utils.logInfo, 3); + }); + + it('should exit consent manager if config is not an object', function () { + setConsentConfig(''); + expect(userCMP).to.be.undefined; + sinon.assert.calledOnce(utils.logWarn); + }); + + it('should exit consentManagement module if config is "undefined"', function () { + setConsentConfig(undefined); + expect(userCMP).to.be.undefined; + sinon.assert.calledOnce(utils.logWarn); + }); + + it('should not produce any consent metadata', function () { + setConsentConfig(undefined) + let consentMetadata = gppDataHandler.getConsentMeta(); + expect(consentMetadata).to.be.undefined; + sinon.assert.calledOnce(utils.logWarn); + }) + + it('should immediately look up consent data', () => { + setConsentConfig({ + gpp: { + cmpApi: 'invalid' + } + }); + expect(gppDataHandler.ready).to.be.true; + }) + }); + + describe('valid setConsentConfig value', function () { + afterEach(function () { + config.resetConfig(); + }); + + it('results in all user settings overriding system defaults', function () { + let allConfig = { + gpp: { + cmpApi: 'iab', + timeout: 7500 + } + }; + + setConsentConfig(allConfig); + expect(userCMP).to.be.equal('iab'); + expect(consentTimeout).to.be.equal(7500); + }); + + it('should recognize config.gpp, with default cmpApi and timeout', function () { + setConsentConfig({ + gpp: {} + }); + + expect(userCMP).to.be.equal('iab'); + expect(consentTimeout).to.be.equal(10000); + }); + + it('should enable gppDataHandler', () => { + setConsentConfig({ + gpp: {} + }); + expect(gppDataHandler.enabled).to.be.true; + }); + }); + + describe('static consent string setConsentConfig value', () => { + afterEach(() => { + config.resetConfig(); + }); + + it('results in user settings overriding system defaults for v2 spec', () => { + let staticConfig = { + gpp: { + cmpApi: 'static', + timeout: 7500, + consentData: { + applicableSections: [7], + gppString: 'ABCDEFG1234', + gppVersion: 1, + sectionId: 3, + sectionList: [] + } + } + }; + + setConsentConfig(staticConfig); + expect(userCMP).to.be.equal('static'); + expect(consentTimeout).to.be.equal(0); // should always return without a timeout when config is used + const consent = gppDataHandler.getConsentData(); + expect(consent.gppString).to.eql(staticConfig.gpp.consentData.gppString); + expect(consent.fullGppData).to.eql(staticConfig.gpp.consentData); + expect(staticConsentData).to.be.equal(staticConfig.gpp.consentData); + }); + }); + }); + + describe('requestBidsHook tests:', function () { + let goodConfig = { + gpp: { + cmpApi: 'iab', + timeout: 7500, + } + }; + + const staticConfig = { + gpp: { + cmpApi: 'static', + timeout: 7500, + consentData: { + gppString: 'abc12345', + applicableSections: [7] + } + } + } + + let didHookReturn; + + beforeEach(resetConsentData); + after(resetConsentData); + + describe('error checks:', function () { + beforeEach(function () { + didHookReturn = false; + sinon.stub(utils, 'logWarn'); + sinon.stub(utils, 'logError'); + }); + + afterEach(function () { + utils.logWarn.restore(); + utils.logError.restore(); + config.resetConfig(); + }); + + it('should throw a warning and return to hooked function when an unknown CMP framework ID is used', function () { + let badCMPConfig = { + gpp: { + cmpApi: 'bad' + } + }; + setConsentConfig(badCMPConfig); + expect(userCMP).to.be.equal(badCMPConfig.gpp.cmpApi); + + requestBidsHook(() => { + didHookReturn = true; + }, {}); + let consent = gppDataHandler.getConsentData(); + + sinon.assert.calledOnce(utils.logWarn); + expect(didHookReturn).to.be.true; + expect(consent).to.be.null; + }); + + it('should call gppDataHandler.setConsentData() when unknown CMP api is used', () => { + setConsentConfig({ + gpp: { + cmpApi: 'invalid' + } + }); + let hookRan = false; + requestBidsHook(() => { + hookRan = true; + }, {}); + expect(hookRan).to.be.true; + expect(gppDataHandler.ready).to.be.true; + }) + + it('should throw proper errors when CMP is not found', function () { + setConsentConfig(goodConfig); + + requestBidsHook(() => { + didHookReturn = true; + }, {}); + let consent = gppDataHandler.getConsentData(); + // throw 2 errors; one for no bidsBackHandler and for CMP not being found (this is an error due to gdpr config) + sinon.assert.calledTwice(utils.logError); + expect(didHookReturn).to.be.false; + expect(consent).to.be.null; + expect(gppDataHandler.ready).to.be.true; + }); + + it('should not trip when adUnits have no size', () => { + setConsentConfig(staticConfig); + let ran = false; + requestBidsHook(() => { + ran = true; + }, { + adUnits: [{ + code: 'test', + mediaTypes: { + video: {} + } + }] + }); + return gppDataHandler.promise.then(() => { + expect(ran).to.be.true; + }); + }); + + it('should continue the auction immediately, without consent data, if timeout is 0', (done) => { + setConsentConfig({ + gpp: { + cmpApi: 'iab', + timeout: 0 + } + }); + window.__gpp = function () {}; + try { + requestBidsHook(() => { + const consent = gppDataHandler.getConsentData(); + expect(consent.applicableSections).to.deep.equal([]); + expect(consent.gppString).to.be.undefined; + done(); + }, {}) + } finally { + delete window.__gpp; + } + }); + }); + + describe('already known consentData:', function () { + let cmpStub = sinon.stub(); + + function mockCMP(cmpResponse) { + return function (...args) { + if (args[0] === 'addEventListener') { + args[1](({ + eventName: 'sectionChange' + })); + } else if (args[0] === 'getGPPData') { + return cmpResponse; + } + } + } + + beforeEach(function () { + didHookReturn = false; + window.__gpp = function () {}; + }); + + afterEach(function () { + config.resetConfig(); + cmpStub.restore(); + delete window.__gpp; + resetConsentData(); + }); + + it('should bypass CMP and simply use previously stored consentData', function () { + let testConsentData = { + applicableSections: [7], + gppString: 'xyz', + }; + + cmpStub = sinon.stub(window, '__gpp').callsFake(mockCMP(testConsentData)); + setConsentConfig(goodConfig); + requestBidsHook(() => {}, {}); + cmpStub.reset(); + + requestBidsHook(() => { + didHookReturn = true; + }, {}); + let consent = gppDataHandler.getConsentData(); + + expect(didHookReturn).to.be.true; + expect(consent.gppString).to.equal(testConsentData.gppString); + expect(consent.applicableSections).to.deep.equal(testConsentData.applicableSections); + sinon.assert.notCalled(cmpStub); + }); + }); + + describe('iframe tests', function () { + let cmpPostMessageCb = () => {}; + let stringifyResponse; + + function createIFrameMarker(frameName) { + let ifr = document.createElement('iframe'); + ifr.width = 0; + ifr.height = 0; + ifr.name = frameName; + document.body.appendChild(ifr); + return ifr; + } + + function creatCmpMessageHandler(prefix, returnEvtValue, returnGPPValue) { + return function (event) { + if (event && event.data) { + let data = event.data; + if (data[`${prefix}Call`]) { + let callId = data[`${prefix}Call`].callId; + let response; + if (data[`${prefix}Call`].command === 'addEventListener') { + response = { + [`${prefix}Return`]: { + callId, + returnValue: returnEvtValue, + success: true + } + } + } else if (data[`${prefix}Call`].command === 'getGPPData') { + response = { + [`${prefix}Return`]: { + callId, + returnValue: returnGPPValue, + success: true + } + } + } + event.source.postMessage(stringifyResponse ? JSON.stringify(response) : response, '*'); + } + } + } + } + + function testIFramedPage(testName, messageFormatString, tarConsentString, tarSections) { + it(`should return the consent string from a postmessage + addEventListener response - ${testName}`, (done) => { + stringifyResponse = messageFormatString; + setConsentConfig(goodConfig); + requestBidsHook(() => { + let consent = gppDataHandler.getConsentData(); + sinon.assert.notCalled(utils.logError); + expect(consent.gppString).to.equal(tarConsentString); + expect(consent.applicableSections).to.deep.equal(tarSections); + done(); + }, {}); + }); + } + + beforeEach(function () { + sinon.stub(utils, 'logError'); + sinon.stub(utils, 'logWarn'); + }); + + afterEach(function () { + utils.logError.restore(); + utils.logWarn.restore(); + config.resetConfig(); + resetConsentData(); + }); + + describe('v2 CMP workflow for iframe pages:', function () { + stringifyResponse = false; + let ifr2 = null; + + beforeEach(function () { + ifr2 = createIFrameMarker('__gppLocator'); + cmpPostMessageCb = creatCmpMessageHandler('__gpp', { + eventName: 'sectionChange' + }, { + gppString: 'abc12345234', + applicableSections: [7] + }); + window.addEventListener('message', cmpPostMessageCb, false); + }); + + afterEach(function () { + delete window.__gpp; // deletes the local copy made by the postMessage CMP call function + document.body.removeChild(ifr2); + window.removeEventListener('message', cmpPostMessageCb); + }); + + testIFramedPage('with/JSON response', false, 'abc12345234', [7]); + testIFramedPage('with/String response', true, 'abc12345234', [7]); + }); + }); + + describe('direct calls to CMP API tests', function () { + let cmpStub = sinon.stub(); + + beforeEach(function () { + didHookReturn = false; + sinon.stub(utils, 'logError'); + sinon.stub(utils, 'logWarn'); + }); + + afterEach(function () { + config.resetConfig(); + cmpStub.restore(); + utils.logError.restore(); + utils.logWarn.restore(); + resetConsentData(); + }); + + describe('v2 CMP workflow for normal pages:', function () { + beforeEach(function () { + window.__gpp = function () {}; + }); + + afterEach(function () { + delete window.__gpp; + }); + + it('performs lookup check and stores consentData for a valid existing user', function () { + let testConsentData = { + gppString: 'abc12345234', + applicableSections: [7] + }; + cmpStub = sinon.stub(window, '__gpp').callsFake((...args) => { + if (args[0] === 'addEventListener') { + args[1]({ + eventName: 'sectionChange' + }); + } else if (args[0] === 'getGPPData') { + return testConsentData; + } + }); + + setConsentConfig(goodConfig); + + requestBidsHook(() => { + didHookReturn = true; + }, {}); + let consent = gppDataHandler.getConsentData(); + sinon.assert.notCalled(utils.logError); + expect(didHookReturn).to.be.true; + expect(consent.gppString).to.equal(testConsentData.gppString); + expect(consent.applicableSections).to.deep.equal(testConsentData.applicableSections); + }); + + it('produces gdpr metadata', function () { + let testConsentData = { + gppString: 'abc12345234', + applicableSections: [7] + }; + cmpStub = sinon.stub(window, '__gpp').callsFake((...args) => { + if (args[0] === 'addEventListener') { + args[1]({ + eventName: 'sectionChange' + }); + } else if (args[0] === 'getGPPData') { + return testConsentData; + } + }); + + setConsentConfig(goodConfig); + + requestBidsHook(() => { + didHookReturn = true; + }, {}); + let consentMeta = gppDataHandler.getConsentMeta(); + sinon.assert.notCalled(utils.logError); + expect(consentMeta.generatedAt).to.be.above(1644367751709); + }); + + it('throws an error when processCmpData check fails + does not call requestBids callback', function () { + let testConsentData = {}; + let bidsBackHandlerReturn = false; + + cmpStub = sinon.stub(window, '__gpp').callsFake((...args) => { + if (args[0] === 'addEventListener') { + args[1]({ + eventName: 'sectionChange' + }); + } else if (args[0] === 'getGPPData') { + return testConsentData; + } + }); + + setConsentConfig(goodConfig); + + sinon.assert.notCalled(utils.logWarn); + sinon.assert.notCalled(utils.logError); + + [utils.logWarn, utils.logError].forEach((stub) => stub.reset()); + + requestBidsHook(() => { + didHookReturn = true; + }, { + bidsBackHandler: () => bidsBackHandlerReturn = true + }); + let consent = gppDataHandler.getConsentData(); + + sinon.assert.calledOnce(utils.logError); + sinon.assert.notCalled(utils.logWarn); + expect(didHookReturn).to.be.false; + expect(bidsBackHandlerReturn).to.be.true; + expect(consent).to.be.null; + expect(gppDataHandler.ready).to.be.true; + }); + + describe('when proper consent is not available', () => { + let gppStub; + + function runAuction() { + setConsentConfig({ + gpp: { + cmpApi: 'iab', + timeout: 10, + } + }); + return new Promise((resolve, reject) => { + requestBidsHook(() => { + didHookReturn = true; + }, {}); + setTimeout(() => didHookReturn ? resolve() : reject(new Error('Auction did not run')), 20); + }) + } + + function mockGppCmp(gppdata) { + gppStub.callsFake((api, cb) => { + if (api === 'addEventListener') { + // eslint-disable-next-line standard/no-callback-literal + cb({ + pingData: { + cmpStatus: 'loaded' + } + }, true); + } + if (api === 'getGPPData') { + return gppdata; + } + }); + } + + beforeEach(() => { + gppStub = sinon.stub(window, '__gpp'); + }); + + afterEach(() => { + gppStub.restore(); + }) + + it('should continue auction with null consent when CMP is unresponsive', () => { + return runAuction().then(() => { + const consent = gppDataHandler.getConsentData(); + expect(consent.applicableSections).to.deep.equal([]); + expect(consent.gppString).to.be.undefined; + expect(gppDataHandler.ready).to.be.true; + }); + }); + + it('should use consent provided by events other than sectionChange', () => { + mockGppCmp({ + gppString: 'mock-consent-string', + applicableSections: [7] + }); + return runAuction().then(() => { + const consent = gppDataHandler.getConsentData(); + expect(consent.applicableSections).to.deep.equal([7]); + expect(consent.gppString).to.equal('mock-consent-string'); + expect(gppDataHandler.ready).to.be.true; + }); + }); + }); + }); + }); + }); +}); diff --git a/test/spec/modules/consentManagementUsp_spec.js b/test/spec/modules/consentManagementUsp_spec.js index 39aeee4470b..e98486754ab 100644 --- a/test/spec/modules/consentManagementUsp_spec.js +++ b/test/spec/modules/consentManagementUsp_spec.js @@ -8,8 +8,9 @@ import { } from 'modules/consentManagementUsp.js'; import * as utils from 'src/utils.js'; import { config } from 'src/config.js'; -import {uspDataHandler} from 'src/adapterManager.js'; +import adapterManager, {gdprDataHandler, uspDataHandler} from 'src/adapterManager.js'; import 'src/prebid.js'; +import {defer} from '../../../src/utils/promise.js'; let expect = require('chai').expect; @@ -23,6 +24,16 @@ function createIFrameMarker() { } describe('consentManagement', function () { + let sandbox; + beforeEach(() => { + sandbox = sinon.sandbox.create(); + sandbox.stub(adapterManager, 'callDataDeletionRequest'); + }); + + afterEach(() => { + sandbox.restore(); + }); + it('should enable itself on requestBids using default values', (done) => { requestBidsHook(() => { expect(uspDataHandler.enabled).to.be.true; @@ -301,8 +312,11 @@ describe('consentManagement', function () { describe('USPAPI workflow for iframed page', function () { let ifr = null; let stringifyResponse = false; + let mockApi, replySent; beforeEach(function () { + mockApi = sinon.stub(); + replySent = defer(); sinon.stub(utils, 'logError'); sinon.stub(utils, 'logWarn'); ifr = createIFrameMarker(); @@ -322,17 +336,21 @@ describe('consentManagement', function () { function uspapiMessageHandler(event) { if (event && event.data) { - var data = event.data; + const data = event.data; if (data.__uspapiCall) { - var callId = data.__uspapiCall.callId; - var response = { - __uspapiReturn: { - callId, - returnValue: { uspString: '1YY' }, - success: true + const {command, version, callId} = data.__uspapiCall; + let response = mockApi(command, version, callId); + if (response) { + response = { + __uspapiReturn: { + callId, + returnValue: response, + success: true + } } - }; - event.source.postMessage(stringifyResponse ? JSON.stringify(response) : response, '*'); + event.source.postMessage(stringifyResponse ? JSON.stringify(response) : response, '*'); + replySent.resolve(); + } } } } @@ -345,6 +363,11 @@ describe('consentManagement', function () { function testIFramedPage(testName, messageFormatString) { it(`should return the consent string from a postmessage + addEventListener response - ${testName}`, (done) => { stringifyResponse = messageFormatString; + mockApi.callsFake((cmd) => { + if (cmd === 'getUSPData') { + return { uspString: '1YY' } + } + }) setConsentConfig(goodConfig); requestBidsHook(() => { let consent = uspDataHandler.getConsentData(); @@ -355,6 +378,20 @@ describe('consentManagement', function () { }, {}); }); } + + it('fires deletion request on registerDeletion', (done) => { + mockApi.callsFake((cmd) => { + return cmd === 'registerDeletion' + }) + sinon.assert.notCalled(adapterManager.callDataDeletionRequest); + setConsentConfig(goodConfig); + replySent.promise.then(() => { + setTimeout(() => { // defer again to give time for the message to get through + sinon.assert.calledOnce(adapterManager.callDataDeletionRequest); + done() + }, 200) + }) + }); }); describe('test without iframe locater', function() { @@ -400,23 +437,19 @@ describe('consentManagement', function () { }); describe('USPAPI workflow for normal pages:', function () { - let uspapiStub = sinon.stub(); let ifr = null; beforeEach(function () { didHookReturn = false; ifr = createIFrameMarker(); - sinon.stub(utils, 'logError'); - sinon.stub(utils, 'logWarn'); + sandbox.stub(utils, 'logError'); + sandbox.stub(utils, 'logWarn'); window.__uspapi = function() {}; }); afterEach(function () { config.resetConfig(); $$PREBID_GLOBAL$$.requestBids.removeAll(); - uspapiStub.restore(); - utils.logError.restore(); - utils.logWarn.restore(); document.body.removeChild(ifr); delete window.__uspapi; resetConsentData(); @@ -427,7 +460,7 @@ describe('consentManagement', function () { uspString: '1NY' }; - uspapiStub = sinon.stub(window, '__uspapi').callsFake((...args) => { + sandbox.stub(window, '__uspapi').callsFake((...args) => { args[2](testConsentData, true); }); @@ -448,7 +481,7 @@ describe('consentManagement', function () { uspString: '1NY' }; - uspapiStub = sinon.stub(window, '__uspapi').callsFake((...args) => { + sandbox.stub(window, '__uspapi').callsFake((...args) => { args[2](testConsentData, true); }); @@ -463,6 +496,32 @@ describe('consentManagement', function () { expect(consentMeta.usp).to.equal(testConsentData.uspString); expect(consentMeta.generatedAt).to.be.above(1644367751709); }); + + it('registers deletion request event listener', () => { + let listener; + sandbox.stub(window, '__uspapi').callsFake((cmd, _, cb) => { + if (cmd === 'registerDeletion') { + listener = cb; + } + }); + setConsentConfig(goodConfig); + sinon.assert.notCalled(adapterManager.callDataDeletionRequest); + listener(); + sinon.assert.calledOnce(adapterManager.callDataDeletionRequest); + }); + + it('does not fail if CMP does not support registerDeletion', () => { + sandbox.stub(window, '__uspapi').callsFake((cmd, _, cb) => { + if (cmd === 'registerDeletion') { + throw new Error('CMP not compliant'); + } else if (cmd === 'getUSPData') { + // eslint-disable-next-line standard/no-callback-literal + cb({uspString: 'string'}, true); + } + }); + setConsentConfig(goodConfig); + expect(uspDataHandler.getConsentData()).to.eql('string'); + }); }); }); }); diff --git a/test/spec/modules/consentManagement_spec.js b/test/spec/modules/consentManagement_spec.js index 47a2e2ab3d9..48b48c987e5 100644 --- a/test/spec/modules/consentManagement_spec.js +++ b/test/spec/modules/consentManagement_spec.js @@ -1,4 +1,15 @@ -import { setConsentConfig, requestBidsHook, resetConsentData, userCMP, consentTimeout, staticConsentData, gdprScope } from 'modules/consentManagement.js'; +import { + setConsentConfig, + requestBidsHook, + resetConsentData, + userCMP, + consentTimeout, + actionTimeout, + staticConsentData, + gdprScope, + loadConsentData, + setActionTimeout +} from 'modules/consentManagement.js'; import { gdprDataHandler } from 'src/adapterManager.js'; import * as utils from 'src/utils.js'; import { config } from 'src/config.js'; @@ -674,6 +685,46 @@ describe('consentManagement', function () { }); }); + it('should timeout after actionTimeout from the first CMP event', (done) => { + mockTcfEvent({ + eventStatus: 'cmpuishown', + tcString: 'mock-consent-string', + vendorData: {} + }); + setConsentConfig({ + timeout: 1000, + actionTimeout: 100, + cmpApi: 'iab', + defaultGdprScope: true + }); + let hookRan = false; + requestBidsHook(() => { + hookRan = true; + }, {}); + setTimeout(() => { + expect(hookRan).to.be.true; + done(); + }, 200) + }); + + it('should still pick up consent data when actionTimeout is 0', (done) => { + mockTcfEvent({ + eventStatus: 'tcloaded', + tcString: 'mock-consent-string', + vendorData: {} + }); + setConsentConfig({ + timeout: 1000, + actionTimeout: 0, + cmpApi: 'iab', + defaultGdprScope: true + }); + requestBidsHook(() => { + expect(gdprDataHandler.getConsentData().consentString).to.eql('mock-consent-string'); + done(); + }, {}) + }) + Object.entries({ 'null': null, 'empty': '', diff --git a/test/spec/modules/consumableBidAdapter_spec.js b/test/spec/modules/consumableBidAdapter_spec.js index d1b310624a6..556dce447b9 100644 --- a/test/spec/modules/consumableBidAdapter_spec.js +++ b/test/spec/modules/consumableBidAdapter_spec.js @@ -625,6 +625,52 @@ describe('Consumable BidAdapter', function () { expect(opts.length).to.equal(1); }); + it('should return a sync url if iframe syncs are enabled and GDPR applies', function () { + let gdprConsent = { + consentString: 'GDPR_CONSENT_STRING', + gdprApplies: true, + } + let opts = spec.getUserSyncs(syncOptions, [AD_SERVER_RESPONSE], gdprConsent); + + expect(opts.length).to.equal(1); + expect(opts[0].url).to.equal('https://sync.serverbid.com/ss/730181.html?gdpr=1&gdpr_consent=GDPR_CONSENT_STRING'); + }) + + it('should return a sync url if iframe syncs are enabled and GDPR is undefined', function () { + let gdprConsent = { + consentString: 'GDPR_CONSENT_STRING', + gdprApplies: undefined, + } + let opts = spec.getUserSyncs(syncOptions, [AD_SERVER_RESPONSE], gdprConsent); + + expect(opts.length).to.equal(1); + expect(opts[0].url).to.equal('https://sync.serverbid.com/ss/730181.html?gdpr=0&gdpr_consent=GDPR_CONSENT_STRING'); + }) + + it('should return a sync url if iframe syncs are enabled and USP applies', function () { + let uspConsent = { + consentString: 'USP_CONSENT_STRING', + } + let opts = spec.getUserSyncs(syncOptions, [AD_SERVER_RESPONSE], {}, uspConsent); + + expect(opts.length).to.equal(1); + expect(opts[0].url).to.equal('https://sync.serverbid.com/ss/730181.html?us_privacy=USP_CONSENT_STRING'); + }) + + it('should return a sync url if iframe syncs are enabled, GDPR and USP applies', function () { + let gdprConsent = { + consentString: 'GDPR_CONSENT_STRING', + gdprApplies: true, + } + let uspConsent = { + consentString: 'USP_CONSENT_STRING', + } + let opts = spec.getUserSyncs(syncOptions, [AD_SERVER_RESPONSE], gdprConsent, uspConsent); + + expect(opts.length).to.equal(1); + expect(opts[0].url).to.equal('https://sync.serverbid.com/ss/730181.html?gdpr=1&gdpr_consent=GDPR_CONSENT_STRING&us_privacy=USP_CONSENT_STRING'); + }) + it('should return a sync url if pixel syncs are enabled and some are returned from the server', function () { let syncOptions = {'pixelEnabled': true}; let opts = spec.getUserSyncs(syncOptions, [AD_SERVER_RESPONSE]); diff --git a/test/spec/modules/conversantAnalyticsAdapter_spec.js b/test/spec/modules/conversantAnalyticsAdapter_spec.js index 48b68d09bc7..ce134f7f6af 100644 --- a/test/spec/modules/conversantAnalyticsAdapter_spec.js +++ b/test/spec/modules/conversantAnalyticsAdapter_spec.js @@ -12,6 +12,7 @@ describe('Conversant analytics adapter tests', function() { let sandbox; // sinon sandbox to make restoring all stubbed objects easier let xhr; // xhr stub from sinon for capturing data sent via ajax let clock; // clock stub from sinon to mock our cache cleanup interval + let logInfoStub; const PREBID_VERSION = '1.2'; const SITE_ID = 108060; @@ -21,14 +22,16 @@ describe('Conversant analytics adapter tests', function() { const VALID_CONFIGURATION = { options: { - site_id: SITE_ID + site_id: SITE_ID, + send_error_data: true } }; const VALID_ALWAYS_SAMPLE_CONFIG = { options: { site_id: SITE_ID, - cnvr_sampling: 1 + cnvr_sampling: 1, + send_error_data: true } }; @@ -45,25 +48,32 @@ describe('Conversant analytics adapter tests', function() { }; sandbox.stub(prebidGlobal, 'getGlobal').returns(getGlobalStub); // getGlobal does not seem to be available in testing so need to mock it clock = sandbox.useFakeTimers(DATESTAMP); // to use sinon fake timers they MUST be created before the interval/timeout is created in the code you are testing. + + logInfoStub = sandbox.stub(utils, 'logInfo');/* .callsFake((arg, arg1, arg2) => { //debugging stuff + console.log(arg); + if (arg1) console.log(arg1); + if (arg2) console.log(arg2); + }); */ + + conversantAnalytics.enableAnalytics(VALID_ALWAYS_SAMPLE_CONFIG); }); afterEach(function () { sandbox.restore(); requests = []; // clean up any requests in our ajax request capture array. + conversantAnalytics.disableAnalytics(); }); describe('Initialization Tests', function() { it('should log error if site id is not passed', function() { sandbox.stub(utils, 'logError'); - + conversantAnalytics.disableAnalytics(); conversantAnalytics.enableAnalytics(); expect(utils.logError.calledWith(CNVR_CONSTANTS.LOG_PREFIX + 'siteId is required.')).to.be.true; - conversantAnalytics.disableAnalytics(); }); it('should not log error if valid config is passed', function() { sandbox.stub(utils, 'logError'); - sandbox.stub(utils, 'logInfo'); conversantAnalytics.enableAnalytics(VALID_CONFIGURATION); expect(utils.logError.called).to.equal(false); @@ -78,7 +88,6 @@ describe('Conversant analytics adapter tests', function() { CNVR_CONSTANTS.LOG_PREFIX + 'Global sample rate set to 1' ) ).to.be.true; - conversantAnalytics.disableAnalytics(); }); it('should sample when sampling set to 1', function() { @@ -86,17 +95,16 @@ describe('Conversant analytics adapter tests', function() { conversantAnalytics.enableAnalytics(VALID_ALWAYS_SAMPLE_CONFIG); expect(utils.logError.called).to.equal(false); expect(cnvrHelper.doSample).to.equal(true); - conversantAnalytics.disableAnalytics(); }); it('should NOT sample when sampling set to 0', function() { sandbox.stub(utils, 'logError'); const NEVER_SAMPLE_CONFIG = utils.deepClone(VALID_ALWAYS_SAMPLE_CONFIG); NEVER_SAMPLE_CONFIG['options'].cnvr_sampling = 0; + conversantAnalytics.disableAnalytics(); conversantAnalytics.enableAnalytics(NEVER_SAMPLE_CONFIG); expect(utils.logError.called).to.equal(false); expect(cnvrHelper.doSample).to.equal(false); - conversantAnalytics.disableAnalytics(); }); }); @@ -113,14 +121,19 @@ describe('Conversant analytics adapter tests', function() { cnvrHelper.auctionIdTimestampCache['keep'] = {timeReceived: DATESTAMP + 1}; cnvrHelper.auctionIdTimestampCache['delete'] = {timeReceived: DATESTAMP - CNVR_CONSTANTS.MAX_MILLISECONDS_IN_CACHE}; + cnvrHelper.bidderErrorCache['keep'] = {timeReceived: DATESTAMP + 1, errors: []}; + cnvrHelper.bidderErrorCache['delete'] = {timeReceived: DATESTAMP - CNVR_CONSTANTS.MAX_MILLISECONDS_IN_CACHE, errors: []}; + expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(2); expect(Object.keys(cnvrHelper.timeoutCache)).to.have.lengthOf(2); expect(Object.keys(cnvrHelper.auctionIdTimestampCache)).to.have.lengthOf(2); + expect(Object.keys(cnvrHelper.bidderErrorCache)).to.have.lengthOf(2); clock.tick(CNVR_CONSTANTS.CACHE_CLEANUP_TIME_IN_MILLIS); expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(1); expect(Object.keys(cnvrHelper.timeoutCache)).to.have.lengthOf(1); expect(Object.keys(cnvrHelper.auctionIdTimestampCache)).to.have.lengthOf(1); + expect(Object.keys(cnvrHelper.bidderErrorCache)).to.have.lengthOf(1); conversantAnalytics.disableAnalytics(); @@ -128,6 +141,7 @@ describe('Conversant analytics adapter tests', function() { expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(0); expect(Object.keys(cnvrHelper.timeoutCache)).to.have.lengthOf(0); expect(Object.keys(cnvrHelper.auctionIdTimestampCache)).to.have.lengthOf(0); + expect(Object.keys(cnvrHelper.bidderErrorCache)).to.have.lengthOf(0); }); it('createBid() should return correct object', function() { @@ -173,6 +187,7 @@ describe('Conversant analytics adapter tests', function() { let payload = cnvrHelper.createPayload(REQUEST_TYPE, AUCTION_ID, myDate); expect(payload).to.deep.equal({ + bidderErrors: [], cnvrSampleRate: 1, globalSampleRate: 1, requestType: REQUEST_TYPE, @@ -184,8 +199,6 @@ describe('Conversant analytics adapter tests', function() { }, adUnits: {} }); - - conversantAnalytics.disableAnalytics(); }); it('keyExistsAndIsObject() should return correct data', function() { @@ -236,6 +249,68 @@ describe('Conversant analytics adapter tests', function() { expect(cnvrHelper.getSampleRate(obj, 'not_a_key', DEFAULT_VAL)).to.equal(DEFAULT_VAL); expect(cnvrHelper.getSampleRate(obj, 'too_small', DEFAULT_VAL)).to.equal(0); }); + + it('getPageUrl() should return correct data', function() { + let url = cnvrHelper.getPageUrl(); + expect(url.length).to.be.above(1); + }); + + it('sendErrorData() should send data via ajax', function() { + const error = { + stack: 'foobar', + message: 'foobar message' + }; + const eventType = 'fooType'; + + expect(requests).to.have.lengthOf(0); + cnvrHelper.sendErrorData(eventType, error); + expect(requests).to.have.lengthOf(1); + + expect(requests[0].url).to.contain('cvx/event/prebidanalyticerrors'); + const data = JSON.parse(requests[0].requestBody); + expect(data.event).to.be.equal(eventType); + expect(data.siteId).to.be.equal(SITE_ID); + expect(data.message).to.not.be.undefined; + expect(data.prebidVersion).to.not.be.undefined; + expect(data.userAgent).to.not.be.undefined; + expect(data.url).to.not.be.undefined; + }); + + it('Should not send data when error logging disabled', function() { + const error = { + stack: 'foobar', + message: 'foobar message' + }; + const eventType = 'fooType'; + + conversantAnalytics.disableAnalytics(); + conversantAnalytics.enableAnalytics({ + options: { + site_id: SITE_ID, + cnvr_sampling: 1, + send_error_data: false + } + }); + expect(cnvrHelper.doSendErrorData).to.be.false; + + expect(requests).to.have.lengthOf(0); + cnvrHelper.sendErrorData(eventType, error); + expect(requests).to.have.lengthOf(0); + + conversantAnalytics.disableAnalytics(); + conversantAnalytics.enableAnalytics({ + options: { + site_id: SITE_ID, + cnvr_sampling: 1, + send_error_data: 0 + } + }); + expect(cnvrHelper.doSendErrorData).to.be.false; + + expect(requests).to.have.lengthOf(0); + cnvrHelper.sendErrorData(eventType, error); + expect(requests).to.have.lengthOf(0); + }); }); describe('Bid Timeout Event Tests', function() { @@ -251,14 +326,6 @@ describe('Conversant analytics adapter tests', function() { 'auctionId': 'afbd6e0b-e45b-46ab-87bf-c0bac0cb8881' }]; - beforeEach(function () { - conversantAnalytics.enableAnalytics(VALID_ALWAYS_SAMPLE_CONFIG); - }); - - afterEach(function () { - conversantAnalytics.disableAnalytics(); - }); - it('should put both items in timeout cache', function() { expect(Object.keys(cnvrHelper.timeoutCache)).to.have.lengthOf(0); events.emit(constants.EVENTS.BID_TIMEOUT, BID_TIMEOUT_PAYLOAD); @@ -284,14 +351,6 @@ describe('Conversant analytics adapter tests', function() { message: 'value' }; - beforeEach(function () { - conversantAnalytics.enableAnalytics(VALID_ALWAYS_SAMPLE_CONFIG); - }); - - afterEach(function () { - conversantAnalytics.disableAnalytics(); - }); - it('should empty adIdLookup and send data', function() { cnvrHelper.adIdLookup[RENDER_FAILED_PAYLOAD.adId] = { bidderCode: 'bidderCode', @@ -323,9 +382,18 @@ describe('Conversant analytics adapter tests', function() { expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(1); events.emit(constants.EVENTS.AD_RENDER_FAILED, RENDER_FAILED_PAYLOAD_NO_ADID); - expect(requests).to.have.lengthOf(0); + expect(requests).to.have.lengthOf(1); expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(1); // same object in cache as before... no change expect(cnvrHelper.adIdLookup[RENDER_FAILED_PAYLOAD.adId]).to.not.be.undefined; + + expect(requests[0].url).to.contain('cvx/event/prebidanalyticerrors'); + const data = JSON.parse(requests[0].requestBody); + expect(data.event).to.be.equal(constants.EVENTS.AD_RENDER_FAILED); + expect(data.siteId).to.be.equal(SITE_ID); + expect(data.message).to.not.be.undefined; + expect(data.prebidVersion).to.not.be.undefined; + expect(data.userAgent).to.not.be.undefined; + expect(data.url).to.not.be.undefined; }); it('should not send data if bad data in lookup', function() { @@ -338,7 +406,16 @@ describe('Conversant analytics adapter tests', function() { expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(1); events.emit(constants.EVENTS.AD_RENDER_FAILED, RENDER_FAILED_PAYLOAD); expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(0); // object should be removed but no call made to send data - expect(requests).to.have.lengthOf(0); + expect(requests).to.have.lengthOf(1); + + expect(requests[0].url).to.contain('cvx/event/prebidanalyticerrors'); + const data = JSON.parse(requests[0].requestBody); + expect(data.event).to.be.equal(constants.EVENTS.AD_RENDER_FAILED); + expect(data.siteId).to.be.equal(SITE_ID); + expect(data.message).to.not.be.undefined; + expect(data.prebidVersion).to.not.be.undefined; + expect(data.userAgent).to.not.be.undefined; + expect(data.url).to.not.be.undefined; }); }); @@ -414,20 +491,22 @@ describe('Conversant analytics adapter tests', function() { ] }; - beforeEach(function () { - conversantAnalytics.enableAnalytics(VALID_ALWAYS_SAMPLE_CONFIG); - }); - - afterEach(function () { - conversantAnalytics.disableAnalytics(); - }); - it('should not send data or put a record in adIdLookup when bad data provided', function() { expect(requests).to.have.lengthOf(0); expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(0); events.emit(constants.EVENTS.BID_WON, BAD_BID_WON_ARGS); - expect(requests).to.have.lengthOf(0); + expect(requests).to.have.lengthOf(1); expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(0); + + // check for error event + expect(requests[0].url).to.contain('cvx/event/prebidanalyticerrors'); + const data = JSON.parse(requests[0].requestBody); + expect(data.event).to.be.equal(constants.EVENTS.BID_WON); + expect(data.siteId).to.be.equal(SITE_ID); + expect(data.message).to.not.be.undefined; + expect(data.prebidVersion).to.not.be.undefined; + expect(data.userAgent).to.not.be.undefined; + expect(data.url).to.not.be.undefined; }); it('should send data and put a record in adIdLookup', function() { @@ -834,14 +913,6 @@ describe('Conversant analytics adapter tests', function() { timeout: 3000 }; - beforeEach(function () { - conversantAnalytics.enableAnalytics(VALID_ALWAYS_SAMPLE_CONFIG); - }); - - afterEach(function () { - conversantAnalytics.disableAnalytics(); - }); - it('should not do anything when auction id doesnt exist', function() { sandbox.stub(utils, 'logError'); @@ -849,30 +920,48 @@ describe('Conversant analytics adapter tests', function() { delete BAD_ARGS.auctionId; expect(requests).to.have.lengthOf(0); events.emit(constants.EVENTS.AUCTION_END, BAD_ARGS); - expect(requests).to.have.lengthOf(0); - expect( - utils.logError.calledWith( - CNVR_CONSTANTS.LOG_PREFIX + 'onAuctionEnd(): No auctionId in args supplied so unable to process event.' - ) - ).to.be.true; + expect(requests).to.have.lengthOf(1); + + // check for error event + expect(requests[0].url).to.contain('cvx/event/prebidanalyticerrors'); + const data = JSON.parse(requests[0].requestBody); + expect(data.event).to.be.equal(constants.EVENTS.AUCTION_END); + expect(data.siteId).to.be.equal(SITE_ID); + expect(data.message).to.not.be.undefined; + expect(data.prebidVersion).to.not.be.undefined; + expect(data.userAgent).to.not.be.undefined; + expect(data.url).to.not.be.undefined; }); it('should send the expected data', function() { sandbox.stub(utils, 'logError'); - sandbox.stub(utils, 'logWarn'); /* .callsFake((arg, arg1, arg2) => { //debugging stuff - console.error(arg); - if (arg1) console.error(arg1); - if (arg2) console.error(arg2); - }); */ + sandbox.stub(utils, 'logWarn'); + expect(requests).to.have.lengthOf(0); const AUCTION_ID = AUCTION_END_PAYLOAD.auctionId; const AD_UNIT_CODE = AUCTION_END_PAYLOAD.adUnits[0].code; const AD_UNIT_CODE_NATIVE = AUCTION_END_PAYLOAD.adUnits[2].code; const timeoutKey = cnvrHelper.getLookupKey(AUCTION_ID, AD_UNIT_CODE, 'appnexus'); + const URL = 'some url'; + cnvrHelper.bidderErrorCache[AUCTION_ID] = { + errors: [{ + status: 500, + message: 'error msg', + bidderCode: 'bidderCode', + url: URL, + }, { + status: 501, + message: 'error msg1', + bidderCode: 'bidderCode1', + url: URL, + }], + timeReceived: Date.now() + }; cnvrHelper.timeoutCache[timeoutKey] = { timeReceived: Date.now() }; expect(Object.keys(cnvrHelper.timeoutCache)).to.have.lengthOf(1); expect(utils.logError.called).to.equal(false); expect(Object.keys(cnvrHelper.auctionIdTimestampCache)).to.have.lengthOf(0); + expect(Object.keys(cnvrHelper.bidderErrorCache)).to.have.lengthOf(1); events.emit(constants.EVENTS.AUCTION_END, AUCTION_END_PAYLOAD); expect(utils.logError.called).to.equal(false); @@ -958,6 +1047,69 @@ describe('Conversant analytics adapter tests', function() { expect(apnNativeBid.adSize.w).to.be.undefined; expect(apnNativeBid.adSize.h).to.be.undefined; expect(apnNativeBid.mediaType).to.equal('native'); + + expect(Object.keys(data.bidderErrors)).to.have.lengthOf(2); + expect(data.bidderErrors[0].status).to.equal(500); + expect(data.bidderErrors[0].url).to.equal(URL); + expect(data.bidderErrors[0].message).to.not.be.undefined; + expect(data.bidderErrors[0].bidderCode).to.not.be.undefined; + + expect(data.bidderErrors[1].status).to.equal(501); + expect(data.bidderErrors[1].url).to.equal(URL); + expect(data.bidderErrors[1].message).to.not.be.undefined; + expect(data.bidderErrors[1].bidderCode).to.not.be.undefined; + + expect(Object.keys(cnvrHelper.bidderErrorCache)).to.have.lengthOf(0); + }); + }); + + describe('Bidder Error Tests', function() { + // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest + const XHR_ERROR_MOCK = { + status: 500, + statusText: 'Internal Server Error' + }; + + // https://docs.prebid.org/dev-docs/bidder-adaptor.html#registering-on-bidder-error + const MOCK_BID_REQUEST = { + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + auctionStart: 1579746300522, + bidderCode: 'myBidderCode', + bidderRequestId: '15246a574e859f', + bids: [{}], + gdprConsent: {consentString: 'BOtmiBKOtmiBKABABAENAFAAAAACeAAA', vendorData: {}, gdprApplies: true}, + refererInfo: { + canonicalUrl: null, + page: 'http://mypage.org?pbjs_debug=true', + domain: 'mypage.org', + ref: null, + numIframes: 0, + reachedTop: true, + isAmp: false, + stack: ['http://mypage.org?pbjs_debug=true'] + } + }; + + it('should record error when bidder_error called', function() { + let warnStub = sandbox.stub(utils, 'logWarn'); + expect(requests).to.have.lengthOf(0); + expect(Object.keys(cnvrHelper.bidderErrorCache)).to.have.lengthOf(0); + expect(warnStub.calledOnce).to.be.false; + + events.emit(constants.EVENTS.BIDDER_ERROR, {'error': XHR_ERROR_MOCK, 'bidderRequest': MOCK_BID_REQUEST}); + expect(Object.keys(cnvrHelper.bidderErrorCache)).to.have.lengthOf(1); + expect(warnStub.calledOnce).to.be.true; + + let errorObj = cnvrHelper.bidderErrorCache[MOCK_BID_REQUEST.auctionId]; + expect(errorObj.errors).to.have.lengthOf(1); + expect(errorObj.errors[0].status).to.equal(XHR_ERROR_MOCK.status); + expect(errorObj.errors[0].message).to.equal(XHR_ERROR_MOCK.statusText); + expect(errorObj.errors[0].bidderCode).to.equal(MOCK_BID_REQUEST.bidderCode); + expect(errorObj.errors[0].url).to.not.be.undefined; + + events.emit(constants.EVENTS.BIDDER_ERROR, {'error': XHR_ERROR_MOCK, 'bidderRequest': MOCK_BID_REQUEST}); + errorObj = cnvrHelper.bidderErrorCache[MOCK_BID_REQUEST.auctionId]; + expect(errorObj.errors).to.have.lengthOf(2); }); }); }); diff --git a/test/spec/modules/cpexIdSystem_spec.js b/test/spec/modules/cpexIdSystem_spec.js index e1320d82a6a..6e004c9f8ca 100644 --- a/test/spec/modules/cpexIdSystem_spec.js +++ b/test/spec/modules/cpexIdSystem_spec.js @@ -1,6 +1,6 @@ -import { cpexIdSubmodule, storage } from 'modules/cpexIdSystem.js'; +import { czechAdIdSubmodule, storage } from 'modules/czechAdIdSystem.js'; -describe('cpexId module', function () { +describe('czechAdId module', function () { let getCookieStub; beforeEach(function (done) { @@ -16,23 +16,23 @@ describe('cpexId module', function () { describe('getId()', function () { it('should return the uid when it exists in cookie', function () { - getCookieStub.withArgs('czaid').returns('cpexIdTest'); - const id = cpexIdSubmodule.getId(); - expect(id).to.be.deep.equal({ id: 'cpexIdTest' }); + getCookieStub.withArgs('czaid').returns('czechAdIdTest'); + const id = czechAdIdSubmodule.getId(); + expect(id).to.be.deep.equal({ id: 'czechAdIdTest' }); }); cookieTestCasesForEmpty.forEach(testCase => it('should not return the uid when it doesnt exist in cookie', function () { getCookieStub.withArgs('czaid').returns(testCase); - const id = cpexIdSubmodule.getId(); + const id = czechAdIdSubmodule.getId(); expect(id).to.be.undefined; })); }); describe('decode()', function () { it('should return the uid when it exists in cookie', function () { - getCookieStub.withArgs('czaid').returns('cpexIdTest'); - const decoded = cpexIdSubmodule.decode(); - expect(decoded).to.be.deep.equal({ cpexId: 'cpexIdTest' }); + getCookieStub.withArgs('czaid').returns('czechAdIdTest'); + const decoded = czechAdIdSubmodule.decode(); + expect(decoded).to.be.deep.equal({ czechAdId: 'czechAdIdTest' }); }); }); }); diff --git a/test/spec/modules/criteoBidAdapter_spec.js b/test/spec/modules/criteoBidAdapter_spec.js index c54453bd7fc..da1a0ca7f32 100755 --- a/test/spec/modules/criteoBidAdapter_spec.js +++ b/test/spec/modules/criteoBidAdapter_spec.js @@ -1156,6 +1156,18 @@ describe('The Criteo bidding adapter', function () { it('should properly build a request with first party data', function () { const siteData = { keywords: ['power tools'], + content: { + data: [{ + name: 'some_provider', + ext: { + segtax: 3 + }, + segment: [ + { 'id': '1001' }, + { 'id': '1002' } + ] + }] + }, ext: { data: { pageType: 'article' @@ -1164,6 +1176,16 @@ describe('The Criteo bidding adapter', function () { }; const userData = { gender: 'M', + data: [{ + name: 'some_provider', + ext: { + segtax: 3 + }, + segment: [ + { 'id': '1001' }, + { 'id': '1002' } + ] + }], ext: { data: { registered: true @@ -1203,7 +1225,8 @@ describe('The Criteo bidding adapter', function () { const request = spec.buildRequests(bidRequests, { ...bidderRequest, ortb2 }); expect(request.data.publisher.ext).to.deep.equal({ data: { pageType: 'article' } }); - expect(request.data.user.ext).to.deep.equal({ data: { registered: true } }); + expect(request.data.user).to.deep.equal(userData); + expect(request.data.site).to.deep.equal(siteData); expect(request.data.slots[0].ext).to.deep.equal({ bidfloor: 0.75, data: { diff --git a/test/spec/modules/cwireBidAdapter_spec.js b/test/spec/modules/cwireBidAdapter_spec.js index f116b184b8c..88c54212aff 100644 --- a/test/spec/modules/cwireBidAdapter_spec.js +++ b/test/spec/modules/cwireBidAdapter_spec.js @@ -1,382 +1,296 @@ -import { expect } from 'chai'; -import * as utils from '../../../src/utils.js'; -import { config } from '../../../src/config.js'; -import { - spec, - CW_PAGE_VIEW_ID, - ENDPOINT_URL, - RENDERER_URL, -} from '../../../modules/cwireBidAdapter.js'; -import * as prebidGlobal from 'src/prebidGlobal.js'; - -// ------------------------------------ -// Bid Request Builder -// ------------------------------------ - -const BID_DEFAULTS = { - request: { - bidder: 'cwire', - auctionId: 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee', - transactionId: 'txaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee', - bidId: 'bid123445', - bidderRequestId: 'brid12345', - code: 'original-div', - }, - params: { - placementId: 123456, - pageId: 777, - }, - sizes: [[300, 250], [1, 1]], -}; - -const BidderRequestBuilder = function BidderRequestBuilder(options) { - const defaults = { - bidderCode: 'cwire', - auctionId: BID_DEFAULTS.request.auctionId, - bidderRequestId: BID_DEFAULTS.request.bidderRequestId, - transactionId: BID_DEFAULTS.request.transactionId, - timeout: 3000, - }; - - const request = { - ...defaults, - ...options - }; - - this.build = () => request; -}; - -const BidRequestBuilder = function BidRequestBuilder(options, deleteKeys) { - const defaults = JSON.parse(JSON.stringify(BID_DEFAULTS)); - - const request = { - ...defaults.request, - ...options - }; - - if (request && utils.isArray(deleteKeys)) { - deleteKeys.forEach((k) => { - delete request[k]; - }) - } - - this.withParams = (options, deleteKeys) => { - request.params = { - ...defaults.params, - ...options - }; - if (request && utils.isArray(deleteKeys)) { - deleteKeys.forEach((k) => { - delete request.params[k]; - }) - } - return this; - }; - - this.build = () => request; -}; +import {expect} from 'chai'; +import {newBidder} from '../../../src/adapters/bidderFactory'; +import {BID_ENDPOINT, spec, storage} from '../../../modules/cwireBidAdapter'; +import {deepClone, logInfo} from '../../../src/utils'; +import * as utils from 'src/utils.js'; +import {sandbox, stub} from 'sinon'; +import {config} from '../../../src/config'; describe('C-WIRE bid adapter', () => { - let sandbox; - - beforeEach(() => { - sandbox = sinon.createSandbox(); + config.setConfig({debug: true}); + const adapter = newBidder(spec); + let bidRequests = [ + { + 'bidder': 'cwire', + 'params': { + 'pageId': '4057', + 'placementId': 'ad-slot-bla' + }, + 'adUnitCode': 'adunit-code', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + 'transactionId': '04f2659e-c005-4eb1-a57c-fa93145e3843' + } + ]; + const response = { + body: { + 'cwid': '2ef90743-7936-4a82-8acf-e73382a64e94', + 'hash': '17112D98BBF55D3A', + 'bids': [{ + 'html': '

Hello world

', + 'cpm': 100, + 'currency': 'CHF', + 'dimensions': [1, 1], + 'netRevenue': true, + 'creativeId': '3454', + 'requestId': '2c634d4ca5ccfb', + 'placementId': 177, + 'transactionId': 'b4b32618-1350-4828-b6f0-fbb5c329e9a4', + 'ttl': 360 + }] + } + } + describe('inherited functions', function () { + it('exists and is a function', function () { + expect(adapter.callBids).to.exist.and.to.be.a('function'); + expect(spec.isBidRequestValid).to.exist.and.to.be.a('function'); + expect(spec.buildRequests).to.exist.and.to.be.a('function'); + expect(spec.interpretResponse).to.exist.and.to.be.a('function'); + }); }); - - afterEach(() => { - sandbox.restore(); - config.resetConfig(); + describe('buildRequests', function () { + it('sends bid request to ENDPOINT via POST', function () { + const request = spec.buildRequests(bidRequests); + expect(request.url).to.equal(BID_ENDPOINT); + expect(request.method).to.equal('POST'); + }); }); + describe('buildRequests with given creative', function () { + let utilsStub; - // START TESTING - describe('C-WIRE - isBidRequestValid', function () { - it('should return true when required params found', function () { - const bid01 = new BidRequestBuilder().withParams().build(); - expect(spec.isBidRequestValid(bid01)).to.equal(true); + before(function () { + utilsStub = stub(utils, 'getParameterByName').callsFake(function () { + return 'str-str' + }); }); - it('should fail if there is no placementId', function () { - const bid01 = new BidRequestBuilder().withParams().build(); - delete bid01.params.placementId - expect(spec.isBidRequestValid(bid01)).to.equal(false); + after(function () { + utilsStub.restore(); }); - it('should fail if invalid placementId type', function () { - const bid01 = new BidRequestBuilder().withParams().build(); - delete bid01.params.placementId; - bid01.placementId = '322'; - expect(spec.isBidRequestValid(bid01)).to.equal(false); + it('should add creativeId if url parameter given', function () { + // set from bid.params + let bidRequest = deepClone(bidRequests[0]); + + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + expect(payload.cwcreative).to.exist; + expect(payload.cwcreative).to.deep.equal('str-str'); + }); + }) + + describe('buildRequests reads adUnit offsetWidth and offsetHeight', function () { + before(function () { + const documentStub = sandbox.stub(document, 'getElementById'); + documentStub.withArgs(`${bidRequests[0].adUnitCode}`).returns({ + offsetWidth: 200, + offsetHeight: 250 + }); }); + it('width and height should be set', function () { + let bidRequest = deepClone(bidRequests[0]); - it('should fail if there is no pageId', function () { - const bid01 = new BidRequestBuilder().withParams().build(); - delete bid01.params.pageId - expect(spec.isBidRequestValid(bid01)).to.equal(false); + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + const el = document.getElementById(`${bidRequest.adUnitCode}`) + + logInfo(JSON.stringify(payload)) + + expect(el).to.exist; + expect(payload.slots[0].cwExt.dimensions.width).to.equal(200); + expect(payload.slots[0].cwExt.dimensions.height).to.equal(250); + expect(payload.slots[0].cwExt.style.maxHeight).to.not.exist; + expect(payload.slots[0].cwExt.style.maxWidth).to.not.exist; + }); + after(function () { + sandbox.restore() + }); + }); + describe('buildRequests reads style attributes', function () { + before(function () { + const documentStub = sandbox.stub(document, 'getElementById'); + documentStub.withArgs(`${bidRequests[0].adUnitCode}`).returns({ + style: { + maxWidth: '400px', + maxHeight: '350px', + } + }); }); + it('css maxWidth should be set', function () { + let bidRequest = deepClone(bidRequests[0]); + + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + const el = document.getElementById(`${bidRequest.adUnitCode}`) + + logInfo(JSON.stringify(payload)) - it('should fail if invalid pageId type', function () { - const bid01 = new BidRequestBuilder().withParams().build(); - delete bid01.params.pageId; - bid01.params.pageId = '3320'; - expect(spec.isBidRequestValid(bid01)).to.equal(false); + expect(el).to.exist; + expect(payload.slots[0].cwExt.style.maxWidth).to.eq('400px'); + !expect(payload.slots[0].cwExt.style.maxHeight).to.eq('350px'); }); + after(function () { + sandbox.restore() + }); + }); - it('should fail if cwcreative of type number', function () { - const bid01 = new BidRequestBuilder().withParams().build(); - delete bid01.params.cwcreative; - bid01.params.cwcreative = 3320; - expect(spec.isBidRequestValid(bid01)).to.equal(false); + describe('buildRequests reads feature flags', function () { + before(function () { + sandbox.stub(utils, 'getParameterByName').callsFake(function () { + return 'feature1,feature2' + }); }); - it('should pass with valid cwcreative of type string', function () { - const bid01 = new BidRequestBuilder().withParams().build(); - bid01.params.cwcreative = 'i-am-a-string'; - expect(spec.isBidRequestValid(bid01)).to.equal(true); + it('read from url parameter', function () { + let bidRequest = deepClone(bidRequests[0]); + + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + + logInfo(JSON.stringify(payload)) + + expect(payload.featureFlags).to.exist; + expect(payload.featureFlags).to.include.members(['feature1', 'feature2']); + }); + after(function () { + sandbox.restore() }); }); - describe('C-WIRE - buildRequests()', function () { - it('creates a valid request', function () { - const bid01 = new BidRequestBuilder({ - mediaTypes: { - banner: { - sizes: [[1, 1]], - } - } - }).withParams({ - cwcreative: '54321', - cwapikey: 'xxx-xxx-yyy-zzz-uuid', - refgroups: 'group_1', - }).build(); - - const bidderRequest01 = new BidderRequestBuilder().build(); - - const requests = spec.buildRequests([bid01], bidderRequest01); - - expect(requests.data.slots.length).to.equal(1); - expect(requests.data.cwid).to.be.null; - expect(requests.data.cwid).to.be.null; - expect(requests.data.slots[0].sizes[0]).to.equal('1x1'); - expect(requests.data.cwcreative).to.equal('54321'); - expect(requests.data.cwapikey).to.equal('xxx-xxx-yyy-zzz-uuid'); - expect(requests.data.refgroups[0]).to.equal('group_1'); + describe('buildRequests reads cwgroups flag', function () { + before(function () { + sandbox.stub(utils, 'getParameterByName').callsFake(function () { + return 'group1,group2' + }); }); - it('creates a valid request - read debug params from second bid', function () { - const bid01 = new BidRequestBuilder().withParams().build(); + it('read from url parameter', function () { + let bidRequest = deepClone(bidRequests[0]); - const bid02 = new BidRequestBuilder({ - mediaTypes: { - banner: { - sizes: [[1, 1]], - } - } - }).withParams({ - cwcreative: '1234', - cwapikey: 'api_key_5', - refgroups: 'group_5', - }).build(); - - const bidderRequest01 = new BidderRequestBuilder().build(); - - const requests = spec.buildRequests([bid01, bid02], bidderRequest01); - - expect(requests.data.slots.length).to.equal(2); - expect(requests.data.cwid).to.be.null; - expect(requests.data.cwid).to.be.null; - expect(requests.data.cwcreative).to.equal('1234'); - expect(requests.data.cwapikey).to.equal('api_key_5'); - expect(requests.data.refgroups[0]).to.equal('group_5'); + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + + logInfo(JSON.stringify(payload)) + + expect(payload.refgroups).to.exist; + expect(payload.refgroups).to.include.members(['group1', 'group2']); + }); + after(function () { + sandbox.restore() }); + }) - it('creates a valid request - read debug params from first bid, ignore second', function () { - const bid01 = new BidRequestBuilder() - .withParams({ - cwcreative: '33', - cwapikey: 'api_key_33', - refgroups: 'group_33', - }).build(); - - const bid02 = new BidRequestBuilder() - .withParams({ - cwcreative: '1234', - cwapikey: 'api_key_5', - refgroups: 'group_5', - }).build(); - - const bidderRequest01 = new BidderRequestBuilder().build(); - - const requests = spec.buildRequests([bid01, bid02], bidderRequest01); - - expect(requests.data.slots.length).to.equal(2); - expect(requests.data.cwid).to.be.null; - expect(requests.data.cwid).to.be.null; - expect(requests.data.cwcreative).to.equal('33'); - expect(requests.data.cwapikey).to.equal('api_key_33'); - expect(requests.data.refgroups[0]).to.equal('group_33'); + describe('buildRequests reads debug flag', function () { + before(function () { + sandbox.stub(utils, 'getParameterByName').callsFake(function () { + return 'true' + }); }); - it('creates a valid request - read debug params from 3 different slots', function () { - const bid01 = new BidRequestBuilder() - .withParams({ - cwcreative: '33', - }).build(); - - const bid02 = new BidRequestBuilder() - .withParams({ - cwapikey: 'api_key_5', - }).build(); - - const bid03 = new BidRequestBuilder() - .withParams({ - refgroups: 'group_5', - }).build(); - const bidderRequest01 = new BidderRequestBuilder().build(); - - const requests = spec.buildRequests([bid01, bid02, bid03], bidderRequest01); - - expect(requests.data.slots.length).to.equal(3); - expect(requests.data.cwid).to.be.null; - expect(requests.data.cwid).to.be.null; - expect(requests.data.cwcreative).to.equal('33'); - expect(requests.data.cwapikey).to.equal('api_key_5'); - expect(requests.data.refgroups[0]).to.equal('group_5'); + it('read from url parameter', function () { + let bidRequest = deepClone(bidRequests[0]); + + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + + logInfo(JSON.stringify(payload)) + + expect(payload.debug).to.exist; + expect(payload.debug).to.equal(true); + }); + after(function () { + sandbox.restore() }); + }) - it('creates a valid request - config is overriden by URL params', function () { - // for whatever reason stub for getWindowLocation does not work - // so this was the closest way to test for get params - const params = sandbox.stub(utils, 'getParameterByName'); - params.withArgs('cwgroups').returns('group_2'); - params.withArgs('cwcreative').returns('654321'); - - const bid01 = new BidRequestBuilder({ - mediaTypes: { - banner: { - sizes: [[1, 1]], - } - } - }).withParams({ - cwcreative: '54321', - cwapikey: 'xxx-xxx-yyy-zzz', - refgroups: 'group_1', - }).build(); - - const bidderRequest01 = new BidderRequestBuilder().build(); - - const requests = spec.buildRequests([bid01], bidderRequest01); - - expect(requests.data.slots.length).to.equal(1); - expect(requests.data.cwid).to.be.null; - expect(requests.data.cwid).to.be.null; - expect(requests.data.slots[0].sizes[0]).to.equal('1x1'); - expect(requests.data.cwcreative).to.equal('654321'); - expect(requests.data.cwapikey).to.equal('xxx-xxx-yyy-zzz'); - expect(requests.data.refgroups[0]).to.equal('group_2'); + describe('buildRequests reads cw_id from Localstorage', function () { + before(function () { + sandbox.stub(storage, 'localStorageIsEnabled').callsFake(() => true); + sandbox.stub(storage, 'setDataInLocalStorage'); + sandbox.stub(storage, 'getDataFromLocalStorage').callsFake((key) => 'taerfagerg'); }); - it('creates a valid request - if params are not set, null or empty array are sent to the API', function () { - const bid01 = new BidRequestBuilder({ - mediaTypes: { - banner: { - sizes: [[1, 1]], - } - } - }).withParams().build(); + it('cw_id is set', function () { + let bidRequest = deepClone(bidRequests[0]); - const bidderRequest01 = new BidderRequestBuilder().build(); + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); - const requests = spec.buildRequests([bid01], bidderRequest01); + logInfo(JSON.stringify(payload)) - expect(requests.data.slots.length).to.equal(1); - expect(requests.data.cwid).to.be.null; - expect(requests.data.cwid).to.be.null; - expect(requests.data.slots[0].sizes[0]).to.equal('1x1'); - expect(requests.data.cwcreative).to.equal(null); - expect(requests.data.cwapikey).to.equal(null); - expect(requests.data.refgroups.length).to.equal(0); + expect(payload.cwid).to.exist; + expect(payload.cwid).to.equal('taerfagerg'); }); - }); + after(function () { + sandbox.restore() + }); + }) - describe('C-WIRE - interpretResponse()', function () { - const serverResponse = { - body: { - bids: [{ - html: '

AD CONTENT

', - currency: 'CHF', - cpm: 43.37, - dimensions: [1, 1], - netRevenue: true, - creativeId: '1337', - requestId: BID_DEFAULTS.request.bidId, - ttl: 3500, - }], - } - }; - - const expectedResponse = [{ - ad: JSON.parse(JSON.stringify(serverResponse.body.bids[0].html)), - bidderCode: BID_DEFAULTS.request.bidder, - cpm: JSON.parse(JSON.stringify(serverResponse.body.bids[0].cpm)), - creativeId: JSON.parse(JSON.stringify(serverResponse.body.bids[0].creativeId)), - currency: JSON.parse(JSON.stringify(serverResponse.body.bids[0].currency)), - height: JSON.parse(JSON.stringify(serverResponse.body.bids[0].dimensions[0])), - width: JSON.parse(JSON.stringify(serverResponse.body.bids[0].dimensions[1])), - netRevenue: JSON.parse(JSON.stringify(serverResponse.body.bids[0].netRevenue)), - requestId: JSON.parse(JSON.stringify(serverResponse.body.bids[0].requestId)), - ttl: JSON.parse(JSON.stringify(serverResponse.body.bids[0].ttl)), - meta: { - advertiserDomains: [], - }, - mediaType: 'banner', - }] - - it('correctly parses response', function () { - const bid01 = new BidRequestBuilder({ - mediaTypes: { - banner: { - sizes: [[1, 1]], - } - } - }).withParams().build(); + describe('buildRequests maps flattens params for legacy compat', function () { + before(function () { + const documentStub = sandbox.stub(document, 'getElementById'); + documentStub.withArgs(`${bidRequests[0].adUnitCode}`).returns({}); + }); + it('pageId flattened', function () { + let bidRequest = deepClone(bidRequests[0]); - const bidderRequest01 = new BidderRequestBuilder().build(); - const requests = spec.buildRequests([bid01], bidderRequest01); + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); - const response = spec.interpretResponse(serverResponse, requests); - expect(response).to.deep.equal(expectedResponse); + logInfo(JSON.stringify(payload)) + + expect(payload.slots[0].pageId).to.exist; + }); + after(function () { + sandbox.restore() }); + }) - it('attaches renderer', function () { - const bid01 = new BidRequestBuilder({ - mediaTypes: { - video: { - playerSize: [[640, 480]], - context: 'outstream', - } - } - }).withParams().build(); - const bidderRequest01 = new BidderRequestBuilder().build(); + describe('pageId and placementId are required params', function () { + it('invalid request', function () { + let bidRequest = deepClone(bidRequests[0]); + delete bidRequest.params + + const valid = spec.isBidRequestValid(bidRequest); + expect(valid).to.be.false; + }) - const _serverResponse = utils.deepClone(serverResponse); - _serverResponse.body.bids[0].vastXml = ''; + it('valid request', function () { + let bidRequest = deepClone(bidRequests[0]); + bidRequest.params.pageId = 42 + bidRequest.params.placementId = 42 - const _expectedResponse = utils.deepClone(expectedResponse); - _expectedResponse[0].mediaType = 'video'; - _expectedResponse[0].videoScript = JSON.parse(JSON.stringify(_serverResponse.body.bids[0].html)); - _expectedResponse[0].vastXml = JSON.parse(JSON.stringify(_serverResponse.body.bids[0].vastXml)); - delete _expectedResponse[0].ad; + const valid = spec.isBidRequestValid(bidRequest); + expect(valid).to.be.true; + }) - const requests = spec.buildRequests([bid01], bidderRequest01); - expect(requests.data.slots[0].sizes).to.deep.equal(['640x480']); + it('cwcreative must be of type string', function () { + let bidRequest = deepClone(bidRequests[0]); + bidRequest.params.pageId = 42 + bidRequest.params.placementId = 42 - const response = spec.interpretResponse(_serverResponse, requests); - expect(response[0].renderer).to.exist; - expect(response[0].renderer.url).to.equals(RENDERER_URL); - expect(response[0].renderer.loaded).to.equals(false); + const valid = spec.isBidRequestValid(bidRequest); + expect(valid).to.be.true; + }) - delete response[0].renderer; - expect(response).to.deep.equal(_expectedResponse); - }); + it('build request adds pageId', function () { + let bidRequest = deepClone(bidRequests[0]); + + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + + expect(payload.slots[0].pageId).to.exist; + }) + }); + + describe('process serverResponse', function () { + it('html to ad mapping', function () { + let bidResponse = deepClone(response); + const bids = spec.interpretResponse(bidResponse, {}); + + expect(bids[0].ad).to.exist; + }) }); }); diff --git a/test/spec/modules/dgkeywordRtdProvider_spec.js b/test/spec/modules/dgkeywordRtdProvider_spec.js index 16f2906b681..754740b7a64 100644 --- a/test/spec/modules/dgkeywordRtdProvider_spec.js +++ b/test/spec/modules/dgkeywordRtdProvider_spec.js @@ -383,10 +383,11 @@ describe('Digital Garage Keyword Module', function () { } let moduleConfig = cloneDeep(DEF_CONFIG); window.localStorage.setItem('ope_fpid', uuid); + moduleConfig.params.enableReadFpid = true; dgRtd.getDgKeywordsAndSet( pbjs, () => { - const url = dgRtd.getProfileApiUrl(null); + const url = dgRtd.getProfileApiUrl(null, moduleConfig.params.enableReadFpid); expect(url.indexOf(uuid) > 0).to.equal(true); expect(url).to.equal(server.requests[0].url); done(); @@ -410,11 +411,10 @@ describe('Digital Garage Keyword Module', function () { } let moduleConfig = cloneDeep(DEF_CONFIG); window.localStorage.setItem('ope_fpid', uuid); - moduleConfig.params.disableReadFpid = true; dgRtd.getDgKeywordsAndSet( pbjs, () => { - const url = dgRtd.getProfileApiUrl(null, moduleConfig.params.disableReadFpid); + const url = dgRtd.getProfileApiUrl(null); expect(url.indexOf(uuid) > 0).to.equal(false); expect(url).to.equal(server.requests[0].url); done(); diff --git a/test/spec/modules/discoveryBidAdapter_spec.js b/test/spec/modules/discoveryBidAdapter_spec.js index a30afd96ad1..078add73046 100644 --- a/test/spec/modules/discoveryBidAdapter_spec.js +++ b/test/spec/modules/discoveryBidAdapter_spec.js @@ -1,14 +1,14 @@ import { expect } from 'chai'; import { spec } from 'modules/discoveryBidAdapter.js'; -describe('DiscoveryDSP:BidAdapterTests', function () { +describe('discovery:BidAdapterTests', function () { let bidRequestData = { - bidderCode: 'DiscoveryDSP', + bidderCode: 'discovery', auctionId: 'ff66e39e-4075-4d18-9854-56fde9b879ac', bidderRequestId: '4fec04e87ad785', bids: [ { - bidder: 'DiscoveryDSP', + bidder: 'discovery', params: { token: 'd0f4902b616cc5c38cbe0a08676d0ed9', }, @@ -32,25 +32,26 @@ describe('DiscoveryDSP:BidAdapterTests', function () { }; let request = []; - it('DiscoveryDSP:validate_pub_params', function () { + it('discovery:validate_pub_params', function () { expect( spec.isBidRequestValid({ - bidder: 'DiscoveryDSP', + bidder: 'discovery', params: { token: ['d0f4902b616cc5c38cbe0a08676d0ed9'], - media: ['test_media'] + tagid: ['test_tagid'], + publisher: ['test_publisher'] }, }) ).to.equal(true); }); - it('DiscoveryDSP:validate_generated_params', function () { + it('discovery:validate_generated_params', function () { request = spec.buildRequests(bidRequestData.bids, bidRequestData); let req_data = JSON.parse(request.data); expect(req_data.imp).to.have.lengthOf(1); }); - it('DiscoveryDSP:validate_response_params', function () { + it('discovery:validate_response_params', function () { let tempAdm = '' tempAdm += '%3Cscr'; tempAdm += 'ipt%3E'; diff --git a/test/spec/modules/eids_spec.js b/test/spec/modules/eids_spec.js index ba9210dcb71..f076866a080 100644 --- a/test/spec/modules/eids_spec.js +++ b/test/spec/modules/eids_spec.js @@ -392,7 +392,7 @@ describe('eids array generation for known sub-modules', function() { const [eid] = createEidsArray(userId); expect(eid).to.deep.equal({ - source: 'amxrtb.com', + source: 'amxdt.net', uids: [{ atype: 1, id, @@ -432,9 +432,9 @@ describe('eids array generation for known sub-modules', function() { }); }); - it('cpexId', () => { + it('czechAdId', () => { const id = 'some-random-id-value' - const userId = { cpexId: id }; + const userId = { czechAdId: id }; const [eid] = createEidsArray(userId); expect(eid).to.deep.equal({ source: 'czechadid.cz', @@ -461,13 +461,16 @@ describe('eids array generation for known sub-modules', function() { ipsum: '' } })).to.deep.equal([{ - atype: 1, - id: 'test-device-id', - ext: { - DeviceID: 'test-device-id', - SingleDeviceID: 'test-single-device-id', - HHID: 'test-household-id' - } + source: 'flashtalking.com', + uids: [{ + atype: 1, + id: 'test-device-id', + ext: { + DeviceID: 'test-device-id', + SingleDeviceID: 'test-single-device-id', + HHID: 'test-household-id' + } + }] }]); }); }); diff --git a/test/spec/modules/emx_digitalBidAdapter_spec.js b/test/spec/modules/emx_digitalBidAdapter_spec.js index d99318b5ddc..d80d0f3e875 100644 --- a/test/spec/modules/emx_digitalBidAdapter_spec.js +++ b/test/spec/modules/emx_digitalBidAdapter_spec.js @@ -707,7 +707,7 @@ describe('emx_digital Adapter', function () { })); }); - it('returns valid advertiser domain', function () { + it('returns valid advertiser domains', function () { const bidResponse = utils.deepClone(serverResponse); let result = spec.interpretResponse({body: bidResponse}); expect(result[0].meta.advertiserDomains).to.deep.equal(expectedResponse[0].meta.advertiserDomains); @@ -724,6 +724,7 @@ describe('emx_digital Adapter', function () { expect(syncs).to.not.be.an('undefined'); expect(syncs).to.have.lengthOf(1); expect(syncs[0].type).to.equal('iframe'); + expect(syncs[0].url).to.equal('https://biddr.brealtime.com/check.html') }); it('should pass gdpr params', function () { @@ -734,6 +735,34 @@ describe('emx_digital Adapter', function () { expect(syncs).to.have.lengthOf(1); expect(syncs[0].type).to.equal('iframe'); expect(syncs[0].url).to.contains('gdpr=0'); + expect(syncs[0].url).to.equal('https://biddr.brealtime.com/check.html?gdpr=0&gdpr_consent=test') + }); + + it('should pass us_privacy string', function () { + let syncs = spec.getUserSyncs({ iframeEnabled: true }, {}, {}, { + consentString: 'test', + }); + expect(syncs).to.not.be.an('undefined'); + expect(syncs).to.have.lengthOf(1); + expect(syncs[0].type).to.equal('iframe'); + expect(syncs[0].url).to.contains('usp=test'); + }); + + it('should pass us_privacy and gdpr strings', function () { + let syncs = spec.getUserSyncs({ iframeEnabled: true }, {}, + { + gdprApplies: true, + consentString: 'test' + }, + { + consentString: 'test' + }); + expect(syncs).to.not.be.an('undefined'); + expect(syncs).to.have.lengthOf(1); + expect(syncs[0].type).to.equal('iframe'); + expect(syncs[0].url).to.contains('gdpr=1'); + expect(syncs[0].url).to.contains('usp=test'); + expect(syncs[0].url).to.equal('https://biddr.brealtime.com/check.html?gdpr=1&gdpr_consent=test&usp=test') }); }); }); diff --git a/test/spec/modules/enrichmentFpdModule_spec.js b/test/spec/modules/enrichmentFpdModule_spec.js index 1c6cab5afec..e69de29bb2d 100644 --- a/test/spec/modules/enrichmentFpdModule_spec.js +++ b/test/spec/modules/enrichmentFpdModule_spec.js @@ -1,158 +0,0 @@ -import { expect } from 'chai'; -import { getRefererInfo } from 'src/refererDetection.js'; -import {processFpd, coreStorage, resetEnrichments} from 'modules/enrichmentFpdModule.js'; -import * as enrichmentModule from 'modules/enrichmentFpdModule.js'; -import {GreedyPromise} from '../../../src/utils/promise.js'; - -describe('the first party data enrichment module', function() { - let width; - let widthStub; - let height; - let heightStub; - let querySelectorStub; - let coreStorageStub; - let canonical; - let keywords; - let lowEntropySuaStub; - let highEntropySuaStub; - - before(function() { - canonical = document.createElement('link'); - canonical.rel = 'canonical'; - keywords = document.createElement('meta'); - keywords.name = 'keywords'; - }); - - beforeEach(function() { - resetEnrichments(); - querySelectorStub = sinon.stub(window.top.document, 'querySelector'); - querySelectorStub.withArgs("link[rel='canonical']").returns(canonical); - querySelectorStub.withArgs("meta[name='keywords']").returns(keywords); - widthStub = sinon.stub(window.top, 'innerWidth').get(function() { - return width; - }); - heightStub = sinon.stub(window.top, 'innerHeight').get(function() { - return height; - }); - coreStorageStub = sinon.stub(coreStorage, 'getCookie'); - coreStorageStub - .onFirstCall() - .returns(null) // co.uk - .onSecondCall() - .returns('writeable'); // domain.co.uk - lowEntropySuaStub = sinon.stub(enrichmentModule.sua, 'le').callsFake(() => null); - highEntropySuaStub = sinon.stub(enrichmentModule.sua, 'he').callsFake(() => GreedyPromise.resolve()); - }); - - afterEach(function() { - widthStub.restore(); - heightStub.restore(); - querySelectorStub.restore(); - coreStorageStub.restore(); - canonical = document.createElement('link'); - canonical.rel = 'canonical'; - keywords = document.createElement('meta'); - keywords.name = 'keywords'; - lowEntropySuaStub.restore(); - highEntropySuaStub.restore(); - }); - - function syncProcessFpd(fpdConf, ortb2Fragments) { - let result; - processFpd(fpdConf, ortb2Fragments).then((res) => { result = res; }); - return result; - }; - - it('adds ref and device values', function() { - width = 800; - height = 500; - - let validated = syncProcessFpd({}, {}).global; - - const {ref, page, domain} = getRefererInfo(); - expect(validated.site.ref).to.equal(ref || undefined); - expect(validated.site.page).to.equal(page || undefined) - expect(validated.site.domain).to.equal(domain || undefined) - expect(validated.device).to.deep.equal({ w: 800, h: 500 }); - expect(validated.site.keywords).to.be.undefined; - }); - - it('adds page domain values if canonical url exists', function() { - width = 800; - height = 500; - canonical.href = 'https://www.subdomain.domain.co.uk/path?query=12345'; - - let validated = syncProcessFpd({}, {}).global; - - expect(validated.site.ref).to.equal(getRefererInfo().ref || undefined); - expect(validated.site.page).to.equal('https://www.subdomain.domain.co.uk/path?query=12345'); - expect(validated.site.domain).to.equal('subdomain.domain.co.uk'); - expect(validated.site.publisher.domain).to.equal('domain.co.uk'); - expect(validated.device).to.deep.equal({ w: 800, h: 500 }); - expect(validated.site.keywords).to.be.undefined; - }); - - it('adds keyword value if keyword meta content exists', function() { - width = 800; - height = 500; - keywords.content = 'value1,value2,value3'; - - let validated = syncProcessFpd({}, {}).global; - - expect(validated.site.keywords).to.equal('value1,value2,value3'); - }); - - it('does not overwrite existing data from getConfig ortb2', function() { - width = 800; - height = 500; - - let validated = syncProcessFpd({}, {global: {device: {w: 1200, h: 700}, site: {ref: 'https://someUrl.com', page: 'test.com'}}}).global; - - expect(validated.site.ref).to.equal('https://someUrl.com'); - expect(validated.site.page).to.equal('test.com'); - expect(validated.device).to.deep.equal({ w: 1200, h: 700 }); - expect(validated.site.keywords).to.be.undefined; - }); - - it('does not run enrichments again on the second call', () => { - width = 1; - height = 2; - const first = syncProcessFpd({}, {}).global; - width = 3; - const second = syncProcessFpd({}, {}).global; - expect(first).to.eql(second); - }); - - describe('device.sua', () => { - it('does not set device.sua if resolved sua is null', () => { - const sua = syncProcessFpd({}, {}).global.device?.sua; - expect(sua).to.not.exist; - }); - it('uses low entropy values if uaHints is []', () => { - lowEntropySuaStub.callsFake(() => ({mock: 'sua'})); - const sua = syncProcessFpd({uaHints: []}, {}).global.device.sua; - expect(sua).to.eql({mock: 'sua'}); - }); - it('uses high entropy values otherwise', () => { - highEntropySuaStub.callsFake((hints) => GreedyPromise.resolve({hints})); - const sua = syncProcessFpd({uaHints: ['h1', 'h2']}, {}).global.device.sua; - expect(sua).to.eql({hints: ['h1', 'h2']}); - }) - }) - - it('should store a reference to gpc witin ortb2.regs.ext if it has been enabled', function() { - let validated; - width = 800; - height = 500; - - validated = syncProcessFpd({}, {}).global; - expect(validated.regs).to.equal(undefined); - - resetEnrichments(); - - const globalPrivacyControlStub = sinon.stub(window, 'navigator').value({globalPrivacyControl: true}); - validated = syncProcessFpd({}, {}).global; - expect(validated.regs.ext.gpc).to.equal(1); - globalPrivacyControlStub.restore(); - }); -}); diff --git a/test/spec/modules/eplanningAnalyticsAdapter_spec.js b/test/spec/modules/eplanningAnalyticsAdapter_spec.js index bb9e6c4fb86..419181de983 100644 --- a/test/spec/modules/eplanningAnalyticsAdapter_spec.js +++ b/test/spec/modules/eplanningAnalyticsAdapter_spec.js @@ -152,9 +152,6 @@ describe('eplanning analytics adapter', function () { // Step 10 check that the host to send the ajax request is configurable via options expect(eplAnalyticsAdapter.context.host).to.equal(initOptions.host); - - // Step 11 verify that we received 7 events (6 E-Planning events + 1 Clean.io event) - sinon.assert.callCount(eplAnalyticsAdapter.track, 7); }); }); }); diff --git a/test/spec/modules/eplanningBidAdapter_spec.js b/test/spec/modules/eplanningBidAdapter_spec.js index a356c9cee95..1a6cfd7afe4 100644 --- a/test/spec/modules/eplanningBidAdapter_spec.js +++ b/test/spec/modules/eplanningBidAdapter_spec.js @@ -729,11 +729,46 @@ describe('E-Planning Adapter', function () { expect(ur).to.equal(bidderRequest.refererInfo.page); }); + it('should return ur parameter without params query string when current window url length is greater than 255', function () { + let bidderRequestParams = bidderRequest; + + bidderRequestParams.refererInfo.page = refererUrl + '?param=' + 'x'.repeat(255); + const ur = spec.buildRequests(bidRequests, bidderRequest).data.ur; + expect(ur).to.equal(refererUrl); + }); + + it('should return ur parameter with a length of 255 when url length is greater than 255', function () { + let bidderRequestParams = bidderRequest; + let url_255_characters = 'https://localhost/abc' + '/subse'.repeat(39); + let refererUrl = url_255_characters + '/ext'.repeat(5) + '?param=' + 'x'.repeat(15); + + bidderRequestParams.refererInfo.page = refererUrl; + const ur = spec.buildRequests(bidRequests, bidderRequest).data.ur; + expect(ur).to.equal(url_255_characters); + }); + it('should return fr parameter when there is a referrer', function () { const request = spec.buildRequests(bidRequests, bidderRequest); const dataRequest = request.data; expect(dataRequest.fr).to.equal(refererUrl); }); + it('should return fr parameter without params query string when ref length is greater than 255', function () { + let bidderRequestParams = bidderRequest; + + bidderRequestParams.refererInfo.ref = refererUrl + '?param=' + 'x'.repeat(255); + const fr = spec.buildRequests(bidRequests, bidderRequest).data.fr; + expect(fr).to.equal(refererUrl); + }); + + it('should return fr parameter with a length of 255 when url length is greater than 255', function () { + let bidderRequestParams = bidderRequest; + let url_255_characters = 'https://localhost/abc' + '/subse'.repeat(39); + let refererUrl = url_255_characters + '/ext'.repeat(5) + '?param=' + 'x'.repeat(15); + + bidderRequestParams.refererInfo.ref = refererUrl; + const fr = spec.buildRequests(bidRequests, bidderRequest).data.fr; + expect(fr).to.equal(url_255_characters); + }); it('should return crs parameter with document charset', function () { let expected; @@ -840,7 +875,7 @@ describe('E-Planning Adapter', function () { }); it('should correctly map the parameters in the response vast', function () { - const bidResponse = spec.interpretResponse(responseVast, { adUnitToBidId: { [CLEAN_ADUNIT_CODE_VAST]: BID_ID } })[0]; + const bidResponse = spec.interpretResponse(responseVast, { adUnitToBidId: { [CLEAN_ADUNIT_CODE_VAST]: BID_ID }, data: { vv: 2 } })[0]; const expectedResponse = { requestId: BID_ID, cpm: CPM, @@ -851,13 +886,13 @@ describe('E-Planning Adapter', function () { netRevenue: true, currency: 'USD', vastXml: ADM_VAST, - mediaTypes: VIDEO + mediaType: VIDEO }; expect(bidResponse).to.deep.equal(expectedResponse); }); it('should correctly map the parameters in the response vast vv 1', function () { - const bidResponse = spec.interpretResponse(responseVastVV1, { adUnitToBidId: { [CLEAN_ADUNIT_CODE_VAST]: BID_ID } })[0]; + const bidResponse = spec.interpretResponse(responseVastVV1, { adUnitToBidId: { [CLEAN_ADUNIT_CODE_VAST]: BID_ID }, data: { vv: 1 } })[0]; const expectedResponse = { requestId: BID_ID, cpm: CPM, @@ -868,7 +903,7 @@ describe('E-Planning Adapter', function () { netRevenue: true, currency: 'USD', vastXml: ADM_VAST_VV_1, - mediaTypes: VIDEO + mediaType: VIDEO }; expect(bidResponse).to.deep.equal(expectedResponse); }); diff --git a/test/spec/modules/feedadBidAdapter_spec.js b/test/spec/modules/feedadBidAdapter_spec.js index 6db0b88a9bf..5789361d2a1 100644 --- a/test/spec/modules/feedadBidAdapter_spec.js +++ b/test/spec/modules/feedadBidAdapter_spec.js @@ -4,6 +4,7 @@ import {BANNER, NATIVE, VIDEO} from '../../../src/mediaTypes.js'; import {server} from 'test/mocks/xhr.js'; const CODE = 'feedad'; +const EXPECTED_ADAPTER_VERSION = '1.0.6'; describe('FeedAdAdapter', function () { describe('Public API', function () { @@ -300,6 +301,20 @@ describe('FeedAdAdapter', function () { expect(result.data.gdprApplies).to.equal(request.gdprConsent.gdprApplies); expect(result.data.consentIabTcf).to.equal(request.gdprConsent.consentString); }); + it('should include adapter and prebid version', function () { + let bid = { + code: 'feedad', + mediaTypes: { + banner: { + sizes: [[320, 250]] + } + }, + params: {clientToken: 'clientToken', placementId: 'placement-id'} + }; + let result = spec.buildRequests([bid], bidderRequest); + expect(result.data.bids[0].params.prebid_adapter_version).to.equal(EXPECTED_ADAPTER_VERSION); + expect(result.data.bids[0].params.prebid_sdk_version).to.equal('$prebid.version$'); + }); }); describe('interpretResponse', function () { @@ -358,75 +373,67 @@ describe('FeedAdAdapter', function () { const pixelSync2 = {type: 'image', url: 'the pixel url 2'}; const iFrameSync1 = {type: 'iframe', url: 'the iFrame url 1'}; const iFrameSync2 = {type: 'iframe', url: 'the iFrame url 2'}; - - it('should pass through the syncs out of the extension fields of the server response', function () { - const serverResponse = [{ + const response1 = { + body: [{ ext: { pixels: [pixelSync1, pixelSync2], - iframes: [iFrameSync1, iFrameSync2], + iframes: [iFrameSync1] + }, + }] + }; + const response2 = { + body: [{ + ext: { + pixels: [pixelSync1], + iframes: [iFrameSync1], } - }]; - const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, serverResponse) + }, { + ext: { + pixels: [pixelSync2], + iframes: [iFrameSync2], + } + }] + }; + it('should pass through the syncs out of the extension fields of the server response', function () { + const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, [response1]) expect(result).to.deep.equal([ pixelSync1, pixelSync2, iFrameSync1, - iFrameSync2, ]); }); it('should concat the syncs of all responses', function () { - const serverResponse = [{ - ext: { - pixels: [pixelSync1], - iframes: [iFrameSync2], - }, - ad: 'ad html', - cpm: 100 - }, { - ext: { - iframes: [iFrameSync1], - } - }, { - ext: { - pixels: [pixelSync2], - } - }]; - const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, serverResponse); + const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, [response1, response2]); expect(result).to.deep.equal([ pixelSync1, + pixelSync2, + iFrameSync1, iFrameSync2, + ]); + }); + + it('should concat the syncs of all bids', function () { + const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, [response2]); + expect(result).to.deep.equal([ + pixelSync1, iFrameSync1, pixelSync2, + iFrameSync2, ]); }); it('should filter out duplicates', function () { - const serverResponse = [{ - ext: { - pixels: [pixelSync1, pixelSync1], - iframes: [iFrameSync2, iFrameSync2], - } - }, { - ext: { - iframes: [iFrameSync2, iFrameSync2], - } - }]; - const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, serverResponse); + const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, [response1, response1]); expect(result).to.deep.equal([ pixelSync1, - iFrameSync2, + pixelSync2, + iFrameSync1, ]); }); it('should not include iFrame syncs if the option is disabled', function () { - const serverResponse = [{ - ext: { - pixels: [pixelSync1, pixelSync2], - iframes: [iFrameSync1, iFrameSync2], - } - }]; - const result = spec.getUserSyncs({iframeEnabled: false, pixelEnabled: true}, serverResponse); + const result = spec.getUserSyncs({iframeEnabled: false, pixelEnabled: true}, [response1]); expect(result).to.deep.equal([ pixelSync1, pixelSync2, @@ -434,27 +441,36 @@ describe('FeedAdAdapter', function () { }); it('should not include pixel syncs if the option is disabled', function () { - const serverResponse = [{ - ext: { - pixels: [pixelSync1, pixelSync2], - iframes: [iFrameSync1, iFrameSync2], - } - }]; - const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: false}, serverResponse); + const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: false}, [response1]); expect(result).to.deep.equal([ iFrameSync1, - iFrameSync2, ]); }); it('should not include any syncs if the sync options are disabled or missing', function () { - const serverResponse = [{ - ext: { - pixels: [pixelSync1, pixelSync2], - iframes: [iFrameSync1, iFrameSync2], - } - }]; - const result = spec.getUserSyncs({iframeEnabled: false, pixelEnabled: false}, serverResponse); + const result = spec.getUserSyncs({iframeEnabled: false, pixelEnabled: false}, [response1]); + expect(result).to.deep.equal([]); + }); + + it('should handle empty responses', function () { + const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, []) + expect(result).to.deep.equal([]); + }); + + it('should not throw if the server response is weird', function () { + const responses = [ + {body: null}, + {body: 'null'}, + {body: 1234}, + {body: {}}, + {body: [{}, 123]}, + ]; + expect(() => spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, responses)).to.not.throw(); + }); + + it('should return empty array if the body extension is null', function () { + const response = {body: [{ext: null}]}; + const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, [response]); expect(result).to.deep.equal([]); }); }); @@ -592,7 +608,8 @@ describe('FeedAdAdapter', function () { prebid_bid_id: bidId, prebid_transaction_id: transactionId, referer, - sdk_version: '1.0.3' + prebid_adapter_version: EXPECTED_ADAPTER_VERSION, + prebid_sdk_version: '$prebid.version$', }; subject(data); expect(server.requests.length).to.equal(1); diff --git a/test/spec/modules/fluctBidAdapter_spec.js b/test/spec/modules/fluctBidAdapter_spec.js index 8ef99727ce7..92a4b42f6f8 100644 --- a/test/spec/modules/fluctBidAdapter_spec.js +++ b/test/spec/modules/fluctBidAdapter_spec.js @@ -94,7 +94,12 @@ describe('fluctAdapter', function () { expect(request.data.params.kv).to.eql(undefined); }); - it('includes filtered user.eids if any exists', function () { + it('includes no data.schain by default', function () { + const request = spec.buildRequests(bidRequests, bidderRequest)[0]; + expect(request.data.schain).to.eql(undefined); + }); + + it('includes filtered user.eids if any exist', function () { const bidRequests2 = bidRequests.map( (bidReq) => Object.assign(bidReq, { userIdAsEids: [ @@ -175,6 +180,37 @@ describe('fluctAdapter', function () { imsids: ['imsid1', 'imsid2'] }); }); + + it('includes data.schain if any exists', function () { + // this should be done by schain.js + const bidRequests2 = bidRequests.map( + (bidReq) => Object.assign(bidReq, { + schain: { + ver: '1.0', + complete: 1, + nodes: [ + { + asi: 'example.com', + sid: 'publisher-id', + hp: 1 + } + ] + } + }) + ); + const request = spec.buildRequests(bidRequests2, bidderRequest)[0]; + expect(request.data.schain).to.eql({ + ver: '1.0', + complete: 1, + nodes: [ + { + asi: 'example.com', + sid: 'publisher-id', + hp: 1 + } + ] + }); + }); }); describe('interpretResponse', function() { diff --git a/test/spec/modules/fpdModule_spec.js b/test/spec/modules/fpdModule_spec.js index 8e95f462830..4536b304f9d 100644 --- a/test/spec/modules/fpdModule_spec.js +++ b/test/spec/modules/fpdModule_spec.js @@ -1,16 +1,14 @@ import {expect} from 'chai'; import {config} from 'src/config.js'; -import {getRefererInfo} from 'src/refererDetection.js'; -import {processFpd, registerSubmodules, startAuctionHook, reset} from 'modules/fpdModule/index.js'; -import * as enrichmentModule from 'modules/enrichmentFpdModule.js'; -import * as validationModule from 'modules/validationFpdModule/index.js'; -import {resetEnrichments} from 'modules/enrichmentFpdModule.js'; -import {GreedyPromise} from '../../../src/utils/promise.js'; +import {registerSubmodules, reset, startAuctionHook} from 'modules/fpdModule/index.js'; describe('the first party data module', function () { afterEach(function () { config.resetConfig(); }); + after(() => { + reset(); + }) describe('startAuctionHook', () => { const mockFpd = { @@ -50,282 +48,4 @@ describe('the first party data module', function () { }); }); }); - - describe('first party data intitializing', function () { - let width; - let widthStub; - let height; - let heightStub; - let querySelectorStub; - let canonical; - let keywords; - let lowEntropySuaStub; - let highEntropySuaStub; - - before(function() { - reset(); - registerSubmodules(enrichmentModule); - registerSubmodules(validationModule); - - canonical = document.createElement('link'); - canonical.rel = 'canonical'; - keywords = document.createElement('meta'); - keywords.name = 'keywords'; - }); - - beforeEach(function() { - resetEnrichments(); - querySelectorStub = sinon.stub(window.top.document, 'querySelector'); - querySelectorStub.withArgs("link[rel='canonical']").returns(canonical); - querySelectorStub.withArgs("meta[name='keywords']").returns(keywords); - widthStub = sinon.stub(window.top, 'innerWidth').get(function () { - return width; - }); - heightStub = sinon.stub(window.top, 'innerHeight').get(function () { - return height; - }); - lowEntropySuaStub = sinon.stub(enrichmentModule.sua, 'le').callsFake(() => null); - highEntropySuaStub = sinon.stub(enrichmentModule.sua, 'he').callsFake(() => GreedyPromise.resolve()); - }); - - afterEach(function() { - widthStub.restore(); - heightStub.restore(); - querySelectorStub.restore(); - canonical = document.createElement('link'); - canonical.rel = 'canonical'; - keywords = document.createElement('meta'); - keywords.name = 'keywords'; - lowEntropySuaStub.restore(); - highEntropySuaStub.restore(); - }); - - it('filters ortb2 data that is set', function () { - const global = { - user: { - data: {}, - gender: 'f', - age: 45 - }, - site: { - content: { - data: [{ - segment: { - test: 1 - }, - name: 'foo' - }, { - segment: [{ - id: 'test' - }, { - id: 3 - }], - name: 'bar' - }] - } - }, - device: { - w: 1, - h: 1 - } - }; - - canonical.href = 'https://www.domain.com/path?query=12345'; - width = 1120; - height = 750; - - return processFpd({global}).then(({global: validated}) => { - expect(validated.site.ref).to.equal(getRefererInfo().ref || undefined); - expect(validated.site.page).to.equal('https://www.domain.com/path?query=12345'); - expect(validated.site.domain).to.equal('domain.com'); - expect(validated.site.content.data).to.deep.equal([{segment: [{id: 'test'}], name: 'bar'}]); - expect(validated.user.data).to.be.undefined; - expect(validated.device).to.deep.to.equal({w: 1, h: 1}); - expect(validated.site.keywords).to.be.undefined; - }); - }); - - it('should not overwrite existing data with default settings', function () { - const global = { - site: { - ref: 'https://referer.com' - } - }; - - return processFpd({global}).then(({global: validated}) => { - expect(validated.site.ref).to.equal('https://referer.com'); - }); - }); - - it('should allow overwrite default data with setConfig', function () { - const global = { - site: { - ref: 'https://referer.com' - } - }; - - return processFpd({global}).then(({global: validated}) => { - expect(validated.site.ref).to.equal('https://referer.com'); - }); - }); - - it('should filter all data', function () { - let global = { - imp: [], - site: { - name: 123, - domain: 456, - page: 789, - ref: 987, - keywords: ['keywords'], - search: 654, - cat: 'cat', - sectioncat: 'sectioncat', - pagecat: 'pagecat', - content: { - data: [{ - name: 1, - segment: [] - }] - } - }, - user: { - yob: 'twenty', - gender: 0, - keywords: ['foobar'], - data: ['test'] - }, - device: [800, 450], - cur: { - adServerCurrency: 'USD' - } - }; - config.setConfig({'firstPartyData': {skipEnrichments: true}}); - return processFpd({global}).then(({global: validated}) => { - expect(validated).to.deep.equal({}); - }); - }); - - it('should add enrichments but not alter any arbitrary ortb2 data', function () { - let global = { - site: { - ext: { - data: { - inventory: ['value1'] - } - } - }, - user: { - ext: { - data: { - visitor: ['value2'] - } - } - }, - cur: ['USD'] - }; - return processFpd({global}).then(({global: validated}) => { - expect(validated.site.ref).to.equal(getRefererInfo().referer); - expect(validated.site.ext.data).to.deep.equal({inventory: ['value1']}); - expect(validated.user.ext.data).to.deep.equal({visitor: ['value2']}); - expect(validated.cur).to.deep.equal(['USD']); - }) - }); - - it('should filter bidderConfig data', function () { - let bidder = { - bidderA: { - site: { - keywords: 'other', - ref: 'https://domain.com' - }, - user: { - keywords: 'test', - data: [{ - segment: [{id: 4}], - name: 't' - }] - } - } - }; - - return processFpd({bidder}).then(({bidder: validated}) => { - expect(validated.bidderA).to.not.be.undefined; - expect(validated.bidderA.user.data).to.be.undefined; - expect(validated.bidderA.user.keywords).to.equal('test'); - expect(validated.bidderA.site.keywords).to.equal('other'); - expect(validated.bidderA.site.ref).to.equal('https://domain.com'); - }) - }); - - it('should not filter bidderConfig data as it is valid', function () { - let bidder = { - bidderA: { - site: { - keywords: 'other', - ref: 'https://domain.com' - }, - user: { - keywords: 'test', - data: [{ - segment: [{id: 'data1_id'}], - name: 'data1' - }] - } - } - }; - - return processFpd({bidder}).then(({bidder: validated}) => { - expect(validated.bidderA).to.not.be.undefined; - expect(validated.bidderA.user.data).to.deep.equal([{segment: [{id: 'data1_id'}], name: 'data1'}]); - expect(validated.bidderA.user.keywords).to.equal('test'); - expect(validated.bidderA.site.keywords).to.equal('other'); - expect(validated.bidderA.site.ref).to.equal('https://domain.com'); - }); - }); - - it('should not set default values if skipEnrichments is turned on', function () { - config.setConfig({'firstPartyData': {skipEnrichments: true}}); - - let global = { - site: { - keywords: 'other' - }, - user: { - keywords: 'test', - data: [{ - segment: [{id: 'data1_id'}], - name: 'data1' - }] - } - }; - - return processFpd({global}).then(({global: validated}) => { - expect(validated.device).to.be.undefined; - expect(validated.site.ref).to.be.undefined; - expect(validated.site.page).to.be.undefined; - expect(validated.site.domain).to.be.undefined; - }); - }); - - it('should not validate ortb2 data if skipValidations is turned on', function () { - config.setConfig({'firstPartyData': {skipValidations: true}}); - - let global = { - site: { - keywords: 'other' - }, - user: { - keywords: 'test', - data: [{ - segment: [{id: 'nonfiltered'}] - }] - } - }; - - return processFpd({global}).then(({global: validated}) => { - expect(validated.user.data).to.deep.equal([{segment: [{id: 'nonfiltered'}]}]); - }); - }); - }); }); diff --git a/test/spec/modules/freewheel-sspBidAdapter_spec.js b/test/spec/modules/freewheel-sspBidAdapter_spec.js index 7ef576fc7ec..4d0c87ace3a 100644 --- a/test/spec/modules/freewheel-sspBidAdapter_spec.js +++ b/test/spec/modules/freewheel-sspBidAdapter_spec.js @@ -84,7 +84,8 @@ describe('freewheelSSP BidAdapter Test', () => { { 'bidder': 'freewheel-ssp', 'params': { - 'zoneId': '277225' + 'zoneId': '277225', + 'bidfloor': 2.00, }, 'adUnitCode': 'adunit-code', 'mediaTypes': { @@ -114,11 +115,36 @@ describe('freewheelSSP BidAdapter Test', () => { } ]; + it('should get bidfloor value from params if no getFloor method', () => { + const request = spec.buildRequests(bidRequests); + const payload = request[0].data; + expect(payload._fw_bidfloor).to.equal(2.00); + expect(payload._fw_bidfloorcur).to.deep.equal('USD'); + }); + + it('should get bidfloor value from getFloor method if available', () => { + const bidRequest = bidRequests[0]; + bidRequest.getFloor = () => ({ currency: 'USD', floor: 1.16 }); + const request = spec.buildRequests(bidRequests); + const payload = request[0].data; + expect(payload._fw_bidfloor).to.equal(1.16); + expect(payload._fw_bidfloorcur).to.deep.equal('USD'); + }); + + it('should return empty bidFloorCurrency when bidfloor <= 0', () => { + const bidRequest = bidRequests[0]; + bidRequest.getFloor = () => ({ currency: 'USD', floor: -1 }); + const request = spec.buildRequests(bidRequests); + const payload = request[0].data; + expect(payload._fw_bidfloor).to.equal(0); + expect(payload._fw_bidfloorcur).to.deep.equal(''); + }); + it('should add parameters to the tag', () => { const request = spec.buildRequests(bidRequests); const payload = request[0].data; expect(payload.reqType).to.equal('AdsSetup'); - expect(payload.protocolVersion).to.equal('2.0'); + expect(payload.protocolVersion).to.equal('4.2'); expect(payload.zoneId).to.equal('277225'); expect(payload.componentId).to.equal('prebid'); expect(payload.componentSubId).to.equal('mustang'); @@ -128,7 +154,7 @@ describe('freewheelSSP BidAdapter Test', () => { it('should return a properly formatted request with schain defined', function () { const request = spec.buildRequests(bidRequests); const payload = request[0].data; - expect(payload.schain).to.deep.equal(bidRequests[0].schain) + expect(payload.schain).to.deep.equal('{\"ver\":\"1.0\",\"complete\":1,\"nodes\":[{\"asi\":\"example.com\",\"sid\":\"0\",\"hp\":1,\"rid\":\"bidrequestid\",\"domain\":\"example.com\"}]}'); }); it('sends bid request to ENDPOINT via GET', () => { @@ -144,7 +170,7 @@ describe('freewheelSSP BidAdapter Test', () => { const request = spec.buildRequests(bidRequests, bidderRequest); const payload = request[0].data; expect(payload.reqType).to.equal('AdsSetup'); - expect(payload.protocolVersion).to.equal('2.0'); + expect(payload.protocolVersion).to.equal('4.2'); expect(payload.zoneId).to.equal('277225'); expect(payload.componentId).to.equal('prebid'); expect(payload.componentSubId).to.equal('mustang'); @@ -164,7 +190,7 @@ describe('freewheelSSP BidAdapter Test', () => { const request = spec.buildRequests(bidRequests, bidderRequest); const payload = request[0].data; expect(payload.reqType).to.equal('AdsSetup'); - expect(payload.protocolVersion).to.equal('2.0'); + expect(payload.protocolVersion).to.equal('4.2'); expect(payload.zoneId).to.equal('277225'); expect(payload.componentId).to.equal('prebid'); expect(payload.componentSubId).to.equal('mustang'); @@ -211,7 +237,7 @@ describe('freewheelSSP BidAdapter Test', () => { const request = spec.buildRequests(bidRequests); const payload = request[0].data; expect(payload.reqType).to.equal('AdsSetup'); - expect(payload.protocolVersion).to.equal('2.0'); + expect(payload.protocolVersion).to.equal('4.2'); expect(payload.zoneId).to.equal('277225'); expect(payload.componentId).to.equal('prebid'); expect(payload.componentSubId).to.equal('mustang'); @@ -231,7 +257,7 @@ describe('freewheelSSP BidAdapter Test', () => { const request = spec.buildRequests(bidRequests, bidderRequest); const payload = request[0].data; expect(payload.reqType).to.equal('AdsSetup'); - expect(payload.protocolVersion).to.equal('2.0'); + expect(payload.protocolVersion).to.equal('4.2'); expect(payload.zoneId).to.equal('277225'); expect(payload.componentId).to.equal('prebid'); expect(payload.componentSubId).to.equal('mustang'); @@ -251,7 +277,7 @@ describe('freewheelSSP BidAdapter Test', () => { const request = spec.buildRequests(bidRequests, bidderRequest); const payload = request[0].data; expect(payload.reqType).to.equal('AdsSetup'); - expect(payload.protocolVersion).to.equal('2.0'); + expect(payload.protocolVersion).to.equal('4.2'); expect(payload.zoneId).to.equal('277225'); expect(payload.componentId).to.equal('prebid'); expect(payload.componentSubId).to.equal('mustang'); @@ -337,7 +363,7 @@ describe('freewheelSSP BidAdapter Test', () => { } ]; - let response = '' + + let response = '' + '' + ' ' + ' Adswizz' + @@ -422,7 +448,7 @@ describe('freewheelSSP BidAdapter Test', () => { it('handles nobid responses', () => { var request = spec.buildRequests(formattedBidRequests); - let response = ''; + let response = ''; let result = spec.interpretResponse(response, request[0]); expect(result.length).to.equal(0); @@ -503,7 +529,7 @@ describe('freewheelSSP BidAdapter Test', () => { } ]; - let response = '' + + let response = '' + '' + ' ' + ' Adswizz' + @@ -599,7 +625,7 @@ describe('freewheelSSP BidAdapter Test', () => { it('handles nobid responses', () => { var request = spec.buildRequests(formattedBidRequests); - let response = ''; + let response = ''; let result = spec.interpretResponse(response, request[0]); expect(result.length).to.equal(0); diff --git a/test/spec/modules/ftrackIdSystem_spec.js b/test/spec/modules/ftrackIdSystem_spec.js index 79a11845a0f..ecd610a12fb 100644 --- a/test/spec/modules/ftrackIdSystem_spec.js +++ b/test/spec/modules/ftrackIdSystem_spec.js @@ -450,13 +450,16 @@ describe('FTRACK ID System', () => { }); expect(getGlobal().getUserIdsAsEids()).to.deep.equal([{ - id: 'device_test_id', - atype: 1, - ext: { - HHID: 'household_test_id', - DeviceID: 'device_test_id', - SingleDeviceID: 'single_device_test_id' - } + source: 'flashtalking.com', + uids: [{ + id: 'device_test_id', + atype: 1, + ext: { + HHID: 'household_test_id', + DeviceID: 'device_test_id', + SingleDeviceID: 'single_device_test_id' + } + }] }]); }); @@ -481,11 +484,14 @@ describe('FTRACK ID System', () => { }); expect(getGlobal().getUserIdsAsEids()).to.deep.equal([{ - id: 'device_test_id', - atype: 1, - ext: { - DeviceID: 'device_test_id' - } + source: 'flashtalking.com', + uids: [{ + id: 'device_test_id', + atype: 1, + ext: { + DeviceID: 'device_test_id' + } + }] }]); }); @@ -509,11 +515,14 @@ describe('FTRACK ID System', () => { }); expect(getGlobal().getUserIdsAsEids()).to.deep.equal([{ - id: '', - atype: 1, - ext: { - HHID: 'household_test_id' - } + source: 'flashtalking.com', + uids: [{ + id: '', + atype: 1, + ext: { + HHID: 'household_test_id' + } + }] }]); }); @@ -537,11 +546,14 @@ describe('FTRACK ID System', () => { }); expect(getGlobal().getUserIdsAsEids()).to.deep.equal([{ - id: '', - atype: 1, - ext: { - SingleDeviceID: 'single_device_test_id' - } + source: 'flashtalking.com', + uids: [{ + id: '', + atype: 1, + ext: { + SingleDeviceID: 'single_device_test_id' + } + }] }]); }); }); diff --git a/test/spec/modules/gdprEnforcement_spec.js b/test/spec/modules/gdprEnforcement_spec.js index ddd522decab..8d58990bb66 100644 --- a/test/spec/modules/gdprEnforcement_spec.js +++ b/test/spec/modules/gdprEnforcement_spec.js @@ -20,6 +20,7 @@ import * as events from 'src/events.js'; import 'modules/appnexusBidAdapter.js'; // some tests expect this to be in the adapter registry import 'src/prebid.js' import {hook} from '../../../src/hook.js'; +import {VENDORLESS_GVLID} from '../../../src/consentHandler.js'; describe('gdpr enforcement', function () { let nextFnSpy; @@ -150,13 +151,13 @@ describe('gdpr enforcement', function () { } }); - deviceAccessHook(nextFnSpy, false); + deviceAccessHook(nextFnSpy); expect(nextFnSpy.calledOnce).to.equal(true); let result = { hasEnforcementHook: true, valid: false } - sinon.assert.calledWith(nextFnSpy, false, undefined, undefined, result); + sinon.assert.calledWith(nextFnSpy, undefined, undefined, result); }); it('should only check for consent for vendor exceptions when enforcePurpose and enforceVendor are false', function () { @@ -178,8 +179,8 @@ describe('gdpr enforcement', function () { consentData.apiVersion = 2; gdprDataHandlerStub.returns(consentData); - deviceAccessHook(nextFnSpy, false, 1, 'appnexus'); - deviceAccessHook(nextFnSpy, false, 5, 'rubicon'); + deviceAccessHook(nextFnSpy, 1, 'appnexus'); + deviceAccessHook(nextFnSpy, 5, 'rubicon'); expect(logWarnSpy.callCount).to.equal(0); }); @@ -201,8 +202,8 @@ describe('gdpr enforcement', function () { consentData.apiVersion = 2; gdprDataHandlerStub.returns(consentData); - deviceAccessHook(nextFnSpy, false, 1, 'appnexus'); - deviceAccessHook(nextFnSpy, false, 3, 'rubicon'); + deviceAccessHook(nextFnSpy, 1, 'appnexus'); + deviceAccessHook(nextFnSpy, 3, 'rubicon'); expect(logWarnSpy.callCount).to.equal(1); }); @@ -224,13 +225,13 @@ describe('gdpr enforcement', function () { consentData.apiVersion = 2; gdprDataHandlerStub.returns(consentData); - deviceAccessHook(nextFnSpy, false, 1, 'appnexus'); + deviceAccessHook(nextFnSpy, 1, 'appnexus'); expect(nextFnSpy.calledOnce).to.equal(true); let result = { hasEnforcementHook: true, valid: true } - sinon.assert.calledWith(nextFnSpy, false, 1, 'appnexus', result); + sinon.assert.calledWith(nextFnSpy, 1, 'appnexus', result); }); it('should use gvlMapping set by publisher', function() { @@ -255,13 +256,13 @@ describe('gdpr enforcement', function () { consentData.apiVersion = 2; gdprDataHandlerStub.returns(consentData); - deviceAccessHook(nextFnSpy, false, 1, 'appnexus'); + deviceAccessHook(nextFnSpy, 1, 'appnexus'); expect(nextFnSpy.calledOnce).to.equal(true); let result = { hasEnforcementHook: true, valid: true } - sinon.assert.calledWith(nextFnSpy, false, 4, 'appnexus', result); + sinon.assert.calledWith(nextFnSpy, 4, 'appnexus', result); config.resetConfig(); }); @@ -290,31 +291,17 @@ describe('gdpr enforcement', function () { consentData.apiVersion = 2; gdprDataHandlerStub.returns(consentData); - deviceAccessHook(nextFnSpy, false, 1, 'appnexus'); + deviceAccessHook(nextFnSpy, 1, 'appnexus'); expect(nextFnSpy.calledOnce).to.equal(true); let result = { hasEnforcementHook: true, valid: true } - sinon.assert.calledWith(nextFnSpy, false, 4, 'appnexus', result); + sinon.assert.calledWith(nextFnSpy, 4, 'appnexus', result); config.resetConfig(); curBidderStub.restore(); }); - it(`should mark module as vendorless for rule validation when isVendorless = true and ${STRICT_STORAGE_ENFORCEMENT} is set`, () => { - setEnforcementConfig({ - [STRICT_STORAGE_ENFORCEMENT]: true - }); - let consentData = { - vendorData: staticConfig.consentData.getTCData, - gdprApplies: true - } - gdprDataHandlerStub.returns(consentData); - const validate = sinon.stub().callsFake(() => true); - deviceAccessHook(nextFnSpy, true, 123, 'mockModule', undefined, {validate}); - expect(validate.args[0][4]('mockModule')).to.be.true; - }); - it(`should not enforce consent for vendorless modules if ${STRICT_STORAGE_ENFORCEMENT} is not set`, () => { setEnforcementConfig({}); let consentData = { @@ -323,9 +310,9 @@ describe('gdpr enforcement', function () { } gdprDataHandlerStub.returns(consentData); const validate = sinon.stub().callsFake(() => false); - deviceAccessHook(nextFnSpy, true, 123, 'mockModule', undefined, {validate}); + deviceAccessHook(nextFnSpy, VENDORLESS_GVLID, 'mockModule', undefined, {validate}); sinon.assert.callCount(validate, 0); - sinon.assert.calledWith(nextFnSpy, true, 123, 'mockModule', {hasEnforcementHook: true, valid: true}); + sinon.assert.calledWith(nextFnSpy, VENDORLESS_GVLID, 'mockModule', {hasEnforcementHook: true, valid: true}); }) }); @@ -804,11 +791,12 @@ describe('gdpr enforcement', function () { }); describe('validateRules', function () { - const createGdprRule = (purposeName = 'storage', enforcePurpose = true, enforceVendor = true, vendorExceptions = []) => ({ + const createGdprRule = (purposeName = 'storage', enforcePurpose = true, enforceVendor = true, vendorExceptions = [], softVendorExceptions = []) => ({ purpose: purposeName, - enforcePurpose: enforcePurpose, - enforceVendor: enforceVendor, - vendorExceptions: vendorExceptions + enforcePurpose, + enforceVendor, + vendorExceptions, + softVendorExceptions, }); const consentData = { @@ -922,6 +910,19 @@ describe('gdpr enforcement', function () { expect(isAllowed).to.equal(true); }); + describe('when the vendor has a softVendorException', () => { + const gdprRule = createGdprRule('storage', true, true, [], [vendorBlockedModule]); + + it('should return false if general consent was not given', () => { + const isAllowed = validateRules(gdprRule, consentDataWithPurposeConsentFalse, vendorBlockedModule, vendorBlockedGvlId); + expect(isAllowed).to.be.false; + }) + it('should return true if general consent was given', () => { + const isAllowed = validateRules(gdprRule, consentData, vendorBlockedModule, vendorBlockedGvlId); + expect(isAllowed).to.be.true; + }) + }) + describe('when module does not need vendor consent', () => { Object.entries({ 'storage': 1, @@ -937,11 +938,9 @@ describe('gdpr enforcement', function () { it(`should be ${t} when purpose is ${t}`, () => { const consent = utils.deepClone(consentData); consent.vendorData.purpose.consents[purposeNo] = consentGiven; - // vendor consent (and gvlid) should be ignored - consent.vendorData.vendor.consents[123] = !consentGiven; // take legitimate interest out of the picture for this test consent.vendorData.purpose.legitimateInterests = {}; - const actual = validateRules(rule, consent, 'mockModule', 123, () => true); + const actual = validateRules(rule, consent, 'mockModule', VENDORLESS_GVLID); expect(actual).to.equal(consentGiven); }) }) @@ -1131,56 +1130,104 @@ describe('gdpr enforcement', function () { }) }); - describe('getGvlid', function() { + describe('gvlid resolution', () => { let sandbox; - let getGvlidForBidAdapterStub; - let getGvlidForUserIdModuleStub; - let getGvlidForAnalyticsAdapterStub; beforeEach(function() { sandbox = sinon.createSandbox(); - getGvlidForBidAdapterStub = sandbox.stub(internal, 'getGvlidForBidAdapter'); - getGvlidForUserIdModuleStub = sandbox.stub(internal, 'getGvlidForUserIdModule'); - getGvlidForAnalyticsAdapterStub = sandbox.stub(internal, 'getGvlidForAnalyticsAdapter'); }); + afterEach(function() { sandbox.restore(); config.resetConfig(); }); - it('should return "null" if called without passing any argument', function() { - const gvlid = getGvlid(); - expect(gvlid).to.equal(null); - }); + describe('getGvlid', function() { + let getGvlidForBidAdapterStub; + let getGvlidForUserIdModuleStub; + let getGvlidForAnalyticsAdapterStub; + beforeEach(function() { + getGvlidForBidAdapterStub = sandbox.stub(internal, 'getGvlidForBidAdapter'); + getGvlidForUserIdModuleStub = sandbox.stub(internal, 'getGvlidForUserIdModule'); + getGvlidForAnalyticsAdapterStub = sandbox.stub(internal, 'getGvlidForAnalyticsAdapter'); + }); - it('should return "null" if GVL ID is not defined for any of these modules: Bid adapter, UserId submodule and Analytics adapter', function() { - getGvlidForBidAdapterStub.withArgs('moduleA').returns(null); - getGvlidForUserIdModuleStub.withArgs('moduleA').returns(null); - getGvlidForAnalyticsAdapterStub.withArgs('moduleA').returns(null); + it('should return "null" if called without passing any argument', function() { + const gvlid = getGvlid(); + expect(gvlid).to.equal(null); + }); - const gvlid = getGvlid('moduleA'); - expect(gvlid).to.equal(null); - }); + it('should return "null" if GVL ID is not defined for any of these modules: Bid adapter, UserId submodule and Analytics adapter', function() { + getGvlidForBidAdapterStub.withArgs('moduleA').returns(null); + getGvlidForUserIdModuleStub.withArgs('moduleA').returns(null); + getGvlidForAnalyticsAdapterStub.withArgs('moduleA').returns(null); - it('should return the GVL ID from gvlMapping if it is defined in setConfig', function() { - config.setConfig({ - gvlMapping: { - moduleA: 1 - } + const gvlid = getGvlid('moduleA'); + expect(gvlid).to.equal(null); + }); + + it('should return the GVL ID from gvlMapping if it is defined in setConfig', function() { + config.setConfig({ + gvlMapping: { + moduleA: 1 + } + }); + + // Actual GVL ID for moduleA is 2, as defined on its the bidAdapter.js file. + getGvlidForBidAdapterStub.withArgs('moduleA').returns(2); + + const gvlid = getGvlid('moduleA'); + expect(gvlid).to.equal(1); }); - // Actual GVL ID for moduleA is 2, as defined on its the bidAdapter.js file. - getGvlidForBidAdapterStub.withArgs('moduleA').returns(2); + it('should return the GVL ID by calling getGvlidForBidAdapter -> getGvlidForUserIdModule -> getGvlidForAnalyticsAdapter in sequence', function() { + getGvlidForBidAdapterStub.withArgs('moduleA').returns(null); + getGvlidForUserIdModuleStub.withArgs('moduleA').returns(null); + getGvlidForAnalyticsAdapterStub.withArgs('moduleA').returns(7); + + expect(getGvlid('moduleA')).to.equal(7); + }); - const gvlid = getGvlid('moduleA'); - expect(gvlid).to.equal(1); + it('should pass extra arguments to analytics\' getGvlid', () => { + getGvlidForAnalyticsAdapterStub.withArgs('analytics').returns(321); + const cfg = {some: 'args'}; + getGvlid('analytics', cfg); + sinon.assert.calledWith(getGvlidForAnalyticsAdapterStub, 'analytics', cfg); + }); }); - it('should return the GVL ID by calling getGvlidForBidAdapter -> getGvlidForUserIdModule -> getGvlidForAnalyticsAdapter in sequence', function() { - getGvlidForBidAdapterStub.withArgs('moduleA').returns(null); - getGvlidForUserIdModuleStub.withArgs('moduleA').returns(null); - getGvlidForAnalyticsAdapterStub.withArgs('moduleA').returns(7); + describe('getGvlidForAnalyticsAdapter', () => { + let getAnalyticsAdapter, adapter, adapterEntry; + + beforeEach(() => { + adapter = {}; + adapterEntry = { + adapter + }; + getAnalyticsAdapter = sandbox.stub(adapterManager, 'getAnalyticsAdapter'); + getAnalyticsAdapter.withArgs('analytics').returns(adapterEntry); + }); + + it('should return gvlid from adapterManager if defined', () => { + adapterEntry.gvlid = 123; + adapter.gvlid = 321 + expect(internal.getGvlidForAnalyticsAdapter('analytics')).to.equal(123); + }); + + it('should return gvlid from adapter if defined', () => { + adapter.gvlid = 321; + expect(internal.getGvlidForAnalyticsAdapter('analytics')).to.equal(321); + }); - expect(getGvlid('moduleA')).to.equal(7); + it('should invoke adapter.gvlid if it\'s a function', () => { + adapter.gvlid = (cfg) => cfg.k + const cfg = {k: 231}; + expect(internal.getGvlidForAnalyticsAdapter('analytics', cfg)).to.eql(231); + }); + + it('should not choke if adapter gvlid fn throws', () => { + adapter.gvlid = () => { throw new Error(); }; + expect(internal.getGvlidForAnalyticsAdapter('analytics')).to.not.be.ok; + }); }); - }); + }) }); diff --git a/test/spec/modules/genericAnalyticsAdapter_spec.js b/test/spec/modules/genericAnalyticsAdapter_spec.js new file mode 100644 index 00000000000..a5a6074c425 --- /dev/null +++ b/test/spec/modules/genericAnalyticsAdapter_spec.js @@ -0,0 +1,284 @@ +import {defaultHandler, GenericAnalytics} from '../../../modules/genericAnalyticsAdapter.js'; +import * as events from 'src/events.js'; +import * as CONSTANTS from 'src/constants.json'; + +const {AUCTION_INIT, BID_RESPONSE} = CONSTANTS.EVENTS; + +describe('Generic analytics', () => { + describe('adapter', () => { + let adapter, sandbox, clock; + beforeEach(() => { + sandbox = sinon.sandbox.create(); + sandbox.stub(events, 'getEvents').returns([]); + clock = sandbox.useFakeTimers(); + adapter = new GenericAnalytics(); + }); + + afterEach(() => { + adapter.disableAnalytics(); + sandbox.restore(); + }); + + describe('configuration', () => { + it('should be accepted if valid', () => { + adapter.enableAnalytics({ + options: { + url: 'mock', + method: 'GET', + batchSize: 123, + batchDelay: 321 + } + }); + expect(adapter.enabled).to.be.true; + }); + + describe('should not work if', () => { + afterEach(function() { + expect(adapter.enabled).to.equal(false, this.currentTest.title); + }); + + it('neither handler nor url are specified', () => { + adapter.enableAnalytics({}); + }); + + ['batchSize', 'batchDelay', 'handler'].forEach(option => { + it(`${option} is not valid`, () => { + adapter.enableAnalytics({ + options: { + url: 'mock', + [option]: false + } + }); + }); + }); + + it('method is not GET or POST', () => { + adapter.enableAnalytics({ + options: { + url: 'mock', + method: 'PATCH' + } + }); + }); + + it('events is not an object', () => { + adapter.enableAnalytics({ + options: { + url: 'mock', + events: null + } + }); + }); + + it('events\' properties are not functions', () => { + adapter.enableAnalytics({ + options: { + url: 'mock', + events: { + bidResponse: null + } + } + }); + }); + }); + }); + + describe('when handler is specified', () => { + let handler; + beforeEach(() => { + handler = sinon.stub(); + }); + + it('should collect events in batches, and call handler', () => { + adapter.enableAnalytics({ + options: { + handler, + batchSize: 2 + } + }); + events.emit(AUCTION_INIT, {i: 0}); + sinon.assert.notCalled(handler); + events.emit(BID_RESPONSE, {i: 0}); + sinon.assert.calledWith(handler, sinon.match((arg) => { + return sinon.match({eventType: AUCTION_INIT, args: {i: 0}}).test(arg[0]) && + sinon.match({eventType: BID_RESPONSE, args: {i: 0}}).test(arg[1]); + })); + }); + + it('should not choke if handler throws', () => { + adapter.enableAnalytics({ + options: { + handler, + batchSize: 1 + } + }); + handler.throws(new Error()); + events.emit(AUCTION_INIT, {i: 0}); + let recv; + handler.reset(); + handler.callsFake((arg) => { + recv = arg; + }); + events.emit(BID_RESPONSE, {i: 1}); + expect(recv).to.eql([{eventType: BID_RESPONSE, args: {i: 1}}]); + }); + + it('should not cause infinite recursion, if handler triggers more events', () => { + let i = 0; + handler.callsFake(() => { + if (i <= 100) { + i++; + events.emit(BID_RESPONSE, {}); + } + }); + adapter.enableAnalytics({ + options: { + handler, + } + }); + events.emit(AUCTION_INIT, {}); + expect(i >= 100).to.be.false; + }); + + it('should send incomplete batch after batchDelay', () => { + adapter.enableAnalytics({ + options: { + batchDelay: 100, + batchSize: 2, + handler + } + }); + [0, 1, 2].forEach(i => events.emit(BID_RESPONSE, {i})); + sinon.assert.calledOnce(handler); + clock.tick(100); + sinon.assert.calledTwice(handler); + }); + + it('does not send empty batches', () => { + adapter.enableAnalytics({ + options: { + batchDelay: 100, + batchSize: 2, + handler + } + }); + [0, 1, 2].forEach(i => events.emit(BID_RESPONSE, {i})); + sinon.assert.calledOnce(handler); + clock.tick(50); + events.emit(BID_RESPONSE, {i: 3}); + sinon.assert.calledTwice(handler); + clock.tick(100); + sinon.assert.calledTwice(handler); + }); + + describe('and options.events is specified', () => { + it('filters out other events', () => { + adapter.enableAnalytics({ + options: { + handler, + events: { + bidResponse(bid) { + return bid; + } + } + } + }); + events.emit(AUCTION_INIT, {}); + sinon.assert.notCalled(handler); + }); + + it('transforms event data', () => { + adapter.enableAnalytics({ + options: { + handler, + events: { + bidResponse(bid) { + return { + extra: 'data', + prop: bid.prop + } + } + } + } + }); + events.emit(BID_RESPONSE, {prop: 'value', i: 0}); + sinon.assert.calledWith(handler, sinon.match(data => sinon.match({extra: 'data', prop: 'value'}).test(data[0]))); + }); + + it('does not choke if an event handler throws', () => { + adapter.enableAnalytics({ + options: { + handler, + events: { + bidResponse(bid) { + return bid; + }, + auctionInit(auction) { + throw new Error(); + } + } + } + }); + events.emit(AUCTION_INIT, {}); + events.emit(BID_RESPONSE, {i: 0}); + sinon.assert.calledOnce(handler); + sinon.assert.calledWith(handler, sinon.match(data => sinon.match({i: 0}).test(data[0]))); + }); + + it('filters out events when their handler returns undefined', () => { + adapter.enableAnalytics({ + options: { + handler, + events: { + auctionInit(auction) { + return auction; + }, + bidResponse(bid) {} + } + } + }); + events.emit(AUCTION_INIT, {i: 0}); + events.emit(BID_RESPONSE, {i: 1}); + sinon.assert.calledOnce(handler); + sinon.assert.calledWith(handler, sinon.match(data => sinon.match({i: 0}).test(data[0]))); + }); + }); + }); + }); + + describe('default handler', () => { + const url = 'mock-url'; + + let ajax; + beforeEach(() => { + ajax = sinon.stub(); + }); + + Object.entries({ + 'GET': (data) => JSON.parse(data.data), + 'POST': (data) => JSON.parse(data) + }).forEach(([method, parse]) => { + describe(`when HTTP method is ${method}`, () => { + it('should send single event when batchSize is 1', () => { + const handler = defaultHandler({url, method, batchSize: 1, ajax}); + const payload = {i: 0}; + handler([payload, {}]); + sinon.assert.calledWith(ajax, url, sinon.match.any, + sinon.match(data => sinon.match(payload).test(parse(data))), + {method} + ); + }); + + it('should send multiple events when batchSize is greater than 1', () => { + const handler = defaultHandler({url, method, batchSize: 10, ajax}); + const payload = [{i: 0}, {i: 1}]; + handler(payload); + sinon.assert.calledWith(ajax, url, sinon.match.any, + sinon.match(data => sinon.match(payload).test(parse(data))), + {method} + ); + }); + }); + }); + }); +}); diff --git a/test/spec/modules/geoedgeRtdProvider_spec.js b/test/spec/modules/geoedgeRtdProvider_spec.js index cf4e0b53fde..eec1feff87a 100644 --- a/test/spec/modules/geoedgeRtdProvider_spec.js +++ b/test/spec/modules/geoedgeRtdProvider_spec.js @@ -2,6 +2,8 @@ import * as utils from '../../../src/utils.js'; import * as hook from '../../../src/hook.js' import { beforeInit, geoedgeSubmodule, setWrapper, wrapper, htmlPlaceholder, WRAPPER_URL, getClientUrl } from '../../../modules/geoedgeRtdProvider.js'; import { server } from '../../../test/mocks/xhr.js'; +import * as events from '../../../src/events.js'; +import CONSTANTS from '../../../src/constants.json'; let key = '123123123'; function makeConfig() { @@ -88,6 +90,19 @@ describe('Geoedge RTD module', function () { let isLinkPreloadAsScript = arg => arg.tagName === 'LINK' && arg.rel === 'preload' && arg.as === 'script' && arg.href === getClientUrl(key); expect(insertElementStub.calledWith(sinon.match(isLinkPreloadAsScript))).to.equal(true); }); + it('should emit billable events with applicable winning bids', function () { + let applicableBid = mockBid('bidderA'); + let nonApplicableBid = mockBid('bidderB'); + let counter = 0; + events.on(CONSTANTS.EVENTS.BILLABLE_EVENT, function (event) { + if (event.vendor === 'geoedge' && event.type === 'impression') { + counter += 1; + } + }); + events.emit(CONSTANTS.EVENTS.BID_WON, applicableBid); + events.emit(CONSTANTS.EVENTS.BID_WON, nonApplicableBid); + expect(counter).to.equal(1); + }); }); describe('onBidResponseEvent', function () { let bidFromA = mockBid('bidderA'); diff --git a/test/spec/modules/globalsunBidAdapter_spec.js b/test/spec/modules/globalsunBidAdapter_spec.js new file mode 100644 index 00000000000..3795f3038a7 --- /dev/null +++ b/test/spec/modules/globalsunBidAdapter_spec.js @@ -0,0 +1,398 @@ +import { expect } from 'chai'; +import { spec } from '../../../modules/globalsunBidAdapter.js'; +import { BANNER, VIDEO, NATIVE } from '../../../src/mediaTypes.js'; +import { getUniqueIdentifierStr } from '../../../src/utils.js'; + +const bidder = 'globalsun' + +describe('GlobalsunBidAdapter', function () { + const bids = [ + { + bidId: getUniqueIdentifierStr(), + bidder: bidder, + mediaTypes: { + [BANNER]: { + sizes: [[300, 250]] + } + }, + params: { + placementId: 'testBanner', + } + }, + { + bidId: getUniqueIdentifierStr(), + bidder: bidder, + mediaTypes: { + [VIDEO]: { + playerSize: [[300, 300]], + minduration: 5, + maxduration: 60 + } + }, + params: { + placementId: 'testVideo', + } + }, + { + bidId: getUniqueIdentifierStr(), + bidder: bidder, + mediaTypes: { + [NATIVE]: { + native: { + title: { + required: true + }, + body: { + required: true + }, + icon: { + required: true, + size: [64, 64] + } + } + } + }, + params: { + placementId: 'testNative', + } + } + ]; + + const invalidBid = { + bidId: getUniqueIdentifierStr(), + bidder: bidder, + mediaTypes: { + [BANNER]: { + sizes: [[300, 250]] + } + }, + params: { + + } + } + + const bidderRequest = { + uspConsent: '1---', + gdprConsent: 'COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw', + refererInfo: { + referer: 'https://test.com' + } + }; + + describe('isBidRequestValid', function () { + it('Should return true if there are bidId, params and key parameters present', function () { + expect(spec.isBidRequestValid(bids[0])).to.be.true; + }); + it('Should return false if at least one of parameters is not present', function () { + expect(spec.isBidRequestValid(invalidBid)).to.be.false; + }); + }); + + describe('buildRequests', function () { + let serverRequest = spec.buildRequests(bids, bidderRequest); + + it('Creates a ServerRequest object with method, URL and data', function () { + expect(serverRequest).to.exist; + expect(serverRequest.method).to.exist; + expect(serverRequest.url).to.exist; + expect(serverRequest.data).to.exist; + }); + + it('Returns POST method', function () { + expect(serverRequest.method).to.equal('POST'); + }); + + it('Returns valid URL', function () { + expect(serverRequest.url).to.equal('https://endpoint.globalsun.io/pbjs'); + }); + + it('Returns general data valid', function () { + let data = serverRequest.data; + expect(data).to.be.an('object'); + expect(data).to.have.all.keys('deviceWidth', + 'deviceHeight', + 'language', + 'secure', + 'host', + 'page', + 'placements', + 'coppa', + 'ccpa', + 'gdpr', + 'tmax' + ); + expect(data.deviceWidth).to.be.a('number'); + expect(data.deviceHeight).to.be.a('number'); + expect(data.language).to.be.a('string'); + expect(data.secure).to.be.within(0, 1); + 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.ccpa).to.be.a('string'); + expect(data.tmax).to.be.a('number'); + expect(data.placements).to.have.lengthOf(3); + }); + + it('Returns valid placements', function () { + const { placements } = serverRequest.data; + for (let i = 0, len = placements.length; i < len; i++) { + const placement = placements[i]; + expect(placement.placementId).to.be.oneOf(['testBanner', 'testVideo', 'testNative']); + expect(placement.adFormat).to.be.oneOf([BANNER, VIDEO, NATIVE]); + expect(placement.bidId).to.be.a('string'); + expect(placement.schain).to.be.an('object'); + expect(placement.bidfloor).to.exist.and.to.equal(0); + expect(placement.type).to.exist.and.to.equal('publisher'); + + if (placement.adFormat === BANNER) { + expect(placement.sizes).to.be.an('array'); + } + switch (placement.adFormat) { + case BANNER: + expect(placement.sizes).to.be.an('array'); + break; + case VIDEO: + expect(placement.playerSize).to.be.an('array'); + expect(placement.minduration).to.be.an('number'); + expect(placement.maxduration).to.be.an('number'); + break; + case NATIVE: + expect(placement.native).to.be.an('object'); + break; + } + } + }); + + it('Returns data with gdprConsent and without uspConsent', function () { + delete bidderRequest.uspConsent; + serverRequest = spec.buildRequests(bids, bidderRequest); + let data = serverRequest.data; + expect(data.gdpr).to.exist; + expect(data.gdpr).to.be.a('string'); + expect(data.gdpr).to.equal(bidderRequest.gdprConsent); + expect(data.ccpa).to.not.exist; + delete bidderRequest.gdprConsent; + }); + + it('Returns data with uspConsent and without gdprConsent', function () { + bidderRequest.uspConsent = '1---'; + delete bidderRequest.gdprConsent; + serverRequest = spec.buildRequests(bids, bidderRequest); + let data = serverRequest.data; + expect(data.ccpa).to.exist; + expect(data.ccpa).to.be.a('string'); + expect(data.ccpa).to.equal(bidderRequest.uspConsent); + expect(data.gdpr).to.not.exist; + }); + + it('Returns empty data if no valid requests are passed', function () { + serverRequest = spec.buildRequests([], bidderRequest); + let data = serverRequest.data; + expect(data.placements).to.be.an('array').that.is.empty; + }); + }); + + describe('interpretResponse', function () { + it('Should interpret banner response', function () { + const banner = { + body: [{ + mediaType: 'banner', + width: 300, + height: 250, + cpm: 0.4, + ad: 'Test', + requestId: '23fhj33i987f', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1', + meta: { + advertiserDomains: ['google.com'], + advertiserId: 1234 + } + }] + }; + let bannerResponses = spec.interpretResponse(banner); + expect(bannerResponses).to.be.an('array').that.is.not.empty; + let dataItem = bannerResponses[0]; + expect(dataItem).to.have.all.keys('requestId', 'cpm', 'width', 'height', 'ad', 'ttl', 'creativeId', + 'netRevenue', 'currency', 'dealId', 'mediaType', 'meta'); + expect(dataItem.requestId).to.equal(banner.body[0].requestId); + expect(dataItem.cpm).to.equal(banner.body[0].cpm); + expect(dataItem.width).to.equal(banner.body[0].width); + expect(dataItem.height).to.equal(banner.body[0].height); + expect(dataItem.ad).to.equal(banner.body[0].ad); + expect(dataItem.ttl).to.equal(banner.body[0].ttl); + expect(dataItem.creativeId).to.equal(banner.body[0].creativeId); + expect(dataItem.netRevenue).to.be.true; + expect(dataItem.currency).to.equal(banner.body[0].currency); + expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains'); + }); + it('Should interpret video response', function () { + const video = { + body: [{ + vastUrl: 'test.com', + mediaType: 'video', + cpm: 0.5, + requestId: '23fhj33i987f', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1', + meta: { + advertiserDomains: ['google.com'], + advertiserId: 1234 + } + }] + }; + let videoResponses = spec.interpretResponse(video); + expect(videoResponses).to.be.an('array').that.is.not.empty; + + let dataItem = videoResponses[0]; + expect(dataItem).to.have.all.keys('requestId', 'cpm', 'vastUrl', 'ttl', 'creativeId', + 'netRevenue', 'currency', 'dealId', 'mediaType', 'meta'); + expect(dataItem.requestId).to.equal('23fhj33i987f'); + expect(dataItem.cpm).to.equal(0.5); + expect(dataItem.vastUrl).to.equal('test.com'); + expect(dataItem.ttl).to.equal(120); + expect(dataItem.creativeId).to.equal('2'); + expect(dataItem.netRevenue).to.be.true; + expect(dataItem.currency).to.equal('USD'); + expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains'); + }); + it('Should interpret native response', function () { + const native = { + body: [{ + mediaType: 'native', + native: { + clickUrl: 'test.com', + title: 'Test', + image: 'test.com', + impressionTrackers: ['test.com'], + }, + ttl: 120, + cpm: 0.4, + requestId: '23fhj33i987f', + creativeId: '2', + netRevenue: true, + currency: 'USD', + meta: { + advertiserDomains: ['google.com'], + advertiserId: 1234 + } + }] + }; + let nativeResponses = spec.interpretResponse(native); + expect(nativeResponses).to.be.an('array').that.is.not.empty; + + let dataItem = nativeResponses[0]; + expect(dataItem).to.have.keys('requestId', 'cpm', 'ttl', 'creativeId', 'netRevenue', 'currency', 'mediaType', 'native', 'meta'); + expect(dataItem.native).to.have.keys('clickUrl', 'impressionTrackers', 'title', 'image') + expect(dataItem.requestId).to.equal('23fhj33i987f'); + expect(dataItem.cpm).to.equal(0.4); + expect(dataItem.native.clickUrl).to.equal('test.com'); + expect(dataItem.native.title).to.equal('Test'); + expect(dataItem.native.image).to.equal('test.com'); + expect(dataItem.native.impressionTrackers).to.be.an('array').that.is.not.empty; + expect(dataItem.native.impressionTrackers[0]).to.equal('test.com'); + expect(dataItem.ttl).to.equal(120); + expect(dataItem.creativeId).to.equal('2'); + expect(dataItem.netRevenue).to.be.true; + expect(dataItem.currency).to.equal('USD'); + expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains'); + }); + it('Should return an empty array if invalid banner response is passed', function () { + const invBanner = { + body: [{ + width: 300, + cpm: 0.4, + ad: 'Test', + requestId: '23fhj33i987f', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1' + }] + }; + + let serverResponses = spec.interpretResponse(invBanner); + expect(serverResponses).to.be.an('array').that.is.empty; + }); + it('Should return an empty array if invalid video response is passed', function () { + const invVideo = { + body: [{ + mediaType: 'video', + cpm: 0.5, + requestId: '23fhj33i987f', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1' + }] + }; + let serverResponses = spec.interpretResponse(invVideo); + expect(serverResponses).to.be.an('array').that.is.empty; + }); + it('Should return an empty array if invalid native response is passed', function () { + const invNative = { + body: [{ + mediaType: 'native', + clickUrl: 'test.com', + title: 'Test', + impressionTrackers: ['test.com'], + ttl: 120, + requestId: '23fhj33i987f', + creativeId: '2', + netRevenue: true, + currency: 'USD', + }] + }; + let serverResponses = spec.interpretResponse(invNative); + expect(serverResponses).to.be.an('array').that.is.empty; + }); + it('Should return an empty array if invalid response is passed', function () { + const invalid = { + body: [{ + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1' + }] + }; + let serverResponses = spec.interpretResponse(invalid); + expect(serverResponses).to.be.an('array').that.is.empty; + }); + }); + + describe('getUserSyncs', function() { + it('Should return array of objects with proper sync config , include GDPR', function() { + const syncData = spec.getUserSyncs({}, {}, { + consentString: 'ALL', + gdprApplies: true, + }, {}); + expect(syncData).to.be.an('array').which.is.not.empty; + expect(syncData[0]).to.be.an('object') + expect(syncData[0].type).to.be.a('string') + expect(syncData[0].type).to.equal('image') + expect(syncData[0].url).to.be.a('string') + expect(syncData[0].url).to.equal('https://cs.globalsun.io/image?pbjs=1&gdpr=1&gdpr_consent=ALL&coppa=0') + }); + it('Should return array of objects with proper sync config , include CCPA', function() { + const syncData = spec.getUserSyncs({}, {}, {}, { + consentString: '1---' + }); + expect(syncData).to.be.an('array').which.is.not.empty; + expect(syncData[0]).to.be.an('object') + expect(syncData[0].type).to.be.a('string') + expect(syncData[0].type).to.equal('image') + expect(syncData[0].url).to.be.a('string') + expect(syncData[0].url).to.equal('https://cs.globalsun.io/image?pbjs=1&ccpa_consent=1---&coppa=0') + }); + }); +}); diff --git a/test/spec/modules/glomexBidAdapter_spec.js b/test/spec/modules/glomexBidAdapter_spec.js index 30157da858b..8c53db8d605 100644 --- a/test/spec/modules/glomexBidAdapter_spec.js +++ b/test/spec/modules/glomexBidAdapter_spec.js @@ -49,6 +49,10 @@ const RESPONSE = { describe('glomexBidAdapter', function () { const adapter = newBidder(spec) + it('should expose gvlid', function() { + expect(spec.gvlid).to.equal(967) + }); + describe('inherited functions', function () { it('exists and is a function', function () { expect(adapter.callBids).to.exist.and.to.be.a('function') diff --git a/test/spec/modules/gravitoIdSystem_spec.js b/test/spec/modules/gravitoIdSystem_spec.js index e904355f7f1..9584f60c81d 100644 --- a/test/spec/modules/gravitoIdSystem_spec.js +++ b/test/spec/modules/gravitoIdSystem_spec.js @@ -40,7 +40,7 @@ describe('gravitompId module', function () { describe('decode()', function () { it('should return the gravitompId when it exists in cookie', function () { const decoded = gravitoIdSystemSubmodule.decode(GRAVITOID_TEST_OBJ); - expect(decoded).to.be.deep.equal({gravitompId: {id: GRAVITOID_TEST_VALUE}}); + expect(decoded).to.be.deep.equal({gravitompId: GRAVITOID_TEST_VALUE}); }); it('should return the undefined when decode id is not "string"', function () { diff --git a/test/spec/modules/gridBidAdapter_spec.js b/test/spec/modules/gridBidAdapter_spec.js index f98ca683024..d411f33ab50 100644 --- a/test/spec/modules/gridBidAdapter_spec.js +++ b/test/spec/modules/gridBidAdapter_spec.js @@ -44,8 +44,9 @@ describe('TheMediaGrid Adapter', function () { return JSON.parse(data); } const bidderRequest = { - refererInfo: {page: 'https://example.com'}, + refererInfo: { page: 'https://example.com' }, bidderRequestId: '22edbae2733bf6', + transactionId: '1239bd74-4511-4335-af21-e828852e25d7', auctionId: '9e2dfbfe-00c7-4f5e-9850-4044df3229c7', timeout: 3000 }; @@ -67,6 +68,7 @@ describe('TheMediaGrid Adapter', function () { 'bidId': '42dbe3a7168a6a', 'bidderRequestId': '22edbae2733bf6', 'auctionId': '9e2dfbfe-00c7-4f5e-9850-4044df3229c7', + transactionId: '1239bd74-4511-4335-af21-e828852e25d7', }, { 'bidder': 'grid', @@ -78,6 +80,7 @@ describe('TheMediaGrid Adapter', function () { 'bidId': '30b31c1838de1e', 'bidderRequestId': '22edbae2733bf6', 'auctionId': '9e2dfbfe-00c7-4f5e-9850-4044df3229c7', + transactionId: '1239bd74-4511-4335-af21-e828852e25d7', }, { 'bidder': 'grid', @@ -95,6 +98,7 @@ describe('TheMediaGrid Adapter', function () { 'bidId': '3150ccb55da321', 'bidderRequestId': '22edbae2733bf6', 'auctionId': '9e2dfbfe-00c7-4f5e-9850-4044df3229c7', + transactionId: '1239bd74-4511-4335-af21-e828852e25d7', }, { 'bidder': 'grid', @@ -115,6 +119,7 @@ describe('TheMediaGrid Adapter', function () { 'bidId': '3150ccb55da321', 'bidderRequestId': '22edbae2733bf6', 'auctionId': '9e2dfbfe-00c7-4f5e-9850-4044df3229c7', + transactionId: '1239bd74-4511-4335-af21-e828852e25d7', } ]; @@ -395,6 +400,158 @@ describe('TheMediaGrid Adapter', function () { getDataFromLocalStorageStub.restore(); }); + it('should send additional request with adUnits with withCriteo parameter', function () { + const fpdUserIdVal = '0b0f84a1-1596-4165-9742-2e1a7dfac57f'; + const getDataFromLocalStorageStub = sinon.stub(storage, 'getDataFromLocalStorage').callsFake( + arg => arg === 'tmguid' ? fpdUserIdVal : null); + + const bidRequestsWithCriteo = bidRequests.map((bid, i) => + i % 2 ? bid : { + ...bid, + params: { + ...bid.params, + withCriteo: true, + networkId: 123 + i + }, + mediaTypes: { + ...bid.mediaTypes, + ...(bid.mediaTypes.video && { video: { + ...bid.mediaTypes.video, + context: 'instream', + protocols: [1, 2, 3], + maxduration: 30, + api: [1, 2], + skip: 1, + placement: 1, + minduration: 0, + playbackmethod: 1, + startdelay: 0 + } + }) + } + }); + + const [request, criteoRequest] = spec.buildRequests(bidRequestsWithCriteo, bidderRequest); + expect(request.data).to.be.an('string'); + expect(criteoRequest.data).to.be.an('object'); + const payload = parseRequest(request.data); + const criteoPayload = criteoRequest.data; + expect(request.url).to.equal('https://grid.bidswitch.net/hbjson'); + expect(criteoRequest.url.replace(/\?.*$/, '')) + .to.equal('https://bidder.criteo.com/cdb'); + expect(payload).to.deep.equal({ + 'id': bidderRequest.bidderRequestId, + 'site': { + 'page': referrer + }, + 'tmax': bidderRequest.timeout, + 'source': { + 'tid': bidderRequest.auctionId, + 'ext': {'wrapper': 'Prebid_js', 'wrapper_version': '$prebid.version$'} + }, + 'user': { + 'id': fpdUserIdVal + }, + 'imp': [{ + 'id': bidRequests[0].bidId, + 'tagid': bidRequests[0].params.uid, + 'ext': {'divid': bidRequests[0].adUnitCode}, + 'bidfloor': bidRequests[0].params.bidFloor, + 'banner': { + 'w': 300, + 'h': 250, + 'format': [{'w': 300, 'h': 250}, {'w': 300, 'h': 600}] + } + }, { + 'id': bidRequests[1].bidId, + 'tagid': bidRequests[1].params.uid, + 'ext': {'divid': bidRequests[1].adUnitCode}, + 'banner': { + 'w': 300, + 'h': 250, + 'format': [{'w': 300, 'h': 250}, {'w': 300, 'h': 600}] + } + }, { + 'id': bidRequests[2].bidId, + 'tagid': bidRequests[2].params.uid, + 'ext': {'divid': bidRequests[2].adUnitCode}, + 'video': { + 'w': 400, + 'h': 600, + 'protocols': [1, 2, 3], + 'mimes': ['video/mp4', 'video/webm', 'application/javascript', 'video/ogg'], + } + }, { + 'id': bidRequests[3].bidId, + 'tagid': bidRequests[3].params.uid, + 'ext': {'divid': bidRequests[3].adUnitCode}, + 'banner': { + 'w': 728, + 'h': 90, + 'format': [{'w': 728, 'h': 90}] + }, + 'video': { + 'w': 400, + 'h': 600, + 'protocols': [1, 2, 3] + } + }] + }); + + expect(criteoPayload).to.deep.equal({ + 'publisher': { + 'ext': undefined, + 'url': bidderRequest.refererInfo.page, + 'networkid': 125 + }, + 'regs': { + 'coppa': undefined + }, + 'slots': [{ + 'impid': bidRequests[0].adUnitCode, + 'transactionid': bidderRequest.transactionId, + 'auctionId': bidderRequest.auctionId, + 'sizes': ['300x250', '300x600'] + }, { + 'impid': bidRequests[2].adUnitCode, + 'transactionid': bidderRequest.transactionId, + 'auctionId': bidderRequest.auctionId, + 'sizes': [], + 'video': { + 'api': [ + 1, + 2 + ], + 'maxduration': 30, + 'mimes': [ + 'video/mp4', + 'video/webm', + 'application/javascript', + 'video/ogg', + ], + 'minduration': 0, + 'placement': 1, + 'playbackmethod': 1, + 'playersizes': [ + '400x600' + ], + 'protocols': [ + 1, + 2, + 3 + ], + 'skip': 1, + 'startdelay': 0 + } + }], + 'user': { + 'ext': undefined + } + }); + + getDataFromLocalStorageStub.restore(); + }); + it('if gdprConsent is present payload must have gdpr params', function () { const gdprBidderRequest = Object.assign({gdprConsent: {consentString: 'AAA', gdprApplies: true}}, bidderRequest); const [request] = spec.buildRequests(bidRequests, gdprBidderRequest); @@ -683,24 +840,6 @@ describe('TheMediaGrid Adapter', function () { expect(payload.site.content.id).to.equal(contentId); }); - it('should be right tmax when timeout in config is less then timeout in bidderRequest', function() { - const getConfigStub = sinon.stub(config, 'getConfig').callsFake( - arg => arg === 'bidderTimeout' ? 2000 : null); - const [request] = spec.buildRequests([bidRequests[0]], bidderRequest); - expect(request.data).to.be.an('string'); - const payload = parseRequest(request.data); - expect(payload.tmax).to.equal(2000); - getConfigStub.restore(); - }); - it('should be right tmax when timeout in bidderRequest is less then timeout in config', function() { - const getConfigStub = sinon.stub(config, 'getConfig').callsFake( - arg => arg === 'bidderTimeout' ? 5000 : null); - const [request] = spec.buildRequests([bidRequests[0]], bidderRequest); - expect(request.data).to.be.an('string'); - const payload = parseRequest(request.data); - expect(payload.tmax).to.equal(3000); - getConfigStub.restore(); - }); it('should contain regs.coppa if coppa is true in config', function () { const getConfigStub = sinon.stub(config, 'getConfig').callsFake( arg => arg === 'coppa' ? true : null); @@ -1365,6 +1504,137 @@ describe('TheMediaGrid Adapter', function () { expect(result).to.deep.equal(expectedResponse); }); + it('should add response with biggest price', function () { + const mainResponse = [ + {'bid': [{'impid': '2164be6358b9', 'price': 1.15, 'adm': '
test content 1
', 'auid': 1, 'h': 250, 'w': 300, dealid: 11}], 'seat': '1'}, + {'bid': [{'impid': '4e111f1b66e4', 'price': 0.5, 'adm': '
test content 2
', 'auid': 2, 'h': 600, 'w': 300, dealid: 12}], 'seat': '1'}, + ]; + const criteoResponse = [ + { + impid: 'adunit-code-1', + cpm: 0.15, + creative: '
test content 3
', + creativecode: 1, + bidId: '2164be6358b9', + currency: 'USD', + width: 300, + height: 250, + dealCode: 11, + zoneid: 123, + ttl: 360, + adomain: ['criteo.com'], + }, + { + impid: 'adunit-code-1', + cpm: 1, + creative: '
test content 4
', + creativecode: 2, + bidId: '4e111f1b66e4', + currency: 'USD', + width: 300, + height: 600, + dealCode: 12, + zoneid: 456, + ttl: 360, + adomain: ['criteo.com'], + } + ]; + const bidRequests = [ + { + 'bidder': 'grid', + 'params': { + 'uid': '1', + 'zoneId': 123, + 'withCriteo': true + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '2164be6358b9', + 'bidderRequestId': '106efe3247', + 'auctionId': '32a1f276cb87cb8', + 'transactionId': '43534f55b213ac', + }, + { + 'bidder': 'grid', + 'params': { + 'uid': '2', + 'zoneId': 456, + 'withCriteo': true + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '4e111f1b66e4', + 'bidderRequestId': '106efe3247', + 'auctionId': '32a1f276cb87cb8', + 'transactionId': '43534f55b213ac', + } + ]; + const bidderRequest = { + refererInfo: { page: 'https://example.com' }, + bidderRequestId: '106efe3247', + transactionId: '43534f55b213ac', + auctionId: '32a1f276cb87cb8', + timeout: 3000 + }; + const [mainRequest, criteoRequest] = spec.buildRequests(bidRequests, bidderRequest); + const expectedMainResponse = [ + { + 'requestId': '2164be6358b9', + 'cpm': 1.15, + 'creativeId': 1, + 'dealId': 11, + 'width': 300, + 'height': 250, + 'ad': '
test content 1
', + 'currency': 'USD', + 'mediaType': 'banner', + 'netRevenue': true, + 'ttl': 360, + 'meta': { + advertiserDomains: [] + }, + }, + { + 'requestId': '4e111f1b66e4', + 'cpm': 0.5, + 'creativeId': 2, + 'dealId': 12, + 'width': 300, + 'height': 600, + 'ad': '
test content 2
', + 'currency': 'USD', + 'mediaType': 'banner', + 'netRevenue': true, + 'ttl': 360, + 'meta': { + advertiserDomains: [] + }, + } + ]; + const expectedCriteoResponse = [ + { + 'requestId': '4e111f1b66e4', + 'cpm': 1, + 'creativeId': 2, + 'dealId': 12, + 'width': 300, + 'height': 600, + 'ad': '
test content 4
', + 'currency': 'USD', + 'netRevenue': true, + 'ttl': 360, + 'meta': { + advertiserDomains: ['criteo.com'] + }, + } + ]; + + const mainResult = spec.interpretResponse({'body': {'seatbid': mainResponse}}, mainRequest); + const criteoResult = spec.interpretResponse({'body': {'slots': criteoResponse}}, criteoRequest); + expect(mainResult).to.deep.equal(expectedMainResponse); + expect(criteoResult).to.deep.equal(expectedCriteoResponse); + }); + it('response with ext.bidder.grid.demandSource', function () { const bidRequests = [ { diff --git a/test/spec/modules/growthCodeAnalyticsAdapter_spec.js b/test/spec/modules/growthCodeAnalyticsAdapter_spec.js new file mode 100644 index 00000000000..e542a2641e8 --- /dev/null +++ b/test/spec/modules/growthCodeAnalyticsAdapter_spec.js @@ -0,0 +1,70 @@ +import adapterManager from '../../../src/adapterManager.js'; +import growthCodeAnalyticsAdapter from '../../../modules/growthCodeAnalyticsAdapter.js'; +import { expect } from 'chai'; +import * as events from '../../../src/events.js'; +import constants from '../../../src/constants.json'; +import { generateUUID } from '../../../src/utils.js'; +import { server } from 'test/mocks/xhr.js'; + +describe('growthCode analytics adapter', () => { + beforeEach(() => { + growthCodeAnalyticsAdapter.enableAnalytics({ + provider: 'growthCodeAnalytics', + options: { + pid: 'TEST01', + trackEvents: [ + 'auctionInit', + 'auctionEnd', + 'bidAdjustment', + 'bidTimeout', + 'bidTimeout', + 'bidRequested', + 'bidResponse', + 'setTargeting', + 'requestBids', + 'addAdUnits', + 'noBid', + 'bidWon', + 'bidderDone'] + } + }); + }); + + afterEach(() => { + growthCodeAnalyticsAdapter.disableAnalytics(); + }); + + it('registers itself with the adapter manager', () => { + const adapter = adapterManager.getAnalyticsAdapter('growthCodeAnalytics'); + expect(adapter).to.exist; + expect(adapter.adapter).to.equal(growthCodeAnalyticsAdapter); + }); + + it('tolerates undefined or empty config', () => { + growthCodeAnalyticsAdapter.enableAnalytics(undefined); + growthCodeAnalyticsAdapter.enableAnalytics({}); + }); + + it('sends auction end events to the backend', () => { + const auction = { + auctionId: generateUUID(), + adUnits: [{ + code: 'usr1234', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600], [728, 90]] + } + }, + adUnitCodes: ['usr1234'] + }], + }; + events.emit(constants.EVENTS.AUCTION_END, auction); + assert(server.requests.length > 0) + const body = JSON.parse(server.requests[0].requestBody); + var eventTypes = []; + body.events.forEach(e => eventTypes.push(e.eventType)); + assert(eventTypes.length > 0) + assert(eventTypes.indexOf(constants.EVENTS.AUCTION_END) > -1); + growthCodeAnalyticsAdapter.disableAnalytics(); + }); +}); diff --git a/test/spec/modules/gumgumBidAdapter_spec.js b/test/spec/modules/gumgumBidAdapter_spec.js index 17fff31f132..80ca85801b6 100644 --- a/test/spec/modules/gumgumBidAdapter_spec.js +++ b/test/spec/modules/gumgumBidAdapter_spec.js @@ -1,5 +1,6 @@ import { BANNER, VIDEO } from 'src/mediaTypes.js'; +import { config } from 'src/config.js'; import { expect } from 'chai'; import { newBidder } from 'src/adapters/bidderFactory.js'; import { spec } from 'modules/gumgumBidAdapter.js'; @@ -484,6 +485,60 @@ describe('gumgumAdapter', function () { const bidRequest = spec.buildRequests(bidRequests, fakeBidRequest)[0]; expect(bidRequest.data).to.not.include.any.keys('gdprConsent') }); + it('should add gpp parameters if gppConsent is present', function () { + const gppConsent = { gppString: 'DBACNYA~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA~1YNN', applicableSections: [7] } + const fakeBidRequest = { gppConsent: gppConsent }; + const bidRequest = spec.buildRequests(bidRequests, fakeBidRequest)[0]; + expect(bidRequest.data.gppConsent).to.exist; + expect(bidRequest.data.gppConsent.gppString).to.equal(gppConsent.gppString); + expect(bidRequest.data.gppConsent.applicableSections).to.equal(gppConsent.applicableSections); + expect(bidRequest.data.gppConsent.gppString).to.eq('DBACNYA~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA~1YNN'); + }); + it('should handle ortb2 parameters', function () { + const ortb2 = { + regs: { + gpp: 'DBACNYA~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA~1YNN', + gpp_sid: [7] + } + } + const fakeBidRequest = { gppConsent: ortb2 }; + const bidRequest = spec.buildRequests(bidRequests, fakeBidRequest)[0]; + expect(bidRequest.data.gppConsent.gppString).to.eq(fakeBidRequest[0]) + }); + it('should handle gppConsent is present but values are undefined case', function () { + const gppConsent = { gppString: undefined, applicableSections: undefined } + const fakeBidRequest = { gppConsent: gppConsent }; + const bidRequest = spec.buildRequests(bidRequests, fakeBidRequest)[0]; + expect(bidRequest.data.gppConsent).to.exist; + expect(bidRequest.data.gppConsent.gppString).to.equal(undefined); + expect(bidRequest.data.gppConsent.applicableSections).to.equal(undefined); + }); + it('should handle ortb2 undefined parameters', function () { + const ortb2 = { + regs: { + gpp: undefined, + gpp_sid: undefined + } + } + const fakeBidRequest = { gppConsent: ortb2 }; + const bidRequest = spec.buildRequests(bidRequests, fakeBidRequest)[0]; + expect(bidRequest.data.gppConsent.gppString).to.eq(undefined) + expect(bidRequest.data.gppConsent.applicableSections).to.eq(undefined) + }); + it('should not set coppa parameter if coppa config is set to false', function () { + config.setConfig({ + coppa: false + }); + const bidRequest = spec.buildRequests(bidRequests)[0]; + expect(bidRequest.data.coppa).to.eq(undefined); + }); + it('should set coppa parameter to 1 if coppa config is set to true', function () { + config.setConfig({ + coppa: true + }); + const bidRequest = spec.buildRequests(bidRequests)[0]; + expect(bidRequest.data.coppa).to.eq(1); + }); it('should add uspConsent parameter if it is present in the bidderRequest', function () { const noUspBidRequest = spec.buildRequests(bidRequests)[0]; const uspConsentObj = { uspConsent: '1YYY' }; diff --git a/test/spec/modules/hadronIdSystem_spec.js b/test/spec/modules/hadronIdSystem_spec.js index ca9eadc7fd4..c998ef2cf14 100644 --- a/test/spec/modules/hadronIdSystem_spec.js +++ b/test/spec/modules/hadronIdSystem_spec.js @@ -24,7 +24,7 @@ describe('HadronIdSystem', function () { const request = server.requests[0]; expect(request.url).to.eq(`https://id.hadron.ad.gt/api/v1/pbhid?partner_id=0&_it=prebid`); request.respond(200, { 'Content-Type': 'application/json' }, JSON.stringify({ hadronId: 'testHadronId1' })); - expect(callbackSpy.lastCall.lastArg).to.deep.equal({hadronId: 'testHadronId1'}); + expect(callbackSpy.lastCall.lastArg).to.deep.equal({ id: { hadronId: 'testHadronId1' } }); }); it('gets a cached hadronid', function() { @@ -33,10 +33,8 @@ describe('HadronIdSystem', function () { }; getDataFromLocalStorageStub.withArgs('auHadronId').returns('tstCachedHadronId1'); - const callbackSpy = sinon.spy(); - const callback = hadronIdSubmodule.getId(config).callback; - callback(callbackSpy); - expect(callbackSpy.lastCall.lastArg).to.deep.equal({hadronId: 'tstCachedHadronId1'}); + const result = hadronIdSubmodule.getId(config); + expect(result).to.deep.equal({ id: { hadronId: 'tstCachedHadronId1' } }); }); it('allows configurable id url', function() { @@ -51,7 +49,7 @@ describe('HadronIdSystem', function () { const request = server.requests[0]; expect(request.url).to.eq('https://hadronid.publync.com?partner_id=0&_it=prebid'); request.respond(200, { 'Content-Type': 'application/json' }, JSON.stringify({ hadronId: 'testHadronId1' })); - expect(callbackSpy.lastCall.lastArg).to.deep.equal({hadronId: 'testHadronId1'}); + expect(callbackSpy.lastCall.lastArg).to.deep.equal({ id: { hadronId: 'testHadronId1' } }); }); }); }); diff --git a/test/spec/modules/holidBidAdapter_spec.js b/test/spec/modules/holidBidAdapter_spec.js new file mode 100644 index 00000000000..e55befd213a --- /dev/null +++ b/test/spec/modules/holidBidAdapter_spec.js @@ -0,0 +1,194 @@ +import { expect } from 'chai' +import { spec } from 'modules/holidBidAdapter.js' + +describe('holidBidAdapterTests', () => { + const bidRequestData = { + bidder: 'holid', + adUnitCode: 'test-div', + bidId: 'bid-id', + auctionId: 'test-id', + params: { adUnitID: '12345' }, + mediaTypes: { banner: {} }, + sizes: [[300, 250]], + ortb2: { + site: { + publisher: { + domain: 'https://foo.bar', + } + }, + regs: { + gdpr: 1, + }, + user: { + ext: { + consent: 'G4ll0p1ng_Un1c0rn5', + } + }, + device: { + h: 410, + w: 1860, + } + } + } + + describe('isBidRequestValid', () => { + const bid = JSON.parse(JSON.stringify(bidRequestData)) + + it('should return true', () => { + expect(spec.isBidRequestValid(bid)).to.equal(true) + }) + + it('should return false when required params are not passed', () => { + const bid = JSON.parse(JSON.stringify(bidRequestData)) + delete bid.params.adUnitID + + expect(spec.isBidRequestValid(bid)).to.equal(false) + }) + }) + + describe('buildRequests', () => { + const bid = JSON.parse(JSON.stringify(bidRequestData)) + const request = spec.buildRequests([bid], bid) + const payload = JSON.parse(request[0].data) + + it('should include ext in imp', () => { + expect(payload.imp[0].ext).to.exist + expect(payload.imp[0].ext).to.deep.equal({ + prebid: { storedrequest: { id: '12345' } }, + }) + }) + + it('should include banner format in imp', () => { + expect(payload.imp[0].banner).to.exist + expect(payload.imp[0].banner).to.deep.equal({ + format: [{ w: 300, h: 250 }], + }) + }) + + it('should include ortb2 first party data', () => { + expect(payload.device.w).to.equal(1860) + expect(payload.device.h).to.equal(410) + expect(payload.user.ext.consent).to.equal('G4ll0p1ng_Un1c0rn5') + expect(payload.regs.gdpr).to.equal(1) + }) + }) + + describe('interpretResponse', () => { + const serverResponse = { + body: { + id: 'test-id', + cur: 'USD', + seatbid: [ + { + bid: [ + { + id: 'testbidid', + price: 0.4, + adm: 'test-ad', + adid: 789456, + crid: 1234, + w: 300, + h: 250, + }, + ], + }, + ], + }, + } + + const interpretedResponse = spec.interpretResponse( + serverResponse, + bidRequestData + ) + + it('should interpret response', () => { + expect(interpretedResponse[0].requestId).to.equal(bidRequestData.bidId) + expect(interpretedResponse[0].cpm).to.equal( + serverResponse.body.seatbid[0].bid[0].price + ) + expect(interpretedResponse[0].ad).to.equal( + serverResponse.body.seatbid[0].bid[0].adm + ) + expect(interpretedResponse[0].creativeId).to.equal( + serverResponse.body.seatbid[0].bid[0].crid + ) + expect(interpretedResponse[0].width).to.equal( + serverResponse.body.seatbid[0].bid[0].w + ) + expect(interpretedResponse[0].height).to.equal( + serverResponse.body.seatbid[0].bid[0].h + ) + expect(interpretedResponse[0].currency).to.equal(serverResponse.body.cur) + }) + }) + + describe('getUserSyncs', () => { + it('should return user sync', () => { + const optionsType = { + iframeEnabled: true, + pixelEnabled: true, + } + const serverResponse = [ + { + body: { + ext: { + responsetimemillis: { + 'test seat 1': 2, + 'test seat 2': 1, + }, + }, + }, + }, + ] + const gdprConsent = { + gdprApplies: 1, + consentString: 'dkj49Sjmfjuj34as:12jaf90123hufabidfy9u23brfpoig', + } + const uspConsent = 'mkjvbiniwot4827obfoy8sdg8203gb' + const expectedUserSyncs = [ + { + type: 'iframe', + url: 'https://null.holid.io/sync.html?bidders=%5B%22test%20seat%201%22%2C%22test%20seat%202%22%5D&gdpr=1&gdpr_consent=dkj49Sjmfjuj34as:12jaf90123hufabidfy9u23brfpoig&usp_consent=mkjvbiniwot4827obfoy8sdg8203gb&type=iframe', + }, + ] + + const userSyncs = spec.getUserSyncs( + optionsType, + serverResponse, + gdprConsent, + uspConsent + ) + + expect(userSyncs).to.deep.equal(expectedUserSyncs) + }) + + it('should return empty user syncs when responsetimemillis is not defined', () => { + const optionsType = { + iframeEnabled: true, + pixelEnabled: true, + } + const serverResponse = [ + { + body: { + ext: {}, + }, + }, + ] + const gdprConsent = { + gdprApplies: 1, + consentString: 'dkj49Sjmfjuj34as:12jaf90123hufabidfy9u23brfpoig', + } + const uspConsent = 'mkjvbiniwot4827obfoy8sdg8203gb' + const expectedUserSyncs = [] + + const userSyncs = spec.getUserSyncs( + optionsType, + serverResponse, + gdprConsent, + uspConsent + ) + + expect(userSyncs).to.deep.equal(expectedUserSyncs) + }) + }) +}) diff --git a/test/spec/modules/id5IdSystem_spec.js b/test/spec/modules/id5IdSystem_spec.js index 8c0f8ad9cf3..392c11f3529 100644 --- a/test/spec/modules/id5IdSystem_spec.js +++ b/test/spec/modules/id5IdSystem_spec.js @@ -52,6 +52,18 @@ describe('ID5 ID System', function () { 'signature': ID5_RESPONSE_SIGNATURE, 'link_type': ID5_RESPONSE_LINK_TYPE }; + const ALLOWED_ID5_VENDOR_DATA = { + purpose: { + consents: { + 1: true + } + }, + vendor: { + consents: { + 131: true + } + } + } function getId5FetchConfig(storageName = ID5_STORAGE_NAME, storageType = 'html5') { return { @@ -205,6 +217,37 @@ describe('ID5 ID System', function () { }); }); + describe('Check for valid consent', function() { + const dataConsentVals = [ + [{purpose: {consents: {1: false}}}, {vendor: {consents: {131: true}}}, ' no purpose consent'], + [{purpose: {consents: {1: true}}}, {vendor: {consents: {131: false}}}, ' no vendor consent'], + [{purpose: {consents: {1: false}}}, {vendor: {consents: {131: false}}}, ' no purpose and vendor consent'], + [{purpose: {consents: undefined}}, {vendor: {consents: {131: true}}}, ' undefined purpose consent'], + [{purpose: {consents: {1: false}}}, {vendor: {consents: undefined}}], ' undefined vendor consent', + [undefined, {vendor: {consents: {131: true}}}, ' undefined purpose'], + [{purpose: {consents: {1: true}}}, {vendor: undefined}, ' undefined vendor'], + [{purpose: {consents: {1: true}}}, {vendor: {consents: {31: true}}}, ' incorrect vendor consent'] + ]; + + dataConsentVals.forEach(function([purposeConsent, vendorConsent, caseName]) { + it('should fail with invalid consent because of ' + caseName, function() { + let dataConsent = { + gdprApplies: true, + consentString: 'consentString', + vendorData: { + purposeConsent, vendorConsent + } + } + expect(id5IdSubmodule.getId(config)).is.eq(undefined); + expect(id5IdSubmodule.getId(config, dataConsent)).is.eq(undefined); + + let cacheIdObject = 'cacheIdObject'; + expect(id5IdSubmodule.extendId(config)).is.eq(undefined); + expect(id5IdSubmodule.extendId(config, dataConsent, cacheIdObject)).is.eq(cacheIdObject); + }); + }); + }); + describe('Xhr Requests from getId()', function () { const responseHeader = {'Content-Type': 'application/json'}; @@ -248,7 +291,8 @@ describe('ID5 ID System', function () { let xhrServerMock = new XhrServerMock(sinon.createFakeServer()) let consentData = { gdprApplies: true, - consentString: 'consentString' + consentString: 'consentString', + vendorData: ALLOWED_ID5_VENDOR_DATA } let submoduleResponse = callSubmoduleGetId(getId5FetchConfig(), consentData, undefined); @@ -297,7 +341,8 @@ describe('ID5 ID System', function () { let xhrServerMock = new XhrServerMock(sinon.createFakeServer()) let consentData = { gdprApplies: true, - consentString: 'consentString' + consentString: 'consentString', + vendorData: ALLOWED_ID5_VENDOR_DATA } let submoduleResponse = callSubmoduleGetId(getId5FetchConfig(), consentData, undefined); diff --git a/test/spec/modules/impactifyBidAdapter_spec.js b/test/spec/modules/impactifyBidAdapter_spec.js index 8bb2d089ad8..215972ff450 100644 --- a/test/spec/modules/impactifyBidAdapter_spec.js +++ b/test/spec/modules/impactifyBidAdapter_spec.js @@ -166,6 +166,19 @@ describe('ImpactifyAdapter', function () { } }; + it('should pass bidfloor', function () { + videoBidRequests[0].getFloor = function() { + return { + currency: 'USD', + floor: 1.23, + } + } + + const res = spec.buildRequests(videoBidRequests, videoBidderRequest) + const resData = JSON.parse(res.data) + expect(resData.imp[0].bidfloor).to.equal(1.23) + }); + it('sends video bid request to ENDPOINT via POST', function () { const request = spec.buildRequests(videoBidRequests, videoBidderRequest); expect(request.url).to.equal(ORIGIN + AUCTIONURI); diff --git a/test/spec/modules/improvedigitalBidAdapter_spec.js b/test/spec/modules/improvedigitalBidAdapter_spec.js index b3b01dc93b5..4ece6c65b68 100644 --- a/test/spec/modules/improvedigitalBidAdapter_spec.js +++ b/test/spec/modules/improvedigitalBidAdapter_spec.js @@ -15,6 +15,8 @@ import 'modules/consentManagementUsp.js'; import 'modules/schain.js'; import {decorateAdUnitsWithNativeParams, toLegacyResponse} from '../../../src/native.js'; import {createEidsArray} from '../../../modules/userId/eids.js'; +import {syncAddFPDToBidderRequest} from '../../helpers/fpd.js'; +import {hook} from '../../../src/hook.js'; describe('Improve Digital Adapter Tests', function () { const METHOD = 'POST'; @@ -168,6 +170,10 @@ describe('Improve Digital Adapter Tests', function () { return bidRequests; } + before(() => { + hook.ready(); + }); + describe('isBidRequestValid', function () { it('should return false when no bid', function () { expect(spec.isBidRequestValid()).to.equal(false); @@ -220,7 +226,7 @@ describe('Improve Digital Adapter Tests', function () { it('should make a well-formed request objects', function () { getConfigStub = sinon.stub(config, 'getConfig'); getConfigStub.withArgs('improvedigital.usePrebidSizes').returns(true); - const request = spec.buildRequests([simpleBidRequest], bidderRequest)[0]; + const request = spec.buildRequests([simpleBidRequest], syncAddFPDToBidderRequest(bidderRequest))[0]; expect(request).to.be.an('object'); expect(request.method).to.equal(METHOD); expect(request.url).to.equal(AD_SERVER_URL); @@ -390,7 +396,7 @@ describe('Improve Digital Adapter Tests', function () { it('should add GDPR consent string', function () { const bidRequest = Object.assign({}, simpleBidRequest); - const payload = JSON.parse(spec.buildRequests([bidRequest], bidderRequestGdpr)[0].data); + const payload = JSON.parse(spec.buildRequests([bidRequest], syncAddFPDToBidderRequest(bidderRequestGdpr))[0].data); expect(payload.regs.ext.gdpr).to.exist.and.to.equal(1); expect(payload.user.ext.consent).to.equal('CONSENT'); expect(payload.user.ext.ConsentedProvidersSettings).to.not.exist; @@ -401,7 +407,16 @@ describe('Improve Digital Adapter Tests', function () { const bidderRequestGdprEmptyAddtl = deepClone(bidderRequestGdpr); bidderRequestGdprEmptyAddtl.gdprConsent.addtlConsent = '1~'; const bidRequest = Object.assign({}, simpleBidRequest); - const payload = JSON.parse(spec.buildRequests([bidRequest], bidderRequestGdprEmptyAddtl)[0].data); + const payload = JSON.parse(spec.buildRequests([bidRequest], syncAddFPDToBidderRequest(bidderRequestGdprEmptyAddtl))[0].data); + expect(payload.user.ext.consented_providers_settings).to.not.exist; + }); + + it('should add ConsentedProvidersSettings when extend mode enabled', function () { + const bidRequest = deepClone(extendBidRequest); + const payload = JSON.parse(spec.buildRequests([bidRequest], syncAddFPDToBidderRequest(bidderRequestGdpr))[0].data); + expect(payload.regs.ext.gdpr).to.exist.and.to.equal(1); + expect(payload.user.ext.consent).to.equal('CONSENT'); + expect(payload.user.ext.ConsentedProvidersSettings.consented_providers).to.exist.and.to.equal('1~1.35.41.101'); expect(payload.user.ext.consented_providers_settings).to.not.exist; }); @@ -416,7 +431,7 @@ describe('Improve Digital Adapter Tests', function () { it('should add CCPA consent string', function () { const bidRequest = Object.assign({}, simpleBidRequest); - const request = spec.buildRequests([bidRequest], {...bidderRequest, ...{ uspConsent: '1YYY' }}); + const request = spec.buildRequests([bidRequest], syncAddFPDToBidderRequest({...bidderRequest, ...{ uspConsent: '1YYY' }})); const payload = JSON.parse(request[0].data); expect(payload.regs.ext.us_privacy).to.equal('1YYY'); }); @@ -425,17 +440,17 @@ describe('Improve Digital Adapter Tests', function () { getConfigStub = sinon.stub(config, 'getConfig'); getConfigStub.withArgs('coppa').returns(true); let bidRequest = Object.assign({}, simpleBidRequest); - let payload = JSON.parse(spec.buildRequests([bidRequest], bidderRequestGdpr)[0].data); + let payload = JSON.parse(spec.buildRequests([bidRequest], syncAddFPDToBidderRequest(bidderRequestGdpr))[0].data); expect(payload.regs.coppa).to.equal(1); getConfigStub.withArgs('coppa').returns(false); bidRequest = Object.assign({}, simpleBidRequest); - payload = JSON.parse(spec.buildRequests([bidRequest], bidderRequestGdpr)[0].data); + payload = JSON.parse(spec.buildRequests([bidRequest], syncAddFPDToBidderRequest(bidderRequestGdpr))[0].data); expect(payload.regs.coppa).to.equal(0); }); it('should add referrer', function () { const bidRequest = Object.assign({}, simpleBidRequest); - const request = spec.buildRequests([bidRequest], bidderRequestReferrer)[0]; + const request = spec.buildRequests([bidRequest], syncAddFPDToBidderRequest(bidderRequestReferrer))[0]; const payload = JSON.parse(request.data); expect(payload.site.page).to.equal('https://blah.com/test.html'); }); @@ -678,21 +693,21 @@ describe('Improve Digital Adapter Tests', function () { page: 'https://improveditigal.com/', domain: 'improveditigal.com' }); - let request = spec.buildRequests([simpleBidRequest], bidderRequestReferrer)[0]; + let request = spec.buildRequests([simpleBidRequest], syncAddFPDToBidderRequest(bidderRequestReferrer))[0]; let payload = JSON.parse(request.data); expect(payload.site.content).does.exist.and.equal('XYZ'); expect(payload.site.page).does.exist.and.equal('https://improveditigal.com/'); expect(payload.site.domain).does.exist.and.equal('improveditigal.com'); getConfigStub.reset(); - request = spec.buildRequests([simpleBidRequest], bidderRequestReferrer)[0]; + request = spec.buildRequests([simpleBidRequest], syncAddFPDToBidderRequest(bidderRequestReferrer))[0]; payload = JSON.parse(request.data); expect(payload.site.content).does.not.exist; expect(payload.site.page).does.exist.and.equal('https://blah.com/test.html'); expect(payload.site.domain).does.exist.and.equal('blah.com'); const ortb2 = {site: {content: 'ZZZ'}}; - request = spec.buildRequests([simpleBidRequest], {...bidderRequestReferrer, ortb2})[0]; + request = spec.buildRequests([simpleBidRequest], syncAddFPDToBidderRequest({...bidderRequestReferrer, ortb2}))[0]; payload = JSON.parse(request.data); expect(payload.site.content).does.exist.and.equal('ZZZ'); expect(payload.site.page).does.exist.and.equal('https://blah.com/test.html'); diff --git a/test/spec/modules/incrxBidAdapter_spec.js b/test/spec/modules/incrxBidAdapter_spec.js index 8fb95742766..3fb4ffe2cd3 100644 --- a/test/spec/modules/incrxBidAdapter_spec.js +++ b/test/spec/modules/incrxBidAdapter_spec.js @@ -71,6 +71,8 @@ describe('IncrementX', function () { cpm: '0.7', ad: '

Ad from IncrementX

', slotBidId: 'bid-id-123456', + adType: '1', + settings: '1,2', nurl: 'htt://nurl.com', statusText: 'Success' } @@ -80,6 +82,8 @@ describe('IncrementX', function () { requestId: 'bid-id-123456', cpm: '0.7', currency: 'USD', + adType: '1', + settings: '1,2', netRevenue: false, width: '300', height: '250', diff --git a/test/spec/modules/invisiblyAnalyticsAdapter_spec.js b/test/spec/modules/invisiblyAnalyticsAdapter_spec.js index d97b0925713..3b3542d43b0 100644 --- a/test/spec/modules/invisiblyAnalyticsAdapter_spec.js +++ b/test/spec/modules/invisiblyAnalyticsAdapter_spec.js @@ -1,5 +1,6 @@ import invisiblyAdapter from 'modules/invisiblyAnalyticsAdapter.js'; import { expect } from 'chai'; +import {expectEvents} from '../../helpers/analytics.js'; let events = require('src/events'); let constants = require('src/constants.json'); @@ -197,14 +198,8 @@ describe('Invisibly Analytics Adapter test suite', function () { account: 'invisibly', }, }); - events.emit(constants.EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT); - events.emit(constants.EVENTS.AUCTION_END, MOCK.AUCTION_END); - events.emit(constants.EVENTS.BID_REQUESTED, MOCK.BID_REQUESTED); - events.emit(constants.EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE); - events.emit(constants.EVENTS.BID_WON, MOCK.BID_WON); - // 5 Invisibly events + 1 Clean.io event - sinon.assert.callCount(invisiblyAdapter.track, 6); + expectEvents().to.beTrackedBy(invisiblyAdapter.track); }); it('should not catch events triggered without invisibly account config', function () { @@ -382,9 +377,6 @@ describe('Invisibly Analytics Adapter test suite', function () { expect(invisiblyEvents.event_data.pageViewId).to.exist; expect(invisiblyEvents.event_data.ver).to.equal(1); expect(invisiblyEvents.event_type).to.equal('PREBID_bidWon'); - - // 1 Invisibly event + 1 Clean.io event - sinon.assert.callCount(invisiblyAdapter.track, 2); }); // spec for bidder done event @@ -522,7 +514,6 @@ describe('Invisibly Analytics Adapter test suite', function () { expect(invisiblyEvents.event_data.auctionId).to.equal( MOCK.AUCTION_END.auctionId ); - sinon.assert.callCount(invisiblyAdapter.track, 1); }); // should not call sendEvent for events not supported by the adapter @@ -541,22 +532,21 @@ describe('Invisibly Analytics Adapter test suite', function () { it('track all event without errors', function () { invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT); - events.emit(constants.EVENTS.AUCTION_END, MOCK.AUCTION_END); - events.emit(constants.EVENTS.BID_ADJUSTMENT, MOCK.BID_ADJUSTMENT); - events.emit(constants.EVENTS.BID_TIMEOUT, MOCK.BID_TIMEOUT); - events.emit(constants.EVENTS.BID_REQUESTED, MOCK.BID_REQUESTED); - events.emit(constants.EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE); - events.emit(constants.EVENTS.NO_BID, MOCK.NO_BID); - events.emit(constants.EVENTS.BID_WON, MOCK.BID_WON); - events.emit(constants.EVENTS.BIDDER_DONE, MOCK.BIDDER_DONE); - events.emit(constants.EVENTS.SET_TARGETING, MOCK.SET_TARGETING); - events.emit(constants.EVENTS.REQUEST_BIDS, MOCK.REQUEST_BIDS); - events.emit(constants.EVENTS.ADD_AD_UNITS, MOCK.ADD_AD_UNITS); - events.emit(constants.EVENTS.AD_RENDER_FAILED, MOCK.AD_RENDER_FAILED); - - // 13 Invisibly events + 1 Clean.io event - sinon.assert.callCount(invisiblyAdapter.track, 14); + expectEvents([ + constants.EVENTS.AUCTION_INIT, + constants.EVENTS.AUCTION_END, + constants.EVENTS.BID_ADJUSTMENT, + constants.EVENTS.BID_TIMEOUT, + constants.EVENTS.BID_REQUESTED, + constants.EVENTS.BID_RESPONSE, + constants.EVENTS.NO_BID, + constants.EVENTS.BID_WON, + constants.EVENTS.BIDDER_DONE, + constants.EVENTS.SET_TARGETING, + constants.EVENTS.REQUEST_BIDS, + constants.EVENTS.ADD_AD_UNITS, + constants.EVENTS.AD_RENDER_FAILED + ]).to.beTrackedBy(invisiblyAdapter.track); }); }); diff --git a/test/spec/modules/ixBidAdapter_spec.js b/test/spec/modules/ixBidAdapter_spec.js index a1b79358e8c..5f104dce13f 100644 --- a/test/spec/modules/ixBidAdapter_spec.js +++ b/test/spec/modules/ixBidAdapter_spec.js @@ -286,6 +286,44 @@ describe('IndexexchangeAdapter', function () { } ]; + const DEFAULT_VIDEO_VALID_BID_MEDIUM_SIZE = [ + { + bidder: 'ix', + params: { + siteId: '456', + video: { + skippable: false, + mimes: [ + 'video/mp4', + 'video/webm' + ], + minduration: 0, + maxduration: 60, + protocols: [2] + }, + size: [640, 480] + }, + sizes: [[640, 480], [200, 400]], + mediaTypes: { + video: { + context: 'instream', + playerSize: [[640, 480], [200, 400]] + } + }, + ortb2Imp: { + ext: { + tid: '173f49a8-7549-4218-a23c-e7ba59b47230' + } + }, + adUnitCode: 'div-gpt-ad-1460505748562-0', + transactionId: '173f49a8-7549-4218-a23c-e7ba59b47230', + bidId: '1a2b3c4e', + bidderRequestId: '11a22b33c44e', + auctionId: '1aa2bb3cc4de', + schain: SAMPLE_SCHAIN + } + ]; + const DEFAULT_MULTIFORMAT_BANNER_VALID_BID = [ { bidder: 'ix', @@ -364,6 +402,78 @@ describe('IndexexchangeAdapter', function () { } ]; + const DEFAULT_MULTIFORMAT_VALID_BID = [ + { + bidder: 'ix', + params: { + tagId: '123', + siteId: '456', + video: { + siteId: '1111' + }, + banner: { + siteId: '2222' + }, + native: { + siteId: '3333' + }, + size: [300, 250] + }, + mediaTypes: { + video: { + context: 'outstream', + playerSize: [[300, 250]], + skippable: false, + mimes: [ + 'video/mp4', + 'video/webm' + ], + minduration: 0, + maxduration: 60, + protocols: [1] + }, + banner: { + sizes: [[300, 250], [300, 600]] + }, + native: { + icon: { + required: false + }, + title: { + len: 25, + required: true + }, + body: { + required: true + }, + image: { + required: true + }, + sponsoredBy: { + required: true + } + } + }, + ortb2Imp: { + ext: { + tid: '173f49a8-7549-4218-a23c-e7ba59b47230', + data: { + pbadslot: 'div-gpt-ad-1460505748562-0' + } + } + }, + nativeOrtbRequest: { + assets: [{id: 0, required: 0, img: {type: 1}}, {id: 1, required: 1, title: {len: 140}}, {id: 2, required: 1, data: {type: 2}}, {id: 3, required: 1, img: {type: 3}}, {id: 4, required: false, video: {mimes: ['video/mp4', 'video/webm'], minduration: 0, maxduration: 120, protocols: [2, 3, 5, 6]}}] + }, + adUnitCode: 'div-gpt-ad-1460505748562-0', + transactionId: '273f49a8-7549-4218-a23c-e7ba59b47230', + bidId: '1a2b3c4e', + bidderRequestId: '11a22b33c44e', + auctionId: '1aa2bb3cc4de', + schain: SAMPLE_SCHAIN + } + ]; + const DEFAULT_NATIVE_VALID_BID = [ { bidder: 'ix', @@ -400,7 +510,7 @@ describe('IndexexchangeAdapter', function () { } }, nativeOrtbRequest: { - assets: [{id: 0, required: 0, img: {type: 1}}, {id: 1, required: 1, title: {len: 140}}, {id: 2, required: 1, data: {type: 2}}, {id: 3, required: 1, img: {type: 3}}, {id: 4, required: false, video: {mimes: ['video/mp4', 'video/webm'], minduration: 0, maxduration: 120, protocols: [2, 3, 5, 6]}}] + assets: [{ id: 0, required: 0, img: { type: 1 } }, { id: 1, required: 1, title: { len: 140 } }, { id: 2, required: 1, data: { type: 2 } }, { id: 3, required: 1, img: { type: 3 } }, { id: 4, required: false, video: { mimes: ['video/mp4', 'video/webm'], minduration: 0, maxduration: 120, protocols: [2, 3, 5, 6] } }] }, adUnitCode: 'div-gpt-ad-1460505748563-0', transactionId: '173f49a8-7549-4218-a23c-e7ba59b47231', @@ -441,7 +551,7 @@ describe('IndexexchangeAdapter', function () { } }, nativeOrtbRequest: { - assets: [{id: 0, required: 0, img: {type: 1}}, {id: 1, required: 1, title: {len: 140}}, {id: 2, required: 1, data: {type: 2}}, {id: 3, required: 1, img: {type: 3}}, {id: 4, required: false, video: {mimes: ['video/mp4', 'video/webm'], minduration: 0, maxduration: 120, protocols: [2, 3, 5, 6]}}] + assets: [{ id: 0, required: 0, img: { type: 1 } }, { id: 1, required: 1, title: { len: 140 } }, { id: 2, required: 1, data: { type: 2 } }, { id: 3, required: 1, img: { type: 3 } }, { id: 4, required: false, video: { mimes: ['video/mp4', 'video/webm'], minduration: 0, maxduration: 120, protocols: [2, 3, 5, 6] } }] }, adUnitCode: 'div-gpt-ad-1460505748562-0', transactionId: '173f49a8-7549-4218-a23c-e7ba59b47230', @@ -548,7 +658,7 @@ describe('IndexexchangeAdapter', function () { } }; - const DEFAULT_VIDEO_BID_RESPONSE_WITH_MTYPE_SET = { + const DEFAULT_VIDEO_BID_RESPONSE_WITH_XML_ADM = { cur: 'USD', id: '1aa2bb3cc4de', seatbid: [ @@ -565,7 +675,6 @@ describe('IndexexchangeAdapter', function () { mtype: 2, adm: ' Test In-Stream Video {} + render: () => { } }; bid.mediaTypes.video.context = 'outstream'; bid.mediaTypes.video.playerSize = [[300, 249]]; @@ -1080,7 +1172,7 @@ describe('IndexexchangeAdapter', function () { bid.nativeOrtbRequest = {} expect(spec.isBidRequestValid(bid)).to.be.false; - bid.nativeOrtbRequest = {assets: []} + bid.nativeOrtbRequest = { assets: [] } expect(spec.isBidRequestValid(bid)).to.be.false; }); }); @@ -1104,10 +1196,10 @@ describe('IndexexchangeAdapter', function () { const cloneValidBid = utils.deepClone(validBid); cloneValidBid[0].userIdAsEids = utils.deepClone(DEFAULT_USERIDASEIDS_DATA); const request = spec.buildRequests(cloneValidBid, ALIAS_OPTIONS); - const payload = JSON.parse(request[0].data.r); + const payload = extractPayload(request[0]); expect(request).to.be.an('array'); expect(request).to.have.lengthOf.above(0); // should be 1 or more - expect(payload.user.eids).to.have.lengthOf(6); + expect(payload.user.eids).to.have.lengthOf(7); expect(payload.user.eids).to.deep.include(DEFAULT_USERID_PAYLOAD[0]); }); }); @@ -1115,7 +1207,7 @@ describe('IndexexchangeAdapter', function () { describe('buildRequestsIdentity', function () { let request; - let query; + let payload; let testCopy; beforeEach(function () { @@ -1124,7 +1216,7 @@ describe('IndexexchangeAdapter', function () { return testCopy; }; request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0]; - query = request.data; + payload = extractPayload(request); }); afterEach(function () { @@ -1137,8 +1229,6 @@ describe('IndexexchangeAdapter', function () { }); it('payload should have correct format and value (single identity partner)', function () { - const payload = JSON.parse(query.r); - expect(payload.user).to.exist; expect(payload.user.eids).to.exist; expect(payload.user.eids).to.be.an('array'); @@ -1146,7 +1236,7 @@ describe('IndexexchangeAdapter', function () { }); it('identity data in impression should have correct format and value (single identity partner)', function () { - const impression = JSON.parse(query.r).user.eids; + const impression = payload.user.eids; expect(impression[0].source).to.equal(testCopy.IdentityIp.data.source); expect(impression[0].uids[0].id).to.equal(testCopy.IdentityIp.data.uids[0].id); }); @@ -1166,8 +1256,6 @@ describe('IndexexchangeAdapter', function () { }); it('payload should have correct format and value (single identity w/ multi ids)', function () { - const payload = JSON.parse(query.r); - expect(payload.user).to.exist; expect(payload.user.eids).to.exist; expect(payload.user.eids).to.be.an('array'); @@ -1175,7 +1263,7 @@ describe('IndexexchangeAdapter', function () { }); it('identity data in impression should have correct format and value (single identity w/ multi ids)', function () { - const impression = JSON.parse(query.r).user.eids; + const impression = payload.user.eids; expect(impression[0].source).to.equal(testCopy.IdentityIp.data.source); expect(impression[0].uids).to.have.lengthOf(3); @@ -1210,8 +1298,6 @@ describe('IndexexchangeAdapter', function () { }); it('payload should have correct format and value (multiple identity partners)', function () { - const payload = JSON.parse(query.r); - expect(payload.user).to.exist; expect(payload.user.eids).to.exist; expect(payload.user.eids).to.be.an('array'); @@ -1219,7 +1305,7 @@ describe('IndexexchangeAdapter', function () { }); it('identity data in impression should have correct format and value (multiple identity partners)', function () { - const impression = JSON.parse(query.r).user.eids; + const impression = payload.user.eids; expect(impression[0].source).to.equal(testCopy.IdentityIp.data.source); expect(impression[0].uids).to.have.lengthOf(1); @@ -1242,8 +1328,7 @@ describe('IndexexchangeAdapter', function () { return undefined; }; request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0]; - query = request.data; - const payload = JSON.parse(query.r); + payload = extractPayload(request); expect(payload.user).to.exist; expect(payload.user.eids).to.not.exist; @@ -1255,8 +1340,7 @@ describe('IndexexchangeAdapter', function () { data: {} } request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0]; - query = request.data; - const payload = JSON.parse(query.r); + payload = extractPayload(request); expect(payload.user).to.exist; expect(payload.user.eids).to.exist; @@ -1265,8 +1349,7 @@ describe('IndexexchangeAdapter', function () { it('payload should not have any user eids if identity data is pending for all partners', function () { testCopy.IdentityIp.responsePending = true; request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0]; - query = request.data; - const payload = JSON.parse(query.r); + payload = extractPayload(request); expect(payload.user).to.exist; expect(payload.user.eids).to.not.exist; @@ -1276,8 +1359,7 @@ describe('IndexexchangeAdapter', function () { testCopy.IdentityIp.responsePending = false; testCopy.IdentityIp.data = {}; request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0]; - query = request.data; - const payload = JSON.parse(query.r); + payload = extractPayload(request); expect(payload.user).to.exist; expect(payload.user.eids).to.not.exist; @@ -1304,9 +1386,8 @@ describe('IndexexchangeAdapter', function () { const cloneValidBid = utils.deepClone(DEFAULT_VIDEO_VALID_BID); cloneValidBid[0].userIdAsEids = utils.deepClone(DEFAULT_USERIDASEIDS_DATA); const request = spec.buildRequests(cloneValidBid, DEFAULT_OPTION)[0]; - const payload = JSON.parse(request.data.r); - - expect(payload.user.eids).to.have.lengthOf(6); + const payload = extractPayload(request); + expect(payload.user.eids).to.have.lengthOf(7); expect(payload.user.eids).to.have.deep.members(DEFAULT_USERID_PAYLOAD); }); @@ -1401,7 +1482,7 @@ describe('IndexexchangeAdapter', function () { cloneValidBid[0].userIdAsEids = utils.deepClone(DEFAULT_USERIDASEIDS_DATA); const request = spec.buildRequests(cloneValidBid, DEFAULT_OPTION)[0]; - const payload = JSON.parse(request.data.r); + const payload = extractPayload(request); validUserIdPayload = utils.deepClone(DEFAULT_USERID_PAYLOAD); validUserIdPayload.push({ @@ -1439,7 +1520,7 @@ describe('IndexexchangeAdapter', function () { }) expect(payload.user).to.exist; - expect(payload.user.eids).to.have.lengthOf(8); + expect(payload.user.eids).to.have.lengthOf(9); expect(payload.user.eids).to.have.deep.members(validUserIdPayload); }); @@ -1480,8 +1561,8 @@ describe('IndexexchangeAdapter', function () { }] }); - const payload = JSON.parse(request.data.r); - expect(payload.user.eids).to.have.lengthOf(7); + const payload = extractPayload(request); + expect(payload.user.eids).to.have.lengthOf(8); expect(payload.user.eids).to.have.deep.members(validUserIdPayload); }); }); @@ -1503,7 +1584,7 @@ describe('IndexexchangeAdapter', function () { bid.userId = DEFAULT_USERID_BID_DATA; const request = spec.buildRequests([bid], DEFAULT_OPTION)[0]; - const r = JSON.parse(request.data.r); + const r = extractPayload(request); expect(r.ext.ixdiag.userIds).to.be.an('array'); expect(r.ext.ixdiag.userIds.should.not.include('lotamePanoramaId')); @@ -1514,8 +1595,8 @@ describe('IndexexchangeAdapter', function () { describe('First party data', function () { it('should not set ixdiag.fpd value if not defined', function () { - const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, {ortb2: {}})[0]; - const r = JSON.parse(request.data.r); + const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, { ortb2: {} })[0]; + const r = extractPayload(request); expect(r.ext.ixdiag.fpd).to.be.undefined; }); @@ -1531,21 +1612,21 @@ describe('IndexexchangeAdapter', function () { } }; - const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, {ortb2})[0]; - const r = JSON.parse(request.data.r); + const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, { ortb2 })[0]; + const r = extractPayload(request); expect(r.ext.ixdiag.fpd).to.exist; }); - it('should set ixdiag.tmax value if it exists using tmax', function () { + it('should set ixdiag.tmax value from bidderRequest overriding global config bidderTimeout', function () { config.setConfig({ bidderTimeout: 250 }); - const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID)[0]; - const r = JSON.parse(request.data.r); + const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, { timeout: 1234 })[0]; + const r = extractPayload(request); - expect(r.ext.ixdiag.tmax).to.equal(250); + expect(r.ext.ixdiag.tmax).to.equal(1234); }); it('should not set ixdiag.tmax value if bidderTimeout is undefined', function () { @@ -1553,11 +1634,18 @@ describe('IndexexchangeAdapter', function () { bidderTimeout: null }) const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID)[0]; - const r = JSON.parse(request.data.r); + const r = extractPayload(request); expect(r.ext.ixdiag.tmax).to.be.undefined }); + it('should set ixdiag.imps to number of impressions', function () { + const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID)[0]; + const r = extractPayload(request); + + expect(r.ext.ixdiag.imps).to.equal(1); + }); + it('should not send information that is not part of openRTB spec v2.5 using ortb2', function () { const ortb2 = { site: { @@ -1571,8 +1659,8 @@ describe('IndexexchangeAdapter', function () { } }; - const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, {ortb2})[0]; - const r = JSON.parse(request.data.r); + const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, { ortb2 })[0]; + const r = extractPayload(request); expect(r.site.keywords).to.exist; expect(r.site.search).to.exist; @@ -1595,46 +1683,72 @@ describe('IndexexchangeAdapter', function () { const bid = utils.deepClone(DEFAULT_BANNER_VALID_BID[0]); bid.mediaTypes.banner.sizes = LARGE_SET_OF_SIZES; - const request = spec.buildRequests([bid], {ortb2})[0]; - const r = JSON.parse(request.data.r); + const request = spec.buildRequests([bid], { ortb2 })[0]; + const r = extractPayload(request); expect(r.site.ref).to.exist; expect(r.site.keywords).to.be.undefined; expect(r.user).to.be.undefined; }); + it('should set gpp and gpp_sid field when defined', function () { + const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, { ortb2: {regs: {gpp: 'gpp', gpp_sid: [1]}} })[0]; + const r = extractPayload(request); + + expect(r.regs.gpp).to.equal('gpp'); + expect(r.regs.gpp_sid).to.be.an('array'); + expect(r.regs.gpp_sid).to.include(1); + }); + it('should not set gpp and gpp_sid field when not defined', function () { + const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, { ortb2: {regs: {}} })[0]; + const r = extractPayload(request); + + expect(r.regs).to.be.undefined; + }); + it('should not set gpp and gpp_sid field when fields arent strings or array defined', function () { + const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, { ortb2: {regs: {gpp: 1, gpp_sid: 'string'}} })[0]; + const r = extractPayload(request); + + expect(r.regs).to.be.undefined; + }); + it('should set gpp info from module when it exists', function () { + const options = { + gppConsent: { + gppString: 'gpp', + applicableSections: [1] + } + }; + const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, options); + const r = extractPayload(request[0]); + + expect(r.regs.gpp).to.equal('gpp'); + expect(r.regs.gpp_sid).to.be.an('array'); + expect(r.regs.gpp_sid).to.include(1); + }); }); describe('buildRequests', function () { let request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0]; const requestUrl = request.url; const requestMethod = request.method; - const query = request.data; + const payloadData = request.data; const bidWithoutSchain = utils.deepClone(DEFAULT_BANNER_VALID_BID); delete bidWithoutSchain[0].schain; const requestWithoutSchain = spec.buildRequests(bidWithoutSchain, DEFAULT_OPTION)[0]; - const queryWithoutSchain = requestWithoutSchain.data; + const payloadWithoutSchain = extractPayload(requestWithoutSchain); const GPID = '/19968336/some-adunit-path'; - it('request should be made to IX endpoint with GET method', function () { - expect(requestMethod).to.equal('GET'); - expect(requestUrl).to.equal(IX_SECURE_ENDPOINT); + it('request should be made to IX endpoint with POST method and siteId in query param', function () { + expect(requestMethod).to.equal('POST'); + expect(requestUrl).to.equal(IX_SECURE_ENDPOINT + '?s=' + DEFAULT_BANNER_VALID_BID[0].params.siteId); + expect(request.option.contentType).to.equal('text/plain') }); it('auction type should be set correctly', function () { - const at = JSON.parse(query.r).at; + const at = payloadData.at; expect(at).to.equal(1); }) - it('query object (version, siteID and request) should be correct', function () { - expect(query.v).to.equal(BANNER_ENDPOINT_VERSION); - expect(query.s).to.equal(DEFAULT_BANNER_VALID_BID[0].params.siteId); - expect(query.r).to.exist; - expect(query.ac).to.equal('j'); - expect(query.sd).to.equal(1); - expect(query.nf).not.to.exist; - }); - it('should send dfp_adunit_code in request if ortb2Imp.ext.data.adserver.adslot exists', function () { const AD_UNIT_CODE = '/19968336/some-adunit-path'; const validBids = utils.deepClone(DEFAULT_BANNER_VALID_BID); @@ -1649,7 +1763,7 @@ describe('IndexexchangeAdapter', function () { } }; const requests = spec.buildRequests(validBids, DEFAULT_OPTION); - const { ext: { dfp_ad_unit_code } } = JSON.parse(requests[0].data.r).imp[0]; + const { ext: { dfp_ad_unit_code } } = extractPayload(requests[0]).imp[0]; expect(dfp_ad_unit_code).to.equal(AD_UNIT_CODE); }); @@ -1661,7 +1775,7 @@ describe('IndexexchangeAdapter', function () { } }; const requests = spec.buildRequests(validBids, DEFAULT_OPTION); - const { ext: { gpid } } = JSON.parse(requests[0].data.r).imp[0]; + const { ext: { gpid } } = extractPayload(requests[0]).imp[0]; expect(gpid).to.equal(GPID); }); @@ -1673,7 +1787,7 @@ describe('IndexexchangeAdapter', function () { } }; const requests = spec.buildRequests(validBids, DEFAULT_OPTION); - const { ext: { gpid } } = JSON.parse(requests[0].data.r).imp[0]; + const { ext: { gpid } } = extractPayload(requests[0]).imp[0]; expect(gpid).to.equal(GPID); }); @@ -1686,7 +1800,7 @@ describe('IndexexchangeAdapter', function () { } }; const requests = spec.buildRequests(validBids, DEFAULT_OPTION); - const imp = JSON.parse(requests[0].data.r).imp[0]; + const imp = extractPayload(requests[0]).imp[0]; expect(deepAccess(imp, 'ext.dfp_ad_unit_code')).to.not.exist; }); @@ -1704,7 +1818,7 @@ describe('IndexexchangeAdapter', function () { } }; const requests = spec.buildRequests(validBids, DEFAULT_OPTION); - const imp = JSON.parse(requests[0].data.r).imp[0]; + const imp = extractPayload(requests[0]).imp[0]; expect(deepAccess(imp, 'ext.gpid')).to.not.exist; }); @@ -1724,13 +1838,13 @@ describe('IndexexchangeAdapter', function () { } }; const requests = spec.buildRequests(validBids, DEFAULT_OPTION); - const imp = JSON.parse(requests[0].data.r).imp[0]; + const imp = extractPayload(requests[0]).imp[0]; expect(deepAccess(imp, 'ext.gpid')).to.equal(GPID); expect(deepAccess(imp, 'ext.dfp_ad_unit_code')).to.equal(AD_UNIT_CODE); }); it('payload should have correct format and value', function () { - const payload = JSON.parse(query.r); + const payload = payloadData; expect(payload.id).to.equal(DEFAULT_BANNER_VALID_BID[0].bidderRequestId); expect(payload.id).to.be.a('string'); expect(payload.site.page).to.equal(DEFAULT_OPTION.refererInfo.page); @@ -1748,7 +1862,7 @@ describe('IndexexchangeAdapter', function () { request = spec.buildRequests(bidWithIntId, DEFAULT_OPTION)[0]; - const payload = JSON.parse(request.data.r); + const payload = extractPayload(request); expect(bidWithIntId[0].bidderRequestId).to.be.a('number'); expect(payload.id).to.equal(bidWithIntId[0].bidderRequestId.toString()); expect(payload.id).to.be.a('string'); @@ -1760,19 +1874,21 @@ describe('IndexexchangeAdapter', function () { request = spec.buildRequests(bidWithIntId, DEFAULT_OPTION)[0]; - const payload = JSON.parse(request.data.r); + const payload = extractPayload(request); expect(bidWithIntId[0].bidderRequestId).to.be.a('number'); expect(payload.id).to.equal(bidWithIntId[0].bidderRequestId.toString()); expect(payload.id).to.be.a('string'); }); it('payload should not include schain when not provided', function () { - const payload = JSON.parse(queryWithoutSchain.r); - expect(payload.source.schain).to.not.exist; // source object currently only written for schain + const payload = payloadWithoutSchain; + + const actualSchain = (((payload || {}).source || {}).ext || {}).schain; + expect(actualSchain).to.not.exist; }); it('impression should have correct format and value', function () { - const impression = JSON.parse(query.r).imp[0]; + const impression = payloadData.imp[0]; const sidValue = DEFAULT_BANNER_VALID_BID[0].params.id; expect(impression.id).to.equal(DEFAULT_BANNER_VALID_BID[0].bidId); @@ -1797,7 +1913,7 @@ describe('IndexexchangeAdapter', function () { request = spec.buildRequests([bid], DEFAULT_OPTION)[0]; - const payload = JSON.parse(request.data.r); + const payload = extractPayload(request); payload.imp[0].banner.format.forEach((imp) => { expect(imp.ext.siteID).to.be.a('string'); }); @@ -1813,7 +1929,7 @@ describe('IndexexchangeAdapter', function () { const expectedFloor = 3.25; bid.getFloor = () => ({ floor: expectedFloor, currency }); const request = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(request.data.r).imp[0]; + const impression = extractPayload(request).imp[0]; expect(impression.bidfloor).to.equal(expectedFloor); expect(impression.bidfloorcur).to.equal(currency); @@ -1825,7 +1941,7 @@ describe('IndexexchangeAdapter', function () { const expectedFloor = 3.25; bid.getFloor = () => ({ floor: expectedFloor, currency }); const request = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(request.data.r).imp[0]; + const impression = extractPayload(request).imp[0]; expect(impression.bidfloor).to.equal(expectedFloor); expect(impression.bidfloorcur).to.equal(currency); @@ -1837,7 +1953,7 @@ describe('IndexexchangeAdapter', function () { bid.params.bidFloor = highFloor; bid.params.bidFloorCur = 'USD' const request = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(request.data.r).imp[0]; + const impression = extractPayload(request).imp[0]; expect(impression.bidfloor).to.equal(highFloor); expect(impression.bidfloorcur).to.equal(bid.params.bidFloorCur); @@ -1851,7 +1967,7 @@ describe('IndexexchangeAdapter', function () { const expectedFloor = highFloor; bid.getFloor = () => ({ floor: expectedFloor, currency }); const requestBidFloor = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(requestBidFloor.data.r).imp[0]; + const impression = extractPayload(requestBidFloor).imp[0]; expect(impression.bidfloor).to.equal(highFloor); expect(impression.bidfloorcur).to.equal(bid.params.bidFloorCur); @@ -1863,7 +1979,7 @@ describe('IndexexchangeAdapter', function () { bid.params.bidFloor = 50; bid.params.bidFloorCur = 'USD'; const requestBidFloor = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(requestBidFloor.data.r).imp[0]; + const impression = extractPayload(requestBidFloor).imp[0]; expect(impression.bidfloor).to.equal(bid.params.bidFloor); expect(impression.bidfloorcur).to.equal(bid.params.bidFloorCur); @@ -1875,7 +1991,7 @@ describe('IndexexchangeAdapter', function () { bid.params.bidFloor = 50; bid.params.bidFloorCur = 'USD'; const requestBidFloor = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(requestBidFloor.data.r).imp[0]; + const impression = extractPayload(requestBidFloor).imp[0]; expect(impression.bidfloor).to.equal(bid.params.bidFloor); expect(impression.bidfloorcur).to.equal(bid.params.bidFloorCur); @@ -1900,7 +2016,7 @@ describe('IndexexchangeAdapter', function () { expect(bid.getFloor.getCall(1).args[0].size[0]).to.equal(500); expect(bid.getFloor.getCall(1).args[0].size[1]).to.equal(400); - const impression = JSON.parse(requestBidFloor.data.r).imp[0]; + const impression = extractPayload(requestBidFloor).imp[0]; expect(impression.bidfloor).to.equal(expectedFloor); expect(impression.bidfloorcur).to.equal(currency); }); @@ -1930,7 +2046,7 @@ describe('IndexexchangeAdapter', function () { expect(bid.getFloor.getCall(0).args[0].size[0]).to.equal(300); expect(bid.getFloor.getCall(0).args[0].size[1]).to.equal(250); - const impression = JSON.parse(requestBidFloor.data.r).imp[0]; + const impression = extractPayload(requestBidFloor).imp[0]; expect(impression.bidfloor).to.equal(expectedFloor); expect(impression.bidfloorcur).to.equal(currency); }); @@ -1940,7 +2056,7 @@ describe('IndexexchangeAdapter', function () { const bid = utils.deepClone(DEFAULT_BANNER_VALID_BID[0]); bid.params.id = 50; const requestBidFloor = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(requestBidFloor.data.r).imp[0]; + const impression = extractPayload(requestBidFloor).imp[0]; expect(impression.id).to.equal(DEFAULT_BANNER_VALID_BID[0].bidId); expect(impression.banner.format[0].w).to.equal(DEFAULT_BANNER_VALID_BID[0].params.size[0]); @@ -1954,7 +2070,7 @@ describe('IndexexchangeAdapter', function () { const bid = utils.deepClone(DEFAULT_BANNER_VALID_BID[0]); bid.params.id = 'abc'; const requestBidFloor = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(requestBidFloor.data.r).imp[0]; + const impression = extractPayload(requestBidFloor).imp[0]; expect(impression.id).to.equal(DEFAULT_BANNER_VALID_BID[0].bidId); expect(impression.banner.format[0].w).to.equal(DEFAULT_BANNER_VALID_BID[0].params.size[0]); @@ -1982,11 +2098,49 @@ describe('IndexexchangeAdapter', function () { }); const requestWithFirstPartyData = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0]; - const pageUrl = JSON.parse(requestWithFirstPartyData.data.r).site.page; + const pageUrl = extractPayload(requestWithFirstPartyData).site.page; const expectedPageUrl = DEFAULT_OPTION.refererInfo.page + '?ab=123&cd=123%23ab&e%2Ff=456&h%3Fg=456%23cd'; expect(pageUrl).to.equal(expectedPageUrl); }); + it('should set device sua if available in fpd and request size does not exceed limit', function () { + const ortb2 = { + device: { + sua: { + platform: { + brand: 'macOS', + version: [ '12', '6', '1' ] + }, + browsers: [ + { + brand: 'Chromium', + version: [ '107', '0', '5249', '119' ] + }, + { + brand: 'Google Chrome', + version: [ '107', '0', '5249', '119' ] + }, + ], + mobile: 0, + model: '' + } + }}; + + const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, { ortb2 })[0]; + const payload = extractPayload(request); + expect(payload.device.sua.platform.brand).to.equal('macOS') + expect(payload.device.sua.mobile).to.equal(0) + }); + + it('should not set device sua if not available in fpd', function () { + const ortb2 = { + device: {}}; + + const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, { ortb2 })[0]; + const payload = extractPayload(request); + expect(payload.device).to.be.undefined + }); + it('should not set first party data if it is not an object', function () { config.setConfig({ ix: { @@ -1995,7 +2149,7 @@ describe('IndexexchangeAdapter', function () { }); const requestFirstPartyDataNumber = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0]; - const pageUrl = JSON.parse(requestFirstPartyDataNumber.data.r).site.page; + const pageUrl = extractPayload(requestFirstPartyDataNumber).site.page; expect(pageUrl).to.equal(DEFAULT_OPTION.refererInfo.page); }); @@ -2006,7 +2160,7 @@ describe('IndexexchangeAdapter', function () { }); const requestWithoutConfig = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0]; - const pageUrl = JSON.parse(requestWithoutConfig.data.r).site.page; + const pageUrl = extractPayload(requestWithoutConfig).site.page; expect(pageUrl).to.equal(DEFAULT_OPTION.refererInfo.page); expect(requestWithoutConfig.data.t).to.be.undefined; @@ -2014,13 +2168,13 @@ describe('IndexexchangeAdapter', function () { it('should not set first party or timeout if it is setConfig is not called', function () { const requestWithoutConfig = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0]; - const pageUrl = JSON.parse(requestWithoutConfig.data.r).site.page; + const pageUrl = extractPayload(requestWithoutConfig).site.page; expect(pageUrl).to.equal(DEFAULT_OPTION.refererInfo.page); expect(requestWithoutConfig.data.t).to.be.undefined; }); - it('should set timeout if publisher set it through setConfig', function () { + it('should no longer set timeout even if publisher set it through setConfig', function () { config.setConfig({ ix: { timeout: 500 @@ -2028,10 +2182,10 @@ describe('IndexexchangeAdapter', function () { }); const requestWithTimeout = spec.buildRequests(DEFAULT_BANNER_VALID_BID, {})[0]; - expect(requestWithTimeout.data.t).to.equal(500); + expect(requestWithTimeout.data.t).to.be.undefined; }); - it('should set timeout if timeout is a string', function () { + it('should no longer set timeout even if timeout is a string', function () { config.setConfig({ ix: { timeout: '500' @@ -2046,11 +2200,10 @@ describe('IndexexchangeAdapter', function () { describe('request should contain both banner and video requests', function () { const request = spec.buildRequests([DEFAULT_BANNER_VALID_BID[0], DEFAULT_VIDEO_VALID_BID[0]], {}); it('should have banner request', () => { - const bannerImpression = JSON.parse(request[0].data.r).imp[0]; + const bannerImpression = extractPayload(request[0]).imp[0]; const sidValue = DEFAULT_BANNER_VALID_BID[0].params.id; - expect(JSON.parse(request[0].data.r).imp).to.have.lengthOf(1); - expect(JSON.parse(request[0].data.v)).to.equal(BANNER_ENDPOINT_VERSION); + expect(extractPayload(request[0]).imp).to.have.lengthOf(1); expect(bannerImpression.id).to.equal(DEFAULT_BANNER_VALID_BID[0].bidId); expect(bannerImpression.banner.format).to.be.length(2); @@ -2067,9 +2220,8 @@ describe('IndexexchangeAdapter', function () { }); it('should have video request', () => { - const videoImpression = JSON.parse(request[1].data.r).imp[0]; + const videoImpression = extractPayload(request[1]).imp[0]; - expect(JSON.parse(request[1].data.v)).to.equal(VIDEO_ENDPOINT_VERSION); expect(videoImpression.id).to.equal(DEFAULT_VIDEO_VALID_BID[0].bidId); expect(videoImpression.video.w).to.equal(DEFAULT_VIDEO_VALID_BID[0].params.size[0]); expect(videoImpression.video.h).to.equal(DEFAULT_VIDEO_VALID_BID[0].params.size[1]); @@ -2080,11 +2232,10 @@ describe('IndexexchangeAdapter', function () { const request = spec.buildRequests([DEFAULT_BANNER_VALID_BID[0], DEFAULT_NATIVE_VALID_BID[0]]); it('should have banner request', () => { - const bannerImpression = JSON.parse(request[0].data.r).imp[0]; + const bannerImpression = extractPayload(request[0]).imp[0]; const sidValue = DEFAULT_BANNER_VALID_BID[0].params.id; - expect(JSON.parse(request[0].data.r).imp).to.have.lengthOf(1); - expect(JSON.parse(request[0].data.v)).to.equal(BANNER_ENDPOINT_VERSION); + expect(extractPayload(request[0]).imp).to.have.lengthOf(1); expect(bannerImpression.id).to.equal(DEFAULT_BANNER_VALID_BID[0].bidId); expect(bannerImpression.banner.format).to.be.length(2); @@ -2101,7 +2252,7 @@ describe('IndexexchangeAdapter', function () { }); it('should have native request', () => { - const nativeImpression = JSON.parse(request[1].data.r).imp[0]; + const nativeImpression = extractPayload(request[1]).imp[0]; expect(request[1].data.hasOwnProperty('v')).to.equal(false); expect(nativeImpression.id).to.equal(DEFAULT_NATIVE_VALID_BID[0].bidId); @@ -2133,8 +2284,6 @@ describe('IndexexchangeAdapter', function () { const requests = spec.buildRequests([bid, DEFAULT_BANNER_VALID_BID[0]], DEFAULT_OPTION); expect(requests).to.be.an('array'); expect(requests).to.have.lengthOf(2); - expect(requests[0].data.sn).to.be.equal(0); - expect(requests[1].data.sn).to.be.equal(1); }); it('6 ad units should generate only 4 requests', function () { @@ -2168,10 +2317,7 @@ describe('IndexexchangeAdapter', function () { for (var i = 0; i < requests.length; i++) { const reqSize = `${requests[i].url}?${utils.parseQueryStringParameters(requests[i].data)}`.length; expect(reqSize).to.be.lessThan(8000); - let payload = JSON.parse(requests[i].data.r); - if (requests.length > 1) { - expect(requests[i].data.sn).to.equal(i); - } + let payload = extractPayload(requests[i]); expect(payload.source.ext.schain).to.deep.equal(SAMPLE_SCHAIN); } }); @@ -2196,7 +2342,7 @@ describe('IndexexchangeAdapter', function () { expect(requests).to.be.an('array'); expect(requests).to.have.lengthOf(1); - const impressions = JSON.parse(requests[0].data.r).imp; + const impressions = extractPayload(requests[0]).imp; expect(impressions).to.be.an('array'); expect(impressions).to.have.lengthOf(3); expect(requests[0].data.sn).to.be.undefined; @@ -2212,7 +2358,7 @@ describe('IndexexchangeAdapter', function () { bid2.params.bidId = '2b3c4d5e'; const request = spec.buildRequests([bid, bid2], DEFAULT_OPTION)[0]; - const impression = JSON.parse(request.data.r).imp[0]; + const impression = extractPayload(request).imp[0]; const sidValue = bid.params.id; expect(impression.id).to.equal(bid.bidId); @@ -2242,7 +2388,7 @@ describe('IndexexchangeAdapter', function () { const bids = [DEFAULT_BANNER_VALID_BID[0], bid]; const request = spec.buildRequests(bids, DEFAULT_OPTION)[0]; - const impressions = JSON.parse(request.data.r).imp; + const impressions = extractPayload(request).imp; expect(impressions).to.be.an('array'); expect(impressions).to.have.lengthOf(2); expect(request.data.sn).to.be.undefined; @@ -2267,7 +2413,7 @@ describe('IndexexchangeAdapter', function () { it('request should not contain the extra video ad sizes that IX is not configured for', function () { const request = spec.buildRequests(DEFAULT_VIDEO_VALID_BID, DEFAULT_OPTION); - const impressions = JSON.parse(request[0].data.r).imp; + const impressions = extractPayload(request[0]).imp; expect(impressions).to.be.an('array'); expect(impressions).to.have.lengthOf(1); @@ -2280,7 +2426,7 @@ describe('IndexexchangeAdapter', function () { const requests = spec.buildRequests([bid1, DEFAULT_BANNER_VALID_BID[0]], DEFAULT_OPTION); - const impressions = JSON.parse(requests[0].data.r).imp; + const impressions = extractPayload(requests[0]).imp; expect(impressions).to.be.an('array'); expect(impressions).to.have.lengthOf(1); @@ -2290,24 +2436,15 @@ describe('IndexexchangeAdapter', function () { describe('buildRequestVideo', function () { const request = spec.buildRequests(DEFAULT_VIDEO_VALID_BID, DEFAULT_OPTION); - const query = request[0].data; - - it('query object (version, siteID and request) should be correct', function () { - expect(query.v).to.equal(VIDEO_ENDPOINT_VERSION); - expect(query.s).to.equal(DEFAULT_VIDEO_VALID_BID[0].params.siteId); - expect(query.r).to.exist; - expect(query.ac).to.equal('j'); - expect(query.sd).to.equal(1); - expect(query.nf).to.equal(1); - }); + const payloadData = request[0].data; it('auction type should be set correctly', function () { - const at = JSON.parse(query.r).at; + const at = payloadData.at; expect(at).to.equal(1); }) it('impression should have correct format and value', function () { - const impression = JSON.parse(query.r).imp[0]; + const impression = payloadData.imp[0]; expect(impression.id).to.equal(DEFAULT_VIDEO_VALID_BID[0].bidId); expect(impression.video.w).to.equal(DEFAULT_VIDEO_VALID_BID[0].params.size[0]); @@ -2326,7 +2463,7 @@ describe('IndexexchangeAdapter', function () { bid.mediaTypes.video.context = 'outstream'; bid.mediaTypes.video.placement = 2; const request = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(request.data.r).imp[0]; + const impression = extractPayload(request).imp[0]; expect(impression.id).to.equal(DEFAULT_VIDEO_VALID_BID[0].bidId); expect(impression.video.placement).to.equal(2); @@ -2336,7 +2473,7 @@ describe('IndexexchangeAdapter', function () { const bid = utils.deepClone(DEFAULT_VIDEO_VALID_BID[0]); bid.params.id = 50; const request = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(request.data.r).imp[0]; + const impression = extractPayload(request).imp[0]; expect(impression.ext.sid).to.equal('50'); }); @@ -2345,7 +2482,7 @@ describe('IndexexchangeAdapter', function () { const bid = utils.deepClone(DEFAULT_VIDEO_VALID_BID[0]); bid.mediaTypes.video.context = 'instream'; const request = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(request.data.r).imp[0]; + const impression = extractPayload(request).imp[0]; expect(impression.id).to.equal(DEFAULT_VIDEO_VALID_BID[0].bidId); expect(impression.video.placement).to.equal(1); @@ -2355,7 +2492,7 @@ describe('IndexexchangeAdapter', function () { const bid = utils.deepClone(DEFAULT_VIDEO_VALID_BID[0]); bid.mediaTypes.video.context = 'outstream'; const request = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(request.data.r).imp[0]; + const impression = extractPayload(request).imp[0]; expect(impression.id).to.equal(DEFAULT_VIDEO_VALID_BID[0].bidId); expect(impression.video.placement).to.equal(4); @@ -2365,7 +2502,7 @@ describe('IndexexchangeAdapter', function () { const bid = utils.deepClone(DEFAULT_VIDEO_VALID_BID[0]); bid.mediaTypes.video.context = 'not-valid'; const request = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(request.data.r).imp[0]; + const impression = extractPayload(request).imp[0]; expect(impression.video.placement).to.be.undefined; }); @@ -2375,7 +2512,7 @@ describe('IndexexchangeAdapter', function () { bid.mediaTypes.video.protocols = [1]; bid.mediaTypes.video.mimes = ['video/override']; const request = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(request.data.r).imp[0]; + const impression = extractPayload(request).imp[0]; expect(impression.video.protocols[0]).to.equal(2); expect(impression.video.mimes[0]).to.not.equal('video/override'); @@ -2386,7 +2523,7 @@ describe('IndexexchangeAdapter', function () { bid.mediaTypes.video.context = 'outstream'; bid.mediaTypes.video.random = true; const request = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(request.data.r).imp[0]; + const impression = extractPayload(request).imp[0]; expect(impression.video.random).to.not.exist; }); @@ -2401,7 +2538,7 @@ describe('IndexexchangeAdapter', function () { bid.mediaTypes.video.api = 2; bid.mediaTypes.video.pos = 0; const request = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(request.data.r).imp[0]; + const impression = extractPayload(request).imp[0]; expect(impression.video.protocols[0]).to.equal(6); expect(impression.video.api).to.equal(2); @@ -2418,15 +2555,14 @@ describe('IndexexchangeAdapter', function () { } }; const requests = spec.buildRequests(validBids, DEFAULT_OPTION); - const { ext: { gpid } } = JSON.parse(requests[0].data.r).imp[0]; + const { ext: { gpid } } = extractPayload(requests[0]).imp[0]; expect(gpid).to.equal(GPID); }); it('should build video request when if video obj is not provided at params level', () => { const request = spec.buildRequests([DEFAULT_VIDEO_VALID_BID_NO_VIDEO_PARAMS[0]], {}); - const videoImpression = JSON.parse(request[0].data.r).imp[0]; + const videoImpression = extractPayload(request[0]).imp[0]; - expect(JSON.parse(request[0].data.v)).to.equal(VIDEO_ENDPOINT_VERSION); expect(videoImpression.id).to.equal(DEFAULT_VIDEO_VALID_BID_NO_VIDEO_PARAMS[0].bidId); expect(videoImpression.video.w).to.equal(DEFAULT_VIDEO_VALID_BID_NO_VIDEO_PARAMS[0].mediaTypes.video.playerSize[0][0]); expect(videoImpression.video.h).to.equal(DEFAULT_VIDEO_VALID_BID_NO_VIDEO_PARAMS[0].mediaTypes.video.playerSize[0][1]); @@ -2440,23 +2576,18 @@ describe('IndexexchangeAdapter', function () { }; const request = spec.buildRequests([bid]); - const videoImpression = JSON.parse(request[0].data.r).imp[0]; + const videoImpression = extractPayload(request[0]).imp[0]; expect(videoImpression.video.placement).to.eq(5); }) }); describe('buildRequestNative', function () { - it('should build request with expected params', function() { - const request = spec.buildRequests(DEFAULT_NATIVE_VALID_BID, DEFAULT_OPTION); - const query = request[0].data; + it('should build request with expected params', function () { + const request = spec.buildRequests(DEFAULT_NATIVE_VALID_BID, DEFAULT_OPTION)[0]; - expect(query.hasOwnProperty('v')).to.equal(false); - expect(query.s).to.equal(DEFAULT_NATIVE_VALID_BID[0].params.siteId); - expect(query.r).to.exist; - expect(query.ac).to.equal('j'); - expect(query.sd).to.equal(1); - expect(JSON.parse(query.r).at).to.equal(1); + expect(request.data).to.exist; + expect(request.method).to.equal('POST') }); it('should send gpid in request if ortb2Imp.ext.gpid exists', function () { @@ -2468,40 +2599,40 @@ describe('IndexexchangeAdapter', function () { } }; const requests = spec.buildRequests(bids, DEFAULT_OPTION); - const { ext: { gpid } } = JSON.parse(requests[0].data.r).imp[0]; + const { ext: { gpid } } = extractPayload(requests[0]).imp[0]; expect(gpid).to.equal(GPID); }); - it('should build request with required asset properties with default values', function() { + it('should build request with required asset properties with default values', function () { const request = spec.buildRequests(DEFAULT_NATIVE_VALID_BID, DEFAULT_OPTION); - const nativeImpression = JSON.parse(request[0].data.r).imp[0]; + const nativeImpression = extractPayload(request[0]).imp[0]; expect(request[0].data.hasOwnProperty('v')).to.equal(false); expect(nativeImpression.id).to.equal(DEFAULT_NATIVE_VALID_BID[0].bidId); expect(nativeImpression.native).to.deep.equal(DEFAULT_NATIVE_IMP); }); - it('should set imp.ext.sid for native imps if params.id exist', function() { + it('should set imp.ext.sid for native imps if params.id exist', function () { const bid = utils.deepClone(DEFAULT_NATIVE_VALID_BID); bid[0].params.id = 'abc' const request = spec.buildRequests(bid, DEFAULT_OPTION); - const nativeImpression = JSON.parse(request[0].data.r).imp[0]; + const nativeImpression = extractPayload(request[0]).imp[0]; expect(nativeImpression.id).to.equal(DEFAULT_NATIVE_VALID_BID[0].bidId); expect(nativeImpression.ext.sid).to.equal('abc'); }); - it('should build request with given asset properties', function() { + it('should build request with given asset properties', function () { let bid = utils.deepClone(DEFAULT_NATIVE_VALID_BID) bid[0].nativeOrtbRequest = { - assets: [{id: 0, required: 0, title: {len: 140}}, {id: 1, required: 0, video: {mimes: ['javascript'], minduration: 10, maxduration: 60, protocols: [1]}}] + assets: [{ id: 0, required: 0, title: { len: 140 } }, { id: 1, required: 0, video: { mimes: ['javascript'], minduration: 10, maxduration: 60, protocols: [1] } }] } const request = spec.buildRequests(bid, DEFAULT_OPTION); - const nativeImpression = JSON.parse(request[0].data.r).imp[0]; - expect(nativeImpression.native).to.deep.equal({request: '{"assets":[{"id":0,"required":0,"title":{"len":140}},{"id":1,"required":0,"video":{"mimes":["javascript"],"minduration":10,"maxduration":60,"protocols":[1]}}],"eventtrackers":[{"event":1,"methods":[1,2]}],"privacy":1}', ver: '1.2'}); + const nativeImpression = extractPayload(request[0]).imp[0]; + expect(nativeImpression.native).to.deep.equal({ request: '{"assets":[{"id":0,"required":0,"title":{"len":140}},{"id":1,"required":0,"video":{"mimes":["javascript"],"minduration":10,"maxduration":60,"protocols":[1]}}],"eventtrackers":[{"event":1,"methods":[1,2]}],"privacy":1}', ver: '1.2' }); }); - it('should build request with all possible Prebid asset properties', function() { + it('should build request with all possible Prebid asset properties', function () { let bid = utils.deepClone(DEFAULT_NATIVE_VALID_BID) bid[0].nativeOrtbRequest = { 'ver': '1.2', @@ -2626,17 +2757,16 @@ describe('IndexexchangeAdapter', function () { ] } const request = spec.buildRequests(bid, DEFAULT_OPTION); - const nativeImpression = JSON.parse(request[0].data.r).imp[0]; - expect(nativeImpression.native).to.deep.equal({request: '{"ver":"1.2","assets":[{"id":0,"required":0,"title":{"len":140}},{"id":1,"required":0,"data":{"type":2}},{"id":2,"required":0,"data":{"type":10}},{"id":3,"required":0,"data":{"type":1}},{"id":4,"required":0,"img":{"type":1}},{"id":5,"required":0,"img":{"type":3}},{"id":6,"required":0},{"id":7,"required":0,"data":{"type":11}},{"id":8,"required":0},{"id":9,"required":0},{"id":10,"required":0,"data":{"type":12}},{"id":11,"required":0,"data":{"type":3}},{"id":12,"required":0,"data":{"type":5}},{"id":13,"required":0,"data":{"type":4}},{"id":14,"required":0,"data":{"type":6}},{"id":15,"required":0,"data":{"type":7}},{"id":16,"required":0,"data":{"type":9}},{"id":17,"required":0,"data":{"type":8}}],"eventtrackers":[{"event":1,"methods":[1,2]}],"privacy":1}', ver: '1.2'}); + const nativeImpression = extractPayload(request[0]).imp[0]; + expect(nativeImpression.native).to.deep.equal({ request: '{"ver":"1.2","assets":[{"id":0,"required":0,"title":{"len":140}},{"id":1,"required":0,"data":{"type":2}},{"id":2,"required":0,"data":{"type":10}},{"id":3,"required":0,"data":{"type":1}},{"id":4,"required":0,"img":{"type":1}},{"id":5,"required":0,"img":{"type":3}},{"id":6,"required":0},{"id":7,"required":0,"data":{"type":11}},{"id":8,"required":0},{"id":9,"required":0},{"id":10,"required":0,"data":{"type":12}},{"id":11,"required":0,"data":{"type":3}},{"id":12,"required":0,"data":{"type":5}},{"id":13,"required":0,"data":{"type":4}},{"id":14,"required":0,"data":{"type":6}},{"id":15,"required":0,"data":{"type":7}},{"id":16,"required":0,"data":{"type":9}},{"id":17,"required":0,"data":{"type":8}}],"eventtrackers":[{"event":1,"methods":[1,2]}],"privacy":1}', ver: '1.2' }); }) }); describe('buildRequestMultiFormat', function () { it('only banner bidder params set', function () { const request = spec.buildRequests(DEFAULT_MULTIFORMAT_BANNER_VALID_BID, {}) - const bannerImpression = JSON.parse(request[0].data.r).imp[0]; - expect(JSON.parse(request[0].data.r).imp).to.have.lengthOf(1); - expect(JSON.parse(request[0].data.v)).to.equal(BANNER_ENDPOINT_VERSION); + const bannerImpression = extractPayload(request[0]).imp[0]; + expect(extractPayload(request[0]).imp).to.have.lengthOf(1); expect(bannerImpression.id).to.equal(DEFAULT_MULTIFORMAT_BANNER_VALID_BID[0].bidId); expect(bannerImpression.banner.format[0].w).to.equal(DEFAULT_MULTIFORMAT_BANNER_VALID_BID[0].params.size[0]); expect(bannerImpression.banner.format[0].h).to.equal(DEFAULT_MULTIFORMAT_BANNER_VALID_BID[0].params.size[1]); @@ -2645,9 +2775,8 @@ describe('IndexexchangeAdapter', function () { describe('only video bidder params set', function () { it('should generate video impression', function () { const request = spec.buildRequests(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID, {}); - const videoImp = JSON.parse(request[1].data.r).imp[0]; - expect(JSON.parse(request[1].data.r).imp).to.have.lengthOf(1); - expect(JSON.parse(request[1].data.v)).to.equal(VIDEO_ENDPOINT_VERSION); + const videoImp = extractPayload(request[1]).imp[0]; + expect(extractPayload(request[1]).imp).to.have.lengthOf(1); expect(videoImp.id).to.equal(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0].bidId); expect(videoImp.video.w).to.equal(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0].params.size[0]); expect(videoImp.video.h).to.equal(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0].params.size[1]); @@ -2659,10 +2788,9 @@ describe('IndexexchangeAdapter', function () { const request = spec.buildRequests(bids, {}); it('should return valid banner requests', function () { - const impressions = JSON.parse(request[0].data.r).imp; + const impressions = extractPayload(request[0]).imp; expect(impressions).to.have.lengthOf(2); - expect(JSON.parse(request[0].data.v)).to.equal(BANNER_ENDPOINT_VERSION); impressions.map((impression, index) => { const bid = bids[index]; @@ -2682,17 +2810,16 @@ describe('IndexexchangeAdapter', function () { }); it('should return valid banner and video requests', function () { - const videoImpression = JSON.parse(request[1].data.r).imp[0]; + const videoImpression = extractPayload(request[1]).imp[0]; - expect(JSON.parse(request[1].data.r).imp).to.have.lengthOf(1); - expect(JSON.parse(request[1].data.v)).to.equal(VIDEO_ENDPOINT_VERSION); + expect(extractPayload(request[1]).imp).to.have.lengthOf(1); expect(videoImpression.id).to.equal(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0].bidId); expect(videoImpression.video.w).to.equal(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0].mediaTypes.video.playerSize[0][0]); expect(videoImpression.video.h).to.equal(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0].mediaTypes.video.playerSize[0][1]); }); it('should contain all correct IXdiag properties', function () { - const diagObj = JSON.parse(request[0].data.r).ext.ixdiag; + const diagObj = extractPayload(request[0]).ext.ixdiag; expect(diagObj.iu).to.equal(0); expect(diagObj.nu).to.equal(0); expect(diagObj.ou).to.equal(2); @@ -2706,9 +2833,51 @@ describe('IndexexchangeAdapter', function () { expect(diagObj.adunitcode).to.equal(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0].adUnitCode) }); }); + + describe('siteId overrides', function () { + it('should use siteId override', function () { + const validBids = DEFAULT_MULTIFORMAT_VALID_BID; + const request = spec.buildRequests(validBids, {}); + const bannerImps = request[0].data.imp[0]; + const videoImps = request[1].data.imp[0]; + const nativeImps = request[2].data.imp[0]; + expect(videoImps.ext.siteID).to.equal('1111'); + bannerImps.banner.format.map(({ ext }) => { + expect(ext.siteID).to.equal('2222'); + }); + expect(nativeImps.ext.siteID).to.equal('3333'); + }); + + it('should use default siteId if overrides are not provided', function () { + const validBids = DEFAULT_MULTIFORMAT_VALID_BID; + delete validBids[0].params.banner; + delete validBids[0].params.video; + delete validBids[0].params.native; + const request = spec.buildRequests(validBids, {}); + const bannerImps = request[0].data.imp[0]; + const videoImps = request[1].data.imp[0]; + const nativeImps = request[2].data.imp[0]; + expect(videoImps.ext.siteID).to.equal('456'); + bannerImps.banner.format.map(({ ext }) => { + expect(ext.siteID).to.equal('456'); + }); + expect(nativeImps.ext.siteID).to.equal('456'); + }); + }); }); describe('interpretResponse', function () { + // generate bidderRequest with real buildRequest logic for intepretResponse testing + let bannerBidderRequest + let videoBidderRequest + let nativeBidderRequest + + beforeEach(() => { + bannerBidderRequest = spec.buildRequests(DEFAULT_BANNER_VALID_BID, {})[0] + videoBidderRequest = spec.buildRequests(DEFAULT_VIDEO_VALID_BID_MEDIUM_SIZE, {})[0] + nativeBidderRequest = spec.buildRequests(DEFAULT_NATIVE_VALID_BID, {})[0] + }); + it('should get correct bid response for banner ad', function () { const expectedParse = [ { @@ -2730,7 +2899,7 @@ describe('IndexexchangeAdapter', function () { } } ]; - const result = spec.interpretResponse({ body: DEFAULT_BANNER_BID_RESPONSE }, { data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: [] }); + const result = spec.interpretResponse({ body: DEFAULT_BANNER_BID_RESPONSE }, bannerBidderRequest); expect(result[0]).to.deep.equal(expectedParse[0]); }); @@ -2754,7 +2923,7 @@ describe('IndexexchangeAdapter', function () { } } ]; - const result = spec.interpretResponse({ body: DEFAULT_BANNER_BID_RESPONSE_WITHOUT_ADOMAIN }, { data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: [] }); + const result = spec.interpretResponse({ body: DEFAULT_BANNER_BID_RESPONSE_WITHOUT_ADOMAIN }, bannerBidderRequest); expect(result[0]).to.deep.equal(expectedParse[0]); }); @@ -2781,7 +2950,7 @@ describe('IndexexchangeAdapter', function () { } } ]; - const result = spec.interpretResponse({ body: bidResponse }, { data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: [] }); + const result = spec.interpretResponse({ body: bidResponse }, bannerBidderRequest); }); it('should set Japanese price correctly', function () { @@ -2807,7 +2976,7 @@ describe('IndexexchangeAdapter', function () { } } ]; - const result = spec.interpretResponse({ body: bidResponse }, { data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: [] }); + const result = spec.interpretResponse({ body: bidResponse }, bannerBidderRequest); expect(result[0]).to.deep.equal(expectedParse[0]); }); @@ -2836,7 +3005,7 @@ describe('IndexexchangeAdapter', function () { } } ]; - const result = spec.interpretResponse({ body: bidResponse }, { data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: [] }); + const result = spec.interpretResponse({ body: bidResponse }, bannerBidderRequest); expect(result[0].dealId).to.equal(expectedParse[0].dealId); }); @@ -2863,7 +3032,7 @@ describe('IndexexchangeAdapter', function () { } } ]; - const result = spec.interpretResponse({ body: bidResponse }, { data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: [] }); + const result = spec.interpretResponse({ body: bidResponse }, bannerBidderRequest); expect(result[0]).to.deep.equal(expectedParse[0]); }); @@ -2891,7 +3060,7 @@ describe('IndexexchangeAdapter', function () { } } ]; - const result = spec.interpretResponse({ body: bidResponse }, { data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: [] }); + const result = spec.interpretResponse({ body: bidResponse }, bannerBidderRequest); expect(result[0].dealId).to.deep.equal(expectedParse[0].dealId); }); @@ -2928,7 +3097,7 @@ describe('IndexexchangeAdapter', function () { } ]; const result = spec.interpretResponse({ body: DEFAULT_VIDEO_BID_RESPONSE }, { - data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: ONE_VIDEO + data: videoBidderRequest.data, validBidRequests: ONE_VIDEO }); expect(result[0]).to.deep.equal(expectedParse[0]); @@ -2936,14 +3105,14 @@ describe('IndexexchangeAdapter', function () { it('should set bid[].renderer if renderer not defined at mediaType.video level', function () { const bid = spec.interpretResponse({ body: DEFAULT_VIDEO_BID_RESPONSE }, { - data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: DEFAULT_MULTIFORMAT_BANNER_VALID_BID + data: videoBidderRequest.data, validBidRequests: DEFAULT_MULTIFORMAT_BANNER_VALID_BID }); expect(bid[0].renderer).to.exist; }); it('should set renderer URL by parsing video response', function () { const bid = spec.interpretResponse({ body: DEFAULT_VIDEO_BID_RESPONSE }, { - data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: DEFAULT_MULTIFORMAT_BANNER_VALID_BID + data: videoBidderRequest.data, validBidRequests: DEFAULT_MULTIFORMAT_BANNER_VALID_BID }); expect(bid[0].renderer.url).to.equal(DEFAULT_VIDEO_BID_RESPONSE.ext.videoplayerurl); }); @@ -2952,10 +3121,10 @@ describe('IndexexchangeAdapter', function () { let outstreamAdUnit = utils.deepClone(DEFAULT_MULTIFORMAT_BANNER_VALID_BID); outstreamAdUnit[0].mediaTypes.video.renderer = { url: 'test', - render: function() {} + render: function () { } }; const bid = spec.interpretResponse({ body: DEFAULT_VIDEO_BID_RESPONSE }, { - data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: outstreamAdUnit + data: videoBidderRequest.data, validBidRequests: outstreamAdUnit }); expect(bid[0].renderer).to.be.undefined; }); @@ -2964,10 +3133,10 @@ describe('IndexexchangeAdapter', function () { let outstreamAdUnit = utils.deepClone(DEFAULT_MULTIFORMAT_BANNER_VALID_BID); outstreamAdUnit[0].renderer = { url: 'test', - render: function() {} + render: function () { } }; const bid = spec.interpretResponse({ body: DEFAULT_VIDEO_BID_RESPONSE }, { - data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: outstreamAdUnit + data: videoBidderRequest.data, validBidRequests: outstreamAdUnit }); expect(bid[0].renderer).to.be.undefined; }); @@ -2978,7 +3147,7 @@ describe('IndexexchangeAdapter', function () { url: 'test' }; const bid = spec.interpretResponse({ body: DEFAULT_VIDEO_BID_RESPONSE }, { - data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: outstreamAdUnit + data: videoBidderRequest.data, validBidRequests: outstreamAdUnit }); expect(bid[0].renderer).to.exist; }); @@ -2987,11 +3156,11 @@ describe('IndexexchangeAdapter', function () { let outstreamAdUnit = utils.deepClone(DEFAULT_MULTIFORMAT_BANNER_VALID_BID); outstreamAdUnit[0].mediaTypes.video.renderer = { url: 'test', - render: function() {}, + render: function () { }, backupOnly: true }; const bid = spec.interpretResponse({ body: DEFAULT_VIDEO_BID_RESPONSE }, { - data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: outstreamAdUnit + data: videoBidderRequest.data, validBidRequests: outstreamAdUnit }); expect(bid[0].renderer).to.exist; }); @@ -3028,20 +3197,61 @@ describe('IndexexchangeAdapter', function () { } } ]; - const result = spec.interpretResponse({ body: DEFAULT_VIDEO_BID_RESPONSE_WITH_MTYPE_SET }, { - data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: ONE_VIDEO + const result = spec.interpretResponse({ body: DEFAULT_VIDEO_BID_RESPONSE_WITH_XML_ADM }, { + data: videoBidderRequest.data, validBidRequests: ONE_VIDEO }); expect(result[0]).to.deep.equal(expectedParse[0]); }); + it('should not set vastxml when vasturl is present and when mtype is 2 (video)', function () { + const expectedParse = [ + { + requestId: '1a2b3c4e', + cpm: 1.1, + creativeId: '12346', + mediaType: 'video', + mediaTypes: { + video: { + context: 'instream', + playerSize: [ + [ + 400, + 100 + ] + ] + } + }, + width: 640, + height: 480, + currency: 'USD', + ttl: 3600, + netRevenue: true, + vastUrl: 'www.abcd.com/vast', + meta: { + networkId: 51, + brandId: 303326, + brandName: 'OECTB', + advertiserDomains: ['www.abcd.com'] + } + } + ]; + let bid_response = DEFAULT_VIDEO_BID_RESPONSE_WITH_XML_ADM; + bid_response.seatbid[0].bid[0].ext['vasturl'] = 'www.abcd.com/vast'; + const result = spec.interpretResponse({ body: bid_response }, { + data: videoBidderRequest.data, validBidRequests: ONE_VIDEO + }); + expect(result[0]).to.deep.equal(expectedParse[0]); + }); + it('bidrequest should not have page if options is undefined', function () { const options = {}; const validBidWithoutreferInfo = spec.buildRequests(DEFAULT_BANNER_VALID_BID, options); - const requestWithoutreferInfo = JSON.parse(validBidWithoutreferInfo[0].data.r); + const requestWithoutreferInfo = extractPayload(validBidWithoutreferInfo[0]); + const expectedURL = IX_SECURE_ENDPOINT + '?s=' + DEFAULT_BANNER_VALID_BID[0].params.siteId expect(requestWithoutreferInfo.site.page).to.be.undefined; - expect(validBidWithoutreferInfo[0].url).to.equal(IX_SECURE_ENDPOINT); + expect(validBidWithoutreferInfo[0].url).to.equal(expectedURL); }); it('bidrequest should not have page if options.refererInfo is an empty object', function () { @@ -3049,10 +3259,11 @@ describe('IndexexchangeAdapter', function () { refererInfo: {} }; const validBidWithoutreferInfo = spec.buildRequests(DEFAULT_BANNER_VALID_BID, options); - const requestWithoutreferInfo = JSON.parse(validBidWithoutreferInfo[0].data.r); + const requestWithoutreferInfo = extractPayload(validBidWithoutreferInfo[0]); + const expectedURL = IX_SECURE_ENDPOINT + '?s=' + DEFAULT_BANNER_VALID_BID[0].params.siteId expect(requestWithoutreferInfo.site.page).to.be.undefined; - expect(validBidWithoutreferInfo[0].url).to.equal(IX_SECURE_ENDPOINT); + expect(validBidWithoutreferInfo[0].url).to.equal(expectedURL); }); it('bidrequest should sent to secure endpoint if page url is secure', function () { @@ -3062,10 +3273,11 @@ describe('IndexexchangeAdapter', function () { } }; const validBidWithoutreferInfo = spec.buildRequests(DEFAULT_BANNER_VALID_BID, options); - const requestWithoutreferInfo = JSON.parse(validBidWithoutreferInfo[0].data.r); + const requestWithoutreferInfo = extractPayload(validBidWithoutreferInfo[0]); + const expectedURL = IX_SECURE_ENDPOINT + '?s=' + DEFAULT_BANNER_VALID_BID[0].params.siteId expect(requestWithoutreferInfo.site.page).to.equal(options.refererInfo.page); - expect(validBidWithoutreferInfo[0].url).to.equal(IX_SECURE_ENDPOINT); + expect(validBidWithoutreferInfo[0].url).to.equal(expectedURL); }); it('should set bid[].ttl to seatbid[].bid[].exp value from response', function () { @@ -3073,16 +3285,16 @@ describe('IndexexchangeAdapter', function () { const VIDEO_RESPONSE_WITH_EXP = utils.deepClone(DEFAULT_VIDEO_BID_RESPONSE); VIDEO_RESPONSE_WITH_EXP.seatbid[0].bid[0].exp = 200; BANNER_RESPONSE_WITH_EXP.seatbid[0].bid[0].exp = 100; - const bannerResult = spec.interpretResponse({ body: BANNER_RESPONSE_WITH_EXP }, { data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: [] }); - const videoResult = spec.interpretResponse({ body: VIDEO_RESPONSE_WITH_EXP }, { data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: [] }); + const bannerResult = spec.interpretResponse({ body: BANNER_RESPONSE_WITH_EXP }, bannerBidderRequest); + const videoResult = spec.interpretResponse({ body: VIDEO_RESPONSE_WITH_EXP }, videoBidderRequest); expect(bannerResult[0].ttl).to.equal(100); expect(videoResult[0].ttl).to.equal(200); }); it('should default bid[].ttl if seat[].bid[].exp is not in the resposne', function () { - const bannerResult = spec.interpretResponse({ body: DEFAULT_BANNER_BID_RESPONSE }, { data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: [] }); - const videoResult = spec.interpretResponse({ body: DEFAULT_VIDEO_BID_RESPONSE }, { data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: [] }); + const bannerResult = spec.interpretResponse({ body: DEFAULT_BANNER_BID_RESPONSE }, bannerBidderRequest); + const videoResult = spec.interpretResponse({ body: DEFAULT_VIDEO_BID_RESPONSE }, videoBidderRequest); expect(bannerResult[0].ttl).to.equal(300); expect(videoResult[0].ttl).to.equal(3600); @@ -3174,7 +3386,7 @@ describe('IndexexchangeAdapter', function () { ttl: 3600 } ]; - const result = spec.interpretResponse({ body: DEFAULT_NATIVE_BID_RESPONSE }, { data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: [] }); + const result = spec.interpretResponse({ body: DEFAULT_NATIVE_BID_RESPONSE }, nativeBidderRequest); expect(result[0]).to.deep.equal(expectedParse[0]); }); }); @@ -3182,7 +3394,7 @@ describe('IndexexchangeAdapter', function () { describe('bidrequest consent', function () { it('should have consent info if gdprApplies and consentString exist', function () { const validBidWithConsent = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION); - const requestWithConsent = JSON.parse(validBidWithConsent[0].data.r); + const requestWithConsent = extractPayload(validBidWithConsent[0]); expect(requestWithConsent.regs.ext.gdpr).to.equal(1); expect(requestWithConsent.user.ext.consent).to.equal('3huaa11=qu3198ae'); @@ -3196,7 +3408,7 @@ describe('IndexexchangeAdapter', function () { } }; const validBidWithConsent = spec.buildRequests(DEFAULT_BANNER_VALID_BID, options); - const requestWithConsent = JSON.parse(validBidWithConsent[0].data.r); + const requestWithConsent = extractPayload(validBidWithConsent[0]); expect(requestWithConsent.regs.ext.gdpr).to.equal(1); expect(requestWithConsent.user).to.be.undefined; @@ -3210,7 +3422,7 @@ describe('IndexexchangeAdapter', function () { } }; const validBidWithConsent = spec.buildRequests(DEFAULT_BANNER_VALID_BID, options); - const requestWithConsent = JSON.parse(validBidWithConsent[0].data.r); + const requestWithConsent = extractPayload(validBidWithConsent[0]); expect(requestWithConsent.regs).to.be.undefined; expect(requestWithConsent.user.ext.consent).to.equal('3huaa11=qu3198ae'); @@ -3219,7 +3431,7 @@ describe('IndexexchangeAdapter', function () { it('should not have consent info if options.gdprConsent is undefined', function () { const options = {}; const validBidWithConsent = spec.buildRequests(DEFAULT_BANNER_VALID_BID, options); - const requestWithConsent = JSON.parse(validBidWithConsent[0].data.r); + const requestWithConsent = extractPayload(validBidWithConsent[0]); expect(requestWithConsent.regs).to.be.undefined; expect(requestWithConsent.user).to.be.undefined; @@ -3230,7 +3442,7 @@ describe('IndexexchangeAdapter', function () { uspConsent: '1YYN' }; const validBidWithUspConsent = spec.buildRequests(DEFAULT_BANNER_VALID_BID, options); - const requestWithUspConsent = JSON.parse(validBidWithUspConsent[0].data.r); + const requestWithUspConsent = extractPayload(validBidWithUspConsent[0]); expect(requestWithUspConsent.regs.ext.us_privacy).to.equal('1YYN'); }); @@ -3238,7 +3450,7 @@ describe('IndexexchangeAdapter', function () { it('should not have us_privacy if uspConsent undefined', function () { const options = {}; const validBidWithUspConsent = spec.buildRequests(DEFAULT_BANNER_VALID_BID, options); - const requestWithUspConsent = JSON.parse(validBidWithUspConsent[0].data.r); + const requestWithUspConsent = extractPayload(validBidWithUspConsent[0]); expect(requestWithUspConsent.regs).to.be.undefined; }); @@ -3252,7 +3464,7 @@ describe('IndexexchangeAdapter', function () { uspConsent: '1YYN' }; const validBidWithConsent = spec.buildRequests(DEFAULT_BANNER_VALID_BID, options); - const requestWithConsent = JSON.parse(validBidWithConsent[0].data.r); + const requestWithConsent = extractPayload(validBidWithConsent[0]); expect(requestWithConsent.regs.ext.gdpr).to.equal(1); expect(requestWithConsent.regs.ext.us_privacy).to.equal('1YYN'); }); @@ -3266,7 +3478,7 @@ describe('IndexexchangeAdapter', function () { }; const validBidWithConsent = spec.buildRequests(DEFAULT_BANNER_VALID_BID, options); - const requestWithConsent = JSON.parse(validBidWithConsent[0].data.r); + const requestWithConsent = extractPayload(validBidWithConsent[0]); expect(requestWithConsent.user.ext.consented_providers_settings.consented_providers).to.equal('1~1.35.41.101'); expect(requestWithConsent.user.ext.consent).to.equal('3huaa11=qu3198ae'); }); @@ -3279,7 +3491,7 @@ describe('IndexexchangeAdapter', function () { }; const validBidWithConsent = spec.buildRequests(DEFAULT_BANNER_VALID_BID, options); - const requestWithConsent = JSON.parse(validBidWithConsent[0].data.r); + const requestWithConsent = extractPayload(validBidWithConsent[0]); expect(utils.deepAccess(requestWithConsent, 'user.ext.consented_providers_settings')).to.not.exist; expect(utils.deepAccess(requestWithConsent, 'user.ext.consent')).to.not.exist; }); @@ -3287,21 +3499,21 @@ describe('IndexexchangeAdapter', function () { it('should set coppa to 1 in config when enabled', () => { config.setConfig({ coppa: true }) const bid = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION); - const r = JSON.parse(bid[0].data.r); + const r = extractPayload(bid[0]); expect(r.regs.coppa).to.equal(1); }); it('should not set coppa in config when disabled', () => { config.setConfig({ coppa: false }) const bid = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION); - const r = JSON.parse(bid[0].data.r); + const r = extractPayload(bid[0]); expect(r.regs.coppa).to.be.undefined; }); it('should not set coppa when not specified in config', () => { config.resetConfig(); const bid = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION); - const r = JSON.parse(bid[0].data.r); + const r = extractPayload(bid[0]); expect(r.regs.coppa).to.be.undefined; }); @@ -3403,125 +3615,62 @@ describe('IndexexchangeAdapter', function () { expect(FEATURE_TOGGLES.featureToggles).to.deep.equal({}); }); - it('should create POST request when pbjs_enable_post feature is active', () => { + it('6 ad units should generate only 1 request if buildRequestV2 FT is enabled', function () { sandbox.stub(storage, 'localStorageIsEnabled').returns(true); - serverResponse.body.ext.features.pbjs_enable_post = { + serverResponse.body.ext.features.pbjs_use_buildRequestV2 = { activated: true }; FEATURE_TOGGLES.setFeatureToggles(serverResponse); - const builtRequests = { - banner: { - request: spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0], - siteId: DEFAULT_BANNER_VALID_BID[0].params.siteId - }, - video: { - request: spec.buildRequests(DEFAULT_VIDEO_VALID_BID, DEFAULT_OPTION)[0], - siteId: DEFAULT_VIDEO_VALID_BID[0].params.siteId - }, - native: { - request: spec.buildRequests(DEFAULT_NATIVE_VALID_BID, DEFAULT_OPTION)[0], - siteId: DEFAULT_NATIVE_VALID_BID[0].params.siteId - } - }; - Object.keys(builtRequests).forEach((reqType) => { - const request = builtRequests[reqType].request; - const siteId = builtRequests[reqType].siteId; - expect(request.method).to.equal('POST'); - expect(request.option.contentType).to.equal('text/plain'); - expect(request.url).to.be.equal(`${IX_SECURE_ENDPOINT}?s=${siteId}`); - expect(request.data.r).to.be.undefined; - expect(request.data.ac).to.be.undefined; - expect(request.data.sd).to.be.undefined; - expect(request.data.v).to.be.undefined; - expect(request.data.nf).to.be.undefined; - }); - }); + const bid1 = utils.deepClone(DEFAULT_BANNER_VALID_BID[0]); + bid1.mediaTypes.banner.sizes = LARGE_SET_OF_SIZES; + bid1.params.siteId = '121'; + bid1.adUnitCode = 'div-gpt-1' + bid1.transactionId = 'tr1'; + bid1.bidId = '2f6g5s5e'; - it('should create GET request when pbjs_enable_post feature is disabled', () => { - sandbox.stub(storage, 'localStorageIsEnabled').returns(true); - serverResponse.body.ext.features.pbjs_enable_post = { - activated: false - }; - FEATURE_TOGGLES.setFeatureToggles(serverResponse); - const builtRequests = { - banner: { - request: spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0], - siteId: DEFAULT_BANNER_VALID_BID[0].params.siteId - }, - video: { - request: spec.buildRequests(DEFAULT_VIDEO_VALID_BID, DEFAULT_OPTION)[0], - siteId: DEFAULT_VIDEO_VALID_BID[0].params.siteId - }, - native: { - request: spec.buildRequests(DEFAULT_NATIVE_VALID_BID, DEFAULT_OPTION)[0], - siteId: DEFAULT_NATIVE_VALID_BID[0].params.siteId - } - }; + const bid2 = utils.deepClone(bid1); + bid2.transactionId = 'tr2'; - Object.keys(builtRequests).forEach((reqType) => { - const request = builtRequests[reqType].request; - const siteId = builtRequests[reqType].siteId; - expect(request.method).to.equal('GET'); - expect(request.url).to.equal(IX_SECURE_ENDPOINT); - expect(request.data.r).to.exist; - expect(request.data.ac).to.equal('j'); - expect(request.data.sd).to.equal(1); - expect(request.data.s).to.equal(siteId); - if (reqType == 'video') { - expect(request.data.nf).to.equal(1); - } + const bid3 = utils.deepClone(bid1); + bid3.transactionId = 'tr3'; - if (reqType === 'native') { - expect(request.data.v).to.be.undefined; - } - }); + const bid4 = utils.deepClone(bid1); + bid4.transactionId = 'tr4'; + + const bid5 = utils.deepClone(bid1); + bid5.transactionId = 'tr5'; + + const bid6 = utils.deepClone(bid1); + bid6.transactionId = 'tr6'; + + const requests = spec.buildRequests([bid1, bid2, bid3, bid4, bid5, bid6], DEFAULT_OPTION); + + expect(requests).to.be.an('array'); + // buildRequestv2 enabled causes only 1 requests to get generated. + expect(requests).to.have.lengthOf(1); + for (let request of requests) { + expect(request.method).to.equal('POST'); + } }); - it('should interpertResponse correctly when pbjs_enable_post feature is active', function () { - serverResponse.body.ext.features.pbjs_enable_post = { + it('1 request with 2 ad units, buildRequestV2 enabled', function () { + sandbox.stub(storage, 'localStorageIsEnabled').returns(true); + serverResponse.body.ext.features.pbjs_use_buildRequestV2 = { activated: true }; FEATURE_TOGGLES.setFeatureToggles(serverResponse); - const postBiddderRequestData = { - id: '345', - imp: [ - { - id: '1a2b3c4e', - banner: { - w: 300, - h: 250, - placement: 1 - } - } - ], - site: { - ref: 'https://ref.com/ref.html', - page: 'https://page.com' - }, - }; - const expectedParse = [ - { - requestId: '1a2b3c4d', - cpm: 1, - creativeId: '12345', - width: 300, - height: 250, - mediaType: 'banner', - ad: '', - currency: 'USD', - ttl: 300, - netRevenue: true, - meta: { - networkId: 50, - brandId: 303325, - brandName: 'OECTA', - advertiserDomains: ['www.abc.com'] - } - } - ]; - const result = spec.interpretResponse({ body: DEFAULT_BANNER_BID_RESPONSE }, { data: postBiddderRequestData, validBidRequests: [] }); - expect(result[0]).to.deep.equal(expectedParse[0]); + + const bid = utils.deepClone(DEFAULT_BANNER_VALID_BID[0]); + bid.mediaTypes.banner.sizes = LARGE_SET_OF_SIZES; + bid.params.siteId = '124'; + bid.adUnitCode = 'div-gpt-1' + bid.transactionId = '152e36d1-1241-4242-t35e-y1dv34d12315'; + bid.bidId = '2f6g5s5e'; + + const requests = spec.buildRequests([bid, DEFAULT_BANNER_VALID_BID[0]], DEFAULT_OPTION); + expect(requests).to.be.an('array'); + expect(requests).to.have.lengthOf(1); }); }); @@ -3640,7 +3789,7 @@ describe('IndexexchangeAdapter', function () { }; expect(spec.isBidRequestValid(bid)).to.be.true; - spec.buildRequests([bid], {ortb2}); + spec.buildRequests([bid], { ortb2 }); expect(JSON.parse(localStorageValues[key])).to.deep.equal({ [TODAY]: { [ERROR_CODES.PB_FPD_EXCEEDS_MAX_SIZE]: 2 } }); }); @@ -3694,30 +3843,24 @@ describe('IndexexchangeAdapter', function () { expect(spec.isBidRequestValid(request)).to.be.true; const data = { - ...utils.deepClone(DEFAULT_BIDDER_REQUEST_DATA[0]), - r: JSON.stringify({ - id: '345', - imp: [ - { - id: '1a2b3c4e', - } - ], - ext: { - ixdiag: { - err: { - '4': 8 - } + id: '345', + imp: [ + { + id: '1a2b3c4e', + } + ], + ext: { + ixdiag: { + err: { + '4': 8 } } - }), + } }; - const validBidRequests = [ - DEFAULT_MULTIFORMAT_BANNER_VALID_BID[0], - DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0] - ]; + const validBidRequest = DEFAULT_MULTIFORMAT_BANNER_VALID_BID[0]; - spec.interpretResponse({ body: DEFAULT_BANNER_BID_RESPONSE }, { data, validBidRequests }); + spec.interpretResponse({ body: DEFAULT_BANNER_BID_RESPONSE }, { data, validBidRequest }); expect(localStorageValues[key]).to.be.undefined; }); diff --git a/test/spec/modules/jixieBidAdapter_spec.js b/test/spec/modules/jixieBidAdapter_spec.js index 0c999f1cd51..c354de3c3ac 100644 --- a/test/spec/modules/jixieBidAdapter_spec.js +++ b/test/spec/modules/jixieBidAdapter_spec.js @@ -71,6 +71,7 @@ describe('jixie Adapter', function () { const clientIdTest1_ = '1aba6a40-f711-11e9-868c-53a2ae972xxx'; const sessionIdTest1_ = '1594782644-1aba6a40-f711-11e9-868c-53a2ae972xxx'; + const jxtokoTest1_ = 'eyJJRCI6ImFiYyJ9'; // to serve as the object that prebid will call jixie buildRequest with: (param2) const bidderRequest_ = { @@ -198,6 +199,9 @@ describe('jixie Adapter', function () { // get the interceptors ready: let getCookieStub = sinon.stub(storage, 'getCookie'); let getLocalStorageStub = sinon.stub(storage, 'getDataFromLocalStorage'); + getCookieStub + .withArgs('_jxtoko') + .returns(jxtokoTest1_); getCookieStub .withArgs('_jxx') .returns(clientIdTest1_); @@ -227,6 +231,7 @@ describe('jixie Adapter', function () { expect(payload).to.have.property('client_id_ls', clientIdTest1_); expect(payload).to.have.property('session_id_c', sessionIdTest1_); expect(payload).to.have.property('session_id_ls', sessionIdTest1_); + expect(payload).to.have.property('jxtoko_id', jxtokoTest1_); expect(payload).to.have.property('device', device_); expect(payload).to.have.property('domain', domain_); expect(payload).to.have.property('pageurl', pageurl_); diff --git a/test/spec/modules/jwplayerRtdProvider_spec.js b/test/spec/modules/jwplayerRtdProvider_spec.js index 77c8ce58442..5a38a971e09 100644 --- a/test/spec/modules/jwplayerRtdProvider_spec.js +++ b/test/spec/modules/jwplayerRtdProvider_spec.js @@ -659,9 +659,9 @@ describe('jwplayerRtdProvider', function() { const segment2 = 'segment2'; const segment3 = 'segment3'; const contentSegments = getContentSegments([segment1, segment2, segment3]); - expect(contentSegments[0]).to.deep.equal({ id: segment1, value: segment1 }); - expect(contentSegments[1]).to.deep.equal({ id: segment2, value: segment2 }); - expect(contentSegments[2]).to.deep.equal({ id: segment3, value: segment3 }); + expect(contentSegments[0]).to.deep.equal({ id: segment1 }); + expect(contentSegments[1]).to.deep.equal({ id: segment2 }); + expect(contentSegments[2]).to.deep.equal({ id: segment3 }); }); }); diff --git a/test/spec/modules/kargoBidAdapter_spec.js b/test/spec/modules/kargoBidAdapter_spec.js index 169ee520f33..525c00d655c 100644 --- a/test/spec/modules/kargoBidAdapter_spec.js +++ b/test/spec/modules/kargoBidAdapter_spec.js @@ -69,7 +69,33 @@ describe('kargo adapter tests', function () { userId: { tdid: 'fake-tdid' }, - sizes: [[320, 50], [300, 250], [300, 600]] + sizes: [[320, 50], [300, 250], [300, 600]], + ortb2: { + device: { + sua: { + platform: { + brand: 'macOS', + version: [ '12', '6', '0' ] + }, + browsers: [ + { + brand: 'Chromium', + version: [ '106', '0', '5249', '119' ] + }, + { + brand: 'Google Chrome', + version: [ '106', '0', '5249', '119' ] + }, + { + brand: 'Not;A=Brand', + version: [ '99', '0', '0', '0' ] + } + ], + mobile: 0, + model: '' + } + } + } }, { params: { @@ -259,6 +285,28 @@ describe('kargo adapter tests', function () { device: { width: screen.width, height: screen.height, + sua: { + platform: { + brand: 'macOS', + version: [ '12', '6', '0' ] + }, + browsers: [ + { + brand: 'Chromium', + version: [ '106', '0', '5249', '119' ] + }, + { + brand: 'Google Chrome', + version: [ '106', '0', '5249', '119' ] + }, + { + brand: 'Not;A=Brand', + version: [ '99', '0', '0', '0' ] + } + ], + mobile: 0, + model: '', + }, }, userIDs: { kargoID: '5f108831-302d-11e7-bf6b-4595acd3bf6c', @@ -280,13 +328,39 @@ describe('kargo adapter tests', function () { prebidRawBidRequests: [ { bidId: 1, + ortb2: { + device: { + sua: { + platform: { + brand: 'macOS', + version: [ '12', '6', '0' ] + }, + browsers: [ + { + brand: 'Chromium', + version: [ '106', '0', '5249', '119' ] + }, + { + brand: 'Google Chrome', + version: [ '106', '0', '5249', '119' ] + }, + { + brand: 'Not;A=Brand', + version: [ '99', '0', '0', '0' ] + } + ], + mobile: 0, + model: '' + } + } + }, params: { placementId: 'foo' }, userId: { tdid: 'fake-tdid' }, - sizes: [[320, 50], [300, 250], [300, 600]] + sizes: [[320, 50], [300, 250], [300, 600]], }, { bidId: 2, @@ -330,7 +404,6 @@ describe('kargo adapter tests', function () { var payload = { timeout: 200, uspConsent: '1---', - foo: 'bar', refererInfo: { page: 'https://www.prebid.org', }, @@ -349,7 +422,6 @@ describe('kargo adapter tests', function () { expect(request.method).to.equal('GET'); expect(request.currency).to.equal('USD'); expect(request.timeout).to.equal(200); - expect(request.foo).to.equal('bar'); expect(krakenParams).to.deep.equal(expected); // Make sure session ID stays the same across requests simulating multiple auctions on one page load for (let i in sessionIds) { @@ -484,6 +556,17 @@ describe('kargo adapter tests', function () { mediaType: 'video', metadata: {}, currency: 'EUR' + }, + 6: { + id: 'bar', + cpm: 2.5, + adm: '', + admUrl: 'https://foobar.com/vast_adm', + width: 300, + height: 250, + mediaType: 'video', + metadata: {}, + currency: 'EUR' } }}, { currency: 'USD', @@ -512,6 +595,11 @@ describe('kargo adapter tests', function () { params: { placementId: 'bar' } + }, { + bidId: 6, + params: { + placementId: 'bar' + } }] }); var expectation = [{ @@ -592,6 +680,22 @@ describe('kargo adapter tests', function () { meta: { mediaType: 'video' } + }, { + requestId: '6', + cpm: 2.5, + width: 300, + height: 250, + ad: '', + vastUrl: 'https://foobar.com/vast_adm', + ttl: 300, + creativeId: 'bar', + dealId: undefined, + netRevenue: true, + currency: 'EUR', + mediaType: 'video', + meta: { + mediaType: 'video' + } }]; expect(resp).to.deep.equal(expectation); }); diff --git a/test/spec/modules/konduitAnalyticsAdapter_spec.js b/test/spec/modules/konduitAnalyticsAdapter_spec.js index 1612138cde4..e79ae2feeeb 100644 --- a/test/spec/modules/konduitAnalyticsAdapter_spec.js +++ b/test/spec/modules/konduitAnalyticsAdapter_spec.js @@ -121,7 +121,5 @@ describe(`Konduit Analytics Adapter`, () => { expect(requestBody.konduitId).to.be.equal(konduitId); expect(requestBody.prebidVersion).to.be.equal('$prebid.version$'); expect(requestBody.environment).to.be.an('object'); - // 6 Konduit events + 1 Clean.io event - sinon.assert.callCount(konduitAnalyticsAdapter.track, 7); }); }); diff --git a/test/spec/modules/kueezRtbBidAdapter_spec.js b/test/spec/modules/kueezRtbBidAdapter_spec.js new file mode 100644 index 00000000000..7c0d8e92001 --- /dev/null +++ b/test/spec/modules/kueezRtbBidAdapter_spec.js @@ -0,0 +1,560 @@ +import {expect} from 'chai'; +import { + spec as adapter, + SUPPORTED_ID_SYSTEMS, + createDomain, + hashCode, + extractPID, + extractCID, + extractSubDomain, + getStorageItem, + 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'; + +const SUB_DOMAIN = 'exchange'; + +const BID = { + 'bidId': '2d52001cabd527', + 'adUnitCode': 'div-gpt-ad-12345-0', + 'params': { + 'subDomain': SUB_DOMAIN, + 'cId': '59db6b3b4ffaa70004f45cdc', + 'pId': '59ac17c192832d0011283fe3', + 'bidFloor': 0.1, + 'ext': { + 'param1': 'loremipsum', + 'param2': 'dolorsitamet' + } + }, + 'placementCode': 'div-gpt-ad-1460505748561-0', + 'transactionId': 'c881914b-a3b5-4ecf-ad9c-1c2f37c6aabf', + 'sizes': [[300, 250], [300, 600]], + 'bidderRequestId': '1fdb5ff1b6eaa7', + 'auctionId': 'auction_id', + 'bidRequestsCount': 4, + 'bidderRequestsCount': 3, + 'bidderWinsCount': 1, + 'requestId': 'b0777d85-d061-450e-9bc7-260dd54bbb7a', + 'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc', + 'mediaTypes': [BANNER] +}; + +const VIDEO_BID = { + 'bidId': '2d52001cabd527', + 'adUnitCode': '63550ad1ff6642d368cba59dh5884270560', + 'bidderRequestId': '12a8ae9ada9c13', + 'transactionId': '56e184c6-bde9-497b-b9b9-cf47a61381ee', + 'auctionId': 'auction_id', + 'bidRequestsCount': 4, + 'bidderRequestsCount': 3, + 'bidderWinsCount': 1, + 'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc', + 'params': { + 'subDomain': SUB_DOMAIN, + 'cId': '635509f7ff6642d368cb9837', + 'pId': '59ac17c192832d0011283fe3', + 'bidFloor': 0.1 + }, + 'sizes': [[545, 307]], + 'mediaTypes': { + 'video': { + 'playerSize': [[545, 307]], + 'context': 'instream', + 'mimes': [ + 'video/mp4', + 'application/javascript' + ], + 'protocols': [2, 3, 5, 6], + 'maxduration': 60, + 'minduration': 0, + 'startdelay': 0, + 'linearity': 1, + 'api': [2], + 'placement': 1 + } + } +} + +const BIDDER_REQUEST = { + 'gdprConsent': { + 'consentString': 'consent_string', + 'gdprApplies': true + }, + 'gppString': 'gpp_string', + 'gppSid': [7], + 'uspConsent': 'consent_string', + 'refererInfo': { + 'page': 'https://www.greatsite.com', + 'ref': 'https://www.somereferrer.com' + }, + 'ortb2': { + 'regs': { + 'gpp': 'gpp_string', + 'gpp_sid': [7] + } + } +}; + +const SERVER_RESPONSE = { + body: { + cid: 'testcid123', + results: [{ + 'ad': '', + 'price': 0.8, + 'creativeId': '12610997325162499419', + 'exp': 30, + 'width': 300, + 'height': 250, + 'advertiserDomains': ['securepubads.g.doubleclick.net'], + 'cookies': [{ + 'src': 'https://sync.com', + 'type': 'iframe' + }, { + 'src': 'https://sync.com', + 'type': 'img' + }] + }] + } +}; + +const VIDEO_SERVER_RESPONSE = { + body: { + 'cid': '635509f7ff6642d368cb9837', + 'results': [{ + 'ad': '', + 'advertiserDomains': ['kueezrtb.com'], + 'exp': 60, + 'width': 545, + 'height': 307, + 'mediaType': 'video', + 'creativeId': '12610997325162499419', + 'price': 2, + 'cookies': [] + }] + } +}; + +const REQUEST = { + data: { + width: 300, + height: 250, + bidId: '2d52001cabd527' + } +}; + +function getTopWindowQueryParams() { + try { + const parsedUrl = utils.parseUrl(window.top.document.URL, {decodeSearchAsString: true}); + return parsedUrl.search; + } catch (e) { + return ''; + } +} + +describe('KueezRtbBidAdapter', function () { + describe('validtae spec', function () { + it('exists and is a function', function () { + expect(adapter.isBidRequestValid).to.exist.and.to.be.a('function'); + }); + + it('exists and is a function', function () { + expect(adapter.buildRequests).to.exist.and.to.be.a('function'); + }); + + it('exists and is a function', function () { + expect(adapter.interpretResponse).to.exist.and.to.be.a('function'); + }); + + it('exists and is a function', function () { + expect(adapter.getUserSyncs).to.exist.and.to.be.a('function'); + }); + + it('exists and is a string', function () { + expect(adapter.code).to.exist.and.to.be.a('string'); + }); + + it('exists and contains media types', function () { + expect(adapter.supportedMediaTypes).to.exist.and.to.be.an('array').with.length(2); + expect(adapter.supportedMediaTypes).to.contain.members([BANNER, VIDEO]); + }); + }); + + describe('validate bid requests', function () { + it('should require cId', function () { + const isValid = adapter.isBidRequestValid({ + params: { + pId: 'pid' + } + }); + expect(isValid).to.be.false; + }); + + it('should require pId', function () { + const isValid = adapter.isBidRequestValid({ + params: { + cId: 'cid' + } + }); + expect(isValid).to.be.false; + }); + + it('should validate correctly', function () { + const isValid = adapter.isBidRequestValid({ + params: { + cId: 'cid', + pId: 'pid' + } + }); + expect(isValid).to.be.true; + }); + }); + + describe('build requests', function () { + let sandbox; + before(function () { + $$PREBID_GLOBAL$$.bidderSettings = { + kueezrtb: { + storageAllowed: true + } + }; + sandbox = sinon.sandbox.create(); + sandbox.stub(Date, 'now').returns(1000); + }); + + it('should build video request', function () { + const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.page); + config.setConfig({ + bidderTimeout: 3000 + }); + const requests = adapter.buildRequests([VIDEO_BID], BIDDER_REQUEST); + expect(requests).to.have.length(1); + expect(requests[0]).to.deep.equal({ + method: 'POST', + url: `${createDomain(SUB_DOMAIN)}/prebid/multi/635509f7ff6642d368cb9837`, + data: { + adUnitCode: '63550ad1ff6642d368cba59dh5884270560', + bidFloor: 0.1, + bidId: '2d52001cabd527', + bidderVersion: adapter.version, + bidderRequestId: '12a8ae9ada9c13', + cb: 1000, + gdpr: 1, + gdprConsent: 'consent_string', + usPrivacy: 'consent_string', + gppString: 'gpp_string', + gppSid: [7], + prebidVersion: version, + transactionId: '56e184c6-bde9-497b-b9b9-cf47a61381ee', + auctionId: 'auction_id', + bidRequestsCount: 4, + bidderRequestsCount: 3, + bidderWinsCount: 1, + bidderTimeout: 3000, + publisherId: '59ac17c192832d0011283fe3', + url: 'https%3A%2F%2Fwww.greatsite.com', + referrer: 'https://www.somereferrer.com', + res: `${window.top.screen.width}x${window.top.screen.height}`, + schain: VIDEO_BID.schain, + sizes: ['545x307'], + uniqueDealId: `${hashUrl}_${Date.now().toString()}`, + uqs: getTopWindowQueryParams(), + mediaTypes: { + video: { + api: [2], + context: 'instream', + linearity: 1, + maxduration: 60, + mimes: [ + 'video/mp4', + 'application/javascript' + ], + minduration: 0, + placement: 1, + playerSize: [[545, 307]], + protocols: [2, 3, 5, 6], + startdelay: 0 + } + } + } + }); + }); + + it('should build banner request for each size', function () { + const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.page); + config.setConfig({ + bidderTimeout: 3000 + }); + const requests = adapter.buildRequests([BID], BIDDER_REQUEST); + expect(requests).to.have.length(1); + expect(requests[0]).to.deep.equal({ + method: 'POST', + url: `${createDomain(SUB_DOMAIN)}/prebid/multi/59db6b3b4ffaa70004f45cdc`, + data: { + gdprConsent: 'consent_string', + gdpr: 1, + gppString: 'gpp_string', + gppSid: [7], + usPrivacy: 'consent_string', + transactionId: 'c881914b-a3b5-4ecf-ad9c-1c2f37c6aabf', + auctionId: 'auction_id', + bidRequestsCount: 4, + bidderRequestsCount: 3, + bidderWinsCount: 1, + bidderTimeout: 3000, + bidderRequestId: '1fdb5ff1b6eaa7', + sizes: ['300x250', '300x600'], + url: 'https%3A%2F%2Fwww.greatsite.com', + referrer: 'https://www.somereferrer.com', + cb: 1000, + bidFloor: 0.1, + bidId: '2d52001cabd527', + adUnitCode: 'div-gpt-ad-12345-0', + publisherId: '59ac17c192832d0011283fe3', + uniqueDealId: `${hashUrl}_${Date.now().toString()}`, + bidderVersion: adapter.version, + prebidVersion: version, + schain: BID.schain, + res: `${window.top.screen.width}x${window.top.screen.height}`, + mediaTypes: [BANNER], + uqs: getTopWindowQueryParams(), + 'ext.param1': 'loremipsum', + 'ext.param2': 'dolorsitamet', + } + }); + }); + + after(function () { + $$PREBID_GLOBAL$$.bidderSettings = {}; + sandbox.restore(); + }); + }); + describe('getUserSyncs', function () { + it('should have valid user sync with iframeEnabled', function () { + const result = adapter.getUserSyncs({iframeEnabled: true}, [SERVER_RESPONSE]); + + expect(result).to.deep.equal([{ + type: 'iframe', + url: 'https://sync.kueezrtb.com/api/sync/iframe/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=' + }]); + }); + + it('should have valid user sync with cid on response', function () { + const result = adapter.getUserSyncs({iframeEnabled: true}, [SERVER_RESPONSE]); + expect(result).to.deep.equal([{ + type: 'iframe', + url: 'https://sync.kueezrtb.com/api/sync/iframe/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=' + }]); + }); + + it('should have valid user sync with pixelEnabled', function () { + const result = adapter.getUserSyncs({pixelEnabled: true}, [SERVER_RESPONSE]); + + expect(result).to.deep.equal([{ + 'url': 'https://sync.kueezrtb.com/api/sync/image/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=', + 'type': 'image' + }]); + }) + }); + + describe('interpret response', function () { + it('should return empty array when there is no response', function () { + const responses = adapter.interpretResponse(null); + expect(responses).to.be.empty; + }); + + it('should return empty array when there is no ad', function () { + const responses = adapter.interpretResponse({price: 1, ad: ''}); + expect(responses).to.be.empty; + }); + + it('should return empty array when there is no price', function () { + const responses = adapter.interpretResponse({price: null, ad: 'great ad'}); + expect(responses).to.be.empty; + }); + + it('should return an array of interpreted banner responses', function () { + const responses = adapter.interpretResponse(SERVER_RESPONSE, REQUEST); + expect(responses).to.have.length(1); + expect(responses[0]).to.deep.equal({ + requestId: '2d52001cabd527', + cpm: 0.8, + width: 300, + height: 250, + creativeId: '12610997325162499419', + currency: 'USD', + netRevenue: true, + ttl: 30, + ad: '', + meta: { + advertiserDomains: ['securepubads.g.doubleclick.net'] + } + }); + }); + + it('should return an array of interpreted video responses', function () { + const responses = adapter.interpretResponse(VIDEO_SERVER_RESPONSE, REQUEST); + expect(responses).to.have.length(1); + expect(responses[0]).to.deep.equal({ + requestId: '2d52001cabd527', + cpm: 2, + width: 545, + height: 307, + mediaType: 'video', + creativeId: '12610997325162499419', + currency: 'USD', + netRevenue: true, + ttl: 60, + vastXml: '', + meta: { + advertiserDomains: ['kueezrtb.com'] + } + }); + }); + + it('should take default TTL', function () { + const serverResponse = utils.deepClone(SERVER_RESPONSE); + delete serverResponse.body.results[0].exp; + const responses = adapter.interpretResponse(serverResponse, REQUEST); + expect(responses).to.have.length(1); + expect(responses[0].ttl).to.equal(300); + }); + }); + + describe('user id system', function () { + Object.keys(SUPPORTED_ID_SYSTEMS).forEach((idSystemProvider) => { + const id = Date.now().toString(); + const bid = utils.deepClone(BID); + + const userId = (function () { + switch (idSystemProvider) { + case 'lipb': + return {lipbid: id}; + case 'parrableId': + return {eid: id}; + case 'id5id': + return {uid: id}; + default: + return id; + } + })(); + + bid.userId = { + [idSystemProvider]: userId + }; + + it(`should include 'uid.${idSystemProvider}' in request params`, function () { + const requests = adapter.buildRequests([bid], BIDDER_REQUEST); + expect(requests[0].data[`uid.${idSystemProvider}`]).to.equal(id); + }); + }); + }); + + describe('alternate param names extractors', function () { + it('should return undefined when param not supported', function () { + const cid = extractCID({'c_id': '1'}); + const pid = extractPID({'p_id': '1'}); + const subDomain = extractSubDomain({'sub_domain': 'prebid'}); + expect(cid).to.be.undefined; + expect(pid).to.be.undefined; + expect(subDomain).to.be.undefined; + }); + + it('should return value when param supported', function () { + const cid = extractCID({'cID': '1'}); + const pid = extractPID({'Pid': '2'}); + const subDomain = extractSubDomain({'subDOMAIN': 'prebid'}); + expect(cid).to.be.equal('1'); + expect(pid).to.be.equal('2'); + expect(subDomain).to.be.equal('prebid'); + }); + }); + + describe('unique deal id', function () { + before(function () { + $$PREBID_GLOBAL$$.bidderSettings = { + kueezrtb: { + storageAllowed: true + } + }; + }); + after(function () { + $$PREBID_GLOBAL$$.bidderSettings = {}; + }); + const key = 'myKey'; + let uniqueDealId; + beforeEach(() => { + uniqueDealId = getUniqueDealId(key, 0); + }) + + it('should get current unique deal id', function (done) { + // waiting some time so `now` will become past + setTimeout(() => { + const current = getUniqueDealId(key); + expect(current).to.be.equal(uniqueDealId); + done(); + }, 200); + }); + + it('should get new unique deal id on expiration', function (done) { + setTimeout(() => { + const current = getUniqueDealId(key, 100); + expect(current).to.not.be.equal(uniqueDealId); + done(); + }, 200) + }); + }); + + describe('storage utils', function () { + before(function () { + $$PREBID_GLOBAL$$.bidderSettings = { + kueezrtb: { + storageAllowed: true + } + }; + }); + after(function () { + $$PREBID_GLOBAL$$.bidderSettings = {}; + }); + it('should get value from storage with create param', function () { + const now = Date.now(); + const clock = useFakeTimers({ + shouldAdvanceTime: true, + now + }); + setStorageItem('myKey', 2020); + const {value, created} = getStorageItem('myKey'); + expect(created).to.be.equal(now); + expect(value).to.be.equal(2020); + expect(typeof value).to.be.equal('number'); + expect(typeof created).to.be.equal('number'); + clock.restore(); + }); + + it('should get external stored value', function () { + const value = 'superman' + window.localStorage.setItem('myExternalKey', value); + const item = getStorageItem('myExternalKey'); + expect(item).to.be.equal(value); + }); + + it('should parse JSON value', function () { + const data = JSON.stringify({event: 'send'}); + const {event} = tryParseJSON(data); + expect(event).to.be.equal('send'); + }); + + it('should get original value on parse fail', function () { + const value = 21; + const parsed = tryParseJSON(value); + expect(typeof parsed).to.be.equal('number'); + expect(parsed).to.be.equal(value); + }); + }); +}); diff --git a/test/spec/modules/limelightDigitalBidAdapter_spec.js b/test/spec/modules/limelightDigitalBidAdapter_spec.js index 4efb4f4e84d..5a92110abb4 100644 --- a/test/spec/modules/limelightDigitalBidAdapter_spec.js +++ b/test/spec/modules/limelightDigitalBidAdapter_spec.js @@ -10,7 +10,12 @@ describe('limelightDigitalAdapter', function () { host: 'exchange.ortb.net', adUnitId: 123, adUnitType: 'banner', - publisherId: 'perfectPublisher' + publisherId: 'perfectPublisher', + custom1: 'custom1', + custom2: 'custom2', + custom3: 'custom3', + custom4: 'custom4', + custom5: 'custom5' }, placementCode: 'placement_0', auctionId: '74f78609-a92d-4cf1-869f-1b244bbfb5d2', @@ -49,7 +54,12 @@ describe('limelightDigitalAdapter', function () { params: { host: 'ads.project-limelight.com', adUnitId: 456, - adUnitType: 'banner' + adUnitType: 'banner', + custom1: 'custom1', + custom2: 'custom2', + custom3: 'custom3', + custom4: 'custom4', + custom5: 'custom5' }, placementCode: 'placement_1', auctionId: '482f88de-29ab-45c8-981a-d25e39454a34', @@ -90,7 +100,12 @@ describe('limelightDigitalAdapter', function () { host: 'exchange.ortb.net', adUnitId: 789, adUnitType: 'video', - publisherId: 'secondPerfectPublisher' + publisherId: 'secondPerfectPublisher', + custom1: 'custom1', + custom2: 'custom2', + custom3: 'custom3', + custom4: 'custom4', + custom5: 'custom5' }, placementCode: 'placement_2', auctionId: 'e4771143-6aa7-41ec-8824-ced4342c96c8', @@ -128,7 +143,12 @@ describe('limelightDigitalAdapter', function () { params: { host: 'exchange.ortb.net', adUnitId: 789, - adUnitType: 'video' + adUnitType: 'video', + custom1: 'custom1', + custom2: 'custom2', + custom3: 'custom3', + custom4: 'custom4', + custom5: 'custom5' }, placementCode: 'placement_2', auctionId: 'e4771143-6aa7-41ec-8824-ced4342c96c8', @@ -196,7 +216,12 @@ describe('limelightDigitalAdapter', function () { 'transactionId', 'publisherId', 'userIdAsEids', - 'supplyChain' + 'supplyChain', + 'custom1', + 'custom2', + 'custom3', + 'custom4', + 'custom5' ); expect(adUnit.id).to.be.a('number'); expect(adUnit.bidId).to.be.a('string'); @@ -205,6 +230,11 @@ describe('limelightDigitalAdapter', function () { expect(adUnit.sizes).to.be.an('array'); expect(adUnit.userIdAsEids).to.be.an('array'); expect(adUnit.supplyChain).to.be.an('object'); + expect(adUnit.custom1).to.be.a('string'); + expect(adUnit.custom2).to.be.a('string'); + expect(adUnit.custom3).to.be.a('string'); + expect(adUnit.custom4).to.be.a('string'); + expect(adUnit.custom5).to.be.a('string'); }) }) }) diff --git a/test/spec/modules/liveIntentAnalyticsAdapter_spec.js b/test/spec/modules/liveIntentAnalyticsAdapter_spec.js index b3a452e5ece..fa4c5cd8cad 100644 --- a/test/spec/modules/liveIntentAnalyticsAdapter_spec.js +++ b/test/spec/modules/liveIntentAnalyticsAdapter_spec.js @@ -2,6 +2,7 @@ import liAnalytics from 'modules/liveIntentAnalyticsAdapter'; import { expect } from 'chai'; import { server } from 'test/mocks/xhr.js'; import { auctionManager } from 'src/auctionManager.js'; +import {expectEvents} from '../../helpers/analytics.js'; let utils = require('src/utils'); let refererDetection = require('src/refererDetection'); @@ -286,12 +287,8 @@ describe('LiveIntent Analytics Adapter ', () => { }); it('track is called', () => { - liAnalytics.enableAnalytics(config); sandbox.stub(liAnalytics, 'track'); - events.emit(constants.EVENTS.AUCTION_END, args); - events.emit(constants.EVENTS.AUCTION_END, args); - events.emit(constants.EVENTS.AUCTION_END, args); - clock.tick(6000); - sinon.assert.callCount(liAnalytics.track, 3) + liAnalytics.enableAnalytics(config); + expectEvents().to.beTrackedBy(liAnalytics.track); }) }); diff --git a/test/spec/modules/livewrappedBidAdapter_spec.js b/test/spec/modules/livewrappedBidAdapter_spec.js index a4fee5e3b26..6bbdf6e1705 100644 --- a/test/spec/modules/livewrappedBidAdapter_spec.js +++ b/test/spec/modules/livewrappedBidAdapter_spec.js @@ -13,6 +13,10 @@ describe('Livewrapped adapter tests', function () { window.livewrapped = undefined; + config.setConfig({ + device: { w: 100, h: 100 } + }); + bidderRequest = { bidderCode: 'livewrapped', auctionId: 'c45dd708-a418-42ec-b8a7-b70a6c6fab0a', @@ -43,6 +47,7 @@ describe('Livewrapped adapter tests', function () { afterEach(function () { sandbox.restore(); + config.resetConfig(); }); describe('isBidRequestValid', function() { @@ -351,7 +356,7 @@ describe('Livewrapped adapter tests', function () { expect(data).to.deep.equal(expectedQuery); }); - it('should make a well-formed single request object with ad blocker revovered parameter', function() { + it('should make a well-formed single request object with ad blocker recovered parameter', function() { sandbox.stub(utils, 'getWindowTop').returns({ I12C: { Morph: 1 } }); sandbox.stub(utils, 'isSafariBrowser').callsFake(() => false); sandbox.stub(storage, 'cookiesAreEnabled').callsFake(() => true); @@ -489,7 +494,7 @@ describe('Livewrapped adapter tests', function () { return {bundle: 'bundle', domain: 'https://appdomain.com'}; } if (key === 'device') { - return {ifa: 'ifa', width: 300, height: 200}; + return {ifa: 'ifa', w: 300, h: 200}; } return origGetConfig.apply(config, arguments); }); @@ -839,6 +844,266 @@ describe('Livewrapped adapter tests', function () { expect(data).to.deep.equal(expectedQuery); }); + + it('width and height should default to values from window when not set in config', function() { + sandbox.stub(utils, 'isSafariBrowser').callsFake(() => false); + sandbox.stub(storage, 'cookiesAreEnabled').callsFake(() => true); + + config.resetConfig(); + + let testbidRequest = clone(bidderRequest); + let result = spec.buildRequests(testbidRequest.bids, testbidRequest); + let data = JSON.parse(result.data); + + expect(result.url).to.equal('https://lwadm.com/ad'); + + let expectedQuery = { + auctionId: 'F7557995-65F5-4682-8782-7D5D34D82A8C', + publisherId: '26947112-2289-405D-88C1-A7340C57E63E', + userId: 'user id', + url: 'https://www.domain.com', + seats: {'dsp': ['seat 1']}, + version: '1.4', + width: window.innerWidth, + height: window.innerHeight, + cookieSupport: true, + adRequests: [{ + adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37', + callerAdUnitId: 'panorama_d_1', + bidId: '2ffb201a808da7', + transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D', + formats: [{width: 980, height: 240}, {width: 980, height: 120}] + }] + }; + + expect(data).to.deep.equal(expectedQuery); + }); + }); + + describe('price floors module', function() { + it('price floors module disabled', function() { + sandbox.stub(utils, 'isSafariBrowser').callsFake(() => false); + sandbox.stub(storage, 'cookiesAreEnabled').callsFake(() => true); + + let testbidRequest = clone(bidderRequest); + let result = spec.buildRequests(testbidRequest.bids, testbidRequest); + let data = JSON.parse(result.data); + + expect(result.url).to.equal('https://lwadm.com/ad'); + + let expectedQuery = { + auctionId: 'F7557995-65F5-4682-8782-7D5D34D82A8C', + publisherId: '26947112-2289-405D-88C1-A7340C57E63E', + userId: 'user id', + url: 'https://www.domain.com', + seats: {'dsp': ['seat 1']}, + version: '1.4', + width: 100, + height: 100, + cookieSupport: true, + adRequests: [{ + adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37', + callerAdUnitId: 'panorama_d_1', + bidId: '2ffb201a808da7', + transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D', + formats: [{width: 980, height: 240}, {width: 980, height: 120}] + }] + }; + + expect(data).to.deep.equal(expectedQuery); + }); + + it('getFloor does not return an object', function() { + sandbox.stub(utils, 'isSafariBrowser').callsFake(() => false); + sandbox.stub(storage, 'cookiesAreEnabled').callsFake(() => true); + + let testbidRequest = clone(bidderRequest); + let bids = testbidRequest.bids.map(b => { + b.getFloor = function () { return undefined; } + return b; + }); + let result = spec.buildRequests(bids, testbidRequest); + let data = JSON.parse(result.data); + + expect(result.url).to.equal('https://lwadm.com/ad'); + + let expectedQuery = { + auctionId: 'F7557995-65F5-4682-8782-7D5D34D82A8C', + publisherId: '26947112-2289-405D-88C1-A7340C57E63E', + userId: 'user id', + url: 'https://www.domain.com', + seats: {'dsp': ['seat 1']}, + version: '1.4', + width: 100, + height: 100, + cookieSupport: true, + adRequests: [{ + adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37', + callerAdUnitId: 'panorama_d_1', + bidId: '2ffb201a808da7', + transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D', + formats: [{width: 980, height: 240}, {width: 980, height: 120}] + }] + }; + + expect(data).to.deep.equal(expectedQuery); + }); + + it('getFloor returns a NaN floor', function() { + sandbox.stub(utils, 'isSafariBrowser').callsFake(() => false); + sandbox.stub(storage, 'cookiesAreEnabled').callsFake(() => true); + + let testbidRequest = clone(bidderRequest); + let bids = testbidRequest.bids.map(b => { + b.getFloor = function () { return { floor: undefined }; } + return b; + }); + let result = spec.buildRequests(bids, testbidRequest); + let data = JSON.parse(result.data); + + expect(result.url).to.equal('https://lwadm.com/ad'); + + let expectedQuery = { + auctionId: 'F7557995-65F5-4682-8782-7D5D34D82A8C', + publisherId: '26947112-2289-405D-88C1-A7340C57E63E', + userId: 'user id', + url: 'https://www.domain.com', + seats: {'dsp': ['seat 1']}, + version: '1.4', + width: 100, + height: 100, + cookieSupport: true, + adRequests: [{ + adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37', + callerAdUnitId: 'panorama_d_1', + bidId: '2ffb201a808da7', + transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D', + formats: [{width: 980, height: 240}, {width: 980, height: 120}] + }] + }; + + expect(data).to.deep.equal(expectedQuery); + }); + + it('getFloor returns unexpected currency', function() { + sandbox.stub(utils, 'isSafariBrowser').callsFake(() => false); + sandbox.stub(storage, 'cookiesAreEnabled').callsFake(() => true); + + let testbidRequest = clone(bidderRequest); + let bids = testbidRequest.bids.map(b => { + b.getFloor = function () { return { floor: 10, currency: 'EUR' }; } + return b; + }); + let result = spec.buildRequests(bids, testbidRequest); + let data = JSON.parse(result.data); + + expect(result.url).to.equal('https://lwadm.com/ad'); + + let expectedQuery = { + auctionId: 'F7557995-65F5-4682-8782-7D5D34D82A8C', + publisherId: '26947112-2289-405D-88C1-A7340C57E63E', + userId: 'user id', + url: 'https://www.domain.com', + seats: {'dsp': ['seat 1']}, + version: '1.4', + width: 100, + height: 100, + cookieSupport: true, + adRequests: [{ + adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37', + callerAdUnitId: 'panorama_d_1', + bidId: '2ffb201a808da7', + transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D', + formats: [{width: 980, height: 240}, {width: 980, height: 120}] + }] + }; + + expect(data).to.deep.equal(expectedQuery); + }); + + it('getFloor returns valid floor - ad server currency', function() { + sandbox.stub(utils, 'isSafariBrowser').callsFake(() => false); + sandbox.stub(storage, 'cookiesAreEnabled').callsFake(() => true); + + let origGetConfig = config.getConfig; + sandbox.stub(config, 'getConfig').callsFake(function (key) { + if (key === 'currency.adServerCurrency') { + return 'EUR'; + } + return origGetConfig.apply(config, arguments); + }); + + let testbidRequest = clone(bidderRequest); + let bids = testbidRequest.bids.map(b => { + b.getFloor = function () { return { floor: 10, currency: 'EUR' }; } + return b; + }); + let result = spec.buildRequests(bids, testbidRequest); + let data = JSON.parse(result.data); + + expect(result.url).to.equal('https://lwadm.com/ad'); + + let expectedQuery = { + auctionId: 'F7557995-65F5-4682-8782-7D5D34D82A8C', + publisherId: '26947112-2289-405D-88C1-A7340C57E63E', + userId: 'user id', + url: 'https://www.domain.com', + seats: {'dsp': ['seat 1']}, + version: '1.4', + width: 100, + height: 100, + cookieSupport: true, + flrCur: 'EUR', + adRequests: [{ + adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37', + callerAdUnitId: 'panorama_d_1', + bidId: '2ffb201a808da7', + transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D', + formats: [{width: 980, height: 240}, {width: 980, height: 120}], + flr: 10 + }] + }; + + expect(data).to.deep.equal(expectedQuery); + }); + + it('getFloor returns valid floor - default currency', function() { + sandbox.stub(utils, 'isSafariBrowser').callsFake(() => false); + sandbox.stub(storage, 'cookiesAreEnabled').callsFake(() => true); + + let testbidRequest = clone(bidderRequest); + let bids = testbidRequest.bids.map(b => { + b.getFloor = function () { return { floor: 10, currency: 'USD' }; } + return b; + }); + let result = spec.buildRequests(bids, testbidRequest); + let data = JSON.parse(result.data); + + expect(result.url).to.equal('https://lwadm.com/ad'); + + let expectedQuery = { + auctionId: 'F7557995-65F5-4682-8782-7D5D34D82A8C', + publisherId: '26947112-2289-405D-88C1-A7340C57E63E', + userId: 'user id', + url: 'https://www.domain.com', + seats: {'dsp': ['seat 1']}, + version: '1.4', + width: 100, + height: 100, + cookieSupport: true, + flrCur: 'USD', + adRequests: [{ + adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37', + callerAdUnitId: 'panorama_d_1', + bidId: '2ffb201a808da7', + transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D', + formats: [{width: 980, height: 240}, {width: 980, height: 120}], + flr: 10 + }] + }; + + expect(data).to.deep.equal(expectedQuery); + }); }); it('should make use of user ids if available', function() { diff --git a/test/spec/modules/lotamePanoramaIdSystem_spec.js b/test/spec/modules/lotamePanoramaIdSystem_spec.js index 5dc055ac080..ea538db08e1 100644 --- a/test/spec/modules/lotamePanoramaIdSystem_spec.js +++ b/test/spec/modules/lotamePanoramaIdSystem_spec.js @@ -18,6 +18,7 @@ describe('LotameId', function() { let removeFromLocalStorageStub; let timeStampStub; let uspConsentDataStub; + let requestHost; const nowTimestamp = new Date().getTime(); @@ -33,6 +34,11 @@ describe('LotameId', function() { ); timeStampStub = sinon.stub(utils, 'timestamp').returns(nowTimestamp); uspConsentDataStub = sinon.stub(uspDataHandler, 'getConsentData'); + if (navigator.userAgent && navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) { + requestHost = 'https://c.ltmsphrcl.net/id'; + } else { + requestHost = 'https://id.crwdcntrl.net/id'; + } }); afterEach(function () { @@ -69,7 +75,7 @@ describe('LotameId', function() { }); it('should call the remote server when getId is called', function () { - expect(request.url).to.be.eq('https://id.crwdcntrl.net/id'); + expect(request.url).to.be.eq(`${requestHost}`); expect(callBackSpy.calledOnce).to.be.true; }); @@ -439,7 +445,7 @@ describe('LotameId', function() { it('should pass the gdpr consent string back', function() { expect(request.url).to.be.eq( - 'https://id.crwdcntrl.net/id?gdpr_applies=true&gdpr_consent=consentGiven' + `${requestHost}?gdpr_applies=true&gdpr_consent=consentGiven` ); }); }); @@ -471,7 +477,7 @@ describe('LotameId', function() { it('should pass the gdpr consent string back', function() { expect(request.url).to.be.eq( - 'https://id.crwdcntrl.net/id?gdpr_applies=true&gdpr_consent=consentGiven' + `${requestHost}?gdpr_applies=true&gdpr_consent=consentGiven` ); }); }); @@ -503,7 +509,7 @@ describe('LotameId', function() { it('should pass the gdpr consent string back', function() { expect(request.url).to.be.eq( - 'https://id.crwdcntrl.net/id?gdpr_applies=true&gdpr_consent=consentGiven' + `${requestHost}?gdpr_applies=true&gdpr_consent=consentGiven` ); }); }); @@ -531,7 +537,7 @@ describe('LotameId', function() { it('should not include the gdpr consent string on the url', function() { expect(request.url).to.be.eq( - 'https://id.crwdcntrl.net/id?gdpr_applies=true' + `${requestHost}?gdpr_applies=true` ); }); }); @@ -560,7 +566,7 @@ describe('LotameId', function() { it('should pass the gdpr consent string back', function() { expect(request.url).to.be.eq( - 'https://id.crwdcntrl.net/id?gdpr_consent=consentGiven' + `${requestHost}?gdpr_consent=consentGiven` ); }); }); @@ -589,7 +595,7 @@ describe('LotameId', function() { it('should pass the gdpr consent string back', function() { expect(request.url).to.be.eq( - 'https://id.crwdcntrl.net/id?gdpr_consent=consentGiven' + `${requestHost}?gdpr_consent=consentGiven` ); }); }); @@ -613,7 +619,7 @@ describe('LotameId', function() { }); it('should pass the gdpr consent string back', function() { - expect(request.url).to.be.eq('https://id.crwdcntrl.net/id'); + expect(request.url).to.be.eq(`${requestHost}`); }); }); @@ -835,7 +841,7 @@ describe('LotameId', function() { it('should pass the usp consent string and client id back', function () { expect(request.url).to.be.eq( - 'https://id.crwdcntrl.net/id?gdpr_applies=false&us_privacy=1NNN&c=1234' + `${requestHost}?gdpr_applies=false&us_privacy=1NNN&c=1234` ); }); @@ -923,7 +929,7 @@ describe('LotameId', function() { it('should pass client id back', function () { expect(request.url).to.be.eq( - 'https://id.crwdcntrl.net/id?gdpr_applies=false&c=1234' + `${requestHost}?gdpr_applies=false&c=1234` ); }); diff --git a/test/spec/modules/magniteAnalyticsAdapter_spec.js b/test/spec/modules/magniteAnalyticsAdapter_spec.js index eb9ba190e33..b27e8f30881 100644 --- a/test/spec/modules/magniteAnalyticsAdapter_spec.js +++ b/test/spec/modules/magniteAnalyticsAdapter_spec.js @@ -3,6 +3,7 @@ import magniteAdapter, { getHostNameFromReferer, storage, rubiConf, + detectBrowserFromUa } from '../../../modules/magniteAnalyticsAdapter.js'; import CONSTANTS from 'src/constants.json'; import { config } from 'src/config.js'; @@ -101,6 +102,11 @@ const MOCK = { 'startTime': 1658868383748 } ], + 'ortb2': { + 'device': { + 'ua': 'Mozilla/ 5.0(Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/ 537.36(KHTML, like Gecko) Chrome/ 109.0.0.0 Safari / 537.36' + } + }, 'refererInfo': { 'page': 'http://a-test-domain.com:8000/test_pages/sanity/TEMP/prebidTest.html?pbjs_debug=true', }, @@ -209,6 +215,9 @@ const ANALYTICS_MESSAGE = { 'start': 1519767013781, 'expires': 1519788613781 }, + 'client': { + 'browser': 'Chrome' + }, 'auctions': [ { 'auctionId': '99785e47-a7c8-4c8a-ae05-ef1c717a4b4d', @@ -306,7 +315,7 @@ const ANALYTICS_MESSAGE = { describe('magnite analytics adapter', function () { let sandbox; let clock; - let getDataFromLocalStorageStub, setDataInLocalStorageStub, localStorageIsEnabledStub; + let getDataFromLocalStorageStub, setDataInLocalStorageStub, localStorageIsEnabledStub, removeDataFromLocalStorageStub; let gptSlot0; let gptSlotRenderEnded0; beforeEach(function () { @@ -325,6 +334,7 @@ describe('magnite analytics adapter', function () { getDataFromLocalStorageStub = sinon.stub(storage, 'getDataFromLocalStorage'); setDataInLocalStorageStub = sinon.stub(storage, 'setDataInLocalStorage'); localStorageIsEnabledStub = sinon.stub(storage, 'localStorageIsEnabled'); + removeDataFromLocalStorageStub = sinon.stub(storage, 'removeDataFromLocalStorage') sandbox = sinon.sandbox.create(); localStorageIsEnabledStub.returns(true); @@ -355,6 +365,7 @@ describe('magnite analytics adapter', function () { getDataFromLocalStorageStub.restore(); setDataInLocalStorageStub.restore(); localStorageIsEnabledStub.restore(); + removeDataFromLocalStorageStub.restore(); magniteAdapter.disableAnalytics(); }); @@ -548,6 +559,49 @@ describe('magnite analytics adapter', function () { ]); }); + [ + { + ua: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15', + expected: 'Safari' + }, + { + ua: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/109.0', + expected: 'Firefox' + }, + { + ua: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/109.0.1518.78', + expected: 'Edge' + }, + { + ua: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 OPR/94.0.0.0', + expected: 'Opera' + } + ].forEach(testData => { + it(`should parse browser from ${testData.expected} user agent correctly`, function () { + expect(detectBrowserFromUa(testData.ua)).to.equal(testData.expected); + }); + }) + + it('should pass along 1x1 size if no sizes in adUnit', function () { + const auctionInit = utils.deepClone(MOCK.AUCTION_INIT); + + delete auctionInit.adUnits[0].sizes; + + events.emit(AUCTION_INIT, auctionInit); + events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); + events.emit(BIDDER_DONE, MOCK.BIDDER_DONE); + events.emit(AUCTION_END, MOCK.AUCTION_END); + clock.tick(rubiConf.analyticsBatchTimeout + 1000); + + let message = JSON.parse(server.requests[0].requestBody); + expect(message.auctions[0].adUnits[0].dimensions).to.deep.equal([ + { + width: 1, + height: 1 + } + ]); + }); + it('should pass along user ids', function () { let auctionInit = utils.deepClone(MOCK.AUCTION_INIT); auctionInit.bidderRequests[0].bids[0].userId = { @@ -602,6 +656,32 @@ describe('magnite analytics adapter', function () { let message = JSON.parse(server.requests[0].requestBody); expect(message.auctions[0].adUnits[0].bids[0].bidResponse.adomains).to.deep.equal(test.expected); }); + + // Network Id tests + [ + { input: 'magnite.com', expected: 'magnite.com' }, + { input: 12345, expected: '12345' }, + { input: ['magnite.com', 12345], expected: 'magnite.com,12345' } + ].forEach((test, index) => { + it(`should handle networkId correctly - #${index + 1}`, function () { + events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); + events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); + + let bidResponse = utils.deepClone(MOCK.BID_RESPONSE); + bidResponse.meta = { + networkId: test.input + }; + + events.emit(BID_RESPONSE, bidResponse); + events.emit(BIDDER_DONE, MOCK.BIDDER_DONE); + events.emit(AUCTION_END, MOCK.AUCTION_END); + events.emit(BID_WON, MOCK.BID_WON); + clock.tick(rubiConf.analyticsBatchTimeout + 1000); + + let message = JSON.parse(server.requests[0].requestBody); + expect(message.auctions[0].adUnits[0].bids[0].bidResponse.networkId).to.equal(test.expected); + }); + }); }); describe('with session handling', function () { @@ -1886,19 +1966,21 @@ describe('magnite analytics adapter', function () { }); }); - it('getHostNameFromReferer correctly grabs hostname from an input URL', function () { - let inputUrl = 'https://www.prebid.org/some/path?pbjs_debug=true'; - expect(getHostNameFromReferer(inputUrl)).to.equal('www.prebid.org'); - inputUrl = 'https://www.prebid.com/some/path?pbjs_debug=true'; - expect(getHostNameFromReferer(inputUrl)).to.equal('www.prebid.com'); - inputUrl = 'https://prebid.org/some/path?pbjs_debug=true'; - expect(getHostNameFromReferer(inputUrl)).to.equal('prebid.org'); - inputUrl = 'http://xn--p8j9a0d9c9a.xn--q9jyb4c/'; - expect(typeof getHostNameFromReferer(inputUrl)).to.equal('string'); - - // not non-UTF char's in query / path which break if noDecodeWholeURL not set - inputUrl = 'https://prebid.org/search_results/%95x%8Em%92%CA/?category=000'; - expect(getHostNameFromReferer(inputUrl)).to.equal('prebid.org'); + describe('getHostNameFromReferer', () => { + it('correctly grabs hostname from an input URL', function () { + let inputUrl = 'https://www.prebid.org/some/path?pbjs_debug=true'; + expect(getHostNameFromReferer(inputUrl)).to.equal('www.prebid.org'); + inputUrl = 'https://www.prebid.com/some/path?pbjs_debug=true'; + expect(getHostNameFromReferer(inputUrl)).to.equal('www.prebid.com'); + inputUrl = 'https://prebid.org/some/path?pbjs_debug=true'; + expect(getHostNameFromReferer(inputUrl)).to.equal('prebid.org'); + inputUrl = 'http://xn--p8j9a0d9c9a.xn--q9jyb4c/'; + expect(typeof getHostNameFromReferer(inputUrl)).to.equal('string'); + + // not non-UTF char's in query / path which break if noDecodeWholeURL not set + inputUrl = 'https://prebid.org/search_results/%95x%8Em%92%CA/?category=000'; + expect(getHostNameFromReferer(inputUrl)).to.equal('prebid.org'); + }); }); describe(`handle currency conversions`, () => { @@ -1939,4 +2021,22 @@ describe('magnite analytics adapter', function () { expect(bidResponseObj.bidPriceUSD).to.equal(0); }); }); + + describe('onDataDeletionRequest', () => { + it('attempts to delete the magnite cookie when local storage is enabled', () => { + magniteAdapter.onDataDeletionRequest(); + + expect(removeDataFromLocalStorageStub.getCall(0).args[0]).to.equal('mgniSession'); + }); + + it('throws an error if it cannot access the cookie', (done) => { + localStorageIsEnabledStub.returns(false); + try { + magniteAdapter.onDataDeletionRequest(); + } catch (error) { + expect(error.message).to.equal('Unable to access local storage, no data deleted'); + done(); + } + }) + }); }); diff --git a/test/spec/modules/medianetAnalyticsAdapter_spec.js b/test/spec/modules/medianetAnalyticsAdapter_spec.js index b75437f2ccd..c408f23c4f4 100644 --- a/test/spec/modules/medianetAnalyticsAdapter_spec.js +++ b/test/spec/modules/medianetAnalyticsAdapter_spec.js @@ -3,6 +3,7 @@ import medianetAnalytics from 'modules/medianetAnalyticsAdapter.js'; import * as utils from 'src/utils.js'; import CONSTANTS from 'src/constants.json'; import * as events from 'src/events.js'; +import {clearEvents} from 'src/events.js'; const { EVENTS: { AUCTION_INIT, BID_REQUESTED, BID_RESPONSE, NO_BID, BID_TIMEOUT, AUCTION_END, SET_TARGETING, BID_WON } @@ -127,7 +128,12 @@ describe('Media.net Analytics Adapter', function() { options: { cid: CUSTOMER_ID } - }; + } + + before(() => { + clearEvents(); + }); + beforeEach(function () { sandbox = sinon.sandbox.create(); }); diff --git a/test/spec/modules/medianetRtdProvider_spec.js b/test/spec/modules/medianetRtdProvider_spec.js index 7d73ecd5d44..f9d4ef7c2cf 100644 --- a/test/spec/modules/medianetRtdProvider_spec.js +++ b/test/spec/modules/medianetRtdProvider_spec.js @@ -66,12 +66,12 @@ describe('medianet realtime module', function () { describe('getTargeting should work correctly', function () { it('should return empty if not loaded', function () { window.mnjs.loaded = false; - assert.deepEqual(medianetRTD.medianetRtdModule.getTargetingData([]), {}); + assert.deepEqual(medianetRTD.medianetRtdModule.getTargetingData([], {}, {}, {}), {}); }); it('should return ad unit codes when ad units are present', function () { const adUnitCodes = ['code1', 'code2']; - assert.deepEqual(medianetRTD.medianetRtdModule.getTargetingData(adUnitCodes), { + assert.deepEqual(medianetRTD.medianetRtdModule.getTargetingData(adUnitCodes, {}, {}, {}), { code1: {'mnadc': 'code1'}, code2: {'mnadc': 'code2'}, }); @@ -79,7 +79,7 @@ describe('medianet realtime module', function () { it('should call mnjs.getTargetingData if loaded', function () { window.mnjs.loaded = true; - medianetRTD.medianetRtdModule.getTargetingData([]); + medianetRTD.medianetRtdModule.getTargetingData([], {}, {}, {}); assert.equal(getTargetingDataSpy.called, true); }); }); diff --git a/test/spec/modules/mgidRtdProvider_spec.js b/test/spec/modules/mgidRtdProvider_spec.js new file mode 100644 index 00000000000..4f70b4d8b7c --- /dev/null +++ b/test/spec/modules/mgidRtdProvider_spec.js @@ -0,0 +1,366 @@ +import { mgidSubmodule, storage } from '../../../modules/mgidRtdProvider.js'; +import {expect} from 'chai'; +import * as refererDetection from '../../../src/refererDetection'; + +describe('Mgid RTD submodule', () => { + let server; + let clock; + let getRefererInfoStub; + let getDataFromLocalStorageStub; + + beforeEach(() => { + server = sinon.fakeServer.create(); + + clock = sinon.useFakeTimers(); + + getRefererInfoStub = sinon.stub(refererDetection, 'getRefererInfo'); + getRefererInfoStub.returns({ + canonicalUrl: 'https://www.test.com/abc' + }); + + getDataFromLocalStorageStub = sinon.stub(storage, 'getDataFromLocalStorage').returns('qwerty654321'); + }); + + afterEach(() => { + server.restore(); + clock.restore(); + getRefererInfoStub.restore(); + getDataFromLocalStorageStub.restore(); + }); + + it('init is successfull, when clientSiteId is defined', () => { + expect(mgidSubmodule.init({params: {clientSiteId: 123}})).to.be.true; + }); + + it('init is unsuccessfull, when clientSiteId is not defined', () => { + expect(mgidSubmodule.init({})).to.be.false; + }); + + it('getBidRequestData send all params to our endpoint and succesfully modifies ortb2', () => { + const responseObj = { + userSegments: ['100', '200'], + userSegtax: 5, + siteSegments: ['300', '400'], + siteSegtax: 7, + muid: 'qwerty654321', + }; + + let reqBidsConfigObj = { + ortb2Fragments: { + global: { + site: { + content: { + language: 'en', + } + } + }, + } + }; + + let onDone = sinon.stub(); + + mgidSubmodule.getBidRequestData( + reqBidsConfigObj, + onDone, + {params: {clientSiteId: 123}}, + { + gdpr: { + gdprApplies: true, + consentString: 'testConsent', + }, + usp: '1YYY', + } + ); + + server.requests[0].respond( + 200, + {'Content-Type': 'application/json'}, + JSON.stringify(responseObj) + ); + + const requestUrl = new URL(server.requests[0].url); + expect(requestUrl.host).to.be.eq('servicer.mgid.com'); + expect(requestUrl.searchParams.get('gdprApplies')).to.be.eq('true'); + expect(requestUrl.searchParams.get('consentData')).to.be.eq('testConsent'); + expect(requestUrl.searchParams.get('uspString')).to.be.eq('1YYY'); + expect(requestUrl.searchParams.get('muid')).to.be.eq('qwerty654321'); + expect(requestUrl.searchParams.get('clientSiteId')).to.be.eq('123'); + expect(requestUrl.searchParams.get('cxurl')).to.be.eq('https://www.test.com/abc'); + expect(requestUrl.searchParams.get('cxlang')).to.be.eq('en'); + + assert.deepInclude( + reqBidsConfigObj.ortb2Fragments.global, + { + site: { + content: { + language: 'en', + data: [ + { + name: 'www.mgid.com', + ext: { + segtax: 7 + }, + segment: [ + { id: '300' }, + { id: '400' }, + ] + } + ], + } + }, + user: { + data: [ + { + name: 'www.mgid.com', + ext: { + segtax: 5 + }, + segment: [ + { id: '100' }, + { id: '200' }, + ] + } + ], + }, + }); + }); + + it('getBidRequestData doesn\'t send params (consent and cxlang), if we haven\'t received them', () => { + let reqBidsConfigObj = { + ortb2Fragments: { + global: {}, + } + }; + + let onDone = sinon.stub(); + + mgidSubmodule.getBidRequestData( + reqBidsConfigObj, + onDone, + {params: {clientSiteId: 123}}, + {} + ); + + server.requests[0].respond( + 200, + {'Content-Type': 'application/json'}, + JSON.stringify({}) + ); + + const requestUrl = new URL(server.requests[0].url); + expect(requestUrl.host).to.be.eq('servicer.mgid.com'); + expect(requestUrl.searchParams.get('gdprApplies')).to.be.null; + expect(requestUrl.searchParams.get('consentData')).to.be.null; + expect(requestUrl.searchParams.get('uspString')).to.be.null; + expect(requestUrl.searchParams.get('muid')).to.be.eq('qwerty654321'); + expect(requestUrl.searchParams.get('clientSiteId')).to.be.eq('123'); + expect(requestUrl.searchParams.get('cxurl')).to.be.eq('https://www.test.com/abc'); + expect(requestUrl.searchParams.get('cxlang')).to.be.null; + expect(onDone.calledOnce).to.be.true; + }); + + it('getBidRequestData send gdprApplies event if it is false', () => { + let reqBidsConfigObj = { + ortb2Fragments: { + global: {}, + } + }; + + let onDone = sinon.stub(); + + mgidSubmodule.getBidRequestData( + reqBidsConfigObj, + onDone, + {params: {clientSiteId: 123}}, + { + gdpr: { + gdprApplies: false, + consentString: 'testConsent', + }, + usp: '1YYY', + } + ); + + server.requests[0].respond( + 200, + {'Content-Type': 'application/json'}, + JSON.stringify({}) + ); + + const requestUrl = new URL(server.requests[0].url); + expect(requestUrl.host).to.be.eq('servicer.mgid.com'); + expect(requestUrl.searchParams.get('gdprApplies')).to.be.eq('false'); + expect(requestUrl.searchParams.get('consentData')).to.be.eq('testConsent'); + expect(requestUrl.searchParams.get('uspString')).to.be.eq('1YYY'); + expect(requestUrl.searchParams.get('muid')).to.be.eq('qwerty654321'); + expect(requestUrl.searchParams.get('clientSiteId')).to.be.eq('123'); + expect(requestUrl.searchParams.get('cxurl')).to.be.eq('https://www.test.com/abc'); + expect(requestUrl.searchParams.get('cxlang')).to.be.null; + expect(onDone.calledOnce).to.be.true; + }); + + it('getBidRequestData use og:url for cxurl, if it is available', () => { + let reqBidsConfigObj = { + ortb2Fragments: { + global: {}, + } + }; + + let onDone = sinon.stub(); + + let metaStub = sinon.stub(document, 'getElementsByTagName').returns([ + { getAttribute: () => 'og:test', content: 'fake' }, + { getAttribute: () => 'og:url', content: 'https://realOgUrl.com/' } + ]); + + mgidSubmodule.getBidRequestData( + reqBidsConfigObj, + onDone, + {params: {clientSiteId: 123}}, + {} + ); + + server.requests[0].respond( + 200, + {'Content-Type': 'application/json'}, + JSON.stringify({}) + ); + + const requestUrl = new URL(server.requests[0].url); + expect(requestUrl.searchParams.get('cxurl')).to.be.eq('https://realOgUrl.com/'); + expect(onDone.calledOnce).to.be.true; + + metaStub.restore(); + }); + + it('getBidRequestData use topMostLocation for cxurl, if nothing else left', () => { + let reqBidsConfigObj = { + ortb2Fragments: { + global: {}, + } + }; + + let onDone = sinon.stub(); + + getRefererInfoStub.returns({ + topmostLocation: 'https://www.test.com/topMost' + }); + + mgidSubmodule.getBidRequestData( + reqBidsConfigObj, + onDone, + {params: {clientSiteId: 123}}, + {} + ); + + server.requests[0].respond( + 200, + {'Content-Type': 'application/json'}, + JSON.stringify({}) + ); + + const requestUrl = new URL(server.requests[0].url); + expect(requestUrl.searchParams.get('cxurl')).to.be.eq('https://www.test.com/topMost'); + expect(onDone.calledOnce).to.be.true; + }); + + it('getBidRequestData won\'t modify ortb2 if response is broken', () => { + let reqBidsConfigObj = { + ortb2Fragments: { + global: {}, + } + }; + + let onDone = sinon.stub(); + + mgidSubmodule.getBidRequestData( + reqBidsConfigObj, + onDone, + {params: {clientSiteId: 123}}, + {} + ); + + server.requests[0].respond( + 200, + {'Content-Type': 'application/json'}, + '{' + ); + + assert.deepEqual(reqBidsConfigObj.ortb2Fragments.global, {}); + expect(onDone.calledOnce).to.be.true; + }); + + it('getBidRequestData won\'t modify ortb2 if response status is not 200', () => { + let reqBidsConfigObj = { + ortb2Fragments: { + global: {}, + } + }; + + let onDone = sinon.stub(); + + mgidSubmodule.getBidRequestData( + reqBidsConfigObj, + onDone, + {params: {clientSiteId: 123}}, + {} + ); + + server.requests[0].respond( + 204, + {'Content-Type': 'application/json'}, + '{}' + ); + + assert.deepEqual(reqBidsConfigObj.ortb2Fragments.global, {}); + expect(onDone.calledOnce).to.be.true; + }); + + it('getBidRequestData won\'t modify ortb2 if response results in error', () => { + let reqBidsConfigObj = { + ortb2Fragments: { + global: {}, + } + }; + + let onDone = sinon.stub(); + + mgidSubmodule.getBidRequestData( + reqBidsConfigObj, + onDone, + {params: {clientSiteId: 123}}, + {} + ); + + server.requests[0].respond( + 500, + {'Content-Type': 'application/json'}, + '{}' + ); + + assert.deepEqual(reqBidsConfigObj.ortb2Fragments.global, {}); + expect(onDone.calledOnce).to.be.true; + }); + + it('getBidRequestData won\'t modify ortb2 if response time hits timeout', () => { + let reqBidsConfigObj = { + ortb2Fragments: { + global: {}, + } + }; + + let onDone = sinon.stub(); + + mgidSubmodule.getBidRequestData( + reqBidsConfigObj, + onDone, + {params: {clientSiteId: 123, timeout: 500}}, + {} + ); + + clock.tick(510); + + assert.deepEqual(reqBidsConfigObj.ortb2Fragments.global, {}); + expect(onDone.calledOnce).to.be.true; + }); +}); diff --git a/test/spec/modules/microadBidAdapter_spec.js b/test/spec/modules/microadBidAdapter_spec.js index cca337c83f2..98edfce20bc 100644 --- a/test/spec/modules/microadBidAdapter_spec.js +++ b/test/spec/modules/microadBidAdapter_spec.js @@ -330,6 +330,54 @@ describe('microadBidAdapter', () => { }) }) }) + + Object.entries({ + 'ID5 ID': { + userId: {id5id: {uid: 'id5id-sample'}}, + userIdAsEids: [ + { + source: 'id5-sync.com', + uids: [{id: 'id5id-sample', aType: 1, ext: {linkType: 2, abTestingControlGroup: false}}] + } + ], + expected: { + aids: JSON.stringify([{type: 8, id: 'id5id-sample', ext: {linkType: 2, abTestingControlGroup: false}}]) + } + }, + 'Unified ID': { + userId: {tdid: 'unified-sample'}, + userIdAsEids: [ + { + source: 'adserver.org', + uids: [{id: 'unified-sample', aType: 1, ext: {rtiPartner: 'TDID'}}] + } + ], + expected: {aids: JSON.stringify([{type: 9, id: 'unified-sample', ext: {rtiPartner: 'TDID'}}])} + }, + 'not add': { + userId: {id5id: {uid: 'id5id-sample'}}, + userIdAsEids: [], + expected: { + aids: JSON.stringify([{type: 8, id: 'id5id-sample'}]) + } + } + }).forEach(([test, arg]) => { + it(`should ${test} ext if it is available in request parameters`, () => { + const bidRequestWithUserId = { + ...bidRequestTemplate, + userId: arg.userId, + userIdAsEids: arg.userIdAsEids + } + const requests = spec.buildRequests([bidRequestWithUserId], bidderRequest) + requests.forEach((request) => { + expect(request.data).to.deep.equal({ + ...expectedResultTemplate, + cbt: request.data.cbt, + ...arg.expected + }) + }) + }); + }) }); describe('interpretResponse', () => { diff --git a/test/spec/modules/minutemediaplusBidAdapter_spec.js b/test/spec/modules/minutemediaplusBidAdapter_spec.js new file mode 100644 index 00000000000..de38554f010 --- /dev/null +++ b/test/spec/modules/minutemediaplusBidAdapter_spec.js @@ -0,0 +1,519 @@ +import { expect } from 'chai'; +import { + spec as adapter, + SUPPORTED_ID_SYSTEMS, + createDomain, + hashCode, + extractPID, + extractCID, + extractSubDomain, + getStorageItem, + setStorageItem, + tryParseJSON, + getUniqueDealId, +} from 'modules/minutemediaplusBidAdapter.js'; +import * as utils from 'src/utils.js'; +import { version } from 'package.json'; +import { useFakeTimers } from 'sinon'; +import { BANNER, VIDEO } from '../../../src/mediaTypes'; + +const SUB_DOMAIN = 'exchange'; + +const BID = { + 'bidId': '2d52001cabd527', + 'adUnitCode': 'div-gpt-ad-12345-0', + 'params': { + 'subDomain': SUB_DOMAIN, + 'cId': '59db6b3b4ffaa70004f45cdc', + 'pId': '59ac17c192832d0011283fe3', + 'bidFloor': 0.1, + 'ext': { + 'param1': 'loremipsum', + 'param2': 'dolorsitamet' + } + }, + 'placementCode': 'div-gpt-ad-1460505748561-0', + 'transactionId': 'c881914b-a3b5-4ecf-ad9c-1c2f37c6aabf', + 'sizes': [[300, 250], [300, 600]], + 'bidderRequestId': '1fdb5ff1b6eaa7', + 'requestId': 'b0777d85-d061-450e-9bc7-260dd54bbb7a', + 'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc', + 'mediaTypes': [BANNER] +}; + +const VIDEO_BID = { + 'bidId': '2d52001cabd527', + 'adUnitCode': '63550ad1ff6642d368cba59dh5884270560', + 'bidderRequestId': '12a8ae9ada9c13', + 'transactionId': '56e184c6-bde9-497b-b9b9-cf47a61381ee', + 'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc', + 'params': { + 'subDomain': SUB_DOMAIN, + 'cId': '635509f7ff6642d368cb9837', + 'pId': '59ac17c192832d0011283fe3', + 'bidFloor': 0.1 + }, + 'sizes': [[545, 307]], + 'mediaTypes': { + 'video': { + 'playerSize': [[545, 307]], + 'context': 'instream', + 'mimes': [ + 'video/mp4', + 'application/javascript' + ], + 'protocols': [2, 3, 5, 6], + 'maxduration': 60, + 'minduration': 0, + 'startdelay': 0, + 'linearity': 1, + 'api': [2], + 'placement': 1 + } + } +} + +const BIDDER_REQUEST = { + 'gdprConsent': { + 'consentString': 'consent_string', + 'gdprApplies': true + }, + 'uspConsent': 'consent_string', + 'refererInfo': { + 'page': 'https://www.greatsite.com', + 'ref': 'https://www.somereferrer.com' + } +}; + +const SERVER_RESPONSE = { + body: { + cid: 'testcid123', + results: [{ + 'ad': '', + 'price': 0.8, + 'creativeId': '12610997325162499419', + 'exp': 30, + 'width': 300, + 'height': 250, + 'advertiserDomains': ['securepubads.g.doubleclick.net'], + 'cookies': [{ + 'src': 'https://sync.com', + 'type': 'iframe' + }, { + 'src': 'https://sync.com', + 'type': 'img' + }] + }] + } +}; + +const VIDEO_SERVER_RESPONSE = { + body: { + 'cid': '635509f7ff6642d368cb9837', + 'results': [{ + 'ad': '', + 'advertiserDomains': ['minutemedia-prebid.com'], + 'exp': 60, + 'width': 545, + 'height': 307, + 'mediaType': 'video', + 'creativeId': '12610997325162499419', + 'price': 2, + 'cookies': [] + }] + } +}; + +const REQUEST = { + data: { + width: 300, + height: 250, + bidId: '2d52001cabd527' + } +}; + +function getTopWindowQueryParams() { + try { + const parsedUrl = utils.parseUrl(window.top.document.URL, { decodeSearchAsString: true }); + return parsedUrl.search; + } catch (e) { + return ''; + } +} + +describe('MinuteMediaPlus Bid Adapter', function () { + describe('validtae spec', function () { + it('exists and is a function', function () { + expect(adapter.isBidRequestValid).to.exist.and.to.be.a('function'); + }); + + it('exists and is a function', function () { + expect(adapter.buildRequests).to.exist.and.to.be.a('function'); + }); + + it('exists and is a function', function () { + expect(adapter.interpretResponse).to.exist.and.to.be.a('function'); + }); + + it('exists and is a function', function () { + expect(adapter.getUserSyncs).to.exist.and.to.be.a('function'); + }); + + it('exists and is a string', function () { + expect(adapter.code).to.exist.and.to.be.a('string'); + }); + + it('exists and contains media types', function () { + expect(adapter.supportedMediaTypes).to.exist.and.to.be.an('array').with.length(2); + expect(adapter.supportedMediaTypes).to.contain.members([BANNER, VIDEO]); + }); + }); + + describe('validate bid requests', function () { + it('should require cId', function () { + const isValid = adapter.isBidRequestValid({ + params: { + pId: 'pid' + } + }); + expect(isValid).to.be.false; + }); + + it('should require pId', function () { + const isValid = adapter.isBidRequestValid({ + params: { + cId: 'cid' + } + }); + expect(isValid).to.be.false; + }); + + it('should validate correctly', function () { + const isValid = adapter.isBidRequestValid({ + params: { + cId: 'cid', + pId: 'pid' + } + }); + expect(isValid).to.be.true; + }); + }); + + describe('build requests', function () { + let sandbox; + before(function () { + $$PREBID_GLOBAL$$.bidderSettings = { + mmplus: { + storageAllowed: true + } + }; + sandbox = sinon.sandbox.create(); + sandbox.stub(Date, 'now').returns(1000); + }); + + it('should build video request', function () { + const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.page); + const requests = adapter.buildRequests([VIDEO_BID], BIDDER_REQUEST); + expect(requests).to.have.length(1); + expect(requests[0]).to.deep.equal({ + method: 'POST', + url: `${createDomain(SUB_DOMAIN)}/prebid/multi/635509f7ff6642d368cb9837`, + data: { + adUnitCode: '63550ad1ff6642d368cba59dh5884270560', + bidFloor: 0.1, + bidId: '2d52001cabd527', + bidderVersion: adapter.version, + cb: 1000, + gdpr: 1, + gdprConsent: 'consent_string', + usPrivacy: 'consent_string', + prebidVersion: version, + publisherId: '59ac17c192832d0011283fe3', + url: 'https%3A%2F%2Fwww.greatsite.com', + referrer: 'https://www.somereferrer.com', + res: `${window.top.screen.width}x${window.top.screen.height}`, + schain: VIDEO_BID.schain, + sizes: ['545x307'], + uniqueDealId: `${hashUrl}_${Date.now().toString()}`, + uqs: getTopWindowQueryParams(), + mediaTypes: { + video: { + api: [2], + context: 'instream', + linearity: 1, + maxduration: 60, + mimes: [ + 'video/mp4', + 'application/javascript' + ], + minduration: 0, + placement: 1, + playerSize: [[545, 307]], + protocols: [2, 3, 5, 6], + startdelay: 0 + } + } + } + }); + }); + + it('should build banner request for each size', function () { + const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.page); + const requests = adapter.buildRequests([BID], BIDDER_REQUEST); + expect(requests).to.have.length(1); + expect(requests[0]).to.deep.equal({ + method: 'POST', + url: `${createDomain(SUB_DOMAIN)}/prebid/multi/59db6b3b4ffaa70004f45cdc`, + data: { + gdprConsent: 'consent_string', + gdpr: 1, + usPrivacy: 'consent_string', + sizes: ['300x250', '300x600'], + url: 'https%3A%2F%2Fwww.greatsite.com', + referrer: 'https://www.somereferrer.com', + cb: 1000, + bidFloor: 0.1, + bidId: '2d52001cabd527', + adUnitCode: 'div-gpt-ad-12345-0', + publisherId: '59ac17c192832d0011283fe3', + uniqueDealId: `${hashUrl}_${Date.now().toString()}`, + bidderVersion: adapter.version, + prebidVersion: version, + schain: BID.schain, + res: `${window.top.screen.width}x${window.top.screen.height}`, + mediaTypes: [BANNER], + uqs: getTopWindowQueryParams(), + 'ext.param1': 'loremipsum', + 'ext.param2': 'dolorsitamet', + } + }); + }); + + after(function () { + $$PREBID_GLOBAL$$.bidderSettings = {}; + sandbox.restore(); + }); + }); + describe('getUserSyncs', function () { + it('should have valid user sync with iframeEnabled', function () { + const result = adapter.getUserSyncs({ iframeEnabled: true }, [SERVER_RESPONSE]); + + expect(result).to.deep.equal([{ + type: 'iframe', + url: 'https://sync.minutemedia-prebid.com/api/sync/iframe/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=' + }]); + }); + + it('should have valid user sync with cid on response', function () { + const result = adapter.getUserSyncs({ iframeEnabled: true }, [SERVER_RESPONSE]); + expect(result).to.deep.equal([{ + type: 'iframe', + url: 'https://sync.minutemedia-prebid.com/api/sync/iframe/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=' + }]); + }); + + it('should have valid user sync with pixelEnabled', function () { + const result = adapter.getUserSyncs({ pixelEnabled: true }, [SERVER_RESPONSE]); + + expect(result).to.deep.equal([{ + 'url': 'https://sync.minutemedia-prebid.com/api/sync/image/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=', + 'type': 'image' + }]); + }) + }); + + describe('interpret response', function () { + it('should return empty array when there is no response', function () { + const responses = adapter.interpretResponse(null); + expect(responses).to.be.empty; + }); + + it('should return empty array when there is no ad', function () { + const responses = adapter.interpretResponse({ price: 1, ad: '' }); + expect(responses).to.be.empty; + }); + + it('should return empty array when there is no price', function () { + const responses = adapter.interpretResponse({ price: null, ad: 'great ad' }); + expect(responses).to.be.empty; + }); + + it('should return an array of interpreted banner responses', function () { + const responses = adapter.interpretResponse(SERVER_RESPONSE, REQUEST); + expect(responses).to.have.length(1); + expect(responses[0]).to.deep.equal({ + requestId: '2d52001cabd527', + cpm: 0.8, + width: 300, + height: 250, + creativeId: '12610997325162499419', + currency: 'USD', + netRevenue: true, + ttl: 30, + ad: '', + meta: { + advertiserDomains: ['securepubads.g.doubleclick.net'] + } + }); + }); + + it('should return an array of interpreted video responses', function () { + const responses = adapter.interpretResponse(VIDEO_SERVER_RESPONSE, REQUEST); + expect(responses).to.have.length(1); + expect(responses[0]).to.deep.equal({ + requestId: '2d52001cabd527', + cpm: 2, + width: 545, + height: 307, + mediaType: 'video', + creativeId: '12610997325162499419', + currency: 'USD', + netRevenue: true, + ttl: 60, + vastXml: '', + meta: { + advertiserDomains: ['minutemedia-prebid.com'] + } + }); + }); + + it('should take default TTL', function () { + const serverResponse = utils.deepClone(SERVER_RESPONSE); + delete serverResponse.body.results[0].exp; + const responses = adapter.interpretResponse(serverResponse, REQUEST); + expect(responses).to.have.length(1); + expect(responses[0].ttl).to.equal(300); + }); + }); + + describe('user id system', function () { + Object.keys(SUPPORTED_ID_SYSTEMS).forEach((idSystemProvider) => { + const id = Date.now().toString(); + const bid = utils.deepClone(BID); + + const userId = (function () { + switch (idSystemProvider) { + case 'lipb': + return { lipbid: id }; + case 'parrableId': + return { eid: id }; + case 'id5id': + return { uid: id }; + default: + return id; + } + })(); + + bid.userId = { + [idSystemProvider]: userId + }; + + it(`should include 'uid.${idSystemProvider}' in request params`, function () { + const requests = adapter.buildRequests([bid], BIDDER_REQUEST); + expect(requests[0].data[`uid.${idSystemProvider}`]).to.equal(id); + }); + }); + }); + + describe('alternate param names extractors', function () { + it('should return undefined when param not supported', function () { + const cid = extractCID({ 'c_id': '1' }); + const pid = extractPID({ 'p_id': '1' }); + const subDomain = extractSubDomain({ 'sub_domain': 'prebid' }); + expect(cid).to.be.undefined; + expect(pid).to.be.undefined; + expect(subDomain).to.be.undefined; + }); + + it('should return value when param supported', function () { + const cid = extractCID({ 'cID': '1' }); + const pid = extractPID({ 'Pid': '2' }); + const subDomain = extractSubDomain({ 'subDOMAIN': 'prebid' }); + expect(cid).to.be.equal('1'); + expect(pid).to.be.equal('2'); + expect(subDomain).to.be.equal('prebid'); + }); + }); + + describe('unique deal id', function () { + before(function () { + $$PREBID_GLOBAL$$.bidderSettings = { + mmplus: { + storageAllowed: true + } + }; + }); + after(function () { + $$PREBID_GLOBAL$$.bidderSettings = {}; + }); + const key = 'myKey'; + let uniqueDealId; + beforeEach(() => { + uniqueDealId = getUniqueDealId(key, 0); + }) + + it('should get current unique deal id', function (done) { + // waiting some time so `now` will become past + setTimeout(() => { + const current = getUniqueDealId(key); + expect(current).to.be.equal(uniqueDealId); + done(); + }, 200); + }); + + it('should get new unique deal id on expiration', function (done) { + setTimeout(() => { + const current = getUniqueDealId(key, 100); + expect(current).to.not.be.equal(uniqueDealId); + done(); + }, 200) + }); + }); + + describe('storage utils', function () { + before(function () { + $$PREBID_GLOBAL$$.bidderSettings = { + mmplus: { + storageAllowed: true + } + }; + }); + after(function () { + $$PREBID_GLOBAL$$.bidderSettings = {}; + }); + it('should get value from storage with create param', function () { + const now = Date.now(); + const clock = useFakeTimers({ + shouldAdvanceTime: true, + now + }); + setStorageItem('myKey', 2020); + const { value, created } = getStorageItem('myKey'); + expect(created).to.be.equal(now); + expect(value).to.be.equal(2020); + expect(typeof value).to.be.equal('number'); + expect(typeof created).to.be.equal('number'); + clock.restore(); + }); + + it('should get external stored value', function () { + const value = 'superman' + window.localStorage.setItem('myExternalKey', value); + const item = getStorageItem('myExternalKey'); + expect(item).to.be.equal(value); + }); + + it('should parse JSON value', function () { + const data = JSON.stringify({ event: 'send' }); + const { event } = tryParseJSON(data); + expect(event).to.be.equal('send'); + }); + + it('should get original value on parse fail', function () { + const value = 21; + const parsed = tryParseJSON(value); + expect(typeof parsed).to.be.equal('number'); + expect(parsed).to.be.equal(value); + }); + }); +}); diff --git a/test/spec/modules/missenaBidAdapter_spec.js b/test/spec/modules/missenaBidAdapter_spec.js index 157137b4730..f61987298e8 100644 --- a/test/spec/modules/missenaBidAdapter_spec.js +++ b/test/spec/modules/missenaBidAdapter_spec.js @@ -13,6 +13,8 @@ describe('Missena Adapter', function () { sizes: [[1, 1]], params: { apiKey: 'PA-34745704', + placement: 'sticky', + formats: ['sticky-banner'], }, }; @@ -70,6 +72,14 @@ describe('Missena Adapter', function () { expect(payload.request_id).to.equal(bidId); }); + it('should send placement', function () { + expect(payload.placement).to.equal('sticky'); + }); + + it('should send formats', function () { + expect(payload.formats).to.eql(['sticky-banner']); + }); + it('should send referer information to the request', function () { expect(payload.referer).to.equal('https://referer'); expect(payload.referer_canonical).to.equal('https://canonical'); diff --git a/test/spec/modules/nativoBidAdapter_spec.js b/test/spec/modules/nativoBidAdapter_spec.js index 4cd4c92281b..4d70e6f7071 100644 --- a/test/spec/modules/nativoBidAdapter_spec.js +++ b/test/spec/modules/nativoBidAdapter_spec.js @@ -5,6 +5,9 @@ import { getMediaWildcardPrices, sizeToString, parseFloorPriceData, + getPageUrlFromBidRequest, + hasProtocol, + addProtocol, } from '../../../modules/nativoBidAdapter' describe('bidDataMap', function () { @@ -647,3 +650,84 @@ describe('parseFloorPriceData', () => { }) }) }) + +describe('hasProtocol', () => { + it('https://www.testpage.com', () => { + expect(hasProtocol('https://www.testpage.com')).to.be.true + }) + it('http://www.testpage.com', () => { + expect(hasProtocol('http://www.testpage.com')).to.be.true + }) + it('//www.testpage.com', () => { + expect(hasProtocol('//www.testpage.com')).to.be.false + }) + it('www.testpage.com', () => { + expect(hasProtocol('www.testpage.com')).to.be.false + }) + it('httpsgsjhgflih', () => { + expect(hasProtocol('httpsgsjhgflih')).to.be.false + }) +}) + +describe('addProtocol', () => { + it('www.testpage.com', () => { + expect(addProtocol('www.testpage.com')).to.be.equal('https://www.testpage.com') + }) + it('//www.testpage.com', () => { + expect(addProtocol('//www.testpage.com')).to.be.equal('https://www.testpage.com') + }) + it('http://www.testpage.com', () => { + expect(addProtocol('http://www.testpage.com')).to.be.equal('http://www.testpage.com') + }) + it('https://www.testpage.com', () => { + expect(addProtocol('https://www.testpage.com')).to.be.equal('https://www.testpage.com') + }) +}) + +describe('getPageUrlFromBidRequest', () => { + const bidRequest = {} + + beforeEach(() => { + bidRequest.params = {} + }) + + it('Returns undefined for no url param', () => { + const url = getPageUrlFromBidRequest(bidRequest) + expect(url).to.be.undefined + }) + + it('@testUrl', () => { + const url = getPageUrlFromBidRequest(bidRequest) + expect(url).to.be.undefined + }) + + it('https://www.testpage.com', () => { + bidRequest.params.url = 'https://www.testpage.com' + const url = getPageUrlFromBidRequest(bidRequest) + expect(url).not.to.be.undefined + }) + + it('https://www.testpage.com/test/path', () => { + bidRequest.params.url = 'https://www.testpage.com/test/path' + const url = getPageUrlFromBidRequest(bidRequest) + expect(url).not.to.be.undefined + }) + + it('www.testpage.com', () => { + bidRequest.params.url = 'www.testpage.com' + const url = getPageUrlFromBidRequest(bidRequest) + expect(url).not.to.be.undefined + }) + + it('http://www.testpage.com', () => { + bidRequest.params.url = 'http://www.testpage.com' + const url = getPageUrlFromBidRequest(bidRequest) + expect(url).not.to.be.undefined + }) + + it('//www.testpage.com', () => { + bidRequest.params.url = '//www.testpage.com' + const url = getPageUrlFromBidRequest(bidRequest) + expect(url).not.to.be.undefined + }) +}) diff --git a/test/spec/modules/neuwoRtdProvider_spec.js b/test/spec/modules/neuwoRtdProvider_spec.js new file mode 100644 index 00000000000..aed9634cd95 --- /dev/null +++ b/test/spec/modules/neuwoRtdProvider_spec.js @@ -0,0 +1,124 @@ +import { server } from 'test/mocks/xhr.js'; +import * as neuwo from 'modules/neuwoRtdProvider'; + +const PUBLIC_TOKEN = 'public_key_0000'; +const config = () => ({ + params: { + publicToken: PUBLIC_TOKEN, + apiUrl: 'https://testing-requirement.neuwo.api' + } +}) + +const apiReturns = () => ({ + somethingExtra: { object: true }, + marketing_categories: { + iab_tier_1: [ + { ID: 'IAB21', label: 'Real Estate', relevance: '0.45699' } + ] + } +}) + +const TAX_ID = '441' + +/** + * Object generator, like above, written using alternative techniques + * @returns object with predefined (expected) bidsConfig fields + */ +function bidsConfiglike() { + return Object.assign({}, { + ortb2Fragments: { global: {} } + }) +} + +describe('neuwoRtdProvider', function () { + describe('neuwoRtdModule', function () { + it('initializes', function () { + expect(neuwo.neuwoRtdModule.init(config())).to.be.true; + }) + it('init needs that public token', function () { + expect(neuwo.neuwoRtdModule.init()).to.be.false; + }) + + describe('segment picking', function () { + it('handles bad inputs', function () { + expect(neuwo.pickSegments()).to.be.an('array').that.is.empty; + expect(neuwo.pickSegments('technically also an array')).to.be.an('array').that.is.empty; + expect(neuwo.pickSegments({ bad_object: 'bad' })).to.be.an('array').that.is.empty; + }) + it('handles malformations', function () { + let result = neuwo.pickSegments([{something_wrong: true}, null, { ID: 'IAB19-20' }, { id: 'IAB3-1', ID: 'IAB9-20' }]) + expect(result[0].id).to.equal('631') + expect(result[1].id).to.equal('58') + expect(result.length).to.equal(2) + }) + }) + + describe('topic injection', function () { + it('mutates bidsConfig', function () { + let topics = apiReturns() + let bidsConfig = bidsConfiglike() + neuwo.injectTopics(topics, bidsConfig, () => { }) + expect(bidsConfig.ortb2Fragments.global.site.content.data[0].name, 'name of first content data object').to.equal(neuwo.DATA_PROVIDER) + expect(bidsConfig.ortb2Fragments.global.site.content.data[0].segment[0].id, 'id of first segment in content.data').to.equal(TAX_ID) + expect(bidsConfig.ortb2Fragments.global.site.cattax, 'category taxonomy code for pagecat').to.equal(6) // CATTAX_IAB + expect(bidsConfig.ortb2Fragments.global.site.pagecat[0], 'category taxonomy code for pagecat').to.equal(TAX_ID) + }) + + it('handles malformed responses', function () { + let topics = { message: 'Forbidden' } + let bidsConfig = bidsConfiglike() + neuwo.injectTopics(topics, bidsConfig, () => { }) + expect(bidsConfig.ortb2Fragments.global.site.content.data[0].name, 'name of first content data object').to.equal(neuwo.DATA_PROVIDER) + expect(bidsConfig.ortb2Fragments.global.site.content.data[0].segment, 'length of segment(s) in content.data').to.be.an('array').that.is.empty; + + topics = '404 wouldn\'t really even show up for injection' + let bdsConfig = bidsConfiglike() + neuwo.injectTopics(topics, bdsConfig, () => { }) + expect(bdsConfig.ortb2Fragments.global.site.content.data[0].name, 'name of first content data object').to.equal(neuwo.DATA_PROVIDER) + expect(bdsConfig.ortb2Fragments.global.site.content.data[0].segment, 'length of segment(s) in content.data').to.be.an('array').that.is.empty; + + topics = undefined + let bdsConfigE = bidsConfiglike() + neuwo.injectTopics(topics, bdsConfigE, () => { }) + expect(bdsConfigE.ortb2Fragments.global.site.content.data[0].name, 'name of first content data object').to.equal(neuwo.DATA_PROVIDER) + expect(bdsConfigE.ortb2Fragments.global.site.content.data[0].segment, 'length of segment(s) in content.data').to.be.an('array').that.is.empty; + }) + }) + + describe('fragment addition', function () { + it('mutates input objects', function () { + let alphabet = { a: { b: { c: {} } } } + neuwo.addFragment(alphabet.a.b.c, 'd.e.f', { g: 'h' }) + expect(alphabet.a.b.c.d.e.f.g).to.equal('h') + }) + }) + + describe('getBidRequestData', function () { + it('forms requests properly and mutates input bidsConfig', function () { + let bids = bidsConfiglike() + let conf = config() + // control xhr api request target for testing + conf.params.argUrl = 'https://publisher.works/article.php?get=horrible_url_for_testing&id=5' + + neuwo.getBidRequestData(bids, () => { }, conf, 'any consent data works, clearly') + + let request = server.requests[0]; + expect(request.url).to.be.a('string').that.includes(conf.params.publicToken) + expect(request.url).to.include(encodeURIComponent(conf.params.argUrl)) + request.respond(200, { 'Content-Type': 'application/json; encoding=UTF-8' }, JSON.stringify(apiReturns())); + + expect(bids.ortb2Fragments.global.site.content.data[0].name, 'name of first content data object').to.equal(neuwo.DATA_PROVIDER) + expect(bids.ortb2Fragments.global.site.content.data[0].segment[0].id, 'id of first segment in content.data').to.equal(TAX_ID) + }) + + it('accepts detail not available result', function () { + let bidsConfig = bidsConfiglike() + let comparison = bidsConfiglike() + neuwo.getBidRequestData(bidsConfig, () => { }, config(), 'consensually') + let request = server.requests[0]; + request.respond(404, { 'Content-Type': 'application/json; encoding=UTF-8' }, JSON.stringify({ detail: 'Basically first time seeing this' })); + expect(bidsConfig).to.deep.equal(comparison) + }) + }) + }) +}) diff --git a/test/spec/modules/nextMillenniumBidAdapter_spec.js b/test/spec/modules/nextMillenniumBidAdapter_spec.js index 36920245070..7f40e7d89f8 100644 --- a/test/spec/modules/nextMillenniumBidAdapter_spec.js +++ b/test/spec/modules/nextMillenniumBidAdapter_spec.js @@ -28,6 +28,34 @@ describe('nextMillenniumBidAdapterTests', function() { } ]; + const serverResponse = { + body: { + id: 'f7b3d2da-e762-410c-b069-424f92c4c4b2', + seatbid: [ + { + bid: [ + { + id: '7457329903666272789', + price: 0.5, + adm: 'Hello! It\'s a test ad!', + adid: '96846035', + adomain: ['test.addomain.com'], + w: 300, + h: 250 + } + ] + } + ], + cur: 'USD', + ext: { + sync: { + image: ['urlA?gdpr={{.GDPR}}'], + iframe: ['urlB'], + } + } + } + }; + const bidRequestDataGI = [ { adUnitCode: 'test-banner-gi', @@ -96,6 +124,47 @@ describe('nextMillenniumBidAdapterTests', function() { expect(JSON.parse(request[0].data).regs.ext.gdpr).to.equal(1); }); + it('Test getUserSyncs function', function () { + const syncOptions = { + 'iframeEnabled': false, + 'pixelEnabled': true + } + let userSync = spec.getUserSyncs(syncOptions, [serverResponse], bidRequestData[0].gdprConsent, bidRequestData[0].uspConsent); + expect(userSync).to.be.an('array').with.lengthOf(1); + expect(userSync[0].type).to.equal('image'); + expect(userSync[0].url).to.equal('urlA?gdpr=1'); + + syncOptions.iframeEnabled = true; + syncOptions.pixelEnabled = false; + userSync = spec.getUserSyncs(syncOptions, [serverResponse], bidRequestData[0].gdprConsent, bidRequestData[0].uspConsent); + expect(userSync).to.be.an('array').with.lengthOf(1); + expect(userSync[0].type).to.equal('iframe'); + expect(userSync[0].url).to.equal('urlB'); + }); + + it('Test getUserSyncs with no response', function () { + const syncOptions = { + 'iframeEnabled': true, + 'pixelEnabled': false + } + let userSync = spec.getUserSyncs(syncOptions, [], bidRequestData[0].gdprConsent, bidRequestData[0].uspConsent); + expect(userSync).to.be.an('array') + expect(userSync[0].type).to.equal('iframe') + expect(userSync[0].url).to.equal('https://cookies.nextmillmedia.com/sync?gdpr=1&gdpr_consent=kjfdniwjnifwenrif3&us_privacy=1---&type=iframe') + }) + + it('Test getUserSyncs function if GDPR is undefined', function () { + const syncOptions = { + 'iframeEnabled': false, + 'pixelEnabled': true + } + + let userSync = spec.getUserSyncs(syncOptions, [serverResponse], undefined, bidRequestData[0].uspConsent); + expect(userSync).to.be.an('array').with.lengthOf(1); + expect(userSync[0].type).to.equal('image'); + expect(userSync[0].url).to.equal('urlA?gdpr=0'); + }); + it('Request params check without GDPR Consent', function () { delete bidRequestData[0].gdprConsent const request = spec.buildRequests(bidRequestData, bidRequestData[0]); @@ -137,50 +206,16 @@ describe('nextMillenniumBidAdapterTests', function() { it('Check if imp object was added', function() { const request = spec.buildRequests(bidRequestData) expect(JSON.parse(request[0].data).imp).to.be.an('array') - }) + }); it('Check if imp prebid stored id is correct', function() { const request = spec.buildRequests(bidRequestData) const requestData = JSON.parse(request[0].data); const storedReqId = requestData.ext.prebid.storedrequest.id; expect(requestData.imp[0].ext.prebid.storedrequest.id).to.equal(storedReqId) - }) - - it('Test getUserSyncs function', function () { - const syncOptions = { - 'iframeEnabled': true - } - const userSync = spec.getUserSyncs(syncOptions); - expect(userSync).to.be.an('array').with.lengthOf(1); - expect(userSync[0].type).to.exist; - expect(userSync[0].url).to.exist; - expect(userSync[0].type).to.be.equal('iframe'); - expect(userSync[0].url).to.be.equal('https://statics.nextmillmedia.com/load-cookie.html?v=4'); }); it('validate_response_params', function() { - const serverResponse = { - body: { - id: 'f7b3d2da-e762-410c-b069-424f92c4c4b2', - seatbid: [ - { - bid: [ - { - id: '7457329903666272789', - price: 0.5, - adm: 'Hello! It\'s a test ad!', - adid: '96846035', - adomain: ['test.addomain.com'], - w: 300, - h: 250 - } - ] - } - ], - cur: 'USD' - } - }; - let bids = spec.interpretResponse(serverResponse, bidRequestData[0]); expect(bids).to.have.lengthOf(1); @@ -275,4 +310,137 @@ describe('nextMillenniumBidAdapterTests', function() { expect(bid.height).to.equal(250); expect(bid.currency).to.equal('USD'); }); + + it('Check function of getting URL for sending statistics data', function() { + const dataForTests = [ + { + eventName: 'bidRequested', + bid: { + bidderCode: 'appnexus', + bids: [{bidder: 'appnexus', params: {}}], + }, + + expected: undefined, + }, + + { + eventName: 'bidRequested', + bid: { + bidderCode: 'appnexus', + bids: [{bidder: 'appnexus', params: {placement_id: '807'}}], + }, + + expected: undefined, + }, + + { + eventName: 'bidRequested', + bid: { + bidderCode: 'nextMillennium', + bids: [{bidder: 'nextMillennium', params: {placement_id: '807'}}], + }, + + expected: 'https://report2.hb.brainlyads.com/statistics/metric?event=bidRequested&bidder=nextMillennium&source=pbjs&placements=807', + }, + + { + eventName: 'bidRequested', + bid: { + bidderCode: 'nextMillennium', + bids: [ + {bidder: 'nextMillennium', params: {placement_id: '807'}}, + {bidder: 'nextMillennium', params: {placement_id: '111'}}, + ], + }, + + expected: 'https://report2.hb.brainlyads.com/statistics/metric?event=bidRequested&bidder=nextMillennium&source=pbjs&placements=807;111', + }, + + { + eventName: 'bidRequested', + bid: { + bidderCode: 'nextMillennium', + bids: [{bidder: 'nextMillennium', params: {placement_id: '807', group_id: '123'}}], + }, + + expected: 'https://report2.hb.brainlyads.com/statistics/metric?event=bidRequested&bidder=nextMillennium&source=pbjs&groups=123', + }, + + { + eventName: 'bidRequested', + bid: { + bidderCode: 'nextMillennium', + bids: [ + {bidder: 'nextMillennium', params: {placement_id: '807', group_id: '123'}}, + {bidder: 'nextMillennium', params: {group_id: '456'}}, + {bidder: 'nextMillennium', params: {placement_id: '222'}}, + ], + }, + + expected: 'https://report2.hb.brainlyads.com/statistics/metric?event=bidRequested&bidder=nextMillennium&source=pbjs&groups=123;456&placements=222', + }, + + { + eventName: 'bidResponse', + bid: { + bidderCode: 'appnexus', + }, + + expected: undefined, + }, + + { + eventName: 'bidResponse', + bid: { + bidderCode: 'nextMillennium', + params: {placement_id: '807'}, + }, + + expected: 'https://report2.hb.brainlyads.com/statistics/metric?event=bidResponse&bidder=nextMillennium&source=pbjs&placements=807', + }, + + { + eventName: 'noBid', + bid: { + bidder: 'appnexus', + }, + + expected: undefined, + }, + + { + eventName: 'noBid', + bid: { + bidder: 'nextMillennium', + params: {placement_id: '807'}, + }, + + expected: 'https://report2.hb.brainlyads.com/statistics/metric?event=noBid&bidder=nextMillennium&source=pbjs&placements=807', + }, + + { + eventName: 'bidTimeout', + bid: { + bidder: 'appnexus', + }, + + expected: undefined, + }, + + { + eventName: 'bidTimeout', + bid: { + bidder: 'nextMillennium', + params: {placement_id: '807'}, + }, + + expected: 'https://report2.hb.brainlyads.com/statistics/metric?event=bidTimeout&bidder=nextMillennium&source=pbjs&placements=807', + }, + ]; + + for (let {eventName, bid, expected} of dataForTests) { + const url = spec.getUrlPixelMetric(eventName, bid); + expect(url).to.equal(expected); + }; + }) }); diff --git a/test/spec/modules/nexx360BidAdapter_spec.js b/test/spec/modules/nexx360BidAdapter_spec.js index 1a695e5f8b3..7645ee59f63 100644 --- a/test/spec/modules/nexx360BidAdapter_spec.js +++ b/test/spec/modules/nexx360BidAdapter_spec.js @@ -6,70 +6,39 @@ import * as utils from 'src/utils.js'; import { requestBidsHook } from 'modules/consentManagement.js'; describe('Nexx360 bid adapter tests', function () { - const DISPLAY_BID_REQUEST = [{ - 'bidder': 'nexx360', - 'params': { - 'account': '1067', - 'tagId': 'luvxjvgn' + const DISPLAY_BID_REQUEST = { + 'id': '77b3f21a-e0df-4495-8bce-4e8a1d2309c1', + 'imp': [ + {'id': '2b4d8fc1c1c7ea', + 'tagid': 'div-1', + 'ext': {'divId': 'div-1', 'nexx360': {'account': '1067', 'tag_id': 'luvxjvgn'}}, + 'banner': {'format': [{'w': 300, 'h': 250}, {'w': 300, 'h': 600}], 'topframe': 1}}, {'id': '38fc428ab96638', 'tagid': 'div-2', 'ext': {'divId': 'div-2', 'nexx360': {'account': '1067', 'tag_id': 'luvxjvgn'}}, 'banner': {'format': [{'w': 728, 'h': 90}, {'w': 970, 'h': 250}], 'topframe': 1}}], + 'cur': ['USD'], + 'at': 1, + 'tmax': 3000, + 'site': {'page': 'https://test.nexx360.io/adapter/index.html?nexx360_test=1', 'domain': 'test.nexx360.io'}, + 'regs': {'coppa': 0, 'ext': {'gdpr': 1}}, + 'device': { + 'dnt': 0, + 'h': 844, + 'w': 390, + 'ua': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1', + 'language': 'fr' }, - 'userId': { - 'id5id': { - 'uid': 'ID5*hQ5WobYI9Od4u52qpaXVKHhxUa4DsOWRAlvaFajm8gINfI1oVAe3UK59416dT4TqDX1pj4MBJ5TYwir6x3JgBw1-avYHSnmvQDdRMbxmC2sNf3ggIRTbyQBdI1RjvHyeDYCsistnTXF_iKF1nutYeQ2BZ4P5d5muZTG7C2PXVFgNg-18io9dCiSjzJXx93KPDYRiuIwtsGGsp51rojlpFw2Fp_dUkjXl4CAblk58DvwNhobwQ27bnBP8F2-Pcs88DYcvKn4r6dm3Vi7ILttxDQ2IgZ2X44ClgjoWh-vRf6ANis8Z7uL16vO8q0P5C21eDYuc4v_KaZqN-p9YWEeEZQ2OpkbRL7n5NieVJExHM6ANkAlLZhVf2T-1906TAIHKDZFm_xMCa1jJfpBqZB2agw2TjfbK6wMtJeHiZaipSuUNlM_CSH0HVXtfMj9yfzjzDZZnltZQ9lvc4JhXye5AwA2X1f9Dhk8VURTvVdfEUlU', - 'ext': { - 'linkType': 2 - } - } - }, - 'userIdAsEids': [ - { - 'source': 'id5-sync.com', - 'uids': [ - { - 'id': 'ID5*hQ5WobYI9Od4u52qpaXVKHhxUa4DsOWRAlvaFajm8gINfI1oVAe3UK59416dT4TqDX1pj4MBJ5TYwir6x3JgBw1-avYHSnmvQDdRMbxmC2sNf3ggIRTbyQBdI1RjvHyeDYCsistnTXF_iKF1nutYeQ2BZ4P5d5muZTG7C2PXVFgNg-18io9dCiSjzJXx93KPDYRiuIwtsGGsp51rojlpFw2Fp_dUkjXl4CAblk58DvwNhobwQ27bnBP8F2-Pcs88DYcvKn4r6dm3Vi7ILttxDQ2IgZ2X44ClgjoWh-vRf6ANis8Z7uL16vO8q0P5C21eDYuc4v_KaZqN-p9YWEeEZQ2OpkbRL7n5NieVJExHM6ANkAlLZhVf2T-1906TAIHKDZFm_xMCa1jJfpBqZB2agw2TjfbK6wMtJeHiZaipSuUNlM_CSH0HVXtfMj9yfzjzDZZnltZQ9lvc4JhXye5AwA2X1f9Dhk8VURTvVdfEUlU', + 'user': { + 'ext': { + 'consent': 'CPgocUAPgocUAAKAsAENCkCsAP_AAH_AAAqIJDtd_H__bW9r-f5_aft0eY1P9_r37uQzDhfNk-8F3L_W_LwX52E7NF36tq4KmR4ku1LBIUNlHMHUDUmwaokVryHsak2cpzNKJ7BEknMZOydYGF9vmxtj-QKY7_5_d3bx2D-t_9v239z3z81Xn3d53-_03LCdV5_9Dfn9fR_bc9KPt_58v8v8_____3_e__3_7994JEAEmGrcQBdmWODNoGEUCIEYVhIVQKACCgGFogMAHBwU7KwCfWECABAKAIwIgQ4AowIBAAAJAEhEAEgRYIAAARAIAAQAIhEIAGBgEFgBYGAQAAgGgYohQACBIQZEBEUpgQFQJBAa2VCCUF0hphAHWWAFBIjYqABEEgIrAAEBYOAYIkBKxYIEmKN8gBGCFAKJUK1EAAAA.YAAAAAAAAAAA', + 'ConsentedProvidersSettings': {'consented_providers': '1~39.43.46.55.61.70.83.89.93.108.117.122.124.131.135.136.143.144.147.149.159.162.167.171.192.196.202.211.218.228.230.239.241.259.266.272.286.291.311.317.322.323.326.327.338.367.371.385.389.394.397.407.413.415.424.430.436.445.449.453.482.486.491.494.495.501.503.505.522.523.540.550.559.560.568.574.576.584.587.591.733.737.745.787.802.803.817.820.821.829.839.864.867.874.899.904.922.931.938.979.981.985.1003.1024.1027.1031.1033.1040.1046.1051.1053.1067.1085.1092.1095.1097.1099.1107.1127.1135.1143.1149.1152.1162.1166.1186.1188.1201.1205.1211.1215.1226.1227.1230.1252.1268.1270.1276.1284.1286.1290.1301.1307.1312.1345.1356.1364.1365.1375.1403.1415.1416.1419.1440.1442.1449.1455.1456.1465.1495.1512.1516.1525.1540.1548.1555.1558.1564.1570.1577.1579.1583.1584.1591.1603.1616.1638.1651.1653.1665.1667.1677.1678.1682.1697.1699.1703.1712.1716.1721.1725.1732.1745.1750.1765.1769.1782.1786.1800.1808.1810.1825.1827.1832.1838.1840.1842.1843.1845.1859.1866.1870.1878.1880.1889.1899.1917.1929.1942.1944.1962.1963.1964.1967.1968.1969.1978.2003.2007.2008.2027.2035.2039.2044.2047.2052.2056.2064.2068.2070.2072.2074.2088.2090.2103.2107.2109.2115.2124.2130.2133.2137.2140.2145.2147.2150.2156.2166.2177.2183.2186.2202.2205.2216.2219.2220.2222.2225.2234.2253.2264.2279.2282.2292.2299.2305.2309.2312.2316.2322.2325.2328.2331.2334.2335.2336.2337.2343.2354.2357.2358.2359.2370.2376.2377.2387.2392.2394.2400.2403.2405.2407.2411.2414.2416.2418.2425.2440.2447.2459.2461.2462.2465.2468.2472.2477.2481.2484.2486.2488.2493.2496.2497.2498.2499.2501.2510.2511.2517.2526.2527.2532.2534.2535.2542.2552.2563.2564.2567.2568.2569.2571.2572.2575.2577.2583.2584.2596.2601.2604.2605.2608.2609.2610.2612.2614.2621.2628.2629.2633.2634.2636.2642.2643.2645.2646.2647.2650.2651.2652.2656.2657.2658.2660.2661.2669.2670.2677.2681.2684.2686.2687.2690.2695.2698.2707.2713.2714.2729.2739.2767.2768.2770.2772.2784.2787.2791.2792.2798.2801.2805.2812.2813.2816.2817.2818.2821.2822.2827.2830.2831.2834.2838.2839.2840.2844.2846.2847.2849.2850.2852.2854.2856.2860.2862.2863.2865.2867.2869.2873.2874.2875.2876.2878.2880.2881.2882.2883.2884.2886.2887.2888.2889.2891.2893.2894.2895.2897.2898.2900.2901.2908.2909.2911.2912.2913.2914.2916.2917.2918.2919.2920.2922.2923.2924.2927.2929.2930.2931.2939.2940.2941.2947.2949.2950.2956.2961.2962.2963.2964.2965.2966.2968.2970.2973.2974.2975.2979.2980.2981.2983.2985.2986.2987.2991.2994.2995.2997.2999.3000.3002.3003.3005.3008.3009.3010.3012.3016.3017.3018.3019.3024.3025.3028.3034.3037.3038.3043.3045.3048.3052.3053.3055.3058.3059.3063.3065.3066.3068.3070.3072.3073.3074.3075.3076.3077.3078.3089.3090.3093.3094.3095.3097.3099.3104.3106.3109.3112.3117.3118.3119.3120.3124.3126.3127.3128.3130.3135.3136.3145.3149.3150.3151.3154.3155.3162.3163.3167.3172.3173.3180.3182.3183.3184.3185.3187.3188.3189.3190.3194.3196.3197.3209.3210.3211.3214.3215.3217.3219.3222.3223.3225.3226.3227.3228.3230.3231.3232.3234.3235.3236.3237.3238.3240.3241.3244.3245.3250.3251.3253.3257.3260.3268.3270.3272.3281.3288.3290.3292.3293.3295.3296.3300.3306.3307.3308.3314.3315.3316.3318.3324.3327.3328.3330'}, + 'eids': [{'source': 'id5-sync.com', + 'uids': [{'id': 'ID5*tdrSpYbccONIbxmulXFRLEil1aozZGGVMo9eEZgydgYoYFZQRYoae3wJyY0YtmXGKGJ7uXIQByQ6f7uzcpy9Oyhj1jGRzCf0BCoI4VkkKZIoZBubolUKUXXxOIdQOz7ZKGV0E3sqi9Zut0BbOuoJAihpLbgfNgDJ0xRmQw04rDooaxn7_TIPzEX5_L5ohNkUKG01Gnh2djvcrcPigKlk7ChwnauCwHIetHYI32yYAnAocYyqoM9XkoVOHtyOTC_UKHIR0qVBVIzJ1Nn_g7kLqyhzfosadKVvf7RQCsE6QrYodtpOJKg7i72-tnMXkzgmKHjh98aEDfTQrZOkKebmAyh6GlOHtYn_sZBFjJwtWp4oe9j2QTNbzK3G0jp1PlJqKHxiu4LawFEKJ3yi5-NFUyh-YkEalJUWyl1cDlWo5NQogAy2HM8N_w0qrVQgNbrTKIHK3KzTXztH7WzBgYrk8g', 'atype': 1, - 'ext': { - 'linkType': 2 - } - } - ] - } - ], - 'mediaTypes': { - 'banner': { - 'sizes': [[300, 250], [300, 600]] - } - }, - 'adUnitCode': 'banner-div', - 'transactionId': '9ad89d90-eb73-41b9-bf5f-7a8e2eecff27', - 'sizes': [[300, 250], [300, 600]], - 'bidId': '4d9e29504f8af6', - 'bidderRequestId': '3423b6bd1a922c', - 'auctionId': '05e0a3a1-9f57-41f6-bbcb-2ba9c9e3d2d5', - 'src': 'client', - 'bidRequestsCount': 1, - 'bidderRequestsCount': 1, - 'bidderWinsCount': 0 - }]; - - const DISPLAY_BID_RESPONSE = {'body': { - 'responses': [ - { - 'bidId': '4d9e29504f8af6', - 'cpm': 0.437245, - 'width': 300, - 'height': 250, - 'creativeId': '98493581', - 'currency': 'EUR', - 'netRevenue': true, - 'type': 'banner', - 'ttl': 360, - 'uuid': 'ce6d1ee3-2a05-4d7c-b97a-9e62097798ec', - 'bidder': 'appnexus', - 'consent': 1, - 'tagId': 'luvxjvgn' - } - ], - }}; + 'ext': {'linkType': 2}}]}, + {'source': 'domain.com', 'uids': [{'id': 'value read from cookie or local storage', 'atype': 1, 'ext': {'stype': 'ppuid'}}]}]}}, + 'ext': { + 'source': 'prebid.js', + 'version': '7.20.0-pre', + 'pageViewId': '5b970aba-51e9-4e0a-8299-f3f5618c695e' + }} const VIDEO_BID_REQUEST = [ { @@ -101,26 +70,6 @@ describe('Nexx360 bid adapter tests', function () { } ] - const VIDEO_BID_RESPONSE = {'body': { - 'responses': [ - { - 'bidId': '2c129e8e01859a', - 'type': 'video', - 'uuid': 'b8e7b2f0-c378-479f-aa4f-4f55d5d7d1d5', - 'cpm': 4.5421, - 'width': 1, - 'height': 1, - 'creativeId': '97517771', - 'currency': 'EUR', - 'netRevenue': true, - 'ttl': 360, - 'bidder': 'appnexus', - 'consent': 1, - 'tagId': 'yqsc1tfj' - } - ] - }}; - const DEFAULT_OPTIONS = { gdprConsent: { gdprApplies: true, @@ -147,159 +96,426 @@ describe('Nexx360 bid adapter tests', function () { }, }; - it('We verify isBidRequestValid with uncorrect bidfloorCurrency', function() { - const bid = { params: { - 'account': '1067', - 'tagId': 'luvxjvgn', - 'bidfloorCurrency': 'AAA', - }}; - expect(spec.isBidRequestValid(bid)).to.be.equal(false); - }); + describe('isBidRequestValid()', function() { + let bannerBid; + beforeEach(function () { + bannerBid = { + 'bidder': 'nexx360', + 'mediaTypes': {'banner': {'sizes': [[300, 250], [300, 600]]}}, + 'adUnitCode': 'div-1', + 'transactionId': '70bdc37e-9475-4b27-8c74-4634bdc2ee66', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '4906582fc87d0c', + 'bidderRequestId': '332fda16002dbe', + 'auctionId': '98932591-c822-42e3-850e-4b3cf748d063', + } + }); + it('We verify isBidRequestValid with uncorrect tagid', function() { + bannerBid.params = { 'tagid': 'luvxjvgn' }; + expect(spec.isBidRequestValid(bannerBid)).to.be.equal(false); + }); - it('We verify isBidRequestValid with uncorrect bidfloor', function() { - const bid = { params: { - 'account': '1067', - 'tagId': 'luvxjvgn', - 'bidfloorCurrency': 'EUR', - 'bidfloor': 'EUR', - }}; - expect(spec.isBidRequestValid(bid)).to.be.equal(false); + it('We verify isBidRequestValid with correct tagId', function() { + bannerBid.params = { 'tagId': 'luvxjvgn' }; + expect(spec.isBidRequestValid(bannerBid)).to.be.equal(true); + }); }); - it('We verify isBidRequestValid with uncorrect keywords', function() { - const bid = { params: { - 'account': '1067', - 'tagId': 'luvxjvgn', - 'bidfloorCurrency': 'EUR', - 'bidfloor': 0.8, - 'keywords': 'test', - }}; - expect(spec.isBidRequestValid(bid)).to.be.equal(false); + describe('when request is for a multiformat ad', function () { + describe('and request config uses mediaTypes video and banner', () => { + const multiformatBid = { + 'bidder': 'nexx360', + 'params': {'tagId': 'luvxjvgn'}, + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250]] + }, + 'video': { + 'playerSize': [300, 250] + } + }, + 'adUnitCode': 'div-1', + 'transactionId': '70bdc37e-9475-4b27-8c74-4634bdc2ee66', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '4906582fc87d0c', + 'bidderRequestId': '332fda16002dbe', + 'auctionId': '98932591-c822-42e3-850e-4b3cf748d063', + } + it('should return true multisize when required params found', function () { + expect(spec.isBidRequestValid(multiformatBid)).to.equal(true); + }); + }); }); - it('Verify banner build request', function () { - const request = spec.buildRequests(DISPLAY_BID_REQUEST, DEFAULT_OPTIONS); - expect(request).to.have.property('url').and.to.equal('https://fast.nexx360.io/prebid'); - expect(request).to.have.property('method').and.to.equal('POST'); - const requestContent = JSON.parse(request.data); - expect(requestContent.userEids.length).to.be.eql(1); - expect(requestContent.userEids[0]).to.have.property('source').and.to.equal('id5-sync.com'); - expect(requestContent.userEids[0]).to.have.property('uids'); - expect(requestContent.userEids[0].uids[0]).to.have.property('id').and.to.equal('ID5*hQ5WobYI9Od4u52qpaXVKHhxUa4DsOWRAlvaFajm8gINfI1oVAe3UK59416dT4TqDX1pj4MBJ5TYwir6x3JgBw1-avYHSnmvQDdRMbxmC2sNf3ggIRTbyQBdI1RjvHyeDYCsistnTXF_iKF1nutYeQ2BZ4P5d5muZTG7C2PXVFgNg-18io9dCiSjzJXx93KPDYRiuIwtsGGsp51rojlpFw2Fp_dUkjXl4CAblk58DvwNhobwQ27bnBP8F2-Pcs88DYcvKn4r6dm3Vi7ILttxDQ2IgZ2X44ClgjoWh-vRf6ANis8Z7uL16vO8q0P5C21eDYuc4v_KaZqN-p9YWEeEZQ2OpkbRL7n5NieVJExHM6ANkAlLZhVf2T-1906TAIHKDZFm_xMCa1jJfpBqZB2agw2TjfbK6wMtJeHiZaipSuUNlM_CSH0HVXtfMj9yfzjzDZZnltZQ9lvc4JhXye5AwA2X1f9Dhk8VURTvVdfEUlU'); - expect(requestContent.adUnits[0]).to.have.property('account').and.to.equal('1067'); - expect(requestContent.adUnits[0]).to.have.property('tagId').and.to.equal('luvxjvgn'); - expect(requestContent.adUnits[0]).to.have.property('label').and.to.equal('banner-div'); - expect(requestContent.adUnits[0]).to.have.property('bidId').and.to.equal('4d9e29504f8af6'); - expect(requestContent.adUnits[0]).to.have.property('auctionId').and.to.equal('05e0a3a1-9f57-41f6-bbcb-2ba9c9e3d2d5'); - expect(requestContent.adUnits[0]).to.have.property('mediatypes').exist; - expect(requestContent.adUnits[0].mediatypes).to.have.property('banner').exist; - expect(requestContent.adUnits[0]).to.have.property('bidfloor').and.to.equal(0); - expect(requestContent.adUnits[0]).to.have.property('bidfloorCurrency').and.to.equal('USD'); - expect(requestContent.adUnits[0]).to.have.property('keywords'); - expect(requestContent.adUnits[0].keywords.length).to.be.eql(0); + describe('when request is for a video ad', function () { + describe('and request config uses mediaTypes video and banner', () => { + const videoBid = { + 'bidder': 'nexx360', + 'params': {'tagId': 'luvxjvgn'}, + 'mediaTypes': { + 'video': { + 'playerSize': [300, 250] + } + }, + 'adUnitCode': 'div-1', + 'transactionId': '70bdc37e-9475-4b27-8c74-4634bdc2ee66', + 'bidId': '4906582fc87d0c', + 'bidderRequestId': '332fda16002dbe', + 'auctionId': '98932591-c822-42e3-850e-4b3cf748d063', + } + it('should return true multisize when required params found', function () { + expect(spec.isBidRequestValid(videoBid)).to.equal(true); + }); + }); }); - it('We add bidfloor and keywords', function() { - const DISPLAY_BID_REQUEST_2 = [ ...DISPLAY_BID_REQUEST ]; - DISPLAY_BID_REQUEST_2[0].params.keywords = { interest: 'cars' }; - DISPLAY_BID_REQUEST_2[0].params.bidfloor = 2.1; - const request = spec.buildRequests(DISPLAY_BID_REQUEST, DEFAULT_OPTIONS); - const requestContent = JSON.parse(request.data); - expect(requestContent.adUnits[0]).to.have.property('bidfloor').and.to.equal(2.1); - expect(requestContent.adUnits[0]).to.have.property('bidfloorCurrency').and.to.equal('USD'); - expect(requestContent.adUnits[0]).to.have.property('keywords'); - expect(requestContent.adUnits[0].keywords.length).to.be.eql(1); - expect(requestContent.adUnits[0].keywords[0].key).to.be.eql('interest'); - expect(requestContent.adUnits[0].keywords[0].value[0]).to.be.eql('cars'); - }); + describe('buildRequests()', function() { + describe('We test with a multiple display bids', function() { + const sampleBids = [ + { + bidder: 'nexx360', + params: { + tagId: 'luvxjvgn' + }, + adUnitCode: 'div-1', + transactionId: '469a570d-f187-488d-b1cb-48c1a2009be9', + sizes: [[300, 250], [300, 600]], + bidId: '44a2706ac3574', + bidderRequestId: '359bf8a3c06b2e', + auctionId: '2e684815-b44e-4e04-b812-56da54adbe74', + userIdAsEids: [ + { + source: 'id5-sync.com', + uids: [ + { + id: 'ID5*xe3R0Pbrc5Y4WBrb5UZSWTiS1t9DU2LgQrhdZOgFdXMoglhqmjs_SfBbyHfSYGZKKIT4Gf-XOQ_anA3iqi0hJSiFyD3aICGHDJFxNS8LO84ohwTQ0EiwOexZAbBlH0chKIhbvdGBfuouNuVF_YHCoyiLQJDp3WQiH96lE9MH2T0ojRqoyR623gxAWlBCBPh7KI4bYtZlet3Vtr-gH5_xqCiSEd7aYV37wHxUTSN38Isok_0qDCHg4pKXCcVM2h6FKJSGmvw-xPm9HkfkIcbh1CiVVG4nREP142XrBecdzhQomNlcalmwdzGHsuHPjTP-KJraa15yvvZDceq-f_YfECicDllYBLEsg24oPRM-ibMonWtT9qOm5dSfWS5G_r09KJ4HMB6REICq1wleDD1mwSigXkM_nxIKa4TxRaRqEekoooWRwuKA5-euHN3xxNfIKKP19EtGhuNTs0YdCSe8_w', + atype: 1, + ext: { + linkType: 2 + } + } + ] + }, + { + source: 'domain.com', + uids: [ + { + id: 'value read from cookie or local storage', + atype: 1, + ext: { + stype: 'ppuid' + } + } + ] + } + ], + }, + { + bidder: 'nexx360', + params: { + tagId: 'luvxjvgn', + allBids: true, + }, + mediaTypes: { + banner: { + sizes: [[728, 90], [970, 250]] + } + }, + adUnitCode: 'div-2', + transactionId: '6196885d-4e76-40dc-a09c-906ed232626b', + sizes: [[728, 90], [970, 250]], + bidId: '5ba94555219a03', + bidderRequestId: '359bf8a3c06b2e', + auctionId: '2e684815-b44e-4e04-b812-56da54adbe74', + } + ] + const bidderRequest = { + bidderCode: 'nexx360', + auctionId: '2e684815-b44e-4e04-b812-56da54adbe74', + bidderRequestId: '359bf8a3c06b2e', + refererInfo: { + reachedTop: true, + isAmp: false, + numIframes: 0, + stack: [ + 'https://test.nexx360.io/adapter/index.html' + ], + topmostLocation: 'https://test.nexx360.io/adapter/index.html', + location: 'https://test.nexx360.io/adapter/index.html', + canonicalUrl: null, + page: 'https://test.nexx360.io/adapter/index.html', + domain: 'test.nexx360.io', + ref: null, + legacy: { + reachedTop: true, + isAmp: false, + numIframes: 0, + stack: [ + 'https://test.nexx360.io/adapter/index.html' + ], + referer: 'https://test.nexx360.io/adapter/index.html', + canonicalUrl: null + }, + }, + gdprConsent: { + gdprApplies: true, + consentString: 'CPhdLUAPhdLUAAKAsAENCmCsAP_AAE7AAAqIJFNd_H__bW9r-f5_aft0eY1P9_r37uQzDhfNk-8F3L_W_LwX52E7NF36tq4KmR4ku1LBIUNlHMHUDUmwaokVryHsak2cpzNKJ7BEknMZOydYGF9vmxtj-QKY7_5_d3bx2D-t_9v239z3z81Xn3d53-_03LCdV5_9Dfn9fR_bc9KPt_58v8v8_____3_e__3_7997BIiAaADgAJYBnwEeAJXAXmAwQBj4DtgHcgPBAeKBIgAA.YAAAAAAAAAAA', + } + }; + it('We perform a test with 2 display adunits', function() { + const displayBids = [...sampleBids]; + displayBids[0].mediaTypes = { + banner: { + sizes: [[300, 250], [300, 600]] + } + }; + const request = spec.buildRequests(displayBids, bidderRequest); + const requestContent = request.data; + expect(request).to.have.property('method').and.to.equal('POST'); + expect(requestContent.id).to.be.eql('2e684815-b44e-4e04-b812-56da54adbe74'); + expect(requestContent.cur[0]).to.be.eql('USD'); + expect(requestContent.imp.length).to.be.eql(2); + expect(requestContent.imp[0].id).to.be.eql('44a2706ac3574'); + expect(requestContent.imp[0].tagid).to.be.eql('div-1'); + expect(requestContent.imp[0].ext.divId).to.be.eql('div-1'); + expect(requestContent.imp[0].ext.nexx360.tagId).to.be.eql('luvxjvgn'); + expect(requestContent.imp[0].ext.nexx360.allBids).to.be.eql(false); + expect(requestContent.imp[0].banner.format.length).to.be.eql(2); + expect(requestContent.imp[0].banner.format[0].w).to.be.eql(300); + expect(requestContent.imp[0].banner.format[0].h).to.be.eql(250); + expect(requestContent.imp[1].ext.nexx360.allBids).to.be.eql(true); + expect(requestContent.regs.ext.gdpr).to.be.eql(1); + expect(requestContent.user.ext.consent).to.be.eql(bidderRequest.gdprConsent.consentString); + expect(requestContent.user.ext.eids.length).to.be.eql(2); + }); - it('Verify banner parse response', function () { - const request = spec.buildRequests(DISPLAY_BID_REQUEST, DEFAULT_OPTIONS); - const response = spec.interpretResponse(DISPLAY_BID_RESPONSE, request); - expect(response).to.have.lengthOf(1); - const bid = response[0]; - expect(bid.cpm).to.equal(0.437245); - expect(bid.adUrl).to.equal('https://fast.nexx360.io/cache?uuid=ce6d1ee3-2a05-4d7c-b97a-9e62097798ec'); - expect(bid.width).to.equal(300); - expect(bid.height).to.equal(250); - expect(bid.creativeId).to.equal('98493581'); - expect(bid.currency).to.equal('EUR'); - expect(bid.netRevenue).to.equal(true); - expect(bid.ttl).to.equal(360); - expect(bid.requestId).to.equal('4d9e29504f8af6'); - expect(bid.nexx360).to.exist; - expect(bid.nexx360.ssp).to.equal('appnexus'); - }); + it('We perform a test with a multiformat adunit', function() { + const multiformatBids = [...sampleBids]; + multiformatBids[0].mediaTypes = { + banner: { + sizes: [[300, 250], [300, 600]] + }, + video: { + context: 'outstream', + playerSize: [640, 480], + mimes: ['video/mp4'], + protocols: [1, 2, 3, 4, 5, 6, 7, 8], + playbackmethod: [2], + skip: 1, + playback_method: ['auto_play_sound_off'] + } + }; + const request = spec.buildRequests(multiformatBids, bidderRequest); + const requestContent = request.data; + expect(requestContent.imp[0].video.context).to.be.eql('outstream'); + expect(requestContent.imp[0].video.playbackmethod[0]).to.be.eql(2); + }); - it('Verify video build request', function () { - const request = spec.buildRequests(VIDEO_BID_REQUEST, DEFAULT_OPTIONS); - expect(request).to.have.property('url').and.to.equal('https://fast.nexx360.io/prebid'); - expect(request).to.have.property('method').and.to.equal('POST'); - const requestContent = JSON.parse(request.data); - expect(requestContent.adUnits[0]).to.have.property('account').and.to.equal('1067'); - expect(requestContent.adUnits[0]).to.have.property('tagId').and.to.equal('yqsc1tfj'); - expect(requestContent.adUnits[0]).to.have.property('label').and.to.equal('video1'); - expect(requestContent.adUnits[0]).to.have.property('bidId').and.to.equal('22f90541e576a3'); - expect(requestContent.adUnits[0]).to.have.property('auctionId').and.to.equal('ed21b528-bcab-47e2-8605-ec9b71000c89'); - expect(requestContent.adUnits[0]).to.have.property('mediatypes').exist; - expect(requestContent.adUnits[0].mediatypes).to.have.property('video').exist; + it('We perform a test with a video adunit', function() { + const videoBids = [sampleBids[0]]; + videoBids[0].mediaTypes = { + video: { + context: 'instream', + playerSize: [640, 480], + mimes: ['video/mp4'], + protocols: [1, 2, 3, 4, 5, 6], + playbackmethod: [2], + skip: 1 + } + }; + const request = spec.buildRequests(videoBids, bidderRequest); + const requestContent = request.data; + expect(request).to.have.property('method').and.to.equal('POST'); + expect(requestContent.imp[0].video.context).to.be.eql('instream'); + expect(requestContent.imp[0].video.playbackmethod[0]).to.be.eql(2); + }) + }); }); - it('Verify video parse response', function () { - const request = spec.buildRequests(VIDEO_BID_REQUEST, DEFAULT_OPTIONS); - const response = spec.interpretResponse(VIDEO_BID_RESPONSE, request); - expect(response).to.have.lengthOf(1); - const bid = response[0]; - expect(bid.cpm).to.equal(4.5421); - expect(bid.vastUrl).to.equal('https://fast.nexx360.io/cache?uuid=b8e7b2f0-c378-479f-aa4f-4f55d5d7d1d5'); - expect(bid.vastImpUrl).to.equal('https://fast.nexx360.io/track-imp?type=prebid&mediatype=video&ssp=appnexus&tag_id=yqsc1tfj&consent=1&price=4.5421'); - expect(bid.width).to.equal(1); - expect(bid.height).to.equal(1); - expect(bid.creativeId).to.equal('97517771'); - expect(bid.currency).to.equal('EUR'); - expect(bid.netRevenue).to.equal(true); - expect(bid.ttl).to.equal(360); - expect(bid.requestId).to.equal('2c129e8e01859a'); - expect(bid.nexx360).to.exist; - expect(bid.nexx360.ssp).to.equal('appnexus'); + describe('interpretResponse()', function() { + it('banner responses', function() { + const response = { + body: { + 'id': 'a8d3a675-a4ba-4d26-807f-c8f2fad821e0', + 'cur': 'USD', + 'seatbid': [ + { + 'bid': [ + { + 'id': '4427551302944024629', + 'impid': '226175918ebeda', + 'price': 1.5, + 'type': 'banner', + 'adomain': [ + 'http://prebid.org' + ], + 'crid': '98493581', + 'ssp': 'appnexus', + 'h': 600, + 'w': 300, + 'cat': [ + 'IAB3-1' + ], + 'creativeuuid': 'fdddcebc-1edf-489d-880d-1418d8bdc493', + 'adUrl': 'https://fast.nexx360.io/cache?uuid=fdddcebc-1edf-489d-880d-1418d8bdc493', + 'ext': { + 'dsp_id': 'ssp1', + 'buyer_id': 'foo', + 'brand_id': 'bar' + } + } + ], + 'seat': 'appnexus' + } + ], + 'cookies': [] + } + }; + const output = spec.interpretResponse(response); + expect(output[0].adUrl).to.be.eql(response.body.seatbid[0].bid[0].adUrl); + expect(output[0].mediaType).to.be.eql(response.body.seatbid[0].bid[0].type); + expect(output[0].currency).to.be.eql(response.body.cur); + expect(output[0].cpm).to.be.eql(response.body.seatbid[0].bid[0].price); + expect(output[0].meta.networkId).to.be.eql(response.body.seatbid[0].bid[0].ext.dsp_id); + expect(output[0].meta.advertiserId).to.be.eql(response.body.seatbid[0].bid[0].ext.buyer_id); + expect(output[0].meta.brandId).to.be.eql(response.body.seatbid[0].bid[0].ext.brand_id); + }); + it('video responses', function() { + const response = { + body: { + 'id': '33894759-0ea2-41f1-84b3-75132eefedb6', + 'cur': 'USD', + 'seatbid': [ + { + 'bid': [ + { + 'id': '294478680080716675', + 'impid': '2c835a6039e65f', + 'price': 5, + 'type': 'instream', + 'adomain': [ + '' + ], + 'crid': '97517771', + 'ssp': 'appnexus', + 'h': 1, + 'w': 1, + 'vastXml': '\n \n \n prebid.org wrapper\n \n \n \n \n \n ' + } + ], + 'seat': 'appnexus' + } + ], + 'cookies': [] + } + }; + const output = spec.interpretResponse(response); + expect(output[0].vastXml).to.be.eql(response.body.seatbid[0].bid[0].vastXml); + expect(output[0].mediaType).to.be.eql('video'); + expect(output[0].currency).to.be.eql(response.body.cur); + expect(output[0].cpm).to.be.eql(response.body.seatbid[0].bid[0].price); + }); }); - it('Verifies bidder code', function () { - expect(spec.code).to.equal('nexx360'); + describe('interpretResponse()', function() { + it('banner responses', function() { + const response = { + body: { + 'id': 'a8d3a675-a4ba-4d26-807f-c8f2fad821e0', + 'cur': 'USD', + 'seatbid': [ + { + 'bid': [ + { + 'id': '4427551302944024629', + 'impid': '226175918ebeda', + 'price': 1.5, + 'type': 'banner', + 'adomain': [ + 'http://prebid.org' + ], + 'crid': '98493581', + 'ssp': 'appnexus', + 'h': 600, + 'w': 300, + 'cat': [ + 'IAB3-1' + ], + 'creativeuuid': 'fdddcebc-1edf-489d-880d-1418d8bdc493', + 'adUrl': 'https://fast.nexx360.io/cache?uuid=fdddcebc-1edf-489d-880d-1418d8bdc493' + } + ], + 'seat': 'appnexus' + } + ], + 'cookies': [] + } + }; + const output = spec.interpretResponse(response); + expect(output[0].adUrl).to.be.eql(response.body.seatbid[0].bid[0].adUrl); + expect(output[0].mediaType).to.be.eql(response.body.seatbid[0].bid[0].type); + expect(output[0].currency).to.be.eql(response.body.cur); + expect(output[0].cpm).to.be.eql(response.body.seatbid[0].bid[0].price); + }); + it('video responses', function() { + const response = { + body: { + 'id': '33894759-0ea2-41f1-84b3-75132eefedb6', + 'cur': 'USD', + 'seatbid': [ + { + 'bid': [ + { + 'id': '294478680080716675', + 'impid': '2c835a6039e65f', + 'price': 5, + 'type': 'instream', + 'adomain': [ + '' + ], + 'crid': '97517771', + 'ssp': 'appnexus', + 'h': 1, + 'w': 1, + 'vastXml': '\n \n \n prebid.org wrapper\n \n \n \n \n \n ' + } + ], + 'seat': 'appnexus' + } + ], + 'cookies': [] + } + }; + const output = spec.interpretResponse(response); + expect(output[0].vastXml).to.be.eql(response.body.seatbid[0].bid[0].vastXml); + expect(output[0].mediaType).to.be.eql('video'); + expect(output[0].currency).to.be.eql(response.body.cur); + expect(output[0].cpm).to.be.eql(response.body.seatbid[0].bid[0].price); + }); }); - it('Verifies bidder aliases', function () { - expect(spec.aliases).to.have.lengthOf(1); - expect(spec.aliases[0]).to.equal('revenuemaker'); - }); - it('Verifies if bid request valid', function () { - expect(spec.isBidRequestValid(DISPLAY_BID_REQUEST[0])).to.equal(true); - }); - it('Verifies bid won', function () { - const request = spec.buildRequests(DISPLAY_BID_REQUEST, DEFAULT_OPTIONS); - const response = spec.interpretResponse(DISPLAY_BID_RESPONSE, request); - const won = spec.onBidWon(response[0]); - expect(won).to.equal(true); - }); - it('Verifies user sync without cookie in bid response', function () { - var syncs = spec.getUserSyncs({}, [DISPLAY_BID_RESPONSE], DEFAULT_OPTIONS.gdprConsent, DEFAULT_OPTIONS.uspConsent); - expect(syncs).to.have.lengthOf(0); - }); - it('Verifies user sync with cookies in bid response', function () { - DISPLAY_BID_RESPONSE.body.cookies = [{'type': 'image', 'url': 'http://www.cookie.sync.org/'}]; - var syncs = spec.getUserSyncs({}, [DISPLAY_BID_RESPONSE], DEFAULT_OPTIONS.gdprConsent); - expect(syncs).to.have.lengthOf(1); - expect(syncs[0]).to.have.property('type').and.to.equal('image'); - expect(syncs[0]).to.have.property('url').and.to.equal('http://www.cookie.sync.org/'); - }); - it('Verifies user sync with no bid response', function() { - var syncs = spec.getUserSyncs({}, null, DEFAULT_OPTIONS.gdprConsent, DEFAULT_OPTIONS.uspConsent); - expect(syncs).to.have.lengthOf(0); - }); - it('Verifies user sync with no bid body response', function() { - var syncs = spec.getUserSyncs({}, [], DEFAULT_OPTIONS.gdprConsent, DEFAULT_OPTIONS.uspConsent); - expect(syncs).to.have.lengthOf(0); - var syncs = spec.getUserSyncs({}, [{}], DEFAULT_OPTIONS.gdprConsent, DEFAULT_OPTIONS.uspConsent); - expect(syncs).to.have.lengthOf(0); + describe('getUserSyncs()', function() { + const response = { body: { cookies: [] } }; + it('Verifies user sync without cookie in bid response', function () { + var syncs = spec.getUserSyncs({}, [response], DEFAULT_OPTIONS.gdprConsent, DEFAULT_OPTIONS.uspConsent); + expect(syncs).to.have.lengthOf(0); + }); + it('Verifies user sync with cookies in bid response', function () { + response.body.cookies = [{'type': 'image', 'url': 'http://www.cookie.sync.org/'}]; + var syncs = spec.getUserSyncs({}, [response], DEFAULT_OPTIONS.gdprConsent); + expect(syncs).to.have.lengthOf(1); + expect(syncs[0]).to.have.property('type').and.to.equal('image'); + expect(syncs[0]).to.have.property('url').and.to.equal('http://www.cookie.sync.org/'); + }); + it('Verifies user sync with no bid response', function() { + var syncs = spec.getUserSyncs({}, null, DEFAULT_OPTIONS.gdprConsent, DEFAULT_OPTIONS.uspConsent); + expect(syncs).to.have.lengthOf(0); + }); + it('Verifies user sync with no bid body response', function() { + var syncs = spec.getUserSyncs({}, [], DEFAULT_OPTIONS.gdprConsent, DEFAULT_OPTIONS.uspConsent); + expect(syncs).to.have.lengthOf(0); + var syncs = spec.getUserSyncs({}, [{}], DEFAULT_OPTIONS.gdprConsent, DEFAULT_OPTIONS.uspConsent); + expect(syncs).to.have.lengthOf(0); + }); }); }); diff --git a/test/spec/modules/novatiqIdSystem_spec.js b/test/spec/modules/novatiqIdSystem_spec.js index b92fb0d219a..6d25601d958 100644 --- a/test/spec/modules/novatiqIdSystem_spec.js +++ b/test/spec/modules/novatiqIdSystem_spec.js @@ -138,16 +138,31 @@ describe('novatiqIdSystem', function () { }); describe('decode', function() { - it('should log message if novatiqId has wrong format', function() { + it('should return the same novatiqId as passed in if not async', function() { const novatiqId = '81b001ec-8914-488c-a96e-8c220d4ee08895ef'; const response = novatiqIdSubmodule.decode(novatiqId); expect(response.novatiq.snowflake).to.have.length(40); }); - it('should log message if novatiqId has wrong format', function() { - const novatiqId = '81b001ec-8914-488c-a96e-8c220d4ee08895ef'; + it('should change the result format if async', function() { + let novatiqId = {}; + novatiqId.id = '81b001ec-8914-488c-a96e-8c220d4ee08895ef'; + novatiqId.syncResponse = 2; const response = novatiqIdSubmodule.decode(novatiqId); - expect(response.novatiq.snowflake).should.be.not.empty; + expect(response.novatiq.ext.syncResponse).should.be.not.empty; + expect(response.novatiq.snowflake.id).should.be.not.empty; + expect(response.novatiq.snowflake.syncResponse).should.be.not.empty; + }); + + it('should remove syncResponse if removeAdditionalInfo true', function() { + let novatiqId = {}; + novatiqId.id = '81b001ec-8914-488c-a96e-8c220d4ee08895ef'; + novatiqId.syncResponse = 2; + var config = {params: {removeAdditionalInfo: true}}; + const response = novatiqIdSubmodule.decode(novatiqId, config); + expect(response.novatiq.ext.syncResponse).should.be.not.empty; + expect(response.novatiq.snowflake.id).should.be.not.empty; + should.equal(response.novatiq.snowflake.syncResponse, undefined); }); }); }) diff --git a/test/spec/modules/oguryBidAdapter_spec.js b/test/spec/modules/oguryBidAdapter_spec.js index b9e4b44b571..f7cdcc0d11a 100644 --- a/test/spec/modules/oguryBidAdapter_spec.js +++ b/test/spec/modules/oguryBidAdapter_spec.js @@ -244,12 +244,16 @@ describe('OguryBidAdapter', function () { describe('buildRequests', function () { const stubbedWidth = 200 const stubbedHeight = 600 + const stubbedCurrentTime = 1234567890 const stubbedWidthMethod = sinon.stub(window.top.document.documentElement, 'clientWidth').get(function() { return stubbedWidth; }); const stubbedHeightMethod = sinon.stub(window.top.document.documentElement, 'clientHeight').get(function() { return stubbedHeight; }); + const stubbedCurrentTimeMethod = sinon.stub(document.timeline, 'currentTime').get(function() { + return stubbedCurrentTime; + }); const defaultTimeout = 1000; const expectedRequestObject = { @@ -266,7 +270,10 @@ describe('OguryBidAdapter', function () { h: 250 }] }, - ext: bidRequests[0].params + ext: { + ...bidRequests[0].params, + timeSpentOnPage: stubbedCurrentTime + } }, { id: bidRequests[1].bidId, tagid: bidRequests[1].params.adUnitId, @@ -276,7 +283,10 @@ describe('OguryBidAdapter', function () { h: 500 }] }, - ext: bidRequests[1].params + ext: { + ...bidRequests[1].params, + timeSpentOnPage: stubbedCurrentTime + } }], regs: { ext: { @@ -295,7 +305,7 @@ describe('OguryBidAdapter', function () { }, ext: { prebidversion: '$prebid.version$', - adapterversion: '1.3.0' + adapterversion: '1.4.0' }, device: { w: stubbedWidth, @@ -306,6 +316,7 @@ describe('OguryBidAdapter', function () { after(function() { stubbedWidthMethod.restore(); stubbedHeightMethod.restore(); + stubbedCurrentTimeMethod.restore(); }); it('sends bid request to ENDPOINT via POST', function () { @@ -316,6 +327,17 @@ describe('OguryBidAdapter', function () { expect(request.method).to.equal('POST'); }); + it('timeSpentOnpage should be 0 if timeline is undefined', function () { + const stubbedTimelineMethod = sinon.stub(document, 'timeline').get(function() { + return undefined; + }); + const validBidRequests = utils.deepClone(bidRequests) + + const request = spec.buildRequests(validBidRequests, bidderRequest); + expect(request.data.imp[0].ext.timeSpentOnPage).to.equal(0); + stubbedTimelineMethod.restore(); + }); + it('bid request object should be conform', function () { const validBidRequests = utils.deepClone(bidRequests) @@ -675,7 +697,7 @@ describe('OguryBidAdapter', function () { advertiserDomains: openRtbBidResponse.body.seatbid[0].bid[0].adomain }, nurl: openRtbBidResponse.body.seatbid[0].bid[0].nurl, - adapterVersion: '1.3.0', + adapterVersion: '1.4.0', prebidVersion: '$prebid.version$' }, { requestId: openRtbBidResponse.body.seatbid[0].bid[1].impid, @@ -692,7 +714,7 @@ describe('OguryBidAdapter', function () { advertiserDomains: openRtbBidResponse.body.seatbid[0].bid[1].adomain }, nurl: openRtbBidResponse.body.seatbid[0].bid[1].nurl, - adapterVersion: '1.3.0', + adapterVersion: '1.4.0', prebidVersion: '$prebid.version$' }] diff --git a/test/spec/modules/onetagBidAdapter_spec.js b/test/spec/modules/onetagBidAdapter_spec.js index 2dc0a43bbb0..5bd65cf0fd5 100644 --- a/test/spec/modules/onetagBidAdapter_spec.js +++ b/test/spec/modules/onetagBidAdapter_spec.js @@ -1,8 +1,8 @@ import { spec, isValid, hasTypeVideo, isSchainValid } from 'modules/onetagBidAdapter.js'; import { expect } from 'chai'; -import {find} from 'src/polyfill.js'; +import { find } from 'src/polyfill.js'; import { BANNER, VIDEO } from 'src/mediaTypes.js'; -import {INSTREAM, OUTSTREAM} from 'src/video.js'; +import { INSTREAM, OUTSTREAM } from 'src/video.js'; describe('onetag', function () { function createBid() { @@ -122,14 +122,14 @@ describe('onetag', function () { it('Should return true when correct multi format bid is passed', function () { expect(spec.isBidRequestValid(createMultiFormatBid())).to.be.true; }); - it('Should split multi format bid into two single format bid with same bidId', function() { - const bids = JSON.parse(spec.buildRequests([ createMultiFormatBid() ]).data).bids; + it('Should split multi format bid into two single format bid with same bidId', function () { + const bids = JSON.parse(spec.buildRequests([createMultiFormatBid()]).data).bids; expect(bids.length).to.equal(2); expect(bids[0].bidId).to.equal(bids[1].bidId); }); - it('Should retrieve correct request bid when extracting video request data', function() { + it('Should retrieve correct request bid when extracting video request data', function () { const requestBid = createMultiFormatBid(); - const multiFormatRequest = spec.buildRequests([ requestBid ]); + const multiFormatRequest = spec.buildRequests([requestBid]); const serverResponse = { body: { bids: [ @@ -173,24 +173,30 @@ describe('onetag', function () { const data = JSON.parse(d); it('Should contain all keys', function () { expect(data).to.be.an('object'); - expect(data).to.include.all.keys('location', 'referrer', 'masked', 'sHeight', 'sWidth', 'docHeight', 'wHeight', 'wWidth', 'oHeight', 'oWidth', 'aWidth', 'aHeight', 'sLeft', 'sTop', 'hLength', 'bids', 'docHidden', 'xOffset', 'yOffset', 'timing', 'version'); - expect(data.location).to.be.a('string'); - expect(data.masked).to.be.oneOf([0, 1, 2]); + expect(data).to.include.all.keys('location', 'referrer', 'stack', 'numIframes', 'sHeight', 'sWidth', 'docHeight', 'wHeight', 'wWidth', 'oHeight', 'oWidth', 'aWidth', 'aHeight', 'sLeft', 'sTop', 'hLength', 'bids', 'docHidden', 'xOffset', 'yOffset', 'networkConnectionType', 'networkEffectiveConnectionType', 'timing', 'version'); + expect(data.location).to.satisfy(function (value) { + return value === null || typeof value === 'string'; + }); expect(data.referrer).to.satisfy(referrer => referrer === null || typeof referrer === 'string'); + expect(data.stack).to.be.an('array'); + expect(data.numIframes).to.be.a('number'); expect(data.sHeight).to.be.a('number'); expect(data.sWidth).to.be.a('number'); expect(data.wWidth).to.be.a('number'); expect(data.wHeight).to.be.a('number'); expect(data.oHeight).to.be.a('number'); expect(data.oWidth).to.be.a('number'); - expect(data.ancestorOrigin).to.satisfy(function (value) { - return value === null || typeof value === 'string'; - }); expect(data.aWidth).to.be.a('number'); expect(data.aHeight).to.be.a('number'); expect(data.sLeft).to.be.a('number'); expect(data.sTop).to.be.a('number'); expect(data.hLength).to.be.a('number'); + expect(data.networkConnectionType).to.satisfy(function (value) { + return value === null || typeof value === 'string' + }); + expect(data.networkEffectiveConnectionType).to.satisfy(function (value) { + return value === null || typeof value === 'string' + }); expect(data.bids).to.be.an('array'); expect(data.version).to.have.all.keys('prebid', 'adapter'); const bids = data['bids']; @@ -231,14 +237,14 @@ describe('onetag', function () { expect(bid.pubId).to.be.a('string'); } }); - } catch (e) {} + } catch (e) { } it('Returns empty data if no valid requests are passed', function () { serverRequest = spec.buildRequests([]); let dataString = serverRequest.data; try { let dataObj = JSON.parse(dataString); expect(dataObj.bids).to.be.an('array').that.is.empty; - } catch (e) {} + } catch (e) { } }); it('should send GDPR consent data', function () { let consentString = 'consentString'; @@ -260,6 +266,27 @@ describe('onetag', function () { expect(payload.gdprConsent.consentString).to.exist.and.to.equal(consentString); expect(payload.gdprConsent.consentRequired).to.exist.and.to.be.true; }); + it('Should send GPP consent data', function () { + let consentString = 'consentString'; + let applicableSections = [1, 2, 3]; + let bidderRequest = { + 'bidderCode': 'onetag', + 'auctionId': '1d1a030790a475', + 'bidderRequestId': '22edbae2733bf6', + 'timeout': 3000, + 'gppConsent': { + gppString: consentString, + applicableSections: applicableSections + } + }; + let serverRequest = spec.buildRequests([bannerBid], bidderRequest); + const payload = JSON.parse(serverRequest.data); + + expect(payload).to.exist; + expect(payload.gppConsent).to.exist; + expect(payload.gppConsent.consentString).to.exist.and.to.equal(consentString); + expect(payload.gppConsent.applicableSections).to.have.same.members(applicableSections); + }); it('Should send us privacy string', function () { let consentString = 'us_foo'; let bidderRequest = { @@ -287,7 +314,7 @@ describe('onetag', function () { let dataItem = interpretedResponse[i]; expect(dataItem).to.include.all.keys('requestId', 'cpm', 'width', 'height', 'ttl', 'creativeId', 'netRevenue', 'currency', 'meta', 'dealId'); if (dataItem.meta.mediaType === VIDEO) { - const {context} = find(requestData.bids, (item) => item.bidId === dataItem.requestId); + const { context } = find(requestData.bids, (item) => item.bidId === dataItem.requestId); if (context === INSTREAM) { expect(dataItem).to.include.all.keys('videoCacheKey', 'vastUrl'); expect(dataItem.vastUrl).to.be.a('string'); @@ -321,7 +348,7 @@ describe('onetag', function () { describe('getUserSyncs', function () { const sync_endpoint = 'https://onetag-sys.com/usync/'; it('Returns an iframe if iframeEnabled is true', function () { - const syncs = spec.getUserSyncs({iframeEnabled: true}); + const syncs = spec.getUserSyncs({ iframeEnabled: true }); expect(syncs).to.be.an('array'); expect(syncs.length).to.equal(1); expect(syncs[0].type).to.equal('iframe'); @@ -369,6 +396,28 @@ describe('onetag', function () { expect(syncs[0].url).to.include(sync_endpoint); expect(syncs[0].url).to.not.match(/(?:[?&](?:gdpr_consent=([^&]*)|gdpr=([^&]*)))+$/); }); + it('Must pass gpp consent string when gppConsent object is available', function () { + const syncs = spec.getUserSyncs({ iframeEnabled: true }, {}, {}, {}, { + gppString: 'foo' + }); + expect(syncs[0].type).to.equal('iframe'); + expect(syncs[0].url).to.include(sync_endpoint); + expect(syncs[0].url).to.match(/(?:[?&](?:gpp_consent=foo([^&]*)))+$/); + }); + it('Must pass no gpp params when consentString is null', function () { + const syncs = spec.getUserSyncs({ iframeEnabled: true }, {}, {}, {}, { + gppString: null + }); + expect(syncs[0].type).to.equal('iframe'); + expect(syncs[0].url).to.include(sync_endpoint); + expect(syncs[0].url).to.not.match(/(?:[?&](?:gpp_consent=([^&]*)))+$/); + }); + it('Must pass no gpp params when consentString is empty', function () { + const syncs = spec.getUserSyncs({ iframeEnabled: true }, {}, {}, {}, {}); + expect(syncs[0].type).to.equal('iframe'); + expect(syncs[0].url).to.include(sync_endpoint); + expect(syncs[0].url).to.not.match(/(?:[?&](?:gpp_consent=([^&]*)))+$/); + }); it('Should send us privacy string', function () { let usConsentString = 'us_foo'; const syncs = spec.getUserSyncs({ iframeEnabled: true }, {}, {}, usConsentString); @@ -383,16 +432,16 @@ describe('onetag', function () { expect(isSchainValid(undefined)).to.be.false; }); it('Should return false when schain is missing nodes key', function () { - const schain = {'otherKey': 'otherValue'}; + const schain = { 'otherKey': 'otherValue' }; expect(isSchainValid(schain)).to.be.false; }); it('Should return false when schain is missing one of the required SupplyChainNode attribute', function () { - const missingAsiNode = {'sid': '00001', 'hp': 1}; - const missingSidNode = {'asi': 'indirectseller.com', 'hp': 1}; - const missingHpNode = {'asi': 'indirectseller.com', 'sid': '00001'}; - expect(isSchainValid({'config': {'nodes': [missingAsiNode]}})).to.be.false; - expect(isSchainValid({'config': {'nodes': [missingSidNode]}})).to.be.false; - expect(isSchainValid({'config': {'nodes': [missingHpNode]}})).to.be.false; + const missingAsiNode = { 'sid': '00001', 'hp': 1 }; + const missingSidNode = { 'asi': 'indirectseller.com', 'hp': 1 }; + const missingHpNode = { 'asi': 'indirectseller.com', 'sid': '00001' }; + expect(isSchainValid({ 'config': { 'nodes': [missingAsiNode] } })).to.be.false; + expect(isSchainValid({ 'config': { 'nodes': [missingSidNode] } })).to.be.false; + expect(isSchainValid({ 'config': { 'nodes': [missingHpNode] } })).to.be.false; }); it('Should return true when schain contains all required attributes', function () { const validSchain = { diff --git a/test/spec/modules/openxBidAdapter_spec.js b/test/spec/modules/openxBidAdapter_spec.js index cc1c2d1e607..8fe220aa202 100644 --- a/test/spec/modules/openxBidAdapter_spec.js +++ b/test/spec/modules/openxBidAdapter_spec.js @@ -1729,6 +1729,47 @@ describe('OpenxAdapter', function () { }); }); }); + describe('with user agent client hints', function () { + it('should add json query param sua with BidRequest.device.sua if available', function () { + const bidderRequestWithUserAgentClientHints = { refererInfo: {}, + ortb2: { + device: { + sua: { + source: 2, + platform: { + brand: 'macOS', + version: [ '12', '4', '0' ] + }, + browsers: [ + { + brand: 'Chromium', + version: [ '106', '0', '5249', '119' ] + }, + { + brand: 'Google Chrome', + version: [ '106', '0', '5249', '119' ] + }, + { + brand: 'Not;A=Brand', + version: [ '99', '0', '0', '0' ] + }], + mobile: 0, + model: 'Pro', + bitness: '64', + architecture: 'x86' + } + } + }}; + + let request = spec.buildRequests([bidRequest], bidderRequestWithUserAgentClientHints); + expect(request[0].data.sua).to.exist; + const payload = JSON.parse(request[0].data.sua); + expect(payload).to.deep.equal(bidderRequestWithUserAgentClientHints.ortb2.device.sua); + const bidderRequestWithoutUserAgentClientHints = {refererInfo: {}, ortb2: {}}; + request = spec.buildRequests([bidRequest], bidderRequestWithoutUserAgentClientHints); + expect(request[0].data.sua).to.not.exist; + }); + }); }); }) diff --git a/test/spec/modules/openxOrtbBidAdapter_spec.js b/test/spec/modules/openxOrtbBidAdapter_spec.js index 09e76d6ca7a..3bb1958c5fe 100644 --- a/test/spec/modules/openxOrtbBidAdapter_spec.js +++ b/test/spec/modules/openxOrtbBidAdapter_spec.js @@ -14,10 +14,16 @@ import 'modules/consentManagement.js'; import 'modules/consentManagementUsp.js'; import 'modules/schain.js'; import {deepClone} from 'src/utils.js'; +import {syncAddFPDToBidderRequest} from '../../helpers/fpd.js'; +import {hook} from '../../../src/hook.js'; const DEFAULT_SYNC = SYNC_URL + '?ph=' + DEFAULT_PH; describe('OpenxRtbAdapter', function () { + before(() => { + hook.ready(); + }); + const adapter = newBidder(spec); describe('inherited functions', function () { @@ -573,6 +579,47 @@ describe('OpenxRtbAdapter', function () { }); }); }); + + describe('with user agent client hints', function () { + it('should add device.sua if available', function () { + const bidderRequestWithUserAgentClientHints = { refererInfo: {}, + ortb2: { + device: { + sua: { + source: 2, + platform: { + brand: 'macOS', + version: [ '12', '4', '0' ] + }, + browsers: [ + { + brand: 'Chromium', + version: [ '106', '0', '5249', '119' ] + }, + { + brand: 'Google Chrome', + version: [ '106', '0', '5249', '119' ] + }, + { + brand: 'Not;A=Brand', + version: [ '99', '0', '0', '0' ] + }], + mobile: 0, + model: 'Pro', + bitness: '64', + architecture: 'x86' + } + } + }}; + + let request = spec.buildRequests(bidRequests, bidderRequestWithUserAgentClientHints); + expect(request[0].data.device.sua).to.exist; + expect(request[0].data.device.sua).to.deep.equal(bidderRequestWithUserAgentClientHints.ortb2.device.sua); + const bidderRequestWithoutUserAgentClientHints = {refererInfo: {}, ortb2: {}}; + request = spec.buildRequests(bidRequests, bidderRequestWithoutUserAgentClientHints); + expect(request[0].data.device?.sua).to.not.exist; + }); + }); }); context('when there is a consent management framework', function () { @@ -634,14 +681,14 @@ describe('OpenxRtbAdapter', function () { }); it('should send a signal to specify that US Privacy applies to this request', function () { - const request = spec.buildRequests(bidRequests, bidderRequest); + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); expect(request[0].data.regs.ext.us_privacy).to.equal('1YYN'); expect(request[1].data.regs.ext.us_privacy).to.equal('1YYN'); }); it('should not send the regs object, when consent string is undefined', function () { delete bidderRequest.uspConsent; - const request = spec.buildRequests(bidRequests, bidderRequest); + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); expect(request[0].data.regs?.us_privacy).to.not.exist; }); }); @@ -676,21 +723,21 @@ describe('OpenxRtbAdapter', function () { it('should send a signal to specify that GDPR applies to this request', function () { bidderRequest.bids = bidRequests; - const request = spec.buildRequests(bidRequests, bidderRequest); + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); expect(request[0].data.regs.ext.gdpr).to.equal(1); expect(request[1].data.regs.ext.gdpr).to.equal(1); }); it('should send the consent string', function () { bidderRequest.bids = bidRequests; - const request = spec.buildRequests(bidRequests, bidderRequest); + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); expect(request[0].data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString); expect(request[1].data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString); }); it('should send the addtlConsent string', function () { bidderRequest.bids = bidRequests; - const request = spec.buildRequests(bidRequests, bidderRequest); + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); expect(request[0].data.user.ext.ConsentedProvidersSettings.consented_providers).to.equal(bidderRequest.gdprConsent.addtlConsent); expect(request[1].data.user.ext.ConsentedProvidersSettings.consented_providers).to.equal(bidderRequest.gdprConsent.addtlConsent); }); @@ -698,7 +745,7 @@ describe('OpenxRtbAdapter', function () { it('should send a signal to specify that GDPR does not apply to this request', function () { bidderRequest.gdprConsent.gdprApplies = false; bidderRequest.bids = bidRequests; - const request = spec.buildRequests(bidRequests, bidderRequest); + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); expect(request[0].data.regs.ext.gdpr).to.equal(0); expect(request[1].data.regs.ext.gdpr).to.equal(0); }); @@ -707,7 +754,7 @@ describe('OpenxRtbAdapter', function () { 'but can send consent data, ', function () { delete bidderRequest.gdprConsent.gdprApplies; bidderRequest.bids = bidRequests; - const request = spec.buildRequests(bidRequests, bidderRequest); + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); expect(request[0].data.regs?.ext?.gdpr).to.not.be.ok; expect(request[0].data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString); expect(request[1].data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString); @@ -716,7 +763,7 @@ describe('OpenxRtbAdapter', function () { it('when consent string is undefined, should not send the consent string, ', function () { delete bidderRequest.gdprConsent.consentString; bidderRequest.bids = bidRequests; - const request = spec.buildRequests(bidRequests, bidderRequest); + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); expect(request[0].data.imp[0].ext.consent).to.equal(undefined); expect(request[1].data.imp[0].ext.consent).to.equal(undefined); }); @@ -725,7 +772,7 @@ describe('OpenxRtbAdapter', function () { context('coppa', function() { it('when there are no coppa param settings, should not send a coppa flag', function () { - const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest); + const request = spec.buildRequests(bidRequestsWithMediaTypes, syncAddFPDToBidderRequest(mockBidderRequest)); expect(request[0].data.regs?.coppa).to.be.not.ok; }); @@ -738,7 +785,7 @@ describe('OpenxRtbAdapter', function () { return utils.deepAccess(mockConfig, key); }); - const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest); + const request = spec.buildRequests(bidRequestsWithMediaTypes, syncAddFPDToBidderRequest(mockBidderRequest)); expect(request[0].data.regs.coppa).to.equal(1); }); @@ -760,21 +807,21 @@ describe('OpenxRtbAdapter', function () { it('when there is a do not track, should send a dnt', function () { doNotTrackStub.returns(1); - const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest); + const request = spec.buildRequests(bidRequestsWithMediaTypes, syncAddFPDToBidderRequest(mockBidderRequest)); expect(request[0].data.device.dnt).to.equal(1); }); it('when there is not do not track, don\'t send dnt', function () { doNotTrackStub.returns(0); - const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest); + const request = spec.buildRequests(bidRequestsWithMediaTypes, syncAddFPDToBidderRequest(mockBidderRequest)); expect(request[0].data.device.dnt).to.equal(0); }); it('when there is no defined do not track, don\'t send dnt', function () { doNotTrackStub.returns(null); - const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest); + const request = spec.buildRequests(bidRequestsWithMediaTypes, syncAddFPDToBidderRequest(mockBidderRequest)); expect(request[0].data.device.dnt).to.equal(0); }); }); @@ -1503,5 +1550,4 @@ describe('OpenxRtbAdapter', function () { }); }); }); -}) -; +}); diff --git a/test/spec/modules/optidigitalBidAdapter_spec.js b/test/spec/modules/optidigitalBidAdapter_spec.js new file mode 100755 index 00000000000..8c222650f7e --- /dev/null +++ b/test/spec/modules/optidigitalBidAdapter_spec.js @@ -0,0 +1,604 @@ +import { expect } from 'chai'; +import { spec } from 'modules/optidigitalBidAdapter.js'; +import * as utils from 'src/utils.js'; + +const ENDPOINT = 'https://pbs.optidigital.com/bidder'; + +describe('optidigitalAdapterTests', function () { + describe('isBidRequestValid', function () { + it('bidRequest with publisherId and placementId', function () { + expect(spec.isBidRequestValid({ + bidder: 'optidigital', + params: { + publisherId: 's123', + placementId: 'Billboard_Top' + } + })).to.equal(true); + }); + it('bidRequest without publisherId', function () { + expect(spec.isBidRequestValid({ + bidder: 'optidigital', + params: { + placementId: 'Billboard_Top' + } + })).to.equal(false); + }); + it('bidRequest without placementId', function () { + expect(spec.isBidRequestValid({ + bidder: 'optidigital', + params: { + publisherId: 's123' + } + })).to.equal(false); + }); + it('bidRequest without required parameters', function () { + expect(spec.isBidRequestValid({ + bidder: 'optidigital', + params: {} + })).to.equal(false); + }); + }); + + describe('buildRequests', function () { + const bidderRequest = { + bids: [ + { + 'bidder': 'optidigital', + 'params': { + 'publisherId': 's123', + 'placementId': 'Billboard_Top', + 'divId': 'Billboard_Top_3c5425', + 'badv': ['example.com'], + 'bcat': ['IAB1-1'], + 'bapp': ['com.blocked'], + 'battr': [1, 2] + }, + 'crumbs': { + 'pubcid': '7769fd03-574c-48fe-b512-8147f7c4023a' + }, + 'ortb2Imp': { + 'ext': { + 'tid': '0cb56262-9637-474d-a572-86fa860fd8b7', + 'data': { + 'adserver': { + 'name': 'gam', + 'adslot': '/19968336/header-bid-tag-0' + }, + 'pbadslot': '/19968336/header-bid-tag-0' + }, + 'gpid': '/19968336/header-bid-tag-0' + } + }, + 'mediaTypes': { + 'banner': { + 'sizes': [ [ 300, 250 ], [ 300, 600 ] ] + } + }, + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'transactionId': '0cb56262-9637-474d-a572-86fa860fd8b7', + 'sizes': [ [ 300, 250 ], [ 300, 600 ] ], + 'bidId': '245d89f17f289f', + 'bidderRequestId': '199d7ffafa1e91', + 'auctionId': 'b66f01cd-3441-4403-99fa-d8062e795933', + 'src': 'client', + 'metrics': { + 'requestBids.usp': 0.5, + 'requestBids.pubCommonId': 0.29999999701976776, + 'requestBids.fpd': 3.1000000089406967, + 'requestBids.validate': 0.5, + 'requestBids.makeRequests': 2.2000000029802322, + 'requestBids.total': 570, + 'requestBids.callBids': 320.5, + 'adapter.client.net': [ + 317.30000001192093 + ], + 'adapters.client.optidigital.net': [ + 317.30000001192093 + ], + 'adapter.client.interpretResponse': [ + 0 + ], + 'adapters.client.optidigital.interpretResponse': [ + 0 + ], + 'adapter.client.validate': 0, + 'adapters.client.optidigital.validate': 0, + 'adapter.client.buildRequests': 1, + 'adapters.client.optidigital.buildRequests': 1, + 'adapter.client.total': 318.59999999403954, + 'adapters.client.optidigital.total': 318.59999999403954 + }, + 'bidRequestsCount': 1, + 'bidderRequestsCount': 1, + 'bidderWinsCount': 0, + 'ortb2': { + 'site': { + 'page': 'https://example.com', + 'ref': 'https://example.com', + 'domain': 'example.com', + 'publisher': { + 'domain': 'example.com' + } + }, + 'device': { + 'w': 1605, + 'h': 1329, + 'dnt': 0, + 'ua': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36', + 'language': 'pl', + 'sua': { + 'source': 2, + 'platform': { + 'brand': 'Windows', + 'version': [ + '10', + '0', + '0' + ] + }, + 'browsers': [ + { + 'brand': 'Not_A Brand', + 'version': [ + '99', + '0', + '0', + '0' + ] + }, + { + 'brand': 'Google Chrome', + 'version': [ + '109', + '0', + '5414', + '75' + ] + }, + { + 'brand': 'Chromium', + 'version': [ + '109', + '0', + '5414', + '75' + ] + } + ], + 'mobile': 0, + 'model': '', + 'bitness': '64', + 'architecture': 'x86' + } + } + } + } + ], + 'refererInfo': { + 'canonicalUrl': 'https://www.prebid.org/the/link/to/the/page' + } + }; + + let validBidRequests = [ + { + 'bidder': 'optidigital', + 'bidId': '51ef8751f9aead', + 'params': { + 'publisherId': 's123', + 'placementId': 'Billboard_Top', + 'badv': ['example.com'], + 'bcat': ['IAB1-1'], + 'bapp': ['com.blocked'], + 'battr': [1, 2] + }, + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec', + 'sizes': [[320, 50], [300, 250], [300, 600]], + 'bidderRequestId': '418b37f85e772c', + 'auctionId': '18fd8b8b0bd757' + } + ] + + it('should return an empty array if there are no bid requests', () => { + const emptyBidRequests = []; + const request = spec.buildRequests(emptyBidRequests, emptyBidRequests); + expect(request).to.be.an('array').that.is.empty; + }); + + it('should send bid request via POST', function() { + const request = spec.buildRequests(validBidRequests, bidderRequest); + expect(request.method).to.equal('POST'); + }); + + it('should send bid request to given endpoint', function() { + const request = spec.buildRequests(validBidRequests, bidderRequest); + expect(request.url).to.equal(ENDPOINT); + }); + + it('should be bidRequest data', function () { + const request = spec.buildRequests(validBidRequests, bidderRequest); + expect(request.data).to.exist; + }); + + it('should add schain object to payload if exists', function () { + const bidRequest = Object.assign({}, validBidRequests[0], { + schain: { + ver: '1.0', + complete: 1, + nodes: [{ + asi: 'examplewebsite.com', + sid: '00001', + hp: 1 + }] + } + }); + const request = spec.buildRequests([bidRequest], bidderRequest); + const payload = JSON.parse(request.data) + expect(payload.schain).to.exist; + expect(payload.schain).to.deep.equal({ + ver: '1.0', + complete: 1, + nodes: [{ + asi: 'examplewebsite.com', + sid: '00001', + hp: 1 + }] + }); + }); + + it('should add adContainerWidth and adContainerHeight to payload if divId exsists in parameter', function () { + let validBidRequestsWithDivId = [ + { + 'bidder': 'optidigital', + 'bidId': '51ef8751f9aead', + 'params': { + 'publisherId': 's123', + 'placementId': 'Billboard_Top', + 'divId': 'div-gpt-ad-1460505748561-0' + }, + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec', + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 50], [300, 250], [300, 600]] + } + }, + 'sizes': [[320, 50], [300, 250], [300, 600]], + 'bidderRequestId': '418b37f85e772c', + 'auctionId': '18fd8b8b0bd757' + } + ] + const request = spec.buildRequests(validBidRequestsWithDivId, bidderRequest); + const payload = JSON.parse(request.data) + payload.imp[0].adContainerWidth = 1920 + payload.imp[0].adContainerHeight = 1080 + expect(payload.imp[0].adContainerWidth).to.exist; + expect(payload.imp[0].adContainerHeight).to.exist; + }); + + it('should add pageTemplate to payload if pageTemplate exsists in parameter', function () { + let validBidRequestsWithDivId = [ + { + 'bidder': 'optidigital', + 'bidId': '51ef8751f9aead', + 'params': { + 'publisherId': 's123', + 'placementId': 'Billboard_Top', + 'pageTemplate': 'home' + }, + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec', + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 50], [300, 250], [300, 600]] + } + }, + 'sizes': [[320, 50], [300, 250], [300, 600]], + 'bidderRequestId': '418b37f85e772c', + 'auctionId': '18fd8b8b0bd757' + } + ] + const request = spec.buildRequests(validBidRequestsWithDivId, bidderRequest); + const payload = JSON.parse(request.data) + payload.imp[0].pageTemplate = 'home' + expect(payload.imp[0].pageTemplate).to.exist; + }); + + it('should add referrer to payload if it exsists in bidderRequest', function () { + bidderRequest.refererInfo.page = 'https://www.prebid.org'; + const request = spec.buildRequests(validBidRequests, bidderRequest); + const payload = JSON.parse(request.data) + expect(payload.referrer).to.equal('https://www.prebid.org'); + }); + + it('should use value for badv, bcat, bapp from params', function () { + bidderRequest.ortb2 = { + 'site': { + 'page': 'https://example.com', + 'ref': 'https://example.com', + 'domain': 'example.com', + 'publisher': { + 'domain': 'example.com' + } + }, + 'device': { + 'w': 1507, + 'h': 1329, + 'dnt': 0, + 'ua': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36', + 'language': 'pl', + 'sua': { + 'source': 2, + 'platform': { + 'brand': 'Windows', + 'version': [ + '10', + '0', + '0' + ] + }, + 'browsers': [ + { + 'brand': 'Not_A Brand', + 'version': [ + '99', + '0', + '0', + '0' + ] + }, + { + 'brand': 'Google Chrome', + 'version': [ + '109', + '0', + '5414', + '120' + ] + }, + { + 'brand': 'Chromium', + 'version': [ + '109', + '0', + '5414', + '120' + ] + } + ], + 'mobile': 0, + 'model': '', + 'bitness': '64', + 'architecture': 'x86' + } + } + }; + const request = spec.buildRequests(validBidRequests, bidderRequest); + const payload = JSON.parse(request.data); + expect(payload.badv).to.deep.equal(validBidRequests[0].params.badv); + expect(payload.bcat).to.deep.equal(validBidRequests[0].params.bcat); + expect(payload.bapp).to.deep.equal(validBidRequests[0].params.bapp); + }); + + it('should send empty GDPR consent and required set to false', function() { + const request = spec.buildRequests(validBidRequests, bidderRequest); + const payload = JSON.parse(request.data); + expect(payload.gdpr.consent).to.equal(''); + expect(payload.gdpr.required).to.equal(false); + }); + + it('should send GDPR to given endpoint', function() { + let consentString = 'DFR8KRePoQNsRREZCADBG+A=='; + bidderRequest.gdprConsent = { + 'consentString': consentString, + 'gdprApplies': true, + 'vendorData': { + 'hasGlobalConsent': false + }, + 'apiVersion': 1 + } + const request = spec.buildRequests(validBidRequests, bidderRequest); + const payload = JSON.parse(request.data); + expect(payload.gdpr).to.exist; + expect(payload.gdpr.consent).to.equal(consentString); + expect(payload.gdpr.required).to.exist.and.to.be.true; + }); + + it('should send empty GDPR consent to endpoint', function() { + let consentString = false; + bidderRequest.gdprConsent = { + 'consentString': consentString, + 'gdprApplies': true, + 'vendorData': { + 'hasGlobalConsent': false + }, + 'apiVersion': 1 + } + const request = spec.buildRequests(validBidRequests, bidderRequest); + const payload = JSON.parse(request.data); + expect(payload.gdpr.consent).to.equal(''); + }); + + it('should send uspConsent to given endpoint', function() { + bidderRequest.uspConsent = '1YYY'; + const request = spec.buildRequests(validBidRequests, bidderRequest); + const payload = JSON.parse(request.data); + expect(payload.uspConsent).to.exist; + }); + + it('should use appropriate mediaTypes banner sizes', function() { + const mediaTypesBannerSize = { + 'mediaTypes': { + 'banner': { + 'sizes': [300, 600] + } + } + }; + returnBannerSizes(mediaTypesBannerSize, '300x600'); + }); + + it('should use appropriate mediaTypes banner sizes as array', function() { + const mediaTypesBannerSize = { + 'mediaTypes': { + 'banner': { + 'sizes': [300, 600] + } + } + }; + returnBannerSizes(mediaTypesBannerSize, ['300x600']); + }); + + it('should fetch floor from floor module if it is available', function() { + let validBidRequestsWithCurrency = [ + { + 'bidder': 'optidigital', + 'bidId': '51ef8751f9aead', + 'params': { + 'publisherId': 's123', + 'placementId': 'Billboard_Top', + 'pageTemplate': 'home', + 'currency': 'USD' + }, + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec', + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 50], [300, 250], [300, 600]] + } + }, + 'sizes': [[320, 50], [300, 250], [300, 600]], + 'bidderRequestId': '418b37f85e772c', + 'auctionId': '18fd8b8b0bd757' + } + ] + let floorInfo; + validBidRequestsWithCurrency[0].getFloor = () => floorInfo; + floorInfo = { currency: 'USD', floor: 1.99 }; + let request = spec.buildRequests(validBidRequestsWithCurrency, bidderRequest); + const payload = JSON.parse(request.data); + expect(payload.imp[0].bidFloor).to.exist; + }); + + function returnBannerSizes(mediaTypes, expectedSizes) { + const bidRequest = Object.assign(validBidRequests[0], mediaTypes); + const request = spec.buildRequests([bidRequest], bidderRequest); + const payload = JSON.parse(request.data); + return payload.imp.forEach(bid => { + if (Array.isArray(expectedSizes)) { + expect(JSON.stringify(bid.sizes)).to.equal(JSON.stringify(expectedSizes)); + } else { + expect(bid.sizes[0]).to.equal(expectedSizes); + } + }); + } + }); + describe('getUserSyncs', function() { + const syncurlIframe = 'https://scripts.opti-digital.com/js/presync.html?endpoint=optidigital'; + let test; + beforeEach(function () { + test = sinon.sandbox.create(); + }); + afterEach(function() { + test.restore(); + }); + + it('should be executed as in config', function() { + expect(spec.getUserSyncs({ iframeEnabled: true }, {}, undefined, undefined)).to.deep.equal([{ + type: 'iframe', url: syncurlIframe + }]); + }); + + it('should return appropriate URL', function() { + expect(spec.getUserSyncs({ iframeEnabled: true }, {}, {gdprApplies: true, consentString: 'foo'}, undefined)).to.deep.equal([{ + type: 'iframe', url: `${syncurlIframe}&gdpr=1&gdpr_consent=foo` + }]); + expect(spec.getUserSyncs({ iframeEnabled: true }, {}, {gdprApplies: false, consentString: 'foo'}, undefined)).to.deep.equal([{ + type: 'iframe', url: `${syncurlIframe}&gdpr=0&gdpr_consent=foo` + }]); + expect(spec.getUserSyncs({ iframeEnabled: true }, {}, {gdprApplies: true, consentString: undefined}, undefined)).to.deep.equal([{ + type: 'iframe', url: `${syncurlIframe}&gdpr=1&gdpr_consent=` + }]); + expect(spec.getUserSyncs({ iframeEnabled: true }, {}, {gdprApplies: true, consentString: 'foo'}, {consentString: 'fooUsp'})).to.deep.equal([{ + type: 'iframe', url: `${syncurlIframe}&gdpr=1&gdpr_consent=foo&ccpa_consent=fooUsp` + }]); + }); + }); + describe('interpretResponse', function () { + it('should get bids', function() { + let bids = { + 'body': { + 'bids': [{ + 'transactionId': 'cf5faec3-fcee-4f26-80ae-fc8b6cf23b7d', + 'placementId': 'Billboard_Top', + 'bidId': '83fb53a5e67f49', + 'ttl': 150, + 'creativeId': 'mobile_pos_2', + 'cur': 'USD', + 'cpm': 0.445455, + 'w': '300', + 'h': '600', + 'adm': '', + 'adomain': [] + }] + } + }; + let expectedResponse = [ + { + 'placementId': 'Billboard_Top', + 'transactionId': 'cf5faec3-fcee-4f26-80ae-fc8b6cf23b7d', + 'requestId': '83fb53a5e67f49', + 'ttl': 150, + 'creativeId': 'mobile_pos_2', + 'currency': 'USD', + 'cpm': 0.445455, + 'width': '300', + 'height': '600', + 'ad': '', + 'netRevenue': true, + 'meta': { + 'advertiserDomains': [] + } + } + ]; + let result = spec.interpretResponse(bids); + expect(result).to.eql(expectedResponse); + }); + + it('should handle empty array bid response', function() { + let bids = { + 'body': { + 'bids': [] + } + }; + let result = spec.interpretResponse(bids); + expect(result.length).to.equal(0); + }); + }); +}); diff --git a/test/spec/modules/optimonAnalyticsAdapter_spec.js b/test/spec/modules/optimonAnalyticsAdapter_spec.js index 406e9cb75c4..f1aa00334b5 100644 --- a/test/spec/modules/optimonAnalyticsAdapter_spec.js +++ b/test/spec/modules/optimonAnalyticsAdapter_spec.js @@ -4,6 +4,7 @@ import optimonAnalyticsAdapter from '../../../modules/optimonAnalyticsAdapter.js import adapterManager from 'src/adapterManager'; import * as events from 'src/events'; import constants from 'src/constants.json' +import {expectEvents} from '../../helpers/analytics.js'; const AD_UNIT_CODE = 'demo-adunit-1'; const PUBLISHER_CONFIG = { @@ -14,14 +15,12 @@ const PUBLISHER_CONFIG = { describe('Optimon Analytics Adapter', () => { const optmn_currentWindow = utils.getWindowSelf(); - let optmn_queue = []; beforeEach(() => { - optmn_currentWindow.OptimonAnalyticsAdapter = (...optmn_args) => optmn_queue.push(optmn_args); + optmn_currentWindow.OptimonAnalyticsAdapter = sinon.stub() adapterManager.enableAnalytics({ provider: 'optimon' }); - optmn_queue = [] }); afterEach(() => { @@ -29,13 +28,6 @@ describe('Optimon Analytics Adapter', () => { }); it('should forward all events to the queue', () => { - const optmn_arguments = [AD_UNIT_CODE, PUBLISHER_CONFIG]; - - events.emit(constants.EVENTS.AUCTION_END, optmn_arguments) - events.emit(constants.EVENTS.BID_TIMEOUT, optmn_arguments) - events.emit(constants.EVENTS.BID_WON, optmn_arguments) - - // 3 Optimon events + 1 Clean.io event - expect(optmn_queue.length).to.eql(4); + expectEvents().to.beBundledTo(optmn_currentWindow.OptimonAnalyticsAdapter); }); }); diff --git a/test/spec/modules/orbitsoftBidAdapter_spec.js b/test/spec/modules/orbitsoftBidAdapter_spec.js new file mode 100644 index 00000000000..8c3187e9324 --- /dev/null +++ b/test/spec/modules/orbitsoftBidAdapter_spec.js @@ -0,0 +1,255 @@ +import {expect} from 'chai'; +import {spec} from 'modules/orbitsoftBidAdapter.js'; + +const ENDPOINT_URL = 'https://orbitsoft.com/php/ads/hb.phps'; +const REFERRER_URL = 'http://referrer.url/?_='; + +describe('Orbitsoft adapter', function () { + describe('implementation', function () { + describe('for requests', function () { + it('should accept valid bid', function () { + let validBid = { + bidder: 'orbitsoft', + params: { + placementId: '123', + requestUrl: ENDPOINT_URL + } + }, + isValid = spec.isBidRequestValid(validBid); + + expect(isValid).to.equal(true); + }); + + it('should reject invalid bid', function () { + let invalidBid = { + bidder: 'orbitsoft' + }, + isValid = spec.isBidRequestValid(invalidBid); + + expect(isValid).to.equal(false); + }); + }); + describe('for requests', function () { + it('should accept valid bid with styles', function () { + let validBid = { + bidder: 'orbitsoft', + params: { + placementId: '123', + requestUrl: ENDPOINT_URL, + style: { + title: { + family: 'Tahoma', + size: 'medium', + weight: 'normal', + style: 'normal', + color: '0053F9' + }, + description: { + family: 'Tahoma', + size: 'medium', + weight: 'normal', + style: 'normal', + color: '0053F9' + }, + url: { + family: 'Tahoma', + size: 'medium', + weight: 'normal', + style: 'normal', + color: '0053F9' + }, + colors: { + background: 'ffffff', + border: 'E0E0E0', + link: '5B99FE' + } + } + }, + refererInfo: {referer: REFERRER_URL}, + }, + isValid = spec.isBidRequestValid(validBid); + expect(isValid).to.equal(true); + + let buildRequest = spec.buildRequests([validBid])[0]; + let requestUrl = buildRequest.url; + let requestUrlParams = buildRequest.data; + expect(requestUrl).to.equal(ENDPOINT_URL); + expect(requestUrlParams).have.property('f1', 'Tahoma'); + expect(requestUrlParams).have.property('fs1', 'medium'); + expect(requestUrlParams).have.property('w1', 'normal'); + expect(requestUrlParams).have.property('s1', 'normal'); + expect(requestUrlParams).have.property('c3', '0053F9'); + expect(requestUrlParams).have.property('f2', 'Tahoma'); + expect(requestUrlParams).have.property('fs2', 'medium'); + expect(requestUrlParams).have.property('w2', 'normal'); + expect(requestUrlParams).have.property('s2', 'normal'); + expect(requestUrlParams).have.property('c4', '0053F9'); + expect(requestUrlParams).have.property('f3', 'Tahoma'); + expect(requestUrlParams).have.property('fs3', 'medium'); + expect(requestUrlParams).have.property('w3', 'normal'); + expect(requestUrlParams).have.property('s3', 'normal'); + expect(requestUrlParams).have.property('c5', '0053F9'); + expect(requestUrlParams).have.property('c2', 'ffffff'); + expect(requestUrlParams).have.property('c1', 'E0E0E0'); + expect(requestUrlParams).have.property('c6', '5B99FE'); + }); + + it('should accept valid bid with custom params', function () { + let validBid = { + bidder: 'orbitsoft', + params: { + placementId: '123', + requestUrl: ENDPOINT_URL, + customParams: { + cacheBuster: 'bf4d7c1', + clickUrl: 'http://testclickurl.com' + } + }, + refererInfo: {referer: REFERRER_URL}, + }, + isValid = spec.isBidRequestValid(validBid); + expect(isValid).to.equal(true); + + let buildRequest = spec.buildRequests([validBid])[0]; + let requestUrlCustomParams = buildRequest.data; + expect(requestUrlCustomParams).have.property('c.cacheBuster', 'bf4d7c1'); + expect(requestUrlCustomParams).have.property('c.clickUrl', 'http://testclickurl.com'); + }); + + it('should reject invalid bid without requestUrl', function () { + let invalidBid = { + bidder: 'orbitsoft', + params: { + placementId: '123' + } + }, + isValid = spec.isBidRequestValid(invalidBid); + + expect(isValid).to.equal(false); + }); + + it('should reject invalid bid without placementId', function () { + let invalidBid = { + bidder: 'orbitsoft', + params: { + requestUrl: ENDPOINT_URL + } + }, + isValid = spec.isBidRequestValid(invalidBid); + + expect(isValid).to.equal(false); + }); + }); + describe('bid responses', function () { + it('should return complete bid response', function () { + let serverResponse = { + body: { + callback_uid: '265b29b70cc106', + cpm: 0.5, + width: 240, + height: 240, + content_url: 'https://orbitsoft.com/php/ads/hb.html', + adomain: ['test.adomain.tld'] + } + }; + + let bidRequests = [ + { + bidder: 'orbitsoft', + params: { + placementId: '123', + requestUrl: ENDPOINT_URL + } + } + ]; + let bids = spec.interpretResponse(serverResponse, {'bidRequest': bidRequests[0]}); + expect(bids).to.be.lengthOf(1); + expect(bids[0].cpm).to.equal(serverResponse.body.cpm); + expect(bids[0].width).to.equal(serverResponse.body.width); + expect(bids[0].height).to.equal(serverResponse.body.height); + expect(bids[0].currency).to.equal('USD'); + expect(bids[0].netRevenue).to.equal(true); + expect(bids[0].adUrl).to.have.length.above(1); + expect(bids[0].adUrl).to.have.string('https://orbitsoft.com/php/ads/hb.html'); + expect(Object.keys(bids[0].meta)).to.include.members(['advertiserDomains']); + expect(bids[0].meta.advertiserDomains).to.deep.equal(serverResponse.body.adomain); + }); + + it('should return empty bid response', function () { + let bidRequests = [ + { + bidder: 'orbitsoft', + params: { + placementId: '123', + requestUrl: ENDPOINT_URL + } + } + ]; + let serverResponse = { + body: { + callback_uid: '265b29b70cc106', + cpm: 0 + } + }, + bids = spec.interpretResponse(serverResponse, {'bidRequest': bidRequests[0]}); + + expect(bids).to.be.lengthOf(0); + }); + + it('should return empty bid response on incorrect size', function () { + let bidRequests = [ + { + bidder: 'orbitsoft', + params: { + placementId: '123', + requestUrl: ENDPOINT_URL + } + } + ]; + let serverResponse = { + body: { + callback_uid: '265b29b70cc106', + cpm: 1.5, + width: 0, + height: 0 + } + }, + bids = spec.interpretResponse(serverResponse, {'bidRequest': bidRequests[0]}); + + expect(bids).to.be.lengthOf(0); + }); + + it('should return empty bid response with error', function () { + let bidRequests = [ + { + bidder: 'orbitsoft', + params: { + placementId: '123', + requestUrl: ENDPOINT_URL + } + } + ]; + let serverResponse = {error: 'error'}, + bids = spec.interpretResponse(serverResponse, {'bidRequest': bidRequests[0]}); + + expect(bids).to.be.lengthOf(0); + }); + + it('should return empty bid response on empty body', function () { + let bidRequests = [ + { + bidder: 'orbitsoft', + params: { + placementId: '123', + requestUrl: ENDPOINT_URL + } + } + ]; + let serverResponse = {}, + bids = spec.interpretResponse(serverResponse, {'bidRequest': bidRequests[0]}); + + expect(bids).to.be.lengthOf(0); + }); + }); + }); +}); diff --git a/test/spec/modules/outbrainBidAdapter_spec.js b/test/spec/modules/outbrainBidAdapter_spec.js index 5d7bebc1de1..f5ce00ed8df 100644 --- a/test/spec/modules/outbrainBidAdapter_spec.js +++ b/test/spec/modules/outbrainBidAdapter_spec.js @@ -1,7 +1,7 @@ -import {expect} from 'chai'; -import {spec} from 'modules/outbrainBidAdapter.js'; -import {config} from 'src/config.js'; -import {server} from 'test/mocks/xhr'; +import { expect } from 'chai'; +import { spec } from 'modules/outbrainBidAdapter.js'; +import { config } from 'src/config.js'; +import { server } from 'test/mocks/xhr'; import { createEidsArray } from 'modules/userId/eids.js'; describe('Outbrain Adapter', function () { @@ -45,6 +45,26 @@ describe('Outbrain Adapter', function () { ] } + const videoBidRequestParams = { + mediaTypes: { + video: { + playerSize: [[640, 480]], + mimes: ['video/mp4'], + protocols: [1, 2, 3, 4, 5, 6, 7, 8], + playbackmethod: [1], + skip: 1, + api: [2], + minbitrate: 1000, + maxbitrate: 3000, + minduration: 3, + maxduration: 10, + startdelay: 2, + placement: 4, + linearity: 1 + } + } + } + describe('isBidRequestValid', function () { before(() => { config.setConfig({ @@ -93,6 +113,34 @@ describe('Outbrain Adapter', function () { } expect(spec.isBidRequestValid(bid)).to.equal(true) }) + it('should succeed when bid contains video', function () { + const bid = { + bidder: 'outbrain', + params: { + publisher: { + id: 'publisher-id', + } + }, + ...videoBidRequestParams, + } + expect(spec.isBidRequestValid(bid)).to.equal(true) + }) + it('should fail when bid contains insufficient video information', function () { + const bid = { + bidder: 'outbrain', + params: { + publisher: { + id: 'publisher-id', + } + }, + mediaTypes: { + video: { + context: 'outstream' + } + }, + } + expect(spec.isBidRequestValid(bid)).to.equal(false) + }) it('should fail if publisher id is not set', function () { const bid = { bidder: 'outbrain', @@ -298,6 +346,61 @@ describe('Outbrain Adapter', function () { expect(res.data).to.deep.equal(JSON.stringify(expectedData)) }) + it('should build video request', function () { + const bidRequest = { + ...commonBidRequest, + ...videoBidRequestParams, + } + const expectedData = { + site: { + page: 'https://example.com/', + publisher: { + id: 'publisher-id' + } + }, + device: { + ua: navigator.userAgent + }, + source: { + fd: 1 + }, + cur: [ + 'USD' + ], + imp: [ + { + id: '1', + video: { + w: 640, + h: 480, + protocols: [1, 2, 3, 4, 5, 6, 7, 8], + playbackmethod: [1], + mimes: ['video/mp4'], + skip: 1, + api: [2], + minbitrate: 1000, + maxbitrate: 3000, + minduration: 3, + maxduration: 10, + startdelay: 2, + placement: 4, + linearity: 1 + } + } + ], + ext: { + prebid: { + channel: { + name: 'pbjs', version: '$prebid.version$' + } + } + } + } + const res = spec.buildRequests([bidRequest], commonBidderRequest) + expect(res.url).to.equal('https://bidder-url.com') + expect(res.data).to.deep.equal(JSON.stringify(expectedData)) + }) + it('should pass optional parameters in request', function () { const bidRequest = { ...commonBidRequest, @@ -390,7 +493,7 @@ describe('Outbrain Adapter', function () { ...commonBidRequest, ...nativeBidRequestParams, } - config.setConfig({coppa: true}) + config.setConfig({ coppa: true }) const res = spec.buildRequests([bidRequest], commonBidderRequest) const resData = JSON.parse(res.data) @@ -412,7 +515,7 @@ describe('Outbrain Adapter', function () { let res = spec.buildRequests([bidRequest], commonBidderRequest); const resData = JSON.parse(res.data) expect(resData.user.ext.eids).to.deep.equal([ - {source: 'liveramp.com', uids: [{id: 'id-value', atype: 3}]} + { source: 'liveramp.com', uids: [{ id: 'id-value', atype: 3 }] } ]); }); @@ -421,7 +524,7 @@ describe('Outbrain Adapter', function () { ...commonBidRequest, ...nativeBidRequestParams, } - bidRequest.getFloor = function() { + bidRequest.getFloor = function () { return { currency: 'USD', floor: 1.23, @@ -619,6 +722,67 @@ describe('Outbrain Adapter', function () { const res = spec.interpretResponse(serverResponse, request) expect(res).to.deep.equal(expectedRes) }); + + it('should interpret video response', function () { + const serverResponse = { + body: { + id: '123', + seatbid: [ + { + bid: [ + { + id: '111', + impid: '1', + price: 1.1, + adm: '\u003cVAST version="3.0"\u003e\u003cAd\u003e\u003cInLine\u003e\u003cAdSystem\u003ezemanta\u003c/AdSystem\u003e\u003cAdTitle\u003e1\u003c/AdTitle\u003e\u003cImpression\u003ehttp://win.com\u003c/Impression\u003e\u003cImpression\u003ehttp://example.com/imptracker\u003c/Impression\u003e\u003cCreatives\u003e\u003cCreative\u003e\u003cLinear\u003e\u003cDuration\u003e00:00:25\u003c/Duration\u003e\u003cTrackingEvents\u003e\u003cTracking event="start"\u003ehttp://example.com/start\u003c/Tracking\u003e\u003cTracking event="progress" offset="00:00:03"\u003ehttp://example.com/p3s\u003c/Tracking\u003e\u003c/TrackingEvents\u003e\u003cVideoClicks\u003e\u003cClickThrough\u003ehttp://link.com\u003c/ClickThrough\u003e\u003c/VideoClicks\u003e\u003cMediaFiles\u003e\u003cMediaFile delivery="progressive" type="video/mp4" bitrate="700" width="640" height="360"\u003ehttps://example.com/123_360p.mp4\u003c/MediaFile\u003e\u003c/MediaFiles\u003e\u003c/Linear\u003e\u003c/Creative\u003e\u003c/Creatives\u003e\u003c/InLine\u003e\u003c/Ad\u003e\u003c/VAST\u003e', + adid: '100', + cid: '5', + crid: '29998660', + cat: ['cat-1'], + adomain: [ + 'example.com' + ], + nurl: 'http://example.com/win/${AUCTION_PRICE}' + } + ], + seat: '100', + group: 1 + } + ], + bidid: '456', + cur: 'USD' + } + } + const request = { + bids: [ + { + ...commonBidRequest, + ...videoBidRequestParams + } + ] + } + const expectedRes = [ + { + requestId: request.bids[0].bidId, + cpm: 1.1, + creativeId: '29998660', + ttl: 360, + netRevenue: false, + currency: 'USD', + mediaType: 'video', + nurl: 'http://example.com/win/${AUCTION_PRICE}', + vastXml: 'zemanta1http://win.comhttp://example.com/imptracker00:00:25http://example.com/starthttp://example.com/p3shttp://link.comhttps://example.com/123_360p.mp4', + meta: { + 'advertiserDomains': [ + 'example.com' + ] + }, + } + ] + + const res = spec.interpretResponse(serverResponse, request) + expect(res).to.deep.equal(expectedRes) + }); }) }) @@ -637,41 +801,41 @@ describe('Outbrain Adapter', function () { }) it('should return user sync if pixel enabled with outbrain config', function () { - const ret = spec.getUserSyncs({pixelEnabled: true}) - expect(ret).to.deep.equal([{type: 'image', url: usersyncUrl}]) + const ret = spec.getUserSyncs({ pixelEnabled: true }) + expect(ret).to.deep.equal([{ type: 'image', url: usersyncUrl }]) }) it('should not return user sync if pixel disabled', function () { - const ret = spec.getUserSyncs({pixelEnabled: false}) + const ret = spec.getUserSyncs({ pixelEnabled: false }) expect(ret).to.be.an('array').that.is.empty }) it('should not return user sync if url is not set', function () { config.resetConfig() - const ret = spec.getUserSyncs({pixelEnabled: true}) + const ret = spec.getUserSyncs({ pixelEnabled: true }) expect(ret).to.be.an('array').that.is.empty }) - it('should pass GDPR consent', function() { - expect(spec.getUserSyncs({ pixelEnabled: true }, {}, {gdprApplies: true, consentString: 'foo'}, undefined)).to.deep.equal([{ + it('should pass GDPR consent', function () { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, { gdprApplies: true, consentString: 'foo' }, undefined)).to.deep.equal([{ type: 'image', url: `${usersyncUrl}?gdpr=1&gdpr_consent=foo` }]); - expect(spec.getUserSyncs({ pixelEnabled: true }, {}, {gdprApplies: false, consentString: 'foo'}, undefined)).to.deep.equal([{ + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, { gdprApplies: false, consentString: 'foo' }, undefined)).to.deep.equal([{ type: 'image', url: `${usersyncUrl}?gdpr=0&gdpr_consent=foo` }]); - expect(spec.getUserSyncs({ pixelEnabled: true }, {}, {gdprApplies: true, consentString: undefined}, undefined)).to.deep.equal([{ + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, { gdprApplies: true, consentString: undefined }, undefined)).to.deep.equal([{ type: 'image', url: `${usersyncUrl}?gdpr=1&gdpr_consent=` }]); }); - it('should pass US consent', function() { + it('should pass US consent', function () { expect(spec.getUserSyncs({ pixelEnabled: true }, {}, undefined, '1NYN')).to.deep.equal([{ type: 'image', url: `${usersyncUrl}?us_privacy=1NYN` }]); }); - it('should pass GDPR and US consent', function() { - expect(spec.getUserSyncs({ pixelEnabled: true }, {}, {gdprApplies: true, consentString: 'foo'}, '1NYN')).to.deep.equal([{ + it('should pass GDPR and US consent', function () { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, { gdprApplies: true, consentString: 'foo' }, '1NYN')).to.deep.equal([{ type: 'image', url: `${usersyncUrl}?gdpr=1&gdpr_consent=foo&us_privacy=1NYN` }]); }); diff --git a/test/spec/modules/permutiveRtdProvider_spec.js b/test/spec/modules/permutiveRtdProvider_spec.js index 9282ec3ac24..5030e662ea9 100644 --- a/test/spec/modules/permutiveRtdProvider_spec.js +++ b/test/spec/modules/permutiveRtdProvider_spec.js @@ -13,13 +13,13 @@ import { deepAccess, deepSetValue, mergeDeep } from '../../../src/utils.js' import { config } from 'src/config.js' describe('permutiveRtdProvider', function () { - before(function () { + beforeEach(function () { const data = getTargetingData() setLocalStorage(data) config.resetConfig() }) - after(function () { + afterEach(function () { const data = getTargetingData() removeLocalStorage(data) config.resetConfig() @@ -242,6 +242,42 @@ describe('permutiveRtdProvider', function () { }) }) it('should not overwrite ortb2 config', function () { + const moduleConfig = getConfig() + const acBidders = moduleConfig.params.acBidders + const sampleOrtbConfig = { + site: { + name: 'example' + }, + user: { + data: [ + { + name: 'www.dataprovider1.com', + ext: { taxonomyname: 'iab_audience_taxonomy' }, + segment: [{ id: '687' }, { id: '123' }] + } + ] + } + } + + const bidderConfig = Object.fromEntries(acBidders.map(bidder => [bidder, sampleOrtbConfig])) + + const transformedUserData = { + name: 'transformation', + ext: { test: true }, + segment: [1, 2, 3] + } + + setBidderRtb(bidderConfig, moduleConfig, { + // TODO: this argument is unused, is the test still valid / needed? + testTransformation: userData => transformedUserData + }) + + acBidders.forEach(bidder => { + expect(bidderConfig[bidder].site.name).to.equal(sampleOrtbConfig.site.name) + expect(bidderConfig[bidder].user.data).to.deep.include.members([sampleOrtbConfig.user.data[0]]) + }) + }) + it('should update user.keywords and not override existing values', function () { const moduleConfig = getConfig() const acBidders = moduleConfig.params.acBidders const sampleOrtbConfig = { @@ -275,10 +311,65 @@ describe('permutiveRtdProvider', function () { acBidders.forEach(bidder => { expect(bidderConfig[bidder].site.name).to.equal(sampleOrtbConfig.site.name) - expect(bidderConfig[bidder].user.keywords).to.equal(sampleOrtbConfig.user.keywords) expect(bidderConfig[bidder].user.data).to.deep.include.members([sampleOrtbConfig.user.data[0]]) + expect(bidderConfig[bidder].user.keywords).to.deep.equal('a,b,p_standard_aud=123,p_standard_aud=abc') }) }) + it('should merge ortb2 correctly for ac and ssps', function () { + setLocalStorage({ + '_ppam': [], + '_psegs': [], + '_pcrprs': ['abc', 'def', 'xyz'], + '_pssps': { + ssps: ['foo', 'bar'], + cohorts: ['xyz', 'uvw'], + } + }) + const moduleConfig = { + name: 'permutive', + waitForIt: true, + params: { + acBidders: ['foo', 'other'], + maxSegs: 30 + } + } + const bidderConfig = {}; + + setBidderRtb(bidderConfig, moduleConfig) + + // include both ac and ssp cohorts, as foo is both in ac bidders and ssps + const expectedFooTargetingData = [ + { id: 'abc' }, + { id: 'def' }, + { id: 'xyz' }, + { id: 'uvw' }, + ] + expect(bidderConfig['foo'].user.data).to.deep.include.members([{ + name: 'permutive.com', + segment: expectedFooTargetingData + }]) + + // don't include ac targeting as it's not in ac bidders + const expectedBarTargetingData = [ + { id: 'xyz' }, + { id: 'uvw' }, + ] + expect(bidderConfig['bar'].user.data).to.deep.include.members([{ + name: 'permutive.com', + segment: expectedBarTargetingData + }]) + + // only include ac targeting as this ssp is not in ssps list + const expectedOtherTargetingData = [ + { id: 'abc' }, + { id: 'def' }, + { id: 'xyz' }, + ] + expect(bidderConfig['other'].user.data).to.deep.include.members([{ + name: 'permutive.com', + segment: expectedOtherTargetingData + }]) + }) }) describe('Getting segments', function () { @@ -291,7 +382,11 @@ describe('permutiveRtdProvider', function () { const segments = getSegments(max) for (const key in segments) { - expect(segments[key]).to.have.length(max) + if (key === 'ssp') { + expect(segments[key].cohorts).to.have.length(max) + } else { + expect(segments[key]).to.have.length(max) + } } }) }) @@ -311,12 +406,13 @@ describe('permutiveRtdProvider', function () { if (bidder === 'appnexus') { expect(deepAccess(params, 'keywords.permutive')).to.eql(data.appnexus) - expect(deepAccess(params, 'keywords.p_standard')).to.eql(data.ac) + expect(deepAccess(params, 'keywords.p_standard')).to.eql(data.ac.concat(data.ssp.cohorts)) } }) }) } }) + it('sets segment targeting for Magnite', function () { const data = transformedTargeting() const adUnits = getAdUnits() @@ -331,12 +427,44 @@ describe('permutiveRtdProvider', function () { if (bidder === 'rubicon') { expect(deepAccess(params, 'visitor.permutive')).to.eql(data.rubicon) - expect(deepAccess(params, 'visitor.p_standard')).to.eql(data.ac) + expect(deepAccess(params, 'visitor.p_standard')).to.eql(data.ac.concat(data.ssp.cohorts)) + } + }) + }) + } + }) + + it('sets segment targeting for Magnite video', function () { + const targetingData = getTargetingData() + targetingData._prubicons.push(321) + + setLocalStorage(targetingData) + + const data = transformedTargeting(targetingData) + const config = getConfig() + + const adUnits = getAdUnits().filter(adUnit => adUnit.mediaTypes.video) + expect(adUnits).to.have.lengthOf(1) + + initSegments({ adUnits }, callback, config) + + function callback() { + adUnits.forEach(adUnit => { + adUnit.bids.forEach(bid => { + const { bidder, params } = bid + + if (bidder === 'rubicon') { + expect( + deepAccess(params, 'visitor.permutive'), + 'Should map all targeting values to a string', + ).to.eql(data.rubicon.map(String)) + expect(deepAccess(params, 'visitor.p_standard')).to.eql(data.ac.concat(data.ssp.cohorts)) } }) }) } }) + it('sets segment targeting for Ozone', function () { const data = transformedTargeting() const adUnits = getAdUnits() @@ -350,7 +478,7 @@ describe('permutiveRtdProvider', function () { const { bidder, params } = bid if (bidder === 'ozone') { - expect(deepAccess(params, 'customData.0.targeting.p_standard')).to.eql(data.ac) + expect(deepAccess(params, 'customData.0.targeting.p_standard')).to.eql(data.ac.concat(data.ssp.cohorts)) } }) }) @@ -384,7 +512,7 @@ describe('permutiveRtdProvider', function () { if (bidder === 'rubicon') { expect(deepAccess(params, 'visitor.permutive')).to.eql(data.gam) - expect(deepAccess(params, 'visitor.p_standard')).to.eql(data.ac) + expect(deepAccess(params, 'visitor.p_standard')).to.eql(data.ac.concat(data.ssp.cohorts)) } }) }) @@ -516,14 +644,13 @@ function getConfig () { } } -function transformedTargeting () { - const data = getTargetingData() - +function transformedTargeting (data = getTargetingData()) { return { ac: [...data._pcrprs, ...data._ppam, ...data._psegs.filter(seg => seg >= 1000000)], appnexus: data._papns, rubicon: data._prubicons, gam: data._pdfps, + ssp: data._pssps, } } @@ -534,7 +661,8 @@ function getTargetingData () { _papns: ['appnexus1', 'appnexus2'], _psegs: ['1234', '1000001', '1000002'], _ppam: ['ppam1', 'ppam2'], - _pcrprs: ['pcrprs1', 'pcrprs2'] + _pcrprs: ['pcrprs1', 'pcrprs2', 'dup'], + _pssps: { ssps: ['xyz', 'abc', 'dup'], cohorts: ['123', 'abc'] } } } @@ -640,6 +768,34 @@ function getAdUnits () { } } ] + }, + { + code: 'myVideoAdUnit', + mediaTypes: { + video: { + context: 'instream', + playerSize: [640, 480], + mimes: ['video/mp4', 'video/x-ms-wmv'], + protocols: [2, 3, 5, 6], + api: [2], + maxduration: 30, + linearity: 1 + } + }, + bids: [{ + bidder: 'rubicon', + params: { + accountId: '9840', + siteId: '123564', + zoneId: '583584', + video: { + language: 'en' + }, + visitor: { + test_kv: ['true'] + } + } + }] } ] } diff --git a/test/spec/modules/pianoDmpAnalyticsAdapter_spec.js b/test/spec/modules/pianoDmpAnalyticsAdapter_spec.js index 49b048f1fe6..0c4949264a7 100644 --- a/test/spec/modules/pianoDmpAnalyticsAdapter_spec.js +++ b/test/spec/modules/pianoDmpAnalyticsAdapter_spec.js @@ -52,19 +52,12 @@ describe('Piano DMP Analytics Adapter', () => { // Then const callQueue = (window.cX || {}).callQueue; - const billableEventIndex = callQueue.findIndex(([, params]) => params.eventType === constants.EVENTS.BILLABLE_EVENT); - if (billableEventIndex > -1) { - callQueue.splice(billableEventIndex, 1); - } - expect(callQueue).to.be.an('array'); - expect(callQueue.length).to.equal(testEvents.length); - - callQueue.forEach(([method, params], index) => { + testEvents.forEach(({event, args}) => { + const [method, params] = callQueue.filter(item => item[1].eventType === event)[0]; expect(method).to.equal('prebid'); - expect(params.eventType).to.equal(testEvents[index].event); - expect(params.params).to.deep.equal(testEvents[index].args); - }); + expect(params.params).to.deep.equal(args); + }) }); }); }); diff --git a/test/spec/modules/prebidServerBidAdapter_spec.js b/test/spec/modules/prebidServerBidAdapter_spec.js index f5f77e61056..820a57b4e83 100644 --- a/test/spec/modules/prebidServerBidAdapter_spec.js +++ b/test/spec/modules/prebidServerBidAdapter_spec.js @@ -1,4 +1,5 @@ -import { expect } from 'chai'; +/* eslint-disable no-trailing-spaces */ +import {expect} from 'chai'; import { PrebidServer as Adapter, resetSyncedStatus, @@ -7,31 +8,30 @@ import { } from 'modules/prebidServerBidAdapter/index.js'; import adapterManager from 'src/adapterManager.js'; import * as utils from 'src/utils.js'; -import { ajax } from 'src/ajax.js'; -import { config } from 'src/config.js'; +import {deepAccess, deepClone} from 'src/utils.js'; +import {ajax} from 'src/ajax.js'; +import {config} from 'src/config.js'; import * as events from 'src/events.js'; import CONSTANTS from 'src/constants.json'; -import { server } from 'test/mocks/xhr.js'; -import { createEidsArray } from 'modules/userId/eids.js'; -import { deepAccess, deepClone } from 'src/utils.js'; -import 'modules/appnexusBidAdapter.js' // appnexus alias test -import 'modules/rubiconBidAdapter.js' // rubicon alias test -import 'src/prebid.js' // $$PREBID_GLOBAL$$.aliasBidder test -import 'modules/currency.js' // adServerCurrency test -// also load modules that register ORTB processors -import 'modules/currency.js'; +import {server} from 'test/mocks/xhr.js'; +import {createEidsArray} from 'modules/userId/eids.js'; +import 'modules/appnexusBidAdapter.js'; // appnexus alias test +import 'modules/rubiconBidAdapter.js'; // rubicon alias test +import 'src/prebid.js'; // $$PREBID_GLOBAL$$.aliasBidder test +import 'modules/currency.js'; // adServerCurrency test import 'modules/userId/index.js'; import 'modules/multibid/index.js'; import 'modules/priceFloors.js'; import 'modules/consentManagement.js'; import 'modules/consentManagementUsp.js'; import 'modules/schain.js'; -import { hook } from '../../../src/hook.js'; -import { decorateAdUnitsWithNativeParams } from '../../../src/native.js'; -import { auctionManager } from '../../../src/auctionManager.js'; -import { stubAuctionIndex } from '../../helpers/indexStub.js'; -import { registerBidder } from 'src/adapters/bidderFactory.js'; +import {hook} from '../../../src/hook.js'; +import {decorateAdUnitsWithNativeParams} from '../../../src/native.js'; +import {auctionManager} from '../../../src/auctionManager.js'; +import {stubAuctionIndex} from '../../helpers/indexStub.js'; +import {registerBidder} from 'src/adapters/bidderFactory.js'; import {getGlobal} from '../../../src/prebidGlobal.js'; +import {syncAddFPDEnrichments, syncAddFPDToBidderRequest} from '../../helpers/fpd.js'; let CONFIG = { accountId: '1', @@ -544,6 +544,16 @@ const RESPONSE_OPENRTB_NATIVE = { ] }; +function addFpdEnrichmentsToS2SRequest(s2sReq, bidderRequests) { + return { + ...s2sReq, + ortb2Fragments: { + ...(s2sReq.ortb2Fragments || {}), + global: syncAddFPDToBidderRequest({...(bidderRequests?.[0] || {}), ortb2: s2sReq.ortb2Fragments?.global || {}}).ortb2 + } + } +} + describe('S2S Adapter', function () { let adapter, addBidResponse = sinon.spy(), @@ -766,7 +776,7 @@ describe('S2S Adapter', function () { let gdprBidRequest = utils.deepClone(BID_REQUESTS); gdprBidRequest[0].gdprConsent = mockConsent(); - adapter.callBids(REQUEST, gdprBidRequest, addBidResponse, done, ajax); + adapter.callBids(addFpdEnrichmentsToS2SRequest(REQUEST, gdprBidRequest), gdprBidRequest, addBidResponse, done, ajax); let requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.regs.ext.gdpr).is.equal(1); @@ -775,7 +785,7 @@ describe('S2S Adapter', function () { config.resetConfig(); config.setConfig({ s2sConfig: CONFIG }); - adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + adapter.callBids(addFpdEnrichmentsToS2SRequest(REQUEST, BID_REQUESTS), BID_REQUESTS, addBidResponse, done, ajax); requestBid = JSON.parse(server.requests[1].requestBody); expect(requestBid.regs).to.not.exist; @@ -791,7 +801,7 @@ describe('S2S Adapter', function () { addtlConsent: 'superduperconsent', }); - adapter.callBids(REQUEST, gdprBidRequest, addBidResponse, done, ajax); + adapter.callBids(addFpdEnrichmentsToS2SRequest(REQUEST, gdprBidRequest), gdprBidRequest, addBidResponse, done, ajax); let requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.regs.ext.gdpr).is.equal(1); @@ -877,13 +887,13 @@ describe('S2S Adapter', function () { $$PREBID_GLOBAL$$.requestBids.removeAll(); }); - it('is added to ortb2 request when in bidRequest', function () { + it('is added to ortb2 request when in FPD', function () { config.setConfig({ s2sConfig: CONFIG }); let uspBidRequest = utils.deepClone(BID_REQUESTS); uspBidRequest[0].uspConsent = '1NYN'; - adapter.callBids(REQUEST, uspBidRequest, addBidResponse, done, ajax); + adapter.callBids(addFpdEnrichmentsToS2SRequest(REQUEST, uspBidRequest), uspBidRequest, addBidResponse, done, ajax); let requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.regs.ext.us_privacy).is.equal('1NYN'); @@ -891,7 +901,7 @@ describe('S2S Adapter', function () { config.resetConfig(); config.setConfig({ s2sConfig: CONFIG }); - adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + adapter.callBids(addFpdEnrichmentsToS2SRequest(REQUEST, BID_REQUESTS), BID_REQUESTS, addBidResponse, done, ajax); requestBid = JSON.parse(server.requests[1].requestBody); expect(requestBid.regs).to.not.exist; @@ -929,7 +939,7 @@ describe('S2S Adapter', function () { consentBidRequest[0].uspConsent = '1NYN'; consentBidRequest[0].gdprConsent = mockConsent(); - adapter.callBids(REQUEST, consentBidRequest, addBidResponse, done, ajax); + adapter.callBids(addFpdEnrichmentsToS2SRequest(REQUEST, consentBidRequest), consentBidRequest, addBidResponse, done, ajax); let requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.regs.ext.us_privacy).is.equal('1NYN'); @@ -977,7 +987,7 @@ describe('S2S Adapter', function () { }; config.setConfig(_config); - adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + adapter.callBids(addFpdEnrichmentsToS2SRequest(REQUEST, BID_REQUESTS), BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); sinon.assert.match(requestBid.device, { ifa: '6D92078A-8246-4BA4-AE5B-76104861E7DC', @@ -1004,7 +1014,7 @@ describe('S2S Adapter', function () { }; config.setConfig(_config); - adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + adapter.callBids(addFpdEnrichmentsToS2SRequest(REQUEST, BID_REQUESTS), BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); sinon.assert.match(requestBid.device, { ifa: '6D92078A-8246-4BA4-AE5B-76104861E7DC', @@ -1367,7 +1377,7 @@ describe('S2S Adapter', function () { }; config.setConfig(_config); - adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + adapter.callBids(addFpdEnrichmentsToS2SRequest(REQUEST, BID_REQUESTS), BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); sinon.assert.match(requestBid.device, { w: window.innerWidth, @@ -1474,7 +1484,7 @@ describe('S2S Adapter', function () { }; config.setConfig(_config); - adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + adapter.callBids(addFpdEnrichmentsToS2SRequest(REQUEST, BID_REQUESTS), BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.site).to.exist.and.to.be.a('object'); expect(requestBid.site.publisher).to.exist.and.to.be.a('object'); @@ -1491,10 +1501,33 @@ describe('S2S Adapter', function () { content: { language: 'en' }, + domain: 'mytestpage.com', page: 'http://mytestpage.com' }); }); + it('site should not be present when app is present', function () { + const _config = { + s2sConfig: CONFIG, + app: { bundle: 'com.test.app' }, + site: { + publisher: { + id: '1234', + domain: 'test.com' + }, + content: { + language: 'en' + } + } + }; + + config.setConfig(_config); + adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + const requestBid = JSON.parse(server.requests[0].requestBody); + expect(requestBid.site).to.not.exist; + expect(requestBid.app).to.exist.and.to.be.a('object'); + }); + it('adds appnexus aliases to request', function () { config.setConfig({ s2sConfig: CONFIG }); @@ -1693,6 +1726,121 @@ describe('S2S Adapter', function () { }]); }); + describe('filterSettings', function () { + const getRequestBid = userSync => { + let cookieSyncConfig = utils.deepClone(CONFIG); + const s2sBidRequest = utils.deepClone(REQUEST); + cookieSyncConfig.syncEndpoint = { p1Consent: 'https://prebid.adnxs.com/pbs/v1/cookie_sync' }; + s2sBidRequest.s2sConfig = cookieSyncConfig; + + config.setConfig({ userSync, s2sConfig: cookieSyncConfig }); + + let bidRequest = utils.deepClone(BID_REQUESTS); + adapter.callBids(s2sBidRequest, bidRequest, addBidResponse, done, ajax); + return JSON.parse(server.requests[0].requestBody); + } + + it('correctly adds filterSettings to the cookie_sync request if userSync.filterSettings is present in the config and only the all key is present in userSync.filterSettings', function () { + const userSync = { + filterSettings: { + all: { + bidders: ['appnexus', 'rubicon', 'pubmatic'], + filter: 'exclude' + } + } + }; + const requestBid = getRequestBid(userSync); + + expect(requestBid.filterSettings).to.deep.equal({ + 'image': { + 'bidders': ['appnexus', 'rubicon', 'pubmatic'], + 'filter': 'exclude' + }, + 'iframe': { + 'bidders': ['appnexus', 'rubicon', 'pubmatic'], + 'filter': 'exclude' + } + }); + }); + + it('correctly adds filterSettings to the cookie_sync request if userSync.filterSettings is present in the config and only the iframe key is present in userSync.filterSettings', function () { + const userSync = { + filterSettings: { + iframe: { + bidders: ['rubicon', 'pubmatic'], + filter: 'include' + } + } + }; + const requestBid = getRequestBid(userSync); + + expect(requestBid.filterSettings).to.deep.equal({ + 'image': { + 'bidders': '*', + 'filter': 'include' + }, + 'iframe': { + 'bidders': ['rubicon', 'pubmatic'], + 'filter': 'include' + } + }); + }); + + it('correctly adds filterSettings to the cookie_sync request if userSync.filterSettings is present in the config and the image and iframe keys are both present in userSync.filterSettings', function () { + const userSync = { + filterSettings: { + image: { + bidders: ['triplelift', 'appnexus'], + filter: 'include' + }, + iframe: { + bidders: ['pulsepoint', 'triplelift', 'appnexus', 'rubicon'], + filter: 'exclude' + } + } + }; + const requestBid = getRequestBid(userSync); + + expect(requestBid.filterSettings).to.deep.equal({ + 'image': { + 'bidders': ['triplelift', 'appnexus'], + 'filter': 'include' + }, + 'iframe': { + 'bidders': ['pulsepoint', 'triplelift', 'appnexus', 'rubicon'], + 'filter': 'exclude' + } + }); + }); + + it('correctly adds filterSettings to the cookie_sync request if userSync.filterSettings is present in the config and the all and iframe keys are both present in userSync.filterSettings', function () { + const userSync = { + filterSettings: { + all: { + bidders: ['triplelift', 'appnexus'], + filter: 'include' + }, + iframe: { + bidders: ['pulsepoint', 'triplelift', 'appnexus', 'rubicon'], + filter: 'exclude' + } + } + }; + const requestBid = getRequestBid(userSync); + + expect(requestBid.filterSettings).to.deep.equal({ + 'image': { + 'bidders': ['triplelift', 'appnexus'], + 'filter': 'include' + }, + 'iframe': { + 'bidders': ['pulsepoint', 'triplelift', 'appnexus', 'rubicon'], + 'filter': 'exclude' + } + }); + }); + }); + it('adds limit to the cookie_sync request if userSyncLimit is greater than 0', function () { let cookieSyncConfig = utils.deepClone(CONFIG); cookieSyncConfig.syncEndpoint = { p1Consent: 'https://prebid.adnxs.com/pbs/v1/cookie_sync' }; @@ -1815,7 +1963,7 @@ describe('S2S Adapter', function () { device: device }); - adapter.callBids(s2sBidRequest, BID_REQUESTS, addBidResponse, done, ajax); + adapter.callBids(addFpdEnrichmentsToS2SRequest(s2sBidRequest, BID_REQUESTS), BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.site).to.exist.and.to.be.a('object'); @@ -2343,7 +2491,11 @@ describe('S2S Adapter', function () { })); const commonContextExpected = utils.mergeDeep({ 'page': 'http://mytestpage.com', - 'publisher': { 'id': '1' } + 'domain': 'mytestpage.com', + 'publisher': { + 'id': '1', + 'domain': 'mytestpage.com' + } }, commonSite); const ortb2Fragments = { @@ -2351,7 +2503,7 @@ describe('S2S Adapter', function () { bidder: Object.fromEntries(allowedBidders.map(bidder => [bidder, {site, user, bcat, badv}])) }; - adapter.callBids({...s2sBidRequest, ortb2Fragments}, bidRequests, addBidResponse, done, ajax); + adapter.callBids(addFpdEnrichmentsToS2SRequest({...s2sBidRequest, ortb2Fragments}, bidRequests), bidRequests, addBidResponse, done, ajax); const parsedRequestBody = JSON.parse(server.requests[0].requestBody); expect(parsedRequestBody.ext.prebid.bidderconfig).to.deep.equal(expected); expect(parsedRequestBody.site).to.deep.equal(commonContextExpected); @@ -2508,6 +2660,62 @@ describe('S2S Adapter', function () { }); }); + describe('Bidder-level ortb2Imp', () => { + beforeEach(() => { + config.setConfig({ + s2sConfig: { + ...CONFIG, + bidders: ['A', 'B'] + } + }) + }) + it('should be set on imp.ext.prebid.imp', () => { + const s2sReq = utils.deepClone(REQUEST); + s2sReq.ad_units[0].ortb2Imp = {l0: 'adUnit'}; + s2sReq.ad_units[0].bids = [ + { + bidder: 'A', + bid_id: 1, + ortb2Imp: { + l2: 'A' + } + }, + { + bidder: 'B', + bid_id: 2, + ortb2Imp: { + l2: 'B' + } + } + ]; + const bidderReqs = [ + { + ...BID_REQUESTS[0], + bidderCode: 'A', + bids: [{ + bidId: 1, + bidder: 'A' + }] + }, + { + ...BID_REQUESTS[0], + bidderCode: 'B', + bids: [{ + bidId: 2, + bidder: 'B' + }] + } + ] + adapter.callBids(s2sReq, bidderReqs, addBidResponse, done, ajax); + const req = JSON.parse(server.requests[0].requestBody); + expect(req.imp[0].l0).to.eql('adUnit'); + expect(req.imp[0].ext.prebid.imp).to.eql({ + A: {l2: 'A'}, + B: {l2: 'B'} + }); + }); + }); + describe('ext.prebid config', function () { it('should send \"imp.ext.prebid.storedrequest.id\" if \"ortb2Imp.ext.prebid.storedrequest.id\" is set', function () { const consentConfig = { s2sConfig: CONFIG }; @@ -2720,6 +2928,21 @@ describe('S2S Adapter', function () { expect(response).to.have.property('ttl', 60); }); + it('handles seatnonbid responses and calls SEAT_NON_BID', function () { + const original = CONFIG; + CONFIG.extPrebid = { returnallbidstatus: true }; + const nonbidResponse = {...RESPONSE_OPENRTB, ext: {seatnonbid: [{}]}}; + config.setConfig({ CONFIG }); + CONFIG = original; + adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + const responding = deepClone(nonbidResponse); + Object.assign(responding.ext.seatnonbid, [{auctionId: 2}]) + server.requests[0].respond(200, {}, JSON.stringify(responding)); + const event = events.emit.secondCall.args; + expect(event[0]).to.equal(CONSTANTS.EVENTS.SEAT_NON_BID); + expect(event[1].seatnonbid[0]).to.have.property('auctionId', 2); + }); + it('respects defaultTtl', function () { const s2sConfig = Object.assign({}, CONFIG, { defaultTtl: 30 diff --git a/test/spec/modules/prebidmanagerAnalyticsAdapter_spec.js b/test/spec/modules/prebidmanagerAnalyticsAdapter_spec.js index 2e1bf4df062..25834e8574d 100644 --- a/test/spec/modules/prebidmanagerAnalyticsAdapter_spec.js +++ b/test/spec/modules/prebidmanagerAnalyticsAdapter_spec.js @@ -1,9 +1,8 @@ -import prebidmanagerAnalytics, { - storage -} from 'modules/prebidmanagerAnalyticsAdapter.js'; +import prebidmanagerAnalytics, {storage} from 'modules/prebidmanagerAnalyticsAdapter.js'; import {expect} from 'chai'; import {server} from 'test/mocks/xhr.js'; import * as utils from 'src/utils.js'; +import {expectEvents} from '../../helpers/analytics.js'; let events = require('src/events'); let constants = require('src/constants.json'); @@ -71,7 +70,7 @@ describe('Prebid Manager Analytics Adapter', function () { prebidmanagerAnalytics.flush(); expect(server.requests.length).to.equal(1); - expect(server.requests[0].url).to.equal('https://endpoint.prebidmanager.com/endpoint'); + expect(server.requests[0].url).to.equal('https://endpt.prebidmanager.com/endpoint'); expect(server.requests[0].requestBody.substring(0, 2)).to.equal('1:'); const pmEvents = JSON.parse(server.requests[0].requestBody.substring(2)); @@ -95,15 +94,7 @@ describe('Prebid Manager Analytics Adapter', function () { } }); - events.emit(constants.EVENTS.AUCTION_INIT, {}); - events.emit(constants.EVENTS.BID_REQUESTED, {}); - events.emit(constants.EVENTS.BID_RESPONSE, {}); - events.emit(constants.EVENTS.BID_WON, {}); - events.emit(constants.EVENTS.AUCTION_END, {}); - events.emit(constants.EVENTS.BID_TIMEOUT, {}); - - // 6 Prebid Manager events + 1 Clean.io event - sinon.assert.callCount(prebidmanagerAnalytics.track, 7); + expectEvents().to.beTrackedBy(prebidmanagerAnalytics.track); }); }); diff --git a/test/spec/modules/priceFloors_spec.js b/test/spec/modules/priceFloors_spec.js index b7d771814d0..f232631d73d 100644 --- a/test/spec/modules/priceFloors_spec.js +++ b/test/spec/modules/priceFloors_spec.js @@ -1495,6 +1495,161 @@ describe('the price floors module', function () { }); }); + it('should use inverseFloorAdjustment function before bidder cpm adjustment', function () { + let functionUsed; + getGlobal().bidderSettings = { + rubicon: { + bidCpmAdjustment: function (bidCpm, bidResponse) { + functionUsed = 'Rubicon Adjustment'; + bidCpm *= 0.5; + if (bidResponse.mediaType === 'video') bidCpm -= 0.18; + return bidCpm; + }, + inverseBidAdjustment: function (bidCpm, bidRequest) { + functionUsed = 'Rubicon Inverse'; + // if video is the only mediaType on Bid Request => add 0.18 + if (bidRequest.mediaTypes.video && Object.keys(bidRequest.mediaTypes).length === 1) bidCpm += 0.18; + return bidCpm / 0.5; + }, + }, + appnexus: { + bidCpmAdjustment: function (bidCpm, bidResponse) { + functionUsed = 'Appnexus Adjustment'; + bidCpm *= 0.75; + if (bidResponse.mediaType === 'video') bidCpm -= 0.18; + return bidCpm; + }, + inverseBidAdjustment: function (bidCpm, bidRequest) { + functionUsed = 'Appnexus Inverse'; + // if video is the only mediaType on Bid Request => add 0.18 + if (bidRequest.mediaTypes.video && Object.keys(bidRequest.mediaTypes).length === 1) bidCpm += 0.18; + return bidCpm / 0.75; + }, + } + }; + + _floorDataForAuction[bidRequest.auctionId] = utils.deepClone(basicFloorConfig); + + _floorDataForAuction[bidRequest.auctionId].data.values = { '*': 1.0 }; + + // start with banner as only mediaType + bidRequest.mediaTypes = { banner: { sizes: [[300, 250]] } }; + let appnexusBid = { + ...bidRequest, + bidder: 'appnexus', + }; + + // should be same as the adjusted calculated inverses above test (banner) + expect(bidRequest.getFloor()).to.deep.equal({ + currency: 'USD', + floor: 2.0 + }); + + // should use rubicon inverse + expect(functionUsed).to.equal('Rubicon Inverse'); + + // appnexus just using banner should be same + expect(appnexusBid.getFloor()).to.deep.equal({ + currency: 'USD', + floor: 1.3334 + }); + + expect(functionUsed).to.equal('Appnexus Inverse'); + + // now since asking for 'video' only mediaType inverse function should include the .18 + bidRequest.mediaTypes = { video: { context: 'instream' } }; + expect(bidRequest.getFloor({ mediaType: 'video' })).to.deep.equal({ + currency: 'USD', + floor: 2.36 + }); + + expect(functionUsed).to.equal('Rubicon Inverse'); + + // now since asking for 'video' inverse function should include the .18 + appnexusBid.mediaTypes = { video: { context: 'instream' } }; + expect(appnexusBid.getFloor({ mediaType: 'video' })).to.deep.equal({ + currency: 'USD', + floor: 1.5734 + }); + + expect(functionUsed).to.equal('Appnexus Inverse'); + }); + + it('should pass inverseFloorAdjustment the bidRequest object so it can be used', function () { + // Adjustment factors based on Bid Media Type + const mediaTypeFactors = { + banner: 0.5, + native: 0.7, + video: 0.9 + } + getGlobal().bidderSettings = { + rubicon: { + bidCpmAdjustment: function (bidCpm, bidResponse) { + return bidCpm * mediaTypeFactors[bidResponse.mediaType]; + }, + inverseBidAdjustment: function (bidCpm, bidRequest) { + // For the inverse we add up each mediaType in the request and divide by number of Mt's to get the inverse number + let factor = Object.keys(bidRequest.mediaTypes).reduce((sum, mediaType) => sum += mediaTypeFactors[mediaType], 0); + factor = factor / Object.keys(bidRequest.mediaTypes).length; + return bidCpm / factor; + }, + } + }; + + _floorDataForAuction[bidRequest.auctionId] = utils.deepClone(basicFloorConfig); + + _floorDataForAuction[bidRequest.auctionId].data.values = { '*': 1.0 }; + + // banner only should be 2 + bidRequest.mediaTypes = { banner: {} }; + expect(bidRequest.getFloor()).to.deep.equal({ + currency: 'USD', + floor: 2.0 + }); + + // native only should be 1.4286 + bidRequest.mediaTypes = { native: {} }; + expect(bidRequest.getFloor()).to.deep.equal({ + currency: 'USD', + floor: 1.4286 + }); + + // video only should be 1.1112 + bidRequest.mediaTypes = { video: {} }; + expect(bidRequest.getFloor()).to.deep.equal({ + currency: 'USD', + floor: 1.1112 + }); + + // video and banner should even out to 0.7 factor so 1.4286 + bidRequest.mediaTypes = { video: {}, banner: {} }; + expect(bidRequest.getFloor()).to.deep.equal({ + currency: 'USD', + floor: 1.4286 + }); + + // video and native should even out to 0.8 factor so -- 1.25 + bidRequest.mediaTypes = { video: {}, native: {} }; + expect(bidRequest.getFloor()).to.deep.equal({ + currency: 'USD', + floor: 1.25 + }); + + // banner and native should even out to 0.6 factor so -- 1.6667 + bidRequest.mediaTypes = { banner: {}, native: {} }; + expect(bidRequest.getFloor()).to.deep.equal({ + currency: 'USD', + floor: 1.6667 + }); + + // all 3 banner video and native should even out to 0.7 factor so -- 1.4286 + bidRequest.mediaTypes = { banner: {}, native: {}, video: {} }; + expect(bidRequest.getFloor()).to.deep.equal({ + currency: 'USD', + floor: 1.4286 + }); + }); + it('should use standard cpmAdjustment if no bidder cpmAdjustment', function () { getGlobal().bidderSettings = { rubicon: { diff --git a/test/spec/modules/proxistoreBidAdapter_spec.js b/test/spec/modules/proxistoreBidAdapter_spec.js index 5b9f35c5bcf..bcddb9e8b04 100644 --- a/test/spec/modules/proxistoreBidAdapter_spec.js +++ b/test/spec/modules/proxistoreBidAdapter_spec.js @@ -55,9 +55,9 @@ describe('ProxistoreBidAdapter', function () { }); describe('buildRequests', function () { const url = { - cookieBase: 'https://abs.proxistore.com/v3/rtb/prebid/multi', + cookieBase: 'https://api.proxistore.com/v3/rtb/prebid/multi', cookieLess: - 'https://abs.cookieless-proxistore.com/v3/rtb/prebid/multi', + 'https://api.cookieless-proxistore.com/v3/rtb/prebid/multi', }; let request = spec.buildRequests([bid], bidderRequest); diff --git a/test/spec/modules/pubmaticAnalyticsAdapter_spec.js b/test/spec/modules/pubmaticAnalyticsAdapter_spec.js index fa4519c84e1..bd35297b027 100755 --- a/test/spec/modules/pubmaticAnalyticsAdapter_spec.js +++ b/test/spec/modules/pubmaticAnalyticsAdapter_spec.js @@ -1,4 +1,4 @@ -import pubmaticAnalyticsAdapter from 'modules/pubmaticAnalyticsAdapter.js'; +import pubmaticAnalyticsAdapter, { getMetadata } from 'modules/pubmaticAnalyticsAdapter.js'; import adapterManager from 'src/adapterManager.js'; import CONSTANTS from 'src/constants.json'; import { config } from 'src/config.js'; @@ -68,6 +68,14 @@ const BID = { 'hb_size': '640x480', 'hb_source': 'server' }, + 'floorData': { + 'cpmAfterAdjustments': 6.3, + 'enforcements': {'enforceJS': true, 'enforcePBS': false, 'floorDeals': false, 'bidAdjustment': true}, + 'floorCurrency': 'USD', + 'floorRule': 'banner', + 'floorRuleValue': 1.1, + 'floorValue': 1.1 + }, getStatusCode() { return 1; } @@ -200,7 +208,18 @@ const MOCK = { 'bidId': '3bd4ebb1c900e2', 'seatBidId': 'aaaa-bbbb-cccc-dddd', 'bidderRequestId': '1be65d7958826a', - 'auctionId': '25c6d7f5-699a-4bfc-87c9-996f915341fa' + 'auctionId': '25c6d7f5-699a-4bfc-87c9-996f915341fa', + 'floorData': { + 'fetchStatus': 'success', + 'floorMin': undefined, + 'floorProvider': 'pubmatic', + 'location': 'fetch', + 'modelTimestamp': undefined, + 'modelVersion': 'floorModelTest', + 'modelWeight': undefined, + 'skipRate': 0, + 'skipped': false + } } ], 'auctionStart': 1519149536560, @@ -343,10 +362,13 @@ describe('pubmatic analytics adapter', function () { expect(data.orig).to.equal('www.test.com'); expect(data.tst).to.equal(1519767016); expect(data.tgid).to.equal(15); + expect(data.fmv).to.equal('floorModelTest'); + expect(data.ft).to.equal(1); expect(data.s).to.be.an('array'); expect(data.s.length).to.equal(2); // slot 1 expect(data.s[0].sn).to.equal('/19968336/header-bid-tag-0'); + expect(data.s[0].fskp).to.equal(0); expect(data.s[0].sz).to.deep.equal(['640x480']); expect(data.s[0].ps).to.be.an('array'); expect(data.s[0].ps.length).to.equal(1); @@ -370,8 +392,10 @@ describe('pubmatic analytics adapter', function () { expect(data.s[0].ps[0].af).to.equal('video'); expect(data.s[0].ps[0].ocpm).to.equal(1.23); expect(data.s[0].ps[0].ocry).to.equal('USD'); + expect(data.s[0].ps[0].frv).to.equal(undefined); // slot 2 expect(data.s[1].sn).to.equal('/19968336/header-bid-tag-1'); + expect(data.s[1].fskp).to.equal(0); expect(data.s[1].sz).to.deep.equal(['1000x300', '970x250', '728x90']); expect(data.s[1].ps).to.be.an('array'); expect(data.s[1].ps.length).to.equal(1); @@ -397,6 +421,7 @@ describe('pubmatic analytics adapter', function () { expect(data.s[1].ps[0].af).to.equal('banner'); expect(data.s[1].ps[0].ocpm).to.equal(1.52); expect(data.s[1].ps[0].ocry).to.equal('USD'); + expect(data.s[1].ps[0].frv).to.equal(undefined); // tracker slot1 let firstTracker = requests[0].url; @@ -446,11 +471,14 @@ describe('pubmatic analytics adapter', function () { let data = getLoggerJsonFromRequest(request.requestBody); expect(data.pubid).to.equal('9999'); expect(data.pid).to.equal('1111'); + expect(data.fmv).to.equal('floorModelTest'); + expect(data.ft).to.equal(1); expect(data.s).to.be.an('array'); expect(data.s.length).to.equal(2); expect(data.tgid).to.equal(0); // slot 1 expect(data.s[0].sn).to.equal('/19968336/header-bid-tag-0'); + expect(data.s[0].fskp).to.equal(0); expect(data.s[0].sz).to.deep.equal(['640x480']); expect(data.s[0].ps).to.be.an('array'); expect(data.s[0].ps.length).to.equal(1); @@ -464,6 +492,7 @@ describe('pubmatic analytics adapter', function () { expect(data.s[0].ps[0].af).to.equal('video'); expect(data.s[0].ps[0].ocpm).to.equal(1.23); expect(data.s[0].ps[0].ocry).to.equal('USD'); + expect(data.s[1].ps[0].frv).to.equal(undefined); // tracker slot1 let firstTracker = requests[0].url; expect(firstTracker.split('?')[0]).to.equal('https://t.pubmatic.com/wt'); @@ -515,6 +544,8 @@ describe('pubmatic analytics adapter', function () { expect(data.pubid).to.equal('9999'); expect(data.pid).to.equal('1111'); expect(data.tgid).to.equal(0);// test group id should be between 0-15 else set to 0 + expect(data.fmv).to.equal('floorModelTest'); + expect(data.ft).to.equal(1); expect(data.s).to.be.an('array'); expect(data.s.length).to.equal(2); // slot 1 @@ -563,6 +594,7 @@ describe('pubmatic analytics adapter', function () { let data = getLoggerJsonFromRequest(request.requestBody); expect(data.tgid).to.equal(0);// test group id should be an INT between 0-15 else set to 0 expect(data.s[1].sn).to.equal('/19968336/header-bid-tag-1'); + expect(data.s[1].fskp).to.equal(0); expect(data.s[1].sz).to.deep.equal(['1000x300', '970x250', '728x90']); expect(data.s[1].ps).to.be.an('array'); expect(data.s[1].ps.length).to.equal(1); @@ -586,6 +618,7 @@ describe('pubmatic analytics adapter', function () { expect(data.s[1].ps[0].af).to.equal(undefined); expect(data.s[1].ps[0].ocpm).to.equal(0); expect(data.s[1].ps[0].ocry).to.equal('USD'); + expect(data.s[1].ps[0].frv).to.equal(undefined); }); it('Logger: post-timeout check without bid response', function() { @@ -643,6 +676,7 @@ describe('pubmatic analytics adapter', function () { let request = requests[0]; let data = getLoggerJsonFromRequest(request.requestBody); expect(data.s[1].sn).to.equal('/19968336/header-bid-tag-1'); + expect(data.s[1].fskp).to.equal(0); expect(data.s[1].sz).to.deep.equal(['1000x300', '970x250', '728x90']); expect(data.s[1].ps).to.be.an('array'); expect(data.s[1].ps.length).to.equal(1); @@ -667,6 +701,7 @@ describe('pubmatic analytics adapter', function () { expect(data.s[1].ps[0].af).to.equal('banner'); expect(data.s[1].ps[0].ocpm).to.equal(1.52); expect(data.s[1].ps[0].ocry).to.equal('USD'); + expect(data.s[1].ps[0].frv).to.equal(undefined); }); it('Logger: currency conversion check', function() { @@ -748,6 +783,7 @@ describe('pubmatic analytics adapter', function () { expect(request.url).to.equal('https://t.pubmatic.com/wl?pubid=9999'); let data = getLoggerJsonFromRequest(request.requestBody); expect(data.s[1].sn).to.equal('/19968336/header-bid-tag-1'); + expect(data.s[1].fskp).to.equal(0); expect(data.s[1].sz).to.deep.equal(['1000x300', '970x250', '728x90']); expect(data.s[1].ps).to.be.an('array'); expect(data.s[1].ps.length).to.equal(1); @@ -772,6 +808,7 @@ describe('pubmatic analytics adapter', function () { expect(data.s[1].ps[0].af).to.equal('banner'); expect(data.s[1].ps[0].ocpm).to.equal(1.52); expect(data.s[1].ps[0].ocry).to.equal('USD'); + expect(data.s[1].ps[0].frv).to.equal(undefined); expect(data.dvc).to.deep.equal({'plt': 2}); // respective tracker slot let firstTracker = requests[1].url; @@ -829,6 +866,7 @@ describe('pubmatic analytics adapter', function () { expect(data.s[1].ps[0].ocpm).to.equal(1.52); expect(data.s[1].ps[0].ocry).to.equal('USD'); expect(data.dvc).to.deep.equal({'plt': 1}); + expect(data.s[1].ps[0].frv).to.equal(undefined); // respective tracker slot let firstTracker = requests[1].url; expect(firstTracker.split('?')[0]).to.equal('https://t.pubmatic.com/wt'); @@ -856,6 +894,7 @@ describe('pubmatic analytics adapter', function () { expect(request.url).to.equal('https://t.pubmatic.com/wl?pubid=9999'); let data = getLoggerJsonFromRequest(request.requestBody); expect(data.s[1].sn).to.equal('/19968336/header-bid-tag-1'); + expect(data.s[1].fskp).to.equal(0); expect(data.s[1].sz).to.deep.equal(['1000x300', '970x250', '728x90']); expect(data.s[1].ps).to.be.an('array'); expect(data.s[1].ps.length).to.equal(1); @@ -880,6 +919,7 @@ describe('pubmatic analytics adapter', function () { expect(data.s[1].ps[0].af).to.equal('banner'); expect(data.s[1].ps[0].ocpm).to.equal(1.52); expect(data.s[1].ps[0].ocry).to.equal('USD'); + expect(data.s[1].ps[0].frv).to.equal(undefined); // respective tracker slot let firstTracker = requests[1].url; expect(firstTracker.split('?')[0]).to.equal('https://t.pubmatic.com/wt'); @@ -979,11 +1019,14 @@ describe('pubmatic analytics adapter', function () { expect(data.orig).to.equal('www.test.com'); expect(data.tst).to.equal(1519767016); expect(data.tgid).to.equal(15); + expect(data.fmv).to.equal('floorModelTest'); + expect(data.ft).to.equal(1); expect(data.s).to.be.an('array'); expect(data.s.length).to.equal(2); // slot 1 expect(data.s[0].sn).to.equal('/19968336/header-bid-tag-0'); + expect(data.s[0].fskp).to.equal(0); expect(data.s[0].sz).to.deep.equal(['640x480']); expect(data.s[0].ps).to.be.an('array'); expect(data.s[0].ps.length).to.equal(1); @@ -1007,9 +1050,11 @@ describe('pubmatic analytics adapter', function () { expect(data.s[0].ps[0].af).to.equal('video'); expect(data.s[0].ps[0].ocpm).to.equal(1.23); expect(data.s[0].ps[0].ocry).to.equal('USD'); + expect(data.s[0].ps[0].frv).to.equal(1.1); // slot 2 expect(data.s[1].sn).to.equal('/19968336/header-bid-tag-1'); + expect(data.s[1].fskp).to.equal(0); expect(data.s[1].sz).to.deep.equal(['1000x300', '970x250', '728x90']); expect(data.s[1].ps).to.be.an('array'); expect(data.s[1].ps.length).to.equal(1); @@ -1035,6 +1080,7 @@ describe('pubmatic analytics adapter', function () { expect(data.s[1].ps[0].af).to.equal('banner'); expect(data.s[1].ps[0].ocpm).to.equal(1.52); expect(data.s[1].ps[0].ocry).to.equal('USD'); + expect(data.s[1].ps[0].frv).to.equal(undefined); // tracker slot1 let firstTracker = requests[0].url; @@ -1091,11 +1137,14 @@ describe('pubmatic analytics adapter', function () { expect(data.orig).to.equal('www.test.com'); expect(data.tst).to.equal(1519767016); expect(data.tgid).to.equal(15); + expect(data.fmv).to.equal('floorModelTest'); + expect(data.ft).to.equal(1); expect(data.s).to.be.an('array'); expect(data.s.length).to.equal(2); // slot 1 expect(data.s[0].sn).to.equal('/19968336/header-bid-tag-0'); + expect(data.s[0].fskp).to.equal(0); expect(data.s[0].sz).to.deep.equal(['640x480']); expect(data.s[0].ps).to.be.an('array'); expect(data.s[0].ps.length).to.equal(1); @@ -1119,6 +1168,7 @@ describe('pubmatic analytics adapter', function () { expect(data.s[0].ps[0].af).to.equal('video'); expect(data.s[0].ps[0].ocpm).to.equal(1.23); expect(data.s[0].ps[0].ocry).to.equal('USD'); + expect(data.s[0].ps[0].frv).to.equal(1.1); // slot 2 expect(data.s[1].sn).to.equal('/19968336/header-bid-tag-1'); @@ -1169,4 +1219,59 @@ describe('pubmatic analytics adapter', function () { expect(data.piid).to.equal('partnerImpressionID-1'); }); }); + + describe('Get Metadata function', function () { + it('should get the metadata object', function () { + const meta = { + networkId: 'nwid', + advertiserId: 'adid', + networkName: 'nwnm', + primaryCatId: 'pcid', + advertiserName: 'adnm', + agencyId: 'agid', + agencyName: 'agnm', + brandId: 'brid', + brandName: 'brnm', + dchain: 'dc', + demandSource: 'ds', + secondaryCatIds: ['secondaryCatIds'] + }; + const metadataObj = getMetadata(meta); + + expect(metadataObj.nwid).to.equal('nwid'); + expect(metadataObj.adid).to.equal('adid'); + expect(metadataObj.nwnm).to.equal('nwnm'); + expect(metadataObj.pcid).to.equal('pcid'); + expect(metadataObj.adnm).to.equal('adnm'); + expect(metadataObj.agid).to.equal('agid'); + expect(metadataObj.agnm).to.equal('agnm'); + expect(metadataObj.brid).to.equal('brid'); + expect(metadataObj.brnm).to.equal('brnm'); + expect(metadataObj.dc).to.equal('dc'); + expect(metadataObj.ds).to.equal('ds'); + expect(metadataObj.scids).to.be.an('array').with.length.above(0); + expect(metadataObj.scids[0]).to.equal('secondaryCatIds'); + }); + + it('should return undefined if meta is null', function () { + const meta = null; + const metadataObj = getMetadata(meta); + expect(metadataObj).to.equal(undefined); + }); + + it('should return undefined if meta is a empty object', function () { + const meta = {}; + const metadataObj = getMetadata(meta); + expect(metadataObj).to.equal(undefined); + }); + + it('should return undefined if meta object has different properties', function () { + const meta = { + a: 123, + b: 456 + }; + const metadataObj = getMetadata(meta); + expect(metadataObj).to.equal(undefined); + }); + }); }); diff --git a/test/spec/modules/pubmaticBidAdapter_spec.js b/test/spec/modules/pubmaticBidAdapter_spec.js index 13b4e31b5c7..ed74792e1cd 100644 --- a/test/spec/modules/pubmaticBidAdapter_spec.js +++ b/test/spec/modules/pubmaticBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec, checkVideoPlacement, _getDomainFromURL, assignDealTier } from 'modules/pubmaticBidAdapter.js'; +import { spec, checkVideoPlacement, _getDomainFromURL, assignDealTier, prepareMetaObject } from 'modules/pubmaticBidAdapter.js'; import * as utils from 'src/utils.js'; import { config } from 'src/config.js'; import { createEidsArray } from 'modules/userId/eids.js'; @@ -553,7 +553,8 @@ describe('PubMatic adapter', function () { 'ext': { 'deal_channel': 6, 'advid': 976, - 'dspid': 123 + 'dspid': 123, + 'dchain': 'dchain' } }] }, { @@ -2607,6 +2608,21 @@ describe('PubMatic adapter', function () { expect(data.imp[1]['video']['h']).to.equal(multipleMediaRequests[1].mediaTypes.video.playerSize[1]); }); + it('should pass device.sua if present in bidderRequest fpd ortb2 object', function () { + const suaObject = {'source': 2, 'platform': {'brand': 'macOS', 'version': ['12', '4', '0']}, 'browsers': [{'brand': 'Not_A Brand', 'version': ['99', '0', '0', '0']}, {'brand': 'Google Chrome', 'version': ['109', '0', '5414', '119']}, {'brand': 'Chromium', 'version': ['109', '0', '5414', '119']}], 'mobile': 0, 'model': '', 'bitness': '64', 'architecture': 'x86'}; + let request = spec.buildRequests(multipleMediaRequests, { + auctionId: 'new-auction-id', + ortb2: { + device: { + sua: suaObject + } + } + }); + let data = JSON.parse(request.data); + expect(data.device.sua).to.exist.and.to.be.an('object'); + expect(data.device.sua).to.deep.equal(suaObject); + }); + it('Request params should have valid native bid request for all valid params', function () { let request = spec.buildRequests(nativeBidRequests, { auctionId: 'new-auction-id' @@ -2639,13 +2655,6 @@ describe('PubMatic adapter', function () { expect(data.imp[0]['native']['request']).to.exist.and.to.equal(validnativeBidImpressionWithRequiredParam.native.request); }); - it('should not have valid native request if assets are not defined with minimum required params and only native is the slot', function () { - let request = spec.buildRequests(nativeBidRequestsWithoutAsset, { - auctionId: 'new-auction-id' - }); - expect(request).to.deep.equal(undefined); - }); - it('Request params should have valid native bid request for all native params', function () { let request = spec.buildRequests(nativeBidRequestsWithAllParams, { auctionId: 'new-auction-id' @@ -2848,7 +2857,7 @@ describe('PubMatic adapter', function () { expect(data.native.request).to.exist; }); - it('Request params - banner and native multiformat request - should not have native object incase of invalid config present', function() { + it('Request params - banner and native multiformat request - should have native object incase of invalid config present', function() { bannerAndNativeBidRequests[0].mediaTypes.native = { title: { required: true }, image: { required: true }, @@ -2868,10 +2877,10 @@ describe('PubMatic adapter', function () { data = data.imp[0]; expect(data.banner).to.exist; - expect(data.native).to.not.exist; + expect(data.native).to.exist; }); - it('Request params - video and native multiformat request - should not have native object incase of invalid config present', function() { + it('Request params - video and native multiformat request - should have native object incase of invalid config present', function() { videoAndNativeBidRequests[0].mediaTypes.native = { title: { required: true }, image: { required: true }, @@ -2891,7 +2900,7 @@ describe('PubMatic adapter', function () { data = data.imp[0]; expect(data.video).to.exist; - expect(data.native).to.not.exist; + expect(data.native).to.exist; }); it('should build video impression if video params are present in adunit.mediaTypes instead of bid.params', function() { @@ -3406,7 +3415,7 @@ describe('PubMatic adapter', function () { let response = spec.interpretResponse(bidResponses, request); expect(response).to.be.an('array').with.length.above(0); expect(response[0].requestId).to.equal(bidResponses.body.seatbid[0].bid[0].impid); - expect(response[0].cpm).to.equal((bidResponses.body.seatbid[0].bid[0].price).toFixed(2)); + expect(response[0].cpm).to.equal(parseFloat((bidResponses.body.seatbid[0].bid[0].price).toFixed(2))); expect(response[0].width).to.equal(bidResponses.body.seatbid[0].bid[0].w); expect(response[0].height).to.equal(bidResponses.body.seatbid[0].bid[0].h); if (bidResponses.body.seatbid[0].bid[0].crid) { @@ -3420,7 +3429,8 @@ describe('PubMatic adapter', function () { expect(response[0].ttl).to.equal(300); expect(response[0].meta.networkId).to.equal(123); expect(response[0].adserverTargeting.hb_buyid_pubmatic).to.equal('BUYER-ID-987'); - expect(response[0].meta.buyerId).to.equal(976); + expect(response[0].meta.buyerId).to.equal('seat-id'); + expect(response[0].meta.dchain).to.equal('dchain'); expect(response[0].meta.clickUrl).to.equal('blackrock.com'); expect(response[0].meta.advertiserDomains[0]).to.equal('blackrock.com'); expect(response[0].referrer).to.include(data.site.ref); @@ -3430,7 +3440,7 @@ describe('PubMatic adapter', function () { expect(response[0].partnerImpId).to.equal(bidResponses.body.seatbid[0].bid[0].id); expect(response[1].requestId).to.equal(bidResponses.body.seatbid[1].bid[0].impid); - expect(response[1].cpm).to.equal((bidResponses.body.seatbid[1].bid[0].price).toFixed(2)); + expect(response[1].cpm).to.equal(parseFloat((bidResponses.body.seatbid[1].bid[0].price).toFixed(2))); expect(response[1].width).to.equal(bidResponses.body.seatbid[1].bid[0].w); expect(response[1].height).to.equal(bidResponses.body.seatbid[1].bid[0].h); if (bidResponses.body.seatbid[1].bid[0].crid) { @@ -3708,7 +3718,87 @@ describe('PubMatic adapter', function () { }); let newresponse = spec.interpretResponse(newvideoBidResponses, newrequest); expect(newresponse[0].mediaType).to.equal('video') - }) + }); + }); + + describe('Preapare metadata', function () { + it('Should copy all fields from ext to meta', function () { + const bid = { + 'adomain': [ + 'mystartab.com' + ], + cat: ['IAB_CATEGORY'], + ext: { + advid: '12', + 'dspid': 6, + 'deal_channel': 1, + 'bidtype': 0, + advertiserId: 'adid', + // networkName: 'nwnm', + // primaryCatId: 'pcid', + // advertiserName: 'adnm', + // agencyId: 'agid', + // agencyName: 'agnm', + // brandId: 'brid', + // brandName: 'brnm', + // dchain: 'dc', + // demandSource: 'ds', + // secondaryCatIds: ['secondaryCatIds'] + } + }; + + const br = {}; + prepareMetaObject(br, bid, null); + expect(br.meta.networkId).to.equal(6); // dspid + expect(br.meta.buyerId).to.equal('12'); // adid + expect(br.meta.advertiserId).to.equal('12'); + // expect(br.meta.networkName).to.equal('nwnm'); + expect(br.meta.primaryCatId).to.equal('IAB_CATEGORY'); + // expect(br.meta.advertiserName).to.equal('adnm'); + expect(br.meta.agencyId).to.equal('12'); + // expect(br.meta.agencyName).to.equal('agnm'); + expect(br.meta.brandId).to.equal('mystartab.com'); + // expect(br.meta.brandName).to.equal('brnm'); + // expect(br.meta.dchain).to.equal('dc'); + expect(br.meta.demandSource).to.equal(6); + expect(br.meta.secondaryCatIds).to.be.an('array').with.length.above(0); + expect(br.meta.secondaryCatIds[0]).to.equal('IAB_CATEGORY'); + expect(br.meta.advertiserDomains).to.be.an('array').with.length.above(0); // adomain + expect(br.meta.clickUrl).to.equal('mystartab.com'); // adomain + }); + + it('Should be empty, when ext and adomain is absent in bid object', function () { + const bid = {}; + const br = {}; + prepareMetaObject(br, bid, null); + expect(Object.keys(br.meta).length).to.equal(0); + }); + + it('Should be empty, when ext and adomain will not have properties', function () { + const bid = { + 'adomain': [], + ext: {} + }; + const br = {}; + prepareMetaObject(br, bid, null); + expect(Object.keys(br.meta).length).to.equal(0); + expect(br.meta.advertiserDomains).to.equal(undefined); // adomain + expect(br.meta.clickUrl).to.equal(undefined); // adomain + }); + + it('Should have buyerId,advertiserId, agencyId value of site ', function () { + const bid = { + 'adomain': [], + ext: { + advid: '12', + } + }; + const br = {}; + prepareMetaObject(br, bid, '5100'); + expect(br.meta.buyerId).to.equal('5100'); // adid + expect(br.meta.advertiserId).to.equal('5100'); + expect(br.meta.agencyId).to.equal('5100'); + }); }); describe('getUserSyncs', function() { @@ -3808,184 +3898,6 @@ describe('PubMatic adapter', function () { }); }); - describe('JW player segment data for S2S', function() { - let sandbox = sinon.sandbox.create(); - beforeEach(function () { - sandbox = sinon.sandbox.create(); - }); - afterEach(function() { - sandbox.restore(); - }); - it('Should append JW player segment data to dctr values in auction endpoint', function() { - var videoAdUnit = { - 'bidderCode': 'pubmatic', - 'bids': [ - { - 'bidder': 'pubmatic', - 'params': { - 'publisherId': '156276', - 'adSlot': 'pubmatic_video2', - 'dctr': 'key1=123|key2=345', - 'pmzoneid': '1243', - 'video': { - 'mimes': ['video/mp4', 'video/x-flv'], - 'skippable': true, - 'minduration': 5, - 'maxduration': 30, - 'startdelay': 5, - 'playbackmethod': [1, 3], - 'api': [1, 2], - 'protocols': [2, 3], - 'battr': [13, 14], - 'linearity': 1, - 'placement': 2, - 'minbitrate': 10, - 'maxbitrate': 10 - } - }, - 'rtd': { - 'jwplayer': { - 'targeting': { - 'segments': ['80011026', '80011035'], - 'content': { - 'id': 'jw_d9J2zcaA' - } - } - } - }, - 'bid_id': '17a6771be26cc4', - 'ortb2Imp': { - 'ext': { - 'data': { - 'pbadslot': 'abcd', - 'jwTargeting': { - 'playerID': 'myElement1', - 'mediaID': 'd9J2zcaA' - } - } - } - } - } - ], - 'auctionStart': 1630923178417, - 'timeout': 1000, - 'src': 's2s' - } - - spec.transformBidParams(bidRequests[0].params, true, videoAdUnit); - expect(bidRequests[0].params.dctr).to.equal('key1:val1,val2|key2:val1|jw-id=jw_d9J2zcaA|jw-80011026=1|jw-80011035=1'); - }); - it('Should send only JW player segment data in auction endpoint, if dctr is missing', function() { - var videoAdUnit = { - 'bidderCode': 'pubmatic', - 'bids': [ - { - 'bidder': 'pubmatic', - 'params': { - 'publisherId': '156276', - 'adSlot': 'pubmatic_video2', - 'dctr': 'key1=123|key2=345', - 'pmzoneid': '1243', - 'video': { - 'mimes': ['video/mp4', 'video/x-flv'], - 'skippable': true, - 'minduration': 5, - 'maxduration': 30, - 'startdelay': 5, - 'playbackmethod': [1, 3], - 'api': [1, 2], - 'protocols': [2, 3], - 'battr': [13, 14], - 'linearity': 1, - 'placement': 2, - 'minbitrate': 10, - 'maxbitrate': 10 - } - }, - 'rtd': { - 'jwplayer': { - 'targeting': { - 'segments': ['80011026', '80011035'], - 'content': { - 'id': 'jw_d9J2zcaA' - } - } - } - }, - 'bid_id': '17a6771be26cc4', - 'ortb2Imp': { - 'ext': { - 'data': { - 'pbadslot': 'abcd', - 'jwTargeting': { - 'playerID': 'myElement1', - 'mediaID': 'd9J2zcaA' - } - } - } - } - } - ], - 'auctionStart': 1630923178417, - 'timeout': 1000, - 'src': 's2s' - } - - delete bidRequests[0].params.dctr; - spec.transformBidParams(bidRequests[0].params, true, videoAdUnit); - expect(bidRequests[0].params.dctr).to.equal('jw-id=jw_d9J2zcaA|jw-80011026=1|jw-80011035=1'); - }); - - it('Should not send any JW player segment data in auction endpoint, if it is not available', function() { - var videoAdUnit = { - 'bidderCode': 'pubmatic', - 'bids': [ - { - 'bidder': 'pubmatic', - 'params': { - 'publisherId': '156276', - 'adSlot': 'pubmatic_video2', - 'dctr': 'key1=123|key2=345', - 'pmzoneid': '1243', - 'video': { - 'mimes': ['video/mp4', 'video/x-flv'], - 'skippable': true, - 'minduration': 5, - 'maxduration': 30, - 'startdelay': 5, - 'playbackmethod': [1, 3], - 'api': [1, 2], - 'protocols': [2, 3], - 'battr': [13, 14], - 'linearity': 1, - 'placement': 2, - 'minbitrate': 10, - 'maxbitrate': 10 - } - }, - 'bid_id': '17a6771be26cc4', - 'ortb2Imp': { - 'ext': { - 'data': { - 'pbadslot': 'abcd', - 'jwTargeting': { - 'playerID': 'myElement1', - 'mediaID': 'd9J2zcaA' - } - } - } - } - } - ], - 'auctionStart': 1630923178417, - 'timeout': 1000, - 'src': 's2s' - } - spec.transformBidParams(bidRequests[0].params, true, videoAdUnit); - expect(bidRequests[0].params.dctr).to.equal('key1:val1,val2|key2:val1'); - }); - }) - describe('Checking for Video.Placement property', function() { let sandbox, utilsMock; const adUnit = 'Div1'; diff --git a/test/spec/modules/pubperfAnalyticsAdapter_spec.js b/test/spec/modules/pubperfAnalyticsAdapter_spec.js index 160529125d3..9949d87a2bc 100644 --- a/test/spec/modules/pubperfAnalyticsAdapter_spec.js +++ b/test/spec/modules/pubperfAnalyticsAdapter_spec.js @@ -1,9 +1,10 @@ import pubperfAnalytics from 'modules/pubperfAnalyticsAdapter.js'; -import { expect } from 'chai'; -import { server } from 'test/mocks/xhr.js'; +import {expect} from 'chai'; +import {server} from 'test/mocks/xhr.js'; +import {expectEvents, fireEvents} from '../../helpers/analytics.js'; + let events = require('src/events'); let utils = require('src/utils.js'); -let constants = require('src/constants.json'); describe('Pubperf Analytics Adapter', function() { describe('Prebid Manager Analytic tests', function() { @@ -22,13 +23,7 @@ describe('Pubperf Analytics Adapter', function() { provider: 'pubperf' }); - events.emit(constants.EVENTS.AUCTION_INIT, {}); - events.emit(constants.EVENTS.BID_REQUESTED, {}); - events.emit(constants.EVENTS.BID_RESPONSE, {}); - events.emit(constants.EVENTS.BID_WON, {}); - events.emit(constants.EVENTS.AUCTION_END, {}); - events.emit(constants.EVENTS.BID_TIMEOUT, {}); - + fireEvents(); expect(server.requests.length).to.equal(0); expect(utils.logError.called).to.equal(true); }); @@ -42,15 +37,7 @@ describe('Pubperf Analytics Adapter', function() { provider: 'pubperf' }); - events.emit(constants.EVENTS.AUCTION_INIT, {}); - events.emit(constants.EVENTS.BID_REQUESTED, {}); - events.emit(constants.EVENTS.BID_RESPONSE, {}); - events.emit(constants.EVENTS.BID_WON, {}); - events.emit(constants.EVENTS.AUCTION_END, {}); - events.emit(constants.EVENTS.BID_TIMEOUT, {}); - - // 6 Pubperf events + 1 Clean.io event - sinon.assert.callCount(pubperfAnalytics.track, 7); + expectEvents().to.beTrackedBy(pubperfAnalytics.track); }); }); }); diff --git a/test/spec/modules/pubstackAnalyticsAdapter_spec.js b/test/spec/modules/pubstackAnalyticsAdapter_spec.js index 3d01a0bb506..fe7441e91e5 100644 --- a/test/spec/modules/pubstackAnalyticsAdapter_spec.js +++ b/test/spec/modules/pubstackAnalyticsAdapter_spec.js @@ -3,17 +3,16 @@ import pubstackAnalytics from '../../../modules/pubstackAnalyticsAdapter.js'; import adapterManager from 'src/adapterManager'; import * as events from 'src/events'; import constants from 'src/constants.json' +import {expectEvents} from '../../helpers/analytics.js'; describe('Pubstack Analytics Adapter', () => { const scope = utils.getWindowSelf(); - let queue = []; beforeEach(() => { - scope.PubstackAnalytics = (...args) => queue.push(args); + scope.PubstackAnalytics = sinon.stub(); adapterManager.enableAnalytics({ provider: 'pubstack' }); - queue = [] }); afterEach(() => { @@ -21,19 +20,6 @@ describe('Pubstack Analytics Adapter', () => { }); it('should forward all events to the queue', () => { - // Given - const args = 'any-args' - - // When - events.emit(constants.EVENTS.AUCTION_END, args) - events.emit(constants.EVENTS.BID_REQUESTED, args) - events.emit(constants.EVENTS.BID_ADJUSTMENT, args) - events.emit(constants.EVENTS.BID_RESPONSE, args) - events.emit(constants.EVENTS.BID_WON, args) - events.emit(constants.EVENTS.NO_BID, args) - - // Then - // 6 Pubstack events + 1 Clean.io event - expect(queue.length).to.eql(7); + expectEvents().to.beBundledTo(scope.PubstackAnalytics); }); }); diff --git a/test/spec/modules/pubwiseAnalyticsAdapter_spec.js b/test/spec/modules/pubwiseAnalyticsAdapter_spec.js index dd5c223b767..e14582edc39 100644 --- a/test/spec/modules/pubwiseAnalyticsAdapter_spec.js +++ b/test/spec/modules/pubwiseAnalyticsAdapter_spec.js @@ -1,6 +1,7 @@ -import { expect } from 'chai'; +import {expect} from 'chai'; import pubwiseAnalytics from 'modules/pubwiseAnalyticsAdapter.js'; -import {server} from 'test/mocks/xhr.js'; +import {expectEvents} from '../../helpers/analytics.js'; + let events = require('src/events'); let adapterManager = require('src/adapterManager').default; let constants = require('src/constants.json'); @@ -58,23 +59,16 @@ describe('PubWise Prebid Analytics', function () { sandbox.spy(pubwiseAnalytics, 'track'); - // sent - events.emit(constants.EVENTS.AUCTION_INIT, mock.AUCTION_INIT); - events.emit(constants.EVENTS.BID_REQUESTED, {}); - events.emit(constants.EVENTS.BID_RESPONSE, {}); - events.emit(constants.EVENTS.BID_WON, {}); - events.emit(constants.EVENTS.AD_RENDER_FAILED, {}); - events.emit(constants.EVENTS.TCF2_ENFORCEMENT, {}); - events.emit(constants.EVENTS.BID_TIMEOUT, {}); - - // forces flush - events.emit(constants.EVENTS.AUCTION_END, {}); - - // eslint-disable-next-line - //console.log(requests); - - /* testing for 6 calls, including the 2 we're not currently tracking */ - sandbox.assert.callCount(pubwiseAnalytics.track, 8); + expectEvents([ + constants.EVENTS.AUCTION_INIT, + constants.EVENTS.BID_REQUESTED, + constants.EVENTS.BID_RESPONSE, + constants.EVENTS.BID_WON, + constants.EVENTS.AD_RENDER_FAILED, + constants.EVENTS.TCF2_ENFORCEMENT, + constants.EVENTS.BID_TIMEOUT, + constants.EVENTS.AUCTION_END, + ]).to.beTrackedBy(pubwiseAnalytics.track); }); it('should initialize the auction properly', function () { diff --git a/test/spec/modules/pubxaiAnalyticsAdapter_spec.js b/test/spec/modules/pubxaiAnalyticsAdapter_spec.js index 1ad23b9a41e..1dce87e4b8e 100644 --- a/test/spec/modules/pubxaiAnalyticsAdapter_spec.js +++ b/test/spec/modules/pubxaiAnalyticsAdapter_spec.js @@ -567,7 +567,9 @@ describe('pubxai analytics adapter', function() { 'host': location.host, 'path': location.pathname, 'search': location.search, - 'adUnitCount': 1 + 'adUnits': [ + '/19968336/header-bid-tag-1' + ] }, 'floorDetail': { 'fetchStatus': 'success', diff --git a/test/spec/modules/pulsepointBidAdapter_spec.js b/test/spec/modules/pulsepointBidAdapter_spec.js index 825b3abf432..60dca9e6da0 100644 --- a/test/spec/modules/pulsepointBidAdapter_spec.js +++ b/test/spec/modules/pulsepointBidAdapter_spec.js @@ -2,7 +2,6 @@ import {expect} from 'chai'; import {spec} from 'modules/pulsepointBidAdapter.js'; import {deepClone} from 'src/utils.js'; -import { config } from 'src/config.js'; describe('PulsePoint Adapter Tests', function () { const slotConfigs = [{ @@ -225,6 +224,8 @@ describe('PulsePoint Adapter Tests', function () { expect(ortbRequest.imp[1].banner).to.not.equal(null); expect(ortbRequest.imp[1].banner.w).to.equal(728); expect(ortbRequest.imp[1].banner.h).to.equal(90); + // tmax + expect(ortbRequest.tmax).to.equal(500); }); it('Verify parse response', function () { @@ -918,4 +919,13 @@ describe('PulsePoint Adapter Tests', function () { } }); }); + + it('Verify bid request timeouts', function () { + const mkRequest = (bidderRequest) => spec.buildRequests(slotConfigs, bidderRequest).data; + // assert default is used when no bidderRequest.timeout value is available + expect(mkRequest(bidderRequest).tmax).to.equal(500) + + // assert bidderRequest value is used when available + expect(mkRequest(Object.assign({}, { timeout: 6000 }, bidderRequest)).tmax).to.equal(6000) + }); }); diff --git a/test/spec/modules/rasBidAdapter_spec.js b/test/spec/modules/rasBidAdapter_spec.js index 8c378aaa416..bfa72a2510e 100644 --- a/test/spec/modules/rasBidAdapter_spec.js +++ b/test/spec/modules/rasBidAdapter_spec.js @@ -59,7 +59,10 @@ describe('rasBidAdapter', function () { area: 'areatest', site: 'test', slotSequence: '0', - network: '4178463' + network: '4178463', + customParams: { + test: 'name=value' + } } }; const bid2 = { @@ -98,6 +101,7 @@ describe('rasBidAdapter', function () { expect(requests[0].url).to.have.string('euconsent=some-consent-string'); expect(requests[0].url).to.have.string('du=https%3A%2F%2Fexample.com%2F'); expect(requests[0].url).to.have.string('dr=https%3A%2F%2Fexample.org%2F'); + expect(requests[0].url).to.have.string('test=name%3Dvalue'); }); it('should return empty consent string when undefined', function () { diff --git a/test/spec/modules/realTimeDataModule_spec.js b/test/spec/modules/realTimeDataModule_spec.js index daeeb9bc47c..ced2f697649 100644 --- a/test/spec/modules/realTimeDataModule_spec.js +++ b/test/spec/modules/realTimeDataModule_spec.js @@ -4,6 +4,7 @@ import * as sinon from 'sinon'; import {default as CONSTANTS} from '../../../src/constants.json'; import * as events from '../../../src/events.js'; import 'src/prebid.js'; +import {attachRealTimeDataProvider, onDataDeletionRequest} from 'modules/rtdModule/index.js'; const getBidRequestDataSpy = sinon.spy(); @@ -305,4 +306,68 @@ describe('Real time module', function () { }); }); }); + + describe('data deletion requests', () => { + let detach = () => null; + + function mkRtdModule(name) { + const mod = { + name, + init: () => true, + onDataDeletionRequest: sinon.stub() + }; + detach = ((orig) => { + const smDetach = attachRealTimeDataProvider(mod); + return function () { + orig(); + smDetach(); + } + })(detach); + return mod; + } + let sm1, sm2, cfg1, cfg2; + beforeEach(() => { + sm1 = mkRtdModule('mockMod1'); + sm2 = mkRtdModule('mockMod2'); + cfg1 = { + name: 'mockMod1', + i: 0 + }; + cfg2 = { + name: 'mockMod2', + i: 1 + }; + rtdModule.init(config); + config.setConfig({ + realTimeData: { + dataProviders: [cfg1, cfg2], + } + }); + }); + afterEach(() => { + detach(); + config.resetConfig(); + }); + + it('calls onDataDeletionRequest on submodules', () => { + const next = sinon.stub(); + onDataDeletionRequest(next, {a: 0}); + sinon.assert.calledWith(next, {a: 0}); + sinon.assert.calledWith(sm1.onDataDeletionRequest, cfg1); + sinon.assert.calledWith(sm2.onDataDeletionRequest, cfg2); + }); + + describe('does not choke if onDataDeletionRequest', () => { + Object.entries({ + 'is missing': () => { delete sm1.onDataDeletionRequest }, + 'throws': () => { sm1.onDataDeletionRequest.throws(new Error()) } + }).forEach(([t, setup]) => { + it(t, () => { + setup(); + onDataDeletionRequest(sinon.stub()); + sinon.assert.calledWith(sm2.onDataDeletionRequest, cfg2); + }) + }) + }) + }); }); diff --git a/test/spec/modules/redtramBidAdapter_spec.js b/test/spec/modules/redtramBidAdapter_spec.js new file mode 100644 index 00000000000..e136c37962b --- /dev/null +++ b/test/spec/modules/redtramBidAdapter_spec.js @@ -0,0 +1,256 @@ +import {expect} from 'chai'; +import {spec} from '../../../modules/redtramBidAdapter.js'; +import { BANNER } from '../../../src/mediaTypes.js'; +import * as utils from '../../../src/utils.js'; + +describe('RedtramBidAdapter', function () { + const bid = { + bidId: '23dc19818e5293', + bidder: 'redtram', + mediaTypes: { + [BANNER]: { + sizes: [[300, 250]] + } + }, + params: { + placementId: 23611, + } + }; + + const bidderRequest = { + refererInfo: { + referer: 'test.com' + } + }; + + describe('isBidRequestValid', function () { + it('Should return true if there are bidId, params and key parameters present', function () { + expect(spec.isBidRequestValid(bid)).to.be.true; + }); + it('Should return false if at least one of parameters is not present', function () { + delete bid.params.placementId; + expect(spec.isBidRequestValid(bid)).to.be.false; + }); + }); + + describe('buildRequests', function () { + let serverRequest = spec.buildRequests([bid], bidderRequest); + it('Creates a ServerRequest object with method, URL and data', function () { + expect(serverRequest).to.exist; + expect(serverRequest.method).to.exist; + expect(serverRequest.url).to.exist; + expect(serverRequest.data).to.exist; + }); + it('Returns POST method', function () { + expect(serverRequest.method).to.equal('POST'); + }); + it('Returns valid URL', function () { + expect(serverRequest.url).to.equal('https://prebid.redtram.com/pbjs'); + }); + it('Returns valid data if array of bids is valid', function () { + let data = serverRequest.data; + expect(data).to.be.an('object'); + expect(data).to.have.all.keys('deviceWidth', 'deviceHeight', 'language', 'host', 'page', 'placements'); + expect(data.deviceWidth).to.be.a('number'); + expect(data.deviceHeight).to.be.a('number'); + expect(data.language).to.be.a('string'); + expect(data.host).to.be.a('string'); + expect(data.page).to.be.a('string'); + expect(data.gdpr).to.not.exist; + expect(data.ccpa).to.not.exist; + let placement = data['placements'][0]; + expect(placement).to.have.keys('placementId', 'bidId', 'adFormat', 'sizes', 'schain', 'bidfloor'); + expect(placement.placementId).to.equal(23611); + expect(placement.bidId).to.equal('23dc19818e5293'); + expect(placement.adFormat).to.equal(BANNER); + expect(placement.schain).to.be.an('object'); + expect(placement.sizes).to.be.an('array'); + expect(placement.bidfloor).to.exist.and.to.equal(0); + }); + + it('Returns data with gdprConsent and without uspConsent', function () { + bidderRequest.gdprConsent = 'test'; + serverRequest = spec.buildRequests([bid], bidderRequest); + let data = serverRequest.data; + expect(data.gdpr).to.exist; + expect(data.gdpr).to.be.a('string'); + expect(data.gdpr).to.equal(bidderRequest.gdprConsent); + expect(data.ccpa).to.not.exist; + delete bidderRequest.gdprConsent; + }); + + it('Returns data with uspConsent and without gdprConsent', function () { + bidderRequest.uspConsent = 'test'; + serverRequest = spec.buildRequests([bid], bidderRequest); + let data = serverRequest.data; + expect(data.ccpa).to.exist; + expect(data.ccpa).to.be.a('string'); + expect(data.ccpa).to.equal(bidderRequest.uspConsent); + expect(data.gdpr).to.not.exist; + }); + + it('Returns empty data if no valid requests are passed', function () { + serverRequest = spec.buildRequests([]); + let data = serverRequest.data; + expect(data.placements).to.be.an('array').that.is.empty; + }); + }); + describe('interpretResponse', function () { + it('Should interpret banner response', function () { + const banner = { + body: [{ + mediaType: 'banner', + width: 300, + height: 250, + cpm: 0.4, + ad: 'Test', + requestId: '23dc19818e5293', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1', + meta: {} + }] + }; + let bannerResponses = spec.interpretResponse(banner); + expect(bannerResponses).to.be.an('array').that.is.not.empty; + let dataItem = bannerResponses[0]; + expect(dataItem).to.have.all.keys('requestId', 'cpm', 'width', 'height', 'ad', 'ttl', 'creativeId', + 'netRevenue', 'currency', 'dealId', 'mediaType', 'meta'); + expect(dataItem.requestId).to.equal('23dc19818e5293'); + expect(dataItem.cpm).to.equal(0.4); + expect(dataItem.width).to.equal(300); + expect(dataItem.height).to.equal(250); + expect(dataItem.ad).to.equal('Test'); + expect(dataItem.ttl).to.equal(120); + expect(dataItem.creativeId).to.equal('2'); + expect(dataItem.netRevenue).to.be.true; + expect(dataItem.currency).to.equal('USD'); + expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains'); + }); + it('Should return an empty array if invalid banner response is passed', function () { + const invBanner = { + body: [{ + width: 300, + cpm: 0.4, + ad: 'Test', + requestId: '23dc19818e5293', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1' + }] + }; + + let serverResponses = spec.interpretResponse(invBanner); + expect(serverResponses).to.be.an('array').that.is.empty; + }); + it('Should return an empty array if invalid response is passed', function () { + const invalid = { + body: [{ + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1' + }] + }; + let serverResponses = spec.interpretResponse(invalid); + expect(serverResponses).to.be.an('array').that.is.empty; + }); + }); + + describe('getUserSyncs', function () { + it('should do nothing on getUserSyncs', function () { + const syncData = spec.getUserSyncs({}, {}, { + consentString: 'ALL', + gdprApplies: true + }, {}); + expect(syncData).to.be.an('array').which.is.not.empty; + expect(syncData[0]).to.be.an('object') + expect(syncData[0].type).to.be.a('string') + expect(syncData[0].type).to.equal('image') + expect(syncData[0].url).to.be.a('string') + expect(syncData[0].url).to.equal('https://prebid.redtram.com/sync/image?pbjs=1&gdpr=1&gdpr_consent=ALL&coppa=0') + }); + }); + + describe('on bidWon', function () { + beforeEach(function() { + sinon.stub(utils, 'triggerPixel'); + }); + afterEach(function() { + utils.triggerPixel.restore(); + }); + it('should replace nurl for banner', function () { + const nurl = 'nurl/?ap=${' + 'AUCTION_PRICE}'; + const bid = { + 'bidderCode': 'redtram', + 'width': 300, + 'height': 250, + 'statusMessage': 'Bid available', + 'adId': '5691dd18ba6ab6', + 'requestId': '23dc19818e5293', + 'transactionId': '948c716b-bf64-4303-bcf4-395c2f6a9770', + 'auctionId': 'a6b7c61f-15a9-481b-8f64-e859787e9c07', + 'mediaType': 'banner', + 'source': 'client', + 'ad': "
\n", + 'cpm': 0.68, + 'nurl': nurl, + 'creativeId': 'test', + 'currency': 'USD', + 'dealId': '', + 'meta': { + 'advertiserDomains': [], + 'dchain': { + 'ver': '1.0', + 'complete': 0, + 'nodes': [ + { + 'name': 'redtram' + } + ] + } + }, + 'netRevenue': true, + 'ttl': 120, + 'metrics': {}, + 'adapterCode': 'redtram', + 'originalCpm': 0.68, + 'originalCurrency': 'USD', + 'responseTimestamp': 1668162732297, + 'requestTimestamp': 1668162732292, + 'bidder': 'redtram', + 'adUnitCode': 'div-prebid', + 'timeToRespond': 5, + 'pbLg': '0.50', + 'pbMg': '0.60', + 'pbHg': '0.68', + 'pbAg': '0.65', + 'pbDg': '0.68', + 'pbCg': '', + 'size': '300x250', + 'adserverTargeting': { + 'hb_bidder': 'redtram', + 'hb_adid': '5691dd18ba6ab6', + 'hb_pb': '0.68', + 'hb_size': '300x250', + 'hb_source': 'client', + 'hb_format': 'banner', + 'hb_adomain': '' + }, + 'status': 'rendered', + 'params': [ + { + 'placementId': 23611 + } + ] + }; + spec.onBidWon(bid); + expect(bid.nurl).to.deep.equal('nurl/?ap=0.68'); + }); + }); +}); diff --git a/test/spec/modules/riseBidAdapter_spec.js b/test/spec/modules/riseBidAdapter_spec.js index 7daedb9015a..4fa4ff354ec 100644 --- a/test/spec/modules/riseBidAdapter_spec.js +++ b/test/spec/modules/riseBidAdapter_spec.js @@ -106,6 +106,9 @@ describe('riseAdapter', function () { bidderCode: 'rise', } const placementId = '12345678'; + const api = [1, 2]; + const mimes = ['application/javascript', 'video/mp4', 'video/quicktime']; + const protocols = [2, 3, 5, 6]; it('sends the placementId to ENDPOINT via POST', function () { bidRequests[0].params.placementId = placementId; @@ -113,6 +116,13 @@ describe('riseAdapter', function () { expect(request.data.bids[0].placementId).to.equal(placementId); }); + it('sends the is_wrapper parameter to ENDPOINT via POST', function() { + const request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data.params).to.be.an('object'); + expect(request.data.params).to.have.property('is_wrapper'); + expect(request.data.params.is_wrapper).to.equal(false); + }); + it('sends bid request to ENDPOINT via POST', function () { const request = spec.buildRequests(bidRequests, bidderRequest); expect(request.url).to.equal(ENDPOINT); @@ -144,6 +154,27 @@ describe('riseAdapter', function () { expect(request.data.bids[0].bidId).to.equal('299ffc8cca0b87'); }); + it('should send the correct supported api array', function () { + bidRequests[0].mediaTypes.video.api = api; + const request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data.bids[0].api).to.be.an('array'); + expect(request.data.bids[0].api).to.eql([1, 2]); + }); + + it('should send the correct mimes array', function () { + bidRequests[1].mediaTypes.banner.mimes = mimes; + const request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data.bids[1].mimes).to.be.an('array'); + expect(request.data.bids[1].mimes).to.eql(['application/javascript', 'video/mp4', 'video/quicktime']); + }); + + it('should send the correct protocols array', function () { + bidRequests[0].mediaTypes.video.protocols = protocols; + const request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data.bids[0].protocols).to.be.an('array'); + expect(request.data.bids[0].protocols).to.eql([2, 3, 5, 6]); + }); + it('should send the correct sizes array', function () { const request = spec.buildRequests(bidRequests, bidderRequest); expect(request.data.bids[0].sizes).to.be.an('array'); diff --git a/test/spec/modules/rtbhouseBidAdapter_spec.js b/test/spec/modules/rtbhouseBidAdapter_spec.js index f4bcb48474a..6d41df7605b 100644 --- a/test/spec/modules/rtbhouseBidAdapter_spec.js +++ b/test/spec/modules/rtbhouseBidAdapter_spec.js @@ -1,6 +1,7 @@ import { expect } from 'chai'; import { OPENRTB, spec } from 'modules/rtbhouseBidAdapter.js'; import { newBidder } from 'src/adapters/bidderFactory.js'; +import { config } from 'src/config.js'; describe('RTBHouseAdapter', () => { const adapter = newBidder(spec); @@ -97,6 +98,10 @@ describe('RTBHouseAdapter', () => { ]; }); + afterEach(function () { + config.resetConfig(); + }); + it('should build test param into the request', () => { let builtTestRequest = spec.buildRequests(bidRequests, bidderRequest).data; expect(JSON.parse(builtTestRequest).test).to.equal(1); @@ -263,6 +268,45 @@ describe('RTBHouseAdapter', () => { expect(data.source).to.not.have.property('ext'); }); + context('FLEDGE', function() { + afterEach(function () { + config.resetConfig(); + }); + + it('sends bid request to FLEDGE ENDPOINT via POST', function () { + let bidRequest = Object.assign([], bidRequests); + delete bidRequest[0].params.test; + config.setConfig({ fledgeConfig: true }); + const request = spec.buildRequests(bidRequest, { ...bidderRequest, fledgeEnabled: true }); + expect(request.url).to.equal('https://prebid-eu.creativecdn.com/bidder/prebidfledge/bids'); + expect(request.method).to.equal('POST'); + }); + + it('when FLEDGE is disabled, should not send imp.ext.ae', function () { + let bidRequest = Object.assign([], bidRequests); + delete bidRequest[0].params.test; + bidRequest[0].ortb2Imp = { + ext: { ae: 2 } + }; + const request = spec.buildRequests(bidRequest, { ...bidderRequest, fledgeEnabled: false }); + let data = JSON.parse(request.data); + if (data.imp[0].ext) { + expect(data.imp[0].ext).to.not.have.property('ae'); + } + }); + + it('when FLEDGE is enabled, should send whatever is set in ortb2imp.ext.ae in all bid requests', function () { + let bidRequest = Object.assign([], bidRequests); + delete bidRequest[0].params.test; + bidRequest[0].ortb2Imp = { + ext: { ae: 2 } + }; + const request = spec.buildRequests(bidRequest, { ...bidderRequest, fledgeEnabled: true }); + let data = JSON.parse(request.data); + expect(data.imp[0].ext.ae).to.equal(2); + }); + }); + describe('native imp', () => { function basicRequest(extension) { return Object.assign({ @@ -460,6 +504,29 @@ describe('RTBHouseAdapter', () => { 'h': 250 }]; + let fledgeResponse = { + 'id': 'bid-identifier', + 'ext': { + 'igbid': [{ + 'impid': 'test-bid-id', + 'igbuyer': [{ + 'igdomain': 'https://buyer-domain.com', + 'buyersignal': {} + }] + }], + 'sellerTimeout': 500, + 'seller': 'https://seller-domain.com', + 'decisionLogicUrl': 'https://seller-domain.com/decision-logic.js' + }, + 'bidid': 'bid-identifier', + 'seatbid': [{ + 'bid': [{ + 'id': 'bid-response-id', + 'impid': 'test-bid-id' + }] + }] + }; + it('should get correct bid response', function () { let expectedResponse = [ { @@ -488,6 +555,18 @@ describe('RTBHouseAdapter', () => { expect(result.length).to.equal(0); }); + context('when the response contains FLEDGE interest groups config', function () { + let bidderRequest; + let response = spec.interpretResponse({body: fledgeResponse}, {bidderRequest}); + + it('should return FLEDGE auction_configs alongside bids', function () { + expect(response).to.have.property('bids'); + expect(response).to.have.property('fledgeAuctionConfigs'); + expect(response.fledgeAuctionConfigs.length).to.equal(1); + expect(response.fledgeAuctionConfigs[0].bidId).to.equal('test-bid-id'); + }); + }); + describe('native', () => { const adm = { native: { diff --git a/test/spec/modules/scatteredBidAdapter_spec.js b/test/spec/modules/scatteredBidAdapter_spec.js new file mode 100644 index 00000000000..7f0b13bc07b --- /dev/null +++ b/test/spec/modules/scatteredBidAdapter_spec.js @@ -0,0 +1,210 @@ +import { spec, converter } from 'modules/scatteredBidAdapter.js'; +import { assert } from 'chai'; +import { config } from 'src/config.js'; +import { deepClone, mergeDeep } from '../../../src/utils'; +describe('Scattered adapter', function () { + describe('isBidRequestValid', function () { + // A valid bid + let validBid = { + bidder: 'scattered', + mediaTypes: { + banner: { + sizes: [[300, 250], [760, 400]] + } + }, + params: { + bidderDomain: 'https://prebid.scattered.eu', + test: 0 + } + }; + + // Because this valid bid is modified to create invalid bids in following tests we first check it. + // We must be sure it is a valid one, not to get false negatives. + it('should accept a valid bid', function () { + assert.isTrue(spec.isBidRequestValid(validBid)); + }); + + it('should skip if bidderDomain info is missing', function () { + let bid = deepClone(validBid); + + delete bid.params.bidderDomain; + assert.isFalse(spec.isBidRequestValid(bid)); + }); + + it('should expect at least one banner size', function () { + let bid = deepClone(validBid); + + delete bid.mediaTypes.banner; + assert.isFalse(spec.isBidRequestValid(bid)); + + // empty sizes array + bid.mediaTypes = { + banner: { + sizes: [] + } + }; + assert.isFalse(spec.isBidRequestValid(bid)); + }); + }); + + describe('buildRequests', function () { + let arrayOfValidBidRequests, validBidderRequest; + + beforeEach(function () { + arrayOfValidBidRequests = [{ + bidder: 'scattered', + params: { + bidderDomain: 'https://prebid.scattered.eu', + test: 0 + }, + mediaTypes: { + banner: { + sizes: [[300, 250], [760, 400]] + }, + adUnitCode: 'test-div', + transactionId: '32d09c47-c6b8-40b0-9605-2e251a472ea4', + bidId: '21adc5d8765aa1', + bidderRequestId: '130728f7662afc', + auctionId: 'b4a45a23-8371-4d87-9308-39146b29ca32', + }, + }]; + + validBidderRequest = { + bidderCode: 'scattered', + auctionId: 'b4a45a23-8371-4d87-9308-39146b29ca32', + gdprConsent: { consentString: 'BOtmiBKOtmiBKABABAENAFAAAAACeAAA', gdprApplies: true }, + refererInfo: { + domain: 'localhost', + page: 'http://localhost:9999/integrationExamples/gpt/hello_world.html?pbjs_debug=true', + }, + ortb2: { + site: { + publisher: { + name: 'publisher1 INC.' + } + } + } + }; + }); + + it('should validate request format', function () { + let request = spec.buildRequests(arrayOfValidBidRequests, validBidderRequest); + assert.equal(request.method, 'POST'); + assert.deepEqual(request.options, { contentType: 'application/json' }); + assert.ok(request.data); + }); + + it('has the right fields filled', function () { + let request = spec.buildRequests(arrayOfValidBidRequests, validBidderRequest); + const bidderRequest = request.data; + assert.equal(bidderRequest.id, validBidderRequest.auctionId); + assert.ok(bidderRequest.site); + assert.ok(bidderRequest.source); + assert.lengthOf(bidderRequest.imp, 1); + }); + + it('should configure the site object', function () { + let request = spec.buildRequests(arrayOfValidBidRequests, validBidderRequest); + const site = request.data.site; + assert.equal(site.publisher.name, validBidderRequest.ortb2.site.publisher.name) + }); + + it('should configure site with ortb2', function () { + const req = mergeDeep({}, validBidderRequest, { + ortb2: { + site: { + id: '876', + publisher: { + domain: 'publisher1.eu' + } + } + } + }); + + let request = spec.buildRequests(arrayOfValidBidRequests, req); + const site = request.data.site; + assert.deepEqual(site, { + id: '876', + publisher: { + domain: 'publisher1.eu', + name: 'publisher1 INC.' + } + }); + }); + + it('should send device info', function () { + it('should send info about device', function () { + config.setConfig({ + device: { w: 375, h: 273 } + }); + + let request = spec.buildRequests(arrayOfValidBidRequests, validBidderRequest); + + assert.equal(request.device.ua, navigator.userAgent); + assert.equal(request.device.w, 375); + assert.equal(request.device.h, 273); + }); + }) + }) +}) + +describe('interpretResponse', function () { + const serverResponse = { + body: { + id: 'b4a45a23-8371-4d87-9308-39146b29ca32', + bidid: '11111111-2222-2222-2222-333333333333', + cur: 'PLN', + seatbid: [{ + bid: [ + { + id: '234234-234234-234234', // bidder generated + impid: '123', + price: '34.2', + nurl: 'https://scattered.eu/nurl', + adm: '
', + cpm: '34.2', + creativeId: '2345-2345-23', + currency: 'PLN', + height: 456, + width: 345, + mediaType: 'banner', + requestId: '123', + ttl: 360, + }; + expect(results.length).to.equal(1); + sinon.assert.match(results[0], expected); + }); +}); diff --git a/test/spec/modules/seedingAllianceAdapter_spec.js b/test/spec/modules/seedingAllianceAdapter_spec.js index 81af9546ff0..6086db01de4 100755 --- a/test/spec/modules/seedingAllianceAdapter_spec.js +++ b/test/spec/modules/seedingAllianceAdapter_spec.js @@ -38,7 +38,7 @@ describe('SeedingAlliance adapter', function () { }); it('should have default request structure', function () { - let keys = 'site,device,cur,imp,user,regs'.split(','); + let keys = 'site,cur,imp,regs'.split(','); let validBidRequests = [{ bidId: 'bidId', params: {} @@ -60,14 +60,17 @@ describe('SeedingAlliance adapter', function () { assert.equal(request.id, validBidRequests[0].auctionId); }); - it('Verify the device', function () { + it('Verify the site url', function () { + let siteUrl = 'https://www.yourdomain.tld/your-directory/'; let validBidRequests = [{ bidId: 'bidId', - params: {} + params: { + url: siteUrl + } }]; let request = JSON.parse(spec.buildRequests(validBidRequests, { refererInfo: { referer: 'page' } }).data); - assert.equal(request.device.ua, navigator.userAgent); + assert.equal(request.site.page, siteUrl); }); it('Verify native asset ids', function () { @@ -109,7 +112,7 @@ describe('SeedingAlliance adapter', function () { }); describe('interpretResponse', function () { - const goodResponse = { + const goodNativeResponse = { body: { cur: 'EUR', id: '4b516b80-886e-4ec0-82ae-9209e6d625fb', @@ -136,51 +139,91 @@ describe('SeedingAlliance adapter', function () { ] } }; + + const goodBannerResponse = { + body: { + cur: 'EUR', + id: 'b4516b80-886e-4ec0-82ae-9209e6d625fb', + seatbid: [ + { + seat: 'seedingAlliance', + bid: [{ + adm: '', + impid: 1, + price: 0.90, + h: 250, + w: 300 + }] + } + ] + } + }; + const badResponse = { body: { cur: 'EUR', id: '4b516b80-886e-4ec0-82ae-9209e6d625fb', seatbid: [] }}; - const bidRequest = { + const bidNativeRequest = { data: {}, - bids: [{ bidId: 'bidId1' }] + bidRequests: [{bidId: 'bidId1', nativeParams: {title: {required: true, len: 800}}}] + }; + + const bidBannerRequest = { + data: {}, + bidRequests: [{bidId: 'bidId1', sizes: [300, 250]}] }; it('should return null if body is missing or empty', function () { - const result = spec.interpretResponse(badResponse, bidRequest); + const result = spec.interpretResponse(badResponse, bidNativeRequest); assert.equal(result.length, 0); delete badResponse.body - const result1 = spec.interpretResponse(badResponse, bidRequest); + const result1 = spec.interpretResponse(badResponse, bidNativeRequest); assert.equal(result.length, 0); }); it('should return the correct params', function () { - const result = spec.interpretResponse(goodResponse, bidRequest); - const bid = goodResponse.body.seatbid[0].bid[0]; - - assert.deepEqual(result[0].currency, goodResponse.body.cur); - assert.deepEqual(result[0].requestId, bidRequest.bids[0].bidId); - assert.deepEqual(result[0].cpm, bid.price); - assert.deepEqual(result[0].creativeId, bid.crid); - assert.deepEqual(result[0].mediaType, 'native'); - assert.deepEqual(result[0].bidderCode, 'seedingAlliance'); + const resultNative = spec.interpretResponse(goodNativeResponse, bidNativeRequest); + const bidNative = goodNativeResponse.body.seatbid[0].bid[0]; + + assert.deepEqual(resultNative[0].bidderCode, 'seedingAlliance'); + assert.deepEqual(resultNative[0].currency, goodNativeResponse.body.cur); + assert.deepEqual(resultNative[0].requestId, bidNativeRequest.bidRequests[0].bidId); + assert.deepEqual(resultNative[0].cpm, bidNative.price); + assert.deepEqual(resultNative[0].creativeId, bidNative.crid); + assert.deepEqual(resultNative[0].mediaType, 'native'); + + const resultBanner = spec.interpretResponse(goodBannerResponse, bidBannerRequest); + + assert.deepEqual(resultBanner[0].bidderCode, 'seedingAlliance'); + assert.deepEqual(resultBanner[0].mediaType, 'banner'); + assert.deepEqual(resultBanner[0].width, bidBannerRequest.bidRequests[0].sizes[0]); + assert.deepEqual(resultBanner[0].height, bidBannerRequest.bidRequests[0].sizes[1]); }); - it('should return the correct tracking links', function () { - const result = spec.interpretResponse(goodResponse, bidRequest); - const bid = goodResponse.body.seatbid[0].bid[0]; + it('should return the correct native tracking links', function () { + const result = spec.interpretResponse(goodNativeResponse, bidNativeRequest); + const bid = goodNativeResponse.body.seatbid[0].bid[0]; const regExpPrice = new RegExp('price=' + bid.price); result[0].native.clickTrackers.forEach(function (clickTracker) { - assert.ok(clickTracker.search(regExpPrice) > -1); + assert.ok(clickTracker.search(regExpPrice) > -1); }); result[0].native.impressionTrackers.forEach(function (impTracker) { - assert.ok(impTracker.search(regExpPrice) > -1); + assert.ok(impTracker.search(regExpPrice) > -1); }); }); + + it('should return the correct banner content', function () { + const result = spec.interpretResponse(goodBannerResponse, bidBannerRequest); + const bid = goodBannerResponse.body.seatbid[0].bid[0]; + const regExpContent = new RegExp(''); + + assert.ok(result[0].ad.search(regExpContent) > -1); + }); }); }); diff --git a/test/spec/modules/seedtagBidAdapter_spec.js b/test/spec/modules/seedtagBidAdapter_spec.js index 05d609e8003..3627296975b 100644 --- a/test/spec/modules/seedtagBidAdapter_spec.js +++ b/test/spec/modules/seedtagBidAdapter_spec.js @@ -1,6 +1,7 @@ import { expect } from 'chai'; import { spec, getTimeoutUrl } from 'modules/seedtagBidAdapter.js'; import * as utils from 'src/utils.js'; +import { config } from '../../../src/config.js'; const PUBLISHER_ID = '0000-0000-01'; const ADUNIT_ID = '000000'; @@ -24,81 +25,118 @@ function getSlotConfigs(mediaTypes, params) { }; } -function createVideoSlotConfig(mediaType) { +function createInStreamSlotConfig(mediaType) { return getSlotConfigs(mediaType, { publisherId: PUBLISHER_ID, adUnitId: ADUNIT_ID, - placement: 'video', + placement: 'inStream', }); } +const createBannerSlotConfig = (placement, mediatypes) => { + return getSlotConfigs(mediatypes || { banner: {} }, { + publisherId: PUBLISHER_ID, + adUnitId: ADUNIT_ID, + placement, + }); +}; + describe('Seedtag Adapter', function () { describe('isBidRequestValid method', function () { describe('returns true', function () { describe('when banner slot config has all mandatory params', () => { - describe('and placement has the correct value', function () { - const createBannerSlotConfig = (placement) => { - return getSlotConfigs( - { banner: {} }, - { - publisherId: PUBLISHER_ID, - adUnitId: ADUNIT_ID, - placement, - } + const placements = ['inBanner', 'inImage', 'inScreen', 'inArticle']; + placements.forEach((placement) => { + it(placement + 'should be valid', function () { + const isBidRequestValid = spec.isBidRequestValid( + createBannerSlotConfig(placement) ); - }; - const placements = [ - 'banner', - 'video', - 'inImage', - 'inScreen', - 'inArticle', - ]; - placements.forEach((placement) => { - it('should be ' + placement, function () { + expect(isBidRequestValid).to.equal(true); + }); + + it( + placement + + ' should be valid when has display and video mediatypes, and video context is outstream', + function () { const isBidRequestValid = spec.isBidRequestValid( - createBannerSlotConfig(placement) + createBannerSlotConfig(placement, { + banner: {}, + video: { + context: 'outstream', + playerSize: [[600, 200]], + }, + }) ); expect(isBidRequestValid).to.equal(true); - }); - }); + } + ); + + it( + placement + + " shouldn't be valid when has display and video mediatypes, and video context is instream", + function () { + const isBidRequestValid = spec.isBidRequestValid( + createBannerSlotConfig(placement, { + banner: {}, + video: { + context: 'instream', + playerSize: [[600, 200]], + }, + }) + ); + expect(isBidRequestValid).to.equal(false); + } + ); }); }); describe('when video slot has all mandatory params', function () { it('should return true, when video context is instream', function () { - const slotConfig = getSlotConfigs( - { - video: { - context: 'instream', - playerSize: [[600, 200]], - }, + const slotConfig = createInStreamSlotConfig({ + video: { + context: 'instream', + playerSize: [[600, 200]], }, - { - publisherId: PUBLISHER_ID, - adUnitId: ADUNIT_ID, - placement: 'video', - } - ); + }); const isBidRequestValid = spec.isBidRequestValid(slotConfig); expect(isBidRequestValid).to.equal(true); }); - - it('should return true, when video context is outstream', function () { + it('should return true, when video context is instream and mediatype is video and banner', function () { + const slotConfig = createInStreamSlotConfig({ + video: { + context: 'instream', + playerSize: [[600, 200]], + }, + banner: {}, + }); + const isBidRequestValid = spec.isBidRequestValid(slotConfig); + expect(isBidRequestValid).to.equal(true); + }); + it('should return false, when video context is instream, but placement is not inStream', function () { const slotConfig = getSlotConfigs( { video: { - context: 'outstream', + context: 'instream', playerSize: [[600, 200]], }, }, { publisherId: PUBLISHER_ID, adUnitId: ADUNIT_ID, - placement: 'video', + placement: 'inBanner', } ); const isBidRequestValid = spec.isBidRequestValid(slotConfig); - expect(isBidRequestValid).to.equal(true); + expect(isBidRequestValid).to.equal(false); + }); + it('should return false, when video context is outstream', function () { + const slotConfig = createInStreamSlotConfig({ + video: { + context: 'outstream', + playerSize: [[600, 200]], + }, + }); + const isBidRequestValid = spec.isBidRequestValid(slotConfig); + expect(isBidRequestValid).to.equal(false); }); }); }); @@ -111,7 +149,7 @@ describe('Seedtag Adapter', function () { const isBidRequestValid = spec.isBidRequestValid( createSlotConfig({ adUnitId: ADUNIT_ID, - placement: 'banner', + placement: 'inBanner', }) ); expect(isBidRequestValid).to.equal(false); @@ -120,7 +158,7 @@ describe('Seedtag Adapter', function () { const isBidRequestValid = spec.isBidRequestValid( createSlotConfig({ publisherId: PUBLISHER_ID, - placement: 'banner', + placement: 'inBanner', }) ); expect(isBidRequestValid).to.equal(false); @@ -145,47 +183,41 @@ describe('Seedtag Adapter', function () { expect(isBidRequestValid).to.equal(false); }); }); + describe('when video mediaType object is not correct', function () { - function createVideoSlotconfig(mediaType) { - return getSlotConfigs(mediaType, { - publisherId: PUBLISHER_ID, - adUnitId: ADUNIT_ID, - placement: 'video', - }); - } it('is a void object', function () { const isBidRequestValid = spec.isBidRequestValid( - createVideoSlotConfig({ video: {} }) + createInStreamSlotConfig({ video: {} }) ); expect(isBidRequestValid).to.equal(false); }); it('does not have playerSize.', function () { const isBidRequestValid = spec.isBidRequestValid( - createVideoSlotConfig({ video: { context: 'instream' } }) + createInStreamSlotConfig({ video: { context: 'instream' } }) ); expect(isBidRequestValid).to.equal(false); }); it('is outstream ', function () { const isBidRequestValid = spec.isBidRequestValid( - createVideoSlotConfig({ + createInStreamSlotConfig({ video: { context: 'outstream', playerSize: [[600, 200]], }, }) ); - expect(isBidRequestValid).to.equal(true); + expect(isBidRequestValid).to.equal(false); }); describe('order does not matter', function () { it('when video is not the first slot', function () { const isBidRequestValid = spec.isBidRequestValid( - createVideoSlotConfig({ banner: {}, video: {} }) + createInStreamSlotConfig({ banner: {}, video: {} }) ); expect(isBidRequestValid).to.equal(false); }); it('when video is the first slot', function () { const isBidRequestValid = spec.isBidRequestValid( - createVideoSlotConfig({ video: {}, banner: {} }) + createInStreamSlotConfig({ video: {}, banner: {} }) ); expect(isBidRequestValid).to.equal(false); }); @@ -199,21 +231,27 @@ describe('Seedtag Adapter', function () { refererInfo: { page: 'referer' }, timeout: 1000, }; - const mandatoryParams = { + const mandatoryDisplayParams = { publisherId: PUBLISHER_ID, adUnitId: ADUNIT_ID, - placement: 'banner', + placement: 'inBanner', + }; + const mandatoryVideoParams = { + publisherId: PUBLISHER_ID, + adUnitId: ADUNIT_ID, + placement: 'inStream', }; - const inStreamParams = Object.assign({}, mandatoryParams, { - video: { - mimes: 'mp4', - }, - }); const validBidRequests = [ - getSlotConfigs({ banner: {} }, mandatoryParams), + getSlotConfigs({ banner: {} }, mandatoryDisplayParams), getSlotConfigs( - { video: { context: 'instream', playerSize: [[300, 200]] } }, - inStreamParams + { + video: { + context: 'instream', + playerSize: [[300, 200]], + mimes: ['video/mp4'], + }, + }, + mandatoryVideoParams ), ]; it('Url params should be correct ', function () { @@ -238,26 +276,6 @@ describe('Seedtag Adapter', function () { expect(data.bidRequests[0].adUnitCode).to.equal('adunit-code'); }); - describe('adPosition param', function () { - it('should sended when publisher set adPosition param', function () { - const params = Object.assign({}, mandatoryParams, { - adPosition: 1, - }); - const validBidRequests = [getSlotConfigs({ banner: {} }, params)]; - const request = spec.buildRequests(validBidRequests, bidderRequest); - const data = JSON.parse(request.data); - expect(data.bidRequests[0].adPosition).to.equal(1); - }); - it('should not sended when publisher has not set adPosition param', function () { - const validBidRequests = [ - getSlotConfigs({ banner: {} }, mandatoryParams), - ]; - const request = spec.buildRequests(validBidRequests, bidderRequest); - const data = JSON.parse(request.data); - expect(data.bidRequests[0].adPosition).to.equal(undefined); - }); - }); - describe('GDPR params', function () { describe('when there arent consent management platform', function () { it('cmp should be false', function () { @@ -309,10 +327,7 @@ describe('Seedtag Adapter', function () { bidderRequest['uspConsent'] = uspConsent; - const request = spec.buildRequests( - validBidRequests, - bidderRequest - ); + const request = spec.buildRequests(validBidRequests, bidderRequest); const payload = JSON.parse(request.data); expect(payload.uspConsent).to.not.exist; @@ -346,7 +361,7 @@ describe('Seedtag Adapter', function () { ); expect(videoBid.supplyTypes[0]).to.equal('video'); expect(videoBid.adUnitId).to.equal('000000'); - expect(videoBid.videoParams.mimes).to.equal('mp4'); + expect(videoBid.videoParams.mimes).to.eql(['video/mp4']); expect(videoBid.videoParams.w).to.equal(300); expect(videoBid.videoParams.h).to.equal(200); expect(videoBid.sizes[0][0]).to.equal(300); @@ -357,6 +372,29 @@ describe('Seedtag Adapter', function () { }); }); + describe('COPPA param', function () { + it('should add COPPA param to payload when prebid config has parameter COPPA equal to true', function () { + config.setConfig({ coppa: true }); + + const request = spec.buildRequests(validBidRequests, bidderRequest); + const data = JSON.parse(request.data); + expect(data.coppa).to.equal(true); + }); + + it('should not add COPPA param to payload when prebid config has parameter COPPA equal to false', function () { + config.setConfig({ coppa: false }); + + const request = spec.buildRequests(validBidRequests, bidderRequest); + const data = JSON.parse(request.data); + expect(data.coppa).to.be.undefined; + }); + + it('should not add COPPA param to payload when prebid config has not parameter COPPA', function () { + const request = spec.buildRequests(validBidRequests, bidderRequest); + const data = JSON.parse(request.data); + expect(data.coppa).to.be.undefined; + }); + }); describe('schain param', function () { it('should add schain to payload when exposed on validBidRequest', function () { // https://github.com/prebid/Prebid.js/blob/master/modules/schain.md#sample-code-for-passing-the-schain-object @@ -398,6 +436,52 @@ describe('Seedtag Adapter', function () { expect(payload.schain).to.not.exist; }); }); + + describe('GPP param', function () { + it('should be added to payload when bidderRequest has gppConsent param', function () { + const gppConsent = { + gppString: 'someGppString', + applicableSections: [7] + } + bidderRequest['gppConsent'] = gppConsent + const request = spec.buildRequests(validBidRequests, bidderRequest); + const data = JSON.parse(request.data); + expect(data.gppConsent).to.exist; + expect(data.gppConsent.gppString).to.equal(gppConsent.gppString); + expect(data.gppConsent.applicableSections[0]).to.equal(gppConsent.applicableSections[0]); + }); + + it('should be undefined on payload when bidderRequest has not gppConsent param', function () { + bidderRequest.gppConsent = undefined + const request = spec.buildRequests(validBidRequests, bidderRequest); + const data = JSON.parse(request.data); + expect(data.gppConsent).to.be.undefined; + }); + + it('should be added to payload when bidderRequest has ortb2 param', function () { + const ortb2 = { + regs: { + gpp: 'someGppString', + gpp_sid: [7] + } + } + bidderRequest['gppConsent'] = undefined + bidderRequest['ortb2'] = ortb2; + const request = spec.buildRequests(validBidRequests, bidderRequest); + const data = JSON.parse(request.data); + expect(data.gppConsent).to.exist; + expect(data.gppConsent.gppString).to.equal(ortb2.regs.gpp); + expect(data.gppConsent.applicableSections[0]).to.equal(ortb2.regs.gpp_sid[0]); + }); + + it('should be added to payload when bidderRequest has neither gppConsent nor ortb2', function () { + bidderRequest['ortb2'] = undefined; + bidderRequest['gppConsent'] = undefined; + const request = spec.buildRequests(validBidRequests, bidderRequest); + const data = JSON.parse(request.data); + expect(data.gppConsent).to.be.undefined; + }); + }); }); describe('interpret response method', function () { @@ -536,11 +620,11 @@ describe('Seedtag Adapter', function () { const timeoutUrl = getTimeoutUrl(timeoutData); expect(timeoutUrl).to.equal( 'https://s.seedtag.com/se/hb/timeout?publisherToken=' + - params.publisherId + - '&adUnitId=' + - params.adUnitId + - '&timeout=' + - timeout + params.publisherId + + '&adUnitId=' + + params.adUnitId + + '&timeout=' + + timeout ); }); @@ -552,11 +636,11 @@ describe('Seedtag Adapter', function () { expect( utils.triggerPixel.calledWith( 'https://s.seedtag.com/se/hb/timeout?publisherToken=' + - params.publisherId + - '&adUnitId=' + - params.adUnitId + - '&timeout=' + - timeout + params.publisherId + + '&adUnitId=' + + params.adUnitId + + '&timeout=' + + timeout ) ).to.equal(true); }); diff --git a/test/spec/modules/sigmoidAnalyticsAdapter_spec.js b/test/spec/modules/sigmoidAnalyticsAdapter_spec.js index 6d772de02eb..6cdc3c448b9 100644 --- a/test/spec/modules/sigmoidAnalyticsAdapter_spec.js +++ b/test/spec/modules/sigmoidAnalyticsAdapter_spec.js @@ -1,5 +1,7 @@ import sigmoidAnalytic from 'modules/sigmoidAnalyticsAdapter.js'; -import { expect } from 'chai'; +import {expect} from 'chai'; +import {expectEvents} from '../../helpers/analytics.js'; + let events = require('src/events'); let adapterManager = require('src/adapterManager').default; let constants = require('src/constants.json'); @@ -32,13 +34,7 @@ describe('sigmoid Prebid Analytic', function () { } }); - events.emit(constants.EVENTS.AUCTION_INIT, {}); - events.emit(constants.EVENTS.AUCTION_END, {}); - events.emit(constants.EVENTS.BID_REQUESTED, {}); - events.emit(constants.EVENTS.BID_RESPONSE, {}); - events.emit(constants.EVENTS.BID_WON, {}); - - sinon.assert.callCount(sigmoidAnalytic.track, 8); + expectEvents().to.beTrackedBy(sigmoidAnalytic.track); }); }); describe('build utm tag data', function () { diff --git a/test/spec/modules/sirdataRtdProvider_spec.js b/test/spec/modules/sirdataRtdProvider_spec.js index 9cf392ebd62..eccc4777906 100644 --- a/test/spec/modules/sirdataRtdProvider_spec.js +++ b/test/spec/modules/sirdataRtdProvider_spec.js @@ -1,17 +1,17 @@ -import { addSegmentData, getSegmentsAndCategories, sirdataSubmodule } from 'modules/sirdataRtdProvider.js'; -import { server } from 'test/mocks/xhr.js'; +import {addSegmentData, getSegmentsAndCategories, sirdataSubmodule} from 'modules/sirdataRtdProvider.js'; +import {server} from 'test/mocks/xhr.js'; const responseHeader = {'Content-Type': 'application/json'}; -describe('sirdataRtdProvider', function() { - describe('sirdataSubmodule', function() { +describe('sirdataRtdProvider', function () { + describe('sirdataSubmodule', function () { it('successfully instantiates', function () { - expect(sirdataSubmodule.init()).to.equal(true); + expect(sirdataSubmodule.init()).to.equal(true); }); }); - describe('Add Segment Data', function() { - it('adds segment data', function() { + describe('Add Segment Data', function () { + it('adds segment data', function () { const config = { params: { setGptKeyValues: false, @@ -42,23 +42,34 @@ describe('sirdataRtdProvider', function() { contextual_categories: {'333333': 100} }; - addSegmentData({adUnits}, data, config, () => {}); + addSegmentData({adUnits}, data, config, () => { + }); expect(adUnits[0].bids[0].params.keywords).to.have.deep.property('sd_rtd', ['111111', '222222', '333333']); - expect(adUnits[0].bids[1].ortb2.site.ext.data).to.have.deep.property('sd_rtd', ['333333']); - expect(adUnits[0].bids[1].ortb2.user.ext.data).to.have.deep.property('sd_rtd', ['111111', '222222']); }); }); - describe('Get Segments And Categories', function() { - it('gets data from async request and adds segment data', function() { + describe('Get Segments And Categories', function () { + it('gets data from async request and adds segment data', function () { + const overrideAppnexus = function (adUnit, list, data, bid) { + deepSetValue(bid, 'params.keywords.custom', list); + } + const config = { params: { setGptKeyValues: false, contextualMinRelevancyScore: 50, bidders: [{ - bidder: 'appnexus' + bidder: 'appnexus', + customFunction: overrideAppnexus }, { - bidder: 'other' + bidder: 'smartadserver' + }, { + bidder: 'ix', + sizeLimit: 1200, + }, { + bidder: 'rubicon', + }, { + bidder: 'proxistore', }] } }; @@ -71,24 +82,107 @@ describe('sirdataRtdProvider', function() { placementId: 13144370 } }, { - bidder: 'other' + bidder: 'smartadserver', + params: { + siteId: 207435, + pageId: 896536, + formatId: 62913 + } + }, { + bidder: 'proxistore', + params: {website: 'demo.sirdata.com', language: 'fr'}, + adUnitCode: 'HALFPAGE_CENTER_LOADER', + transactionId: '92ac333a-a569-4827-abf1-01fc9d19278a', + sizes: [[300, 600]], + mediaTypes: { + banner: { + filteredSizeConfig: [ + {minViewPort: [1600, 0], sizes: [[300, 600]]}, + ], + sizeConfig: [ + {minViewPort: [0, 0], sizes: [[300, 600]]}, + {minViewPort: [768, 0], sizes: [[300, 600]]}, + {minViewPort: [1200, 0], sizes: [[300, 600]]}, + {minViewPort: [1600, 0], sizes: [[300, 600]]}, + ], + sizes: [[300, 600]], + }, + }, + bidId: '190bab495bc5f6e', + bidderRequestId: '18c0b0f0c91cd88', + auctionId: '9bdd917b-908d-4d9f-8f2f-d443277a62fc', + src: 'client', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, + }, { + bidder: 'ix', + params: { + siteId: '12345', + size: [300, 600] + } + }, { + bidder: 'rubicon', + params: { + accountId: 14062, + siteId: 70608, + zoneId: 498816 + } }] - }] + }], + ortb2Fragments: { + global: {} + } }; let data = { - segments: [111111, 222222], - contextual_categories: {'333333': 100} + 'segments': [111111, 222222], + 'segtaxid': null, + 'cattaxid': null, + 'contextual_categories': {'333333': 100}, + 'shared_taxonomy': { + '27440': { + 'segments': [444444, 555555], + 'segtaxid': 552, + 'cattaxid': 553, + 'contextual_categories': {'666666': 100} + } + }, + 'global_taxonomy': { + '9998': { + 'segments': [123, 234], + 'segtaxid': 4, + 'cattaxid': 7, + 'contextual_categories': {'345': 100, '456': 100} + } + } }; - getSegmentsAndCategories(reqBidsConfigObj, () => {}, config, {}); + getSegmentsAndCategories(reqBidsConfigObj, () => { + }, config, {}); let request = server.requests[0]; request.respond(200, responseHeader, JSON.stringify(data)); - expect(reqBidsConfigObj.adUnits[0].bids[0].params.keywords).to.have.deep.property('sd_rtd', ['111111', '222222', '333333']); - expect(reqBidsConfigObj.adUnits[0].bids[1].ortb2.site.ext.data).to.have.deep.property('sd_rtd', ['333333']); - expect(reqBidsConfigObj.adUnits[0].bids[1].ortb2.user.ext.data).to.have.deep.property('sd_rtd', ['111111', '222222']); + expect(reqBidsConfigObj.adUnits[0].bids[1].params).to.have.deep.property('target', 'sd_rtd=111111;sd_rtd=222222;sd_rtd=333333;sd_rtd=444444;sd_rtd=555555;sd_rtd=666666'); + + expect(reqBidsConfigObj.ortb2Fragments.global.site.content.data[0].name).to.equal( + 'sirdata.com' + ); + expect(reqBidsConfigObj.ortb2Fragments.global.site.content.data[0].segment).to.eql([ + {id: '345'}, + {id: '456'} + ]); + expect(reqBidsConfigObj.ortb2Fragments.global.site.content.data[0].ext.segtax).to.equal(7); + + expect(reqBidsConfigObj.ortb2Fragments.global.user.data[0].name).to.equal( + 'sirdata.com' + ); + expect(reqBidsConfigObj.ortb2Fragments.global.user.data[0].segment).to.eql([ + {id: '123'}, + {id: '234'} + ]); + expect(reqBidsConfigObj.ortb2Fragments.global.user.data[0].ext.segtax).to.equal(4); }); }); }); diff --git a/test/spec/modules/smaatoBidAdapter_spec.js b/test/spec/modules/smaatoBidAdapter_spec.js index c7dbf1363e7..7891a49b9db 100644 --- a/test/spec/modules/smaatoBidAdapter_spec.js +++ b/test/spec/modules/smaatoBidAdapter_spec.js @@ -297,6 +297,21 @@ describe('smaatoBidAdapterTest', () => { expect(req.regs.ext.us_privacy).to.equal('uspConsentString'); }); + it('sends gpp', () => { + const ortb2 = { + regs: { + gpp: 'gppString', + gpp_sid: [7] + } + }; + + const reqs = spec.buildRequests([singleBannerBidRequest], {...defaultBidderRequest, ortb2}); + + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.regs.ext.gpp).to.eql('gppString'); + expect(req.regs.ext.gpp_sid).to.eql([7]); + }); + it('sends no schain if no schain exists', () => { const reqs = spec.buildRequests([singleBannerBidRequest], defaultBidderRequest); diff --git a/test/spec/modules/smartadserverBidAdapter_spec.js b/test/spec/modules/smartadserverBidAdapter_spec.js index 727a7d7c1d6..97250ad0ebc 100644 --- a/test/spec/modules/smartadserverBidAdapter_spec.js +++ b/test/spec/modules/smartadserverBidAdapter_spec.js @@ -1,4 +1,5 @@ import { expect } from 'chai'; +import { BANNER, VIDEO } from 'src/mediaTypes.js'; import { config } from 'src/config.js'; import { spec } from 'modules/smartadserverBidAdapter.js'; @@ -158,12 +159,44 @@ describe('Smart bid adapter tests', function () { } }; + var sellerDefinedAudience = [ + { + 'name': 'hearst.com', + 'ext': { 'segtax': 1 }, + 'segment': [ + { 'id': '1001' }, + { 'id': '1002' } + ] + } + ]; + + var sellerDefinedContext = [ + { + 'name': 'cnn.com', + 'ext': { 'segtax': 2 }, + 'segment': [ + { 'id': '2002' } + ] + } + ]; + it('Verify build request', function () { config.setConfig({ 'currency': { 'adServerCurrency': 'EUR' + }, + ortb2: { + 'user': { + 'data': sellerDefinedAudience + }, + 'site': { + 'content': { + 'data': sellerDefinedContext + } + } } }); + const request = spec.buildRequests(DEFAULT_PARAMS); expect(request[0]).to.have.property('url').and.to.equal('https://prg.smartadserver.com/prebid/v1'); expect(request[0]).to.have.property('method').and.to.equal('POST'); @@ -186,6 +219,8 @@ describe('Smart bid adapter tests', function () { expect(requestContent).to.have.property('buid').and.to.equal('7569'); expect(requestContent).to.have.property('appname').and.to.equal('Mozilla'); expect(requestContent).to.have.property('ckid').and.to.equal(42); + expect(requestContent).to.have.property('sda').and.to.deep.equal(sellerDefinedAudience); + expect(requestContent).to.have.property('sdc').and.to.deep.equal(sellerDefinedContext); }); it('Verify parse response with no ad', function () { @@ -200,6 +235,27 @@ describe('Smart bid adapter tests', function () { }).to.not.throw(); }); + it('Should not nest response if ad and adUrl empty', () => { + const BID_RESPONSE_EMPTY = { + body: { + ad: null, + adUrl: null, + cpm: 0.92, + isNoAd: false + } + }; + + const request = spec.buildRequests(DEFAULT_PARAMS); + const bids = spec.interpretResponse(BID_RESPONSE_EMPTY, request[0]); + + expect(bids).to.have.lengthOf(0); + expect(() => { + spec.interpretResponse(BID_RESPONSE_EMPTY, { + data: 'invalid Json' + }); + }).to.not.throw(); + }); + it('Verify parse response', function () { const request = spec.buildRequests(DEFAULT_PARAMS); const bids = spec.interpretResponse(BID_RESPONSE, request[0]); @@ -337,8 +393,8 @@ describe('Smart bid adapter tests', function () { describe('gdpr tests', function () { afterEach(function () { + config.setConfig({ ortb2: undefined }); config.resetConfig(); - $$PREBID_GLOBAL$$.requestBids.removeAll(); }); it('Verify build request with GDPR', function () { @@ -387,10 +443,33 @@ describe('Smart bid adapter tests', function () { }); }); + describe('GPP', function () { + it('should be added to payload when gppConsent available in bidder request', function () { + const options = { + gppConsent: { + gppString: 'some-gpp-string', + applicableSections: [3, 5] + } + }; + const request = spec.buildRequests(DEFAULT_PARAMS_WO_OPTIONAL, options); + const payload = JSON.parse(request[0].data); + + expect(payload).to.have.property('gpp').and.to.equal(options.gppConsent.gppString); + expect(payload).to.have.property('gpp_sid').and.to.be.an('array'); + expect(payload.gpp_sid).to.have.lengthOf(2).and.to.deep.equal(options.gppConsent.applicableSections); + }); + + it('should be undefined on payload when gppConsent unavailable in bidder request', function () { + const request = spec.buildRequests(DEFAULT_PARAMS_WO_OPTIONAL, {}); + const payload = JSON.parse(request[0].data); + + expect(payload.gpp).to.be.undefined; + }); + }); + describe('ccpa/us privacy tests', function () { afterEach(function () { config.resetConfig(); - $$PREBID_GLOBAL$$.requestBids.removeAll(); }); it('Verify build request with us privacy', function () { @@ -419,7 +498,6 @@ describe('Smart bid adapter tests', function () { describe('Instream video tests', function () { afterEach(function () { config.resetConfig(); - $$PREBID_GLOBAL$$.requestBids.removeAll(); }); const INSTREAM_DEFAULT_PARAMS = [{ @@ -468,6 +546,16 @@ describe('Smart bid adapter tests', function () { config.setConfig({ 'currency': { 'adServerCurrency': 'EUR' + }, + ortb2: { + 'user': { + 'data': sellerDefinedAudience + }, + 'site': { + 'content': { + 'data': sellerDefinedContext + } + } } }); const request = spec.buildRequests(INSTREAM_DEFAULT_PARAMS); @@ -486,6 +574,8 @@ describe('Smart bid adapter tests', function () { expect(requestContent).to.have.property('buid').and.to.equal('7569'); expect(requestContent).to.have.property('appname').and.to.equal('Mozilla'); expect(requestContent).to.have.property('ckid').and.to.equal(42); + expect(requestContent).to.have.property('sda').and.to.deep.equal(sellerDefinedAudience); + expect(requestContent).to.have.property('sdc').and.to.deep.equal(sellerDefinedContext); expect(requestContent).to.have.property('isVideo').and.to.equal(true); expect(requestContent).to.have.property('videoData'); expect(requestContent.videoData).to.have.property('videoProtocol').and.to.equal(6); @@ -678,7 +768,6 @@ describe('Smart bid adapter tests', function () { describe('Outstream video tests', function () { afterEach(function () { config.resetConfig(); - $$PREBID_GLOBAL$$.requestBids.removeAll(); }); const OUTSTREAM_DEFAULT_PARAMS = [{ @@ -727,6 +816,16 @@ describe('Smart bid adapter tests', function () { config.setConfig({ 'currency': { 'adServerCurrency': 'EUR' + }, + ortb2: { + 'user': { + 'data': sellerDefinedAudience + }, + 'site': { + 'content': { + 'data': sellerDefinedContext + } + } } }); const request = spec.buildRequests(OUTSTREAM_DEFAULT_PARAMS); @@ -745,6 +844,8 @@ describe('Smart bid adapter tests', function () { expect(requestContent).to.have.property('buid').and.to.equal('7579'); expect(requestContent).to.have.property('appname').and.to.equal('Mozilla'); expect(requestContent).to.have.property('ckid').and.to.equal(43); + expect(requestContent).to.have.property('sda').and.to.deep.equal(sellerDefinedAudience); + expect(requestContent).to.have.property('sdc').and.to.deep.equal(sellerDefinedContext); expect(requestContent).to.have.property('isVideo').and.to.equal(false); expect(requestContent).to.have.property('videoData'); expect(requestContent.videoData).to.have.property('videoProtocol').and.to.equal(7); @@ -975,6 +1076,17 @@ describe('Smart bid adapter tests', function () { }); describe('Floors module', function () { + const getFloor = (bid) => { + switch (bid.mediaType) { + case BANNER: + return { currency: 'USD', floor: 1.93 }; + case VIDEO: + return { currency: 'USD', floor: 2.72 }; + default: + return {}; + } + }; + it('should include floor from bid params', function() { const bidRequest = JSON.parse((spec.buildRequests(DEFAULT_PARAMS))[0].data); expect(bidRequest.bidfloor).to.deep.equal(DEFAULT_PARAMS[0].params.bidfloor); @@ -1014,12 +1126,91 @@ describe('Smart bid adapter tests', function () { const floor = spec.getBidFloor(bidRequest, null); expect(floor).to.deep.equal(0); }); + + it('should take floor from bidder params over ad unit', function() { + const bidRequest = [{ + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + getFloor, + params: { siteId: 1234, pageId: 678, formatId: 73, bidfloor: 1.25 } + }]; + + const request = spec.buildRequests(bidRequest); + const requestContent = JSON.parse(request[0].data); + + expect(requestContent).to.have.property('bidfloor').and.to.equal(1.25); + }); + + it('should take floor from banner ad unit', function() { + const bidRequest = [{ + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]] + } + }, + getFloor, + params: { siteId: 1234, pageId: 678, formatId: 73 } + }]; + + const request = spec.buildRequests(bidRequest); + const requestContent = JSON.parse(request[0].data); + + expect(requestContent).to.have.property('bidfloor').and.to.equal(1.93); + }); + + it('should take floor from video ad unit', function() { + const bidRequest = [{ + mediaTypes: { + video: { + context: 'outstream', + playerSize: [[640, 480]] + } + }, + getFloor, + params: { siteId: 1234, pageId: 678, formatId: 73 } + }]; + + const request = spec.buildRequests(bidRequest); + const requestContent = JSON.parse(request[0].data); + + expect(requestContent).to.have.property('bidfloor').and.to.equal(2.72); + }); + + it('should take floor from multiple media type ad unit', function() { + const bidRequest = [{ + mediaTypes: { + banner: { + sizes: [[300, 600]] + }, + video: { + context: 'outstream', + playerSize: [[640, 480]] + } + }, + getFloor, + params: { siteId: 1234, pageId: 678, formatId: 73 } + }]; + + const requests = spec.buildRequests(bidRequest); + expect(requests).to.have.lengthOf(2); + + const requestContents = requests.map(r => JSON.parse(r.data)); + const videoRequest = requestContents.filter(r => r.videoData)[0]; + expect(videoRequest).to.not.equal(null).and.to.not.be.undefined; + expect(videoRequest).to.have.property('bidfloor').and.to.equal(2.72); + + const bannerRequest = requestContents.filter(r => !r.videoData)[0]; + expect(bannerRequest).to.not.equal(null).and.to.not.be.undefined; + expect(bannerRequest).to.have.property('bidfloor').and.to.equal(1.93); + }); }); describe('Verify bid requests with multiple mediaTypes', function () { afterEach(function () { config.resetConfig(); - $$PREBID_GLOBAL$$.requestBids.removeAll(); }); var DEFAULT_PARAMS_MULTIPLE_MEDIA_TYPES = [{ diff --git a/test/spec/modules/smartxBidAdapter_spec.js b/test/spec/modules/smartxBidAdapter_spec.js index 58ce50efb8e..c3d0711632e 100644 --- a/test/spec/modules/smartxBidAdapter_spec.js +++ b/test/spec/modules/smartxBidAdapter_spec.js @@ -342,6 +342,48 @@ describe('The smartx adapter', function () { expect(request.data.imp[0].video.minduration).to.equal(3); expect(request.data.imp[0].video.maxduration).to.equal(15); }); + + it('should pass schain param', function () { + var request; + + bid.schain = { + complete: 1, + nodes: [ + { + asi: 'indirectseller.com', + sid: '00001', + hp: 1 + } + ] + } + + request = spec.buildRequests([bid], bidRequestObj)[0]; + + expect(request.data.source).to.deep.equal({ + ext: { + schain: { + complete: 1, + nodes: [ + { + asi: 'indirectseller.com', + sid: '00001', + hp: 1 + } + ] + } + } + }) + }); + + it('should pass sitekey param', function () { + var request; + + bid.params.sitekey = 'foo' + + request = spec.buildRequests([bid], bidRequestObj)[0]; + + expect(request.data.site.content.ext.sitekey).to.equal('foo'); + }); }); describe('interpretResponse', function () { diff --git a/test/spec/modules/smartytechBidAdapter_spec.js b/test/spec/modules/smartytechBidAdapter_spec.js new file mode 100644 index 00000000000..b41b0280235 --- /dev/null +++ b/test/spec/modules/smartytechBidAdapter_spec.js @@ -0,0 +1,320 @@ +import {expect} from 'chai'; +import {spec, ENDPOINT_PROTOCOL, ENDPOINT_DOMAIN, ENDPOINT_PATH} from 'modules/smartytechBidAdapter'; +import {newBidder} from 'src/adapters/bidderFactory.js'; + +const BIDDER_CODE = 'smartytech'; + +describe('SmartyTechDSPAdapter: inherited functions', function () { + let adapter; + beforeEach(() => { + adapter = newBidder(spec); + }); + it('exists and is a function', function () { + expect(adapter.callBids).to.be.exist.and.to.be.a('function'); + }); + it(`bidder code is ${BIDDER_CODE}`, function () { + expect(spec.code).to.be.equal(BIDDER_CODE); + }) +}); + +describe('SmartyTechDSPAdapter: isBidRequestValid', function () { + it('Invalid bid request. Should return false', function () { + const bidFixture = { + params: { + use_id: 13144375 + } + } + + expect(spec.isBidRequestValid(bidFixture)).to.be.false + }); + it('Valid bid request. Should return true', function () { + const bidFixture = { + params: { + endpointId: 13144375 + } + } + expect(spec.isBidRequestValid(bidFixture)).to.be.true + }); + + it('Invalid bid request. Check video block', function () { + const bidFixture = { + params: { + endpointId: 1 + }, + mediaTypes: { + video: {} + } + } + expect(spec.isBidRequestValid(bidFixture)).to.be.false + }); + + it('Invalid bid request. Check playerSize', function () { + const bidFixture = { + params: { + endpointId: 1 + }, + mediaTypes: { + video: { + playerSize: '300x250' + } + } + } + expect(spec.isBidRequestValid(bidFixture)).to.be.false + }); + + it('Invalid bid request. Check context', function () { + const bidFixture = { + params: { + endpointId: 1 + }, + mediaTypes: { + video: { + playerSize: [300, 250] + } + } + } + expect(spec.isBidRequestValid(bidFixture)).to.be.false + }); + + it('Valid bid request. valid video bid', function () { + const bidFixture = { + params: { + endpointId: 1 + }, + mediaTypes: { + video: { + playerSize: [300, 250], + context: 'instream' + } + } + } + expect(spec.isBidRequestValid(bidFixture)).to.be.true + }); + + it('Invalid bid request. Check banner block', function () { + const bidFixture = { + params: { + endpointId: 1 + }, + mediaTypes: { + banner: {} + } + } + expect(spec.isBidRequestValid(bidFixture)).to.be.false + }); + + it('Invalid bid request. Check banner sizes', function () { + const bidFixture = { + params: { + endpointId: 1 + }, + mediaTypes: { + banner: { + sizes: '300x250' + } + } + } + expect(spec.isBidRequestValid(bidFixture)).to.be.false + }); + + it('Valid bid request. valid banner bid', function () { + const bidFixture = { + params: { + endpointId: 1 + }, + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + } + } + expect(spec.isBidRequestValid(bidFixture)).to.be.true + }); +}); + +function mockRandomSizeArray(len) { + return Array.apply(null, {length: len}).map(i => { + return [Math.floor(Math.random() * 800), Math.floor(Math.random() * 800)] + }); +} + +function mockBidRequestListData(mediaType, size) { + return Array.apply(null, {length: size}).map((i, index) => { + const id = Math.floor(Math.random() * 800) * (index + 1); + let mediaTypes; + + if (mediaType == 'video') { + mediaTypes = { + video: { + playerSize: mockRandomSizeArray(1), + context: 'instream' + }, + } + } else { + mediaTypes = { + banner: { + sizes: mockRandomSizeArray(index + 1) + } + } + } + + return { + adUnitCode: `adUnitCode-${id}`, + mediaTypes: mediaTypes, + bidId: `bidId-${id}`, + params: { + endpointId: id + } + } + }); +} + +function mockRefererData() { + return { + refererInfo: { + page: 'https://some-test.page' + } + } +} + +function mockResponseData(requestData) { + let data = {} + requestData.data.forEach((request, index) => { + const rndIndex = Math.floor(Math.random() * 800); + let width, height, mediaType; + if (request.video !== undefined) { + width = request.video.playerSize[0][0]; + height = request.video.playerSize[0][1]; + mediaType = 'video'; + } else { + width = request.banner.sizes[0][0]; + height = request.banner.sizes[0][1]; + mediaType = 'banner'; + } + + data[request.adUnitCode] = { + ad: `ad-${rndIndex}`, + width: width, + height: height, + creativeId: `creative-id-${index}`, + cpm: Math.floor(Math.random() * 100), + currency: `UAH-${rndIndex}`, + mediaType: mediaType + }; + }); + return { + body: data + } +}; + +describe('SmartyTechDSPAdapter: buildRequests', () => { + let mockBidRequest; + let mockReferer; + beforeEach(() => { + mockBidRequest = mockBidRequestListData('banner', 8); + mockReferer = mockRefererData(); + }); + it('has return data', () => { + const request = spec.buildRequests(mockBidRequest, mockReferer); + expect(request).not.null; + }); + it('correct request URL', () => { + const request = spec.buildRequests(mockBidRequest, mockReferer); + expect(request.url).to.be.equal(`${ENDPOINT_PROTOCOL}://${ENDPOINT_DOMAIN}${ENDPOINT_PATH}`) + }); + it('correct request method', () => { + const request = spec.buildRequests(mockBidRequest, mockReferer); + expect(request.method).to.be.equal(`POST`) + }); + it('correct request data', () => { + const data = spec.buildRequests(mockBidRequest, mockReferer).data; + data.forEach((request, index) => { + expect(request.adUnitCode).to.be.equal(mockBidRequest[index].adUnitCode); + expect(request.banner).to.be.equal(mockBidRequest[index].mediaTypes.banner); + expect(request.bidId).to.be.equal(mockBidRequest[index].bidId); + expect(request.endpointId).to.be.equal(mockBidRequest[index].params.endpointId); + expect(request.referer).to.be.equal(mockReferer.refererInfo.page); + }) + }); +}); + +describe('SmartyTechDSPAdapter: interpretResponse', () => { + let mockBidRequest; + let mockReferer; + let request; + let mockResponse; + beforeEach(() => { + const brData = mockBidRequestListData('banner', 2); + mockReferer = mockRefererData(); + request = spec.buildRequests(brData, mockReferer); + mockBidRequest = { + data: brData + } + mockResponse = mockResponseData(request); + }); + + it('interpretResponse: empty data request', () => { + delete mockResponse['body'] + const data = spec.interpretResponse(mockResponse, mockBidRequest); + expect(data.length).to.be.equal(0); + }); + + it('interpretResponse: response data and convert data arrays has same length', () => { + const keys = Object.keys(mockResponse.body); + const data = spec.interpretResponse(mockResponse, mockBidRequest); + expect(data.length).to.be.equal(keys.length); + }); + + it('interpretResponse: convert to correct data', () => { + const keys = Object.keys(mockResponse.body); + const data = spec.interpretResponse(mockResponse, mockBidRequest); + + data.forEach((responseItem, index) => { + expect(responseItem.ad).to.be.equal(mockResponse.body[keys[index]].ad); + expect(responseItem.cpm).to.be.equal(mockResponse.body[keys[index]].cpm); + expect(responseItem.creativeId).to.be.equal(mockResponse.body[keys[index]].creativeId); + expect(responseItem.currency).to.be.equal(mockResponse.body[keys[index]].currency); + expect(responseItem.netRevenue).to.be.true; + expect(responseItem.ttl).to.be.equal(60); + expect(responseItem.requestId).to.be.equal(mockBidRequest.data[index].bidId); + expect(responseItem.width).to.be.equal(mockResponse.body[keys[index]].width); + expect(responseItem.height).to.be.equal(mockResponse.body[keys[index]].height); + expect(responseItem.mediaType).to.be.equal(mockResponse.body[keys[index]].mediaType); + }); + }); +}); + +describe('SmartyTechDSPAdapter: interpretResponse video', () => { + let mockBidRequest; + let mockReferer; + let request; + let mockResponse; + beforeEach(() => { + const brData = mockBidRequestListData('video', 2); + mockReferer = mockRefererData(); + request = spec.buildRequests(brData, mockReferer); + mockBidRequest = { + data: brData + } + mockResponse = mockResponseData(request); + }); + + it('interpretResponse: convert to correct data', () => { + const keys = Object.keys(mockResponse.body); + const data = spec.interpretResponse(mockResponse, mockBidRequest); + + data.forEach((responseItem, index) => { + expect(responseItem.ad).to.be.equal(mockResponse.body[keys[index]].ad); + expect(responseItem.cpm).to.be.equal(mockResponse.body[keys[index]].cpm); + expect(responseItem.creativeId).to.be.equal(mockResponse.body[keys[index]].creativeId); + expect(responseItem.currency).to.be.equal(mockResponse.body[keys[index]].currency); + expect(responseItem.netRevenue).to.be.true; + expect(responseItem.ttl).to.be.equal(60); + expect(responseItem.requestId).to.be.equal(mockBidRequest.data[index].bidId); + expect(responseItem.width).to.be.equal(mockResponse.body[keys[index]].width); + expect(responseItem.height).to.be.equal(mockResponse.body[keys[index]].height); + expect(responseItem.mediaType).to.be.equal(mockResponse.body[keys[index]].mediaType); + expect(responseItem.vastXml).to.be.equal(mockResponse.body[keys[index]].ad); + }); + }); +}); diff --git a/test/spec/modules/smilewantedBidAdapter_spec.js b/test/spec/modules/smilewantedBidAdapter_spec.js index b9a816cf3d5..44d2c7c6507 100644 --- a/test/spec/modules/smilewantedBidAdapter_spec.js +++ b/test/spec/modules/smilewantedBidAdapter_spec.js @@ -1,9 +1,6 @@ import { expect } from 'chai'; import { spec } from 'modules/smilewantedBidAdapter.js'; -import { newBidder } from 'src/adapters/bidderFactory.js'; import { config } from 'src/config.js'; -import * as utils from 'src/utils.js'; -import { requestBidsHook } from 'modules/consentManagement.js'; const DISPLAY_REQUEST = [{ adUnitCode: 'sw_300x250', @@ -20,6 +17,37 @@ const DISPLAY_REQUEST = [{ transactionId: 'trans_abcd1234' }]; +const DISPLAY_REQUEST_WITH_EIDS = [{ + adUnitCode: 'sw_300x250', + bidId: '12345', + sizes: [ + [300, 250], + [300, 200] + ], + bidder: 'smilewanted', + params: { + zoneId: 1 + }, + requestId: 'request_abcd1234', + transactionId: 'trans_abcd1234', + userIdAsEids: [{ + source: 'pubcid.org', + uids: [{ + id: 'some-random-id-value', + atype: 1 + }] + }, { + source: 'adserver.org', + uids: [{ + id: 'some-random-id-value', + atype: 1, + ext: { + rtiPartner: 'TDID' + } + }] + }] +}]; + const DISPLAY_REQUEST_WITH_POSITION_TYPE = [{ adUnitCode: 'sw_300x250', bidId: '12345', @@ -170,6 +198,29 @@ describe('smilewantedBidAdapterTests', function () { expect(requestContent).to.have.property('pageDomain').and.to.equal('https://localhost/Prebid.js/integrationExamples/gpt/hello_world.html'); }); + it('Verify external ids in request and ids found', function () { + config.setConfig({ + 'currency': { + 'adServerCurrency': 'EUR' + } + }); + const request = spec.buildRequests(DISPLAY_REQUEST_WITH_EIDS, {}); + const requestContent = JSON.parse(request[0].data); + + expect(requestContent).to.have.property('eids'); + expect(requestContent.eids).to.not.equal(null).and.to.not.be.undefined; + expect(requestContent.eids.length).to.greaterThan(0); + for (let index in requestContent.eids) { + let eid = requestContent.eids[index]; + expect(eid.source).to.not.equal(null).and.to.not.be.undefined; + expect(eid.uids).to.not.equal(null).and.to.not.be.undefined; + for (let uidsIndex in eid.uids) { + let uid = eid.uids[uidsIndex]; + expect(uid.id).to.not.equal(null).and.to.not.be.undefined; + } + } + }); + describe('gdpr tests', function () { afterEach(function () { config.resetConfig(); diff --git a/test/spec/modules/sonobiBidAdapter_spec.js b/test/spec/modules/sonobiBidAdapter_spec.js index 7803cfff394..56ed4d5196e 100644 --- a/test/spec/modules/sonobiBidAdapter_spec.js +++ b/test/spec/modules/sonobiBidAdapter_spec.js @@ -287,6 +287,7 @@ describe('SonobiBidAdapter', function () { }, mediaTypes: { video: { + sizes: [[300, 250], [300, 600]], context: 'outstream' } } @@ -331,7 +332,7 @@ describe('SonobiBidAdapter', function () { }]; let keyMakerData = { - '30b31c1838de1f': '1a2b3c4d5e6f1a2b3c4d||f=1.25,gpid=/123123/gpt_publisher/adunit-code-1,c=v,', + '30b31c1838de1f': '1a2b3c4d5e6f1a2b3c4d|300x250,300x600|f=1.25,gpid=/123123/gpt_publisher/adunit-code-1,c=v,', '30b31c1838de1d': '1a2b3c4d5e6f1a2b3c4e|300x250,300x600|f=0.42,gpid=/123123/gpt_publisher/adunit-code-3,c=d,', '/7780971/sparks_prebid_LB|30b31c1838de1e': '300x250,300x600|gpid=/7780971/sparks_prebid_LB,c=d,', }; @@ -370,7 +371,7 @@ describe('SonobiBidAdapter', function () { } } }; - const bidRequests = spec.buildRequests(bidRequest, {...bidderRequests, ortb2}); + const bidRequests = spec.buildRequests(bidRequest, { ...bidderRequests, ortb2 }); expect(bidRequests.data.fpd).to.equal(JSON.stringify(ortb2)); }); @@ -539,7 +540,7 @@ describe('SonobiBidAdapter', function () { ]); }); - it('should return a properly formatted request with userid as a JSON-encoded set of User ID results', function () { + it('should return a properly formatted request with the userid value omitted when the userId object is present on the bidRequest. ', function () { bidRequest[0].userId = { 'pubcid': 'abcd-efg-0101', 'tdid': 'td-abcd-efg-0101', 'id5id': { 'uid': 'ID5-ZHMOrVeUVTUKgrZ-a2YGxeh5eS_pLzHCQGYOEAiTBQ', 'ext': { 'linkType': 2 } } }; bidRequest[1].userId = { 'pubcid': 'abcd-efg-0101', 'tdid': 'td-abcd-efg-0101', 'id5id': { 'uid': 'ID5-ZHMOrVeUVTUKgrZ-a2YGxeh5eS_pLzHCQGYOEAiTBQ', 'ext': { 'linkType': 2 } } }; const bidRequests = spec.buildRequests(bidRequest, bidderRequests); @@ -547,29 +548,7 @@ describe('SonobiBidAdapter', function () { expect(bidRequests.method).to.equal('GET'); expect(bidRequests.data.ref).not.to.be.empty; expect(bidRequests.data.s).not.to.be.empty; - expect(JSON.parse(bidRequests.data.userid)).to.eql({ 'pubcid': 'abcd-efg-0101', 'tdid': 'td-abcd-efg-0101', 'id5id': 'ID5-ZHMOrVeUVTUKgrZ-a2YGxeh5eS_pLzHCQGYOEAiTBQ' }); - }); - - it('should return a properly formatted request with userid omitted if there are no userIds', function () { - bidRequest[0].userId = {}; - bidRequest[1].userId = {}; - const bidRequests = spec.buildRequests(bidRequest, bidderRequests); - expect(bidRequests.url).to.equal('https://apex.go.sonobi.com/trinity.json'); - expect(bidRequests.method).to.equal('GET'); - expect(bidRequests.data.ref).not.to.be.empty; - expect(bidRequests.data.s).not.to.be.empty; - expect(bidRequests.data.userid).to.equal(undefined); - }); - - it('should return a properly formatted request with userid omitted', function () { - bidRequest[0].userId = undefined; - bidRequest[1].userId = undefined; - const bidRequests = spec.buildRequests(bidRequest, bidderRequests); - expect(bidRequests.url).to.equal('https://apex.go.sonobi.com/trinity.json'); - expect(bidRequests.method).to.equal('GET'); - expect(bidRequests.data.ref).not.to.be.empty; - expect(bidRequests.data.s).not.to.be.empty; - expect(bidRequests.data.userid).to.equal(undefined); + expect(bidRequests.data.userid).to.be.undefined; }); it('should return a properly formatted request with keywrods included as a csv of strings', function () { diff --git a/test/spec/modules/sovrnAnalyticsAdapter_spec.js b/test/spec/modules/sovrnAnalyticsAdapter_spec.js index 8284bb54e9b..68552eb3d8a 100644 --- a/test/spec/modules/sovrnAnalyticsAdapter_spec.js +++ b/test/spec/modules/sovrnAnalyticsAdapter_spec.js @@ -1,8 +1,10 @@ import sovrnAnalyticsAdapter from '../../../modules/sovrnAnalyticsAdapter.js'; -import { expect } from 'chai'; +import {expect} from 'chai'; import {config} from 'src/config.js'; import adaptermanager from 'src/adapterManager.js'; -import { server } from 'test/mocks/xhr.js'; +import {server} from 'test/mocks/xhr.js'; +import {expectEvents, fireEvents} from '../../helpers/analytics.js'; + var assert = require('assert'); let events = require('src/events'); @@ -195,15 +197,7 @@ describe('Sovrn Analytics Adapter', function () { sovrnId: 123 } }); - - events.emit(constants.EVENTS.AUCTION_INIT, {}); - events.emit(constants.EVENTS.AUCTION_END, {}); - events.emit(constants.EVENTS.BID_REQUESTED, {}); - events.emit(constants.EVENTS.BID_RESPONSE, {}); - events.emit(constants.EVENTS.BID_WON, {}); - - // 5 SovrnAnalytics events + 1 Clean.io event - sinon.assert.callCount(sovrnAnalyticsAdapter.track, 6); + expectEvents().to.beTrackedBy(sovrnAnalyticsAdapter.track); }); it('should catch no events if no affiliate id', function () { @@ -212,13 +206,7 @@ describe('Sovrn Analytics Adapter', function () { options: { } }); - - events.emit(constants.EVENTS.AUCTION_INIT, {}); - events.emit(constants.EVENTS.AUCTION_END, {}); - events.emit(constants.EVENTS.BID_REQUESTED, {}); - events.emit(constants.EVENTS.BID_RESPONSE, {}); - events.emit(constants.EVENTS.BID_WON, {}); - + fireEvents(); sinon.assert.callCount(sovrnAnalyticsAdapter.track, 0); }); }); diff --git a/test/spec/modules/sspBCBidAdapter_spec.js b/test/spec/modules/sspBCBidAdapter_spec.js index d182b9db24c..8c9bbe3b336 100644 --- a/test/spec/modules/sspBCBidAdapter_spec.js +++ b/test/spec/modules/sspBCBidAdapter_spec.js @@ -557,6 +557,7 @@ describe('SSPBC adapter', function () { const nativeAssets = payloadNative.imp && payloadNative.imp[0].native.request; expect(payloadNative.imp.length).to.equal(1); + expect(nativeAssets).to.contain('{"id":0,"required":true,"title":{"len":80}}'); expect(nativeAssets).to.contain('{"id":2,"required":true,"img":{"type":1,"w":50,"h":50}}'); expect(nativeAssets).to.contain('{"id":3,"required":true,"img":{"type":3,"w":150,"h":50}}'); @@ -610,14 +611,14 @@ describe('SSPBC adapter', function () { expect(result.length).to.equal(bids.length); expect(resultSingle.length).to.equal(1); - expect(resultSingle[0]).to.have.keys('ad', 'cpm', 'width', 'height', 'bidderCode', 'mediaType', 'meta', 'requestId', 'creativeId', 'currency', 'netRevenue', 'ttl'); + expect(resultSingle[0]).to.have.keys('ad', 'cpm', 'width', 'height', 'bidderCode', 'mediaType', 'meta', 'requestId', 'creativeId', 'currency', 'netRevenue', 'ttl', 'vurls'); }); it('should create bid from OneCode (parameter-less) request, if response contains siteId', function () { let resultOneCode = spec.interpretResponse(serverResponseOneCode, requestOneCode); expect(resultOneCode.length).to.equal(1); - expect(resultOneCode[0]).to.have.keys('ad', 'cpm', 'width', 'height', 'bidderCode', 'mediaType', 'meta', 'requestId', 'creativeId', 'currency', 'netRevenue', 'ttl'); + expect(resultOneCode[0]).to.have.keys('ad', 'cpm', 'width', 'height', 'bidderCode', 'mediaType', 'meta', 'requestId', 'creativeId', 'currency', 'netRevenue', 'ttl', 'vurls'); }); it('should not create bid from OneCode (parameter-less) request, if response does not contain siteId', function () { @@ -648,7 +649,7 @@ describe('SSPBC adapter', function () { expect(resultVideo.length).to.equal(1); let videoBid = resultVideo[0]; - expect(videoBid).to.have.keys('adType', 'bidderCode', 'cpm', 'creativeId', 'currency', 'width', 'height', 'meta', 'mediaType', 'netRevenue', 'requestId', 'ttl', 'vastContent', 'vastXml', 'vastUrl'); + expect(videoBid).to.have.keys('adType', 'bidderCode', 'cpm', 'creativeId', 'currency', 'width', 'height', 'meta', 'mediaType', 'netRevenue', 'requestId', 'ttl', 'vastContent', 'vastXml', 'vastUrl', 'vurls'); expect(videoBid.adType).to.equal('instream'); expect(videoBid.mediaType).to.equal('video'); expect(videoBid.vastXml).to.match(/^<\?xml.*<\/VAST>$/); @@ -662,8 +663,8 @@ describe('SSPBC adapter', function () { expect(resultNative.length).to.equal(1); let nativeBid = resultNative[0]; - expect(nativeBid).to.have.keys('bidderCode', 'cpm', 'creativeId', 'currency', 'width', 'height', 'meta', 'mediaType', 'netRevenue', 'requestId', 'ttl', 'native'); - expect(nativeBid.native).to.have.keys('image', 'icon', 'title', 'sponsoredBy', 'body', 'clickUrl', 'impressionTrackers', 'javascriptTrackers'); + expect(nativeBid).to.have.keys('bidderCode', 'cpm', 'creativeId', 'currency', 'width', 'height', 'meta', 'mediaType', 'netRevenue', 'requestId', 'ttl', 'native', 'vurls'); + expect(nativeBid.native).to.have.keys('image', 'icon', 'title', 'sponsoredBy', 'body', 'clickUrl', 'impressionTrackers', 'javascriptTrackers', 'clickTrackers'); }); }); diff --git a/test/spec/modules/taboolaBidAdapter_spec.js b/test/spec/modules/taboolaBidAdapter_spec.js index 9af11363957..0c01244033e 100644 --- a/test/spec/modules/taboolaBidAdapter_spec.js +++ b/test/spec/modules/taboolaBidAdapter_spec.js @@ -2,6 +2,7 @@ import {expect} from 'chai'; import {spec, internal, END_POINT_URL, userData} from 'modules/taboolaBidAdapter.js'; import {config} from '../../../src/config' import * as utils from '../../../src/utils' +import {server} from '../../mocks/xhr' describe('Taboola Adapter', function () { let hasLocalStorage, cookiesAreEnabled, getDataFromLocalStorage, localStorageIsEnabled, getCookie, commonBidRequest; @@ -89,46 +90,32 @@ describe('Taboola Adapter', function () { } expect(spec.isBidRequestValid(bid)).to.equal(true) }) + }) - it('should succeed when url is null', function () { - const bid = { - bidder: 'taboola', - params: { - publisherId: 'publisherId', - tagId: 'below the article', - endpointUrl: null - }, - ...displayBidRequestParams - } - expect(spec.isBidRequestValid(bid)).to.equal(true) - }) - - it('should succeed when url is empty string', function () { - const bid = { - bidder: 'taboola', - params: { - publisherId: 'publisherId', - tagId: 'below the article', - endpointUrl: '' - }, - ...displayBidRequestParams - } - expect(spec.isBidRequestValid(bid)).to.equal(true) - }) + describe('onBidWon', function () { + it('onBidWon exist as a function', () => { + expect(spec.onBidWon).to.exist.and.to.be.a('function'); + }); - it('should succeed when url is filled', function () { + it('should resolve price macro in nurl', function () { + const nurl = 'http://win.example.com/${AUCTION_PRICE}'; const bid = { - bidder: 'taboola', - params: { - publisherId: 'publisherId', - tagId: 'below the article', - endpointUrl: 'https://example.com' - }, - ...displayBidRequestParams + requestId: 1, + cpm: 2, + originalCpm: 3.4, + creativeId: 1, + ttl: 60, + netRevenue: true, + mediaType: 'banner', + ad: '...', + width: 300, + height: 250, + nurl: nurl } - expect(spec.isBidRequestValid(bid)).to.equal(true) - }) - }) + spec.onBidWon(bid); + expect(server.requests[0].url).to.equals('http://win.example.com/3.4') + }); + }); describe('buildRequests', function () { const defaultBidRequest = { @@ -161,7 +148,8 @@ describe('Taboola Adapter', function () { }, 'tagid': commonBidRequest.params.tagId, 'bidfloor': null, - 'bidfloorcur': 'USD' + 'bidfloorcur': 'USD', + 'ext': {} }], 'site': { 'id': commonBidRequest.params.publisherId, @@ -176,11 +164,13 @@ describe('Taboola Adapter', function () { 'source': {'fd': 1}, 'bcat': [], 'badv': [], + 'wlang': [], 'user': { 'buyeruid': 0, 'ext': {}, }, - 'regs': {'coppa': 0, 'ext': {}} + 'regs': {'coppa': 0, 'ext': {}}, + 'ext': {} }; const res = spec.buildRequests([defaultBidRequest], commonBidderRequest); @@ -189,44 +179,6 @@ describe('Taboola Adapter', function () { expect(res.data).to.deep.equal(JSON.stringify(expectedData)); }); - it('should fill the url when it is passed', function () { - const commonBidRequestWithUrl = { - bidder: 'taboola', - params: { - publisherId: 'publisherId', - tagId: 'placement name', - endpointUrl: 'https://example.com' - }, - bidId: 'aa43860a-4644-442a-b5e0-93f268cs4d19', - auctionId: '65746dca-26f3-4186-be13-dfa63469b1b7', - } - let defaultBidRequestWithUrl = { - ...commonBidRequestWithUrl, - ...displayBidRequestParams, - } - const res = spec.buildRequests([defaultBidRequestWithUrl], commonBidderRequest); - expect(res.url).to.equal(`${commonBidRequestWithUrl.params.endpointUrl}/${commonBidRequest.params.publisherId}`); - }) - - it('should fill default url when url param is empty string', function () { - const commonBidRequestWithUrl = { - bidder: 'taboola', - params: { - publisherId: 'publisherId', - tagId: 'placement name', - endpointUrl: '' - }, - bidId: 'aa43860a-4644-442a-b5e0-93f268cs4d19', - auctionId: '65746dca-26f3-4186-be13-dfa63469b1b7', - } - let defaultBidRequestWithUrl = { - ...commonBidRequestWithUrl, - ...displayBidRequestParams, - } - const res = spec.buildRequests([defaultBidRequestWithUrl], commonBidderRequest); - expect(res.url).to.equal(`${END_POINT_URL}/${commonBidRequestWithUrl.params.publisherId}`); - }) - it('should pass optional parameters in request', function () { const optionalParams = { bidfloor: 0.25, @@ -244,6 +196,77 @@ describe('Taboola Adapter', function () { expect(resData.imp[0].bidfloorcur).to.deep.equal('EUR'); }); + it('should pass bid floor', function () { + const bidRequest = { + ...defaultBidRequest, + params: {...commonBidRequest.params}, + getFloor: function() { + return { + currency: 'USD', + floor: 2.7, + } + } + }; + const res = spec.buildRequests([bidRequest], commonBidderRequest); + const resData = JSON.parse(res.data); + expect(resData.imp[0].bidfloor).to.deep.equal(2.7); + expect(resData.imp[0].bidfloorcur).to.deep.equal('USD'); + }); + + it('should pass bid floor even if it is a bid floor param', function () { + const optionalParams = { + bidfloor: 0.25, + bidfloorcur: 'EUR' + }; + + const bidRequest = { + ...defaultBidRequest, + params: {...commonBidRequest.params, ...optionalParams}, + getFloor: function() { + return { + currency: 'USD', + floor: 2.7, + } + } + }; + const res = spec.buildRequests([bidRequest], commonBidderRequest); + const resData = JSON.parse(res.data); + expect(resData.imp[0].bidfloor).to.deep.equal(2.7); + expect(resData.imp[0].bidfloorcur).to.deep.equal('USD'); + }); + + it('should pass impression position', function () { + const optionalParams = { + position: 2 + }; + + const bidRequest = { + ...defaultBidRequest, + params: {...commonBidRequest.params, ...optionalParams} + }; + + const res = spec.buildRequests([bidRequest], commonBidderRequest); + const resData = JSON.parse(res.data); + expect(resData.imp[0].banner.pos).to.deep.equal(2); + }); + + it('should pass gpid if configured', function () { + const ortb2Imp = { + ext: { + gpid: '/homepage/#1' + } + } + const bidRequest = { + ...defaultBidRequest, + ortb2Imp: ortb2Imp, + params: {...commonBidRequest.params} + }; + + const res = spec.buildRequests([bidRequest], commonBidderRequest); + const resData = JSON.parse(res.data); + expect(resData.imp[0].ext.gpid).to.deep.equal('/homepage/#1'); + }); + it('should pass bidder timeout', function () { const bidderRequest = { ...commonBidderRequest, @@ -254,6 +277,40 @@ describe('Taboola Adapter', function () { expect(resData.tmax).to.equal(500); }); + describe('first party data', function () { + it('should parse first party data', function () { + const bidderRequest = { + ...commonBidderRequest, + ortb2: { + bcat: ['EX1', 'EX2', 'EX3'], + badv: ['site.com'], + wlang: ['de'], + } + } + const res = spec.buildRequests([defaultBidRequest], bidderRequest); + const resData = JSON.parse(res.data); + expect(resData.bcat).to.deep.equal(bidderRequest.ortb2.bcat) + expect(resData.badv).to.deep.equal(bidderRequest.ortb2.badv) + expect(resData.wlang).to.deep.equal(bidderRequest.ortb2.wlang) + }); + + it('should pass pageType if exists in ortb2', function () { + const bidderRequest = { + ...commonBidderRequest, + ortb2: { + ext: { + data: { + pageType: 'news' + } + } + } + } + const res = spec.buildRequests([defaultBidRequest], bidderRequest); + const resData = JSON.parse(res.data); + expect(resData.ext.pageType).to.deep.equal(bidderRequest.ortb2.ext.data.pageType); + }); + }); + describe('handle privacy segments when building request', function () { it('should pass GDPR consent', function () { const bidderRequest = { @@ -272,6 +329,20 @@ describe('Taboola Adapter', function () { expect(resData.regs.ext.gdpr).to.equal(1) }); + it('should pass GPP consent if exist in ortb2', function () { + const ortb2 = { + regs: { + gpp: 'testGpp', + gpp_sid: [1, 2, 3] + } + } + + const res = spec.buildRequests([defaultBidRequest], {...commonBidderRequest, ortb2}) + const resData = JSON.parse(res.data) + expect(resData.regs.ext.gpp).to.equal('testGpp') + expect(resData.regs.ext.gpp_sid).to.deep.equal([1, 2, 3]) + }); + it('should pass us privacy consent', function () { const bidderRequest = { refererInfo: { @@ -389,7 +460,9 @@ describe('Taboola Adapter', function () { 'w': 300, 'h': 250, 'exp': 60, - 'lurl': 'http://us-trc.taboola.com/sample' + 'lurl': 'http://us-trc.taboola.com/sample', + 'nurl': 'http://win.example.com/', + } ], 'seat': '14204545260' @@ -475,7 +548,8 @@ describe('Taboola Adapter', function () { 'w': 300, 'h': 250, 'exp': 60, - 'lurl': 'http://us-trc.taboola.com/sample' + 'lurl': 'http://us-trc.taboola.com/sample', + 'nurl': 'http://win.example.com/' }, { 'id': '0b3dd94348-134b-435f-8db5-6bf5afgfc39e86c', @@ -491,7 +565,9 @@ describe('Taboola Adapter', function () { 'w': 300, 'h': 250, 'exp': 60, - 'lurl': 'http://us-trc.taboola.com/sample' + 'lurl': 'http://us-trc.taboola.com/sample', + 'nurl': 'http://win.example.com/' + } ], 'seat': '14204545260' @@ -515,6 +591,7 @@ describe('Taboola Adapter', function () { ad: multiServerResponse.body.seatbid[0].bid[0].adm, width: bid.w, height: bid.h, + nurl: 'http://win.example.com/', meta: { 'advertiserDomains': bid.adomain }, @@ -530,6 +607,7 @@ describe('Taboola Adapter', function () { ad: multiServerResponse.body.seatbid[0].bid[1].adm, width: bid.w, height: bid.h, + nurl: 'http://win.example.com/', meta: { 'advertiserDomains': bid.adomain }, @@ -554,6 +632,7 @@ describe('Taboola Adapter', function () { ad: bid.adm, width: bid.w, height: bid.h, + nurl: 'http://win.example.com/', meta: { 'advertiserDomains': bid.adomain }, @@ -580,6 +659,7 @@ describe('Taboola Adapter', function () { ad: bid.adm, width: bid.w, height: bid.h, + nurl: 'http://win.example.com/', meta: { 'advertiserDomains': bid.adomain }, @@ -590,8 +670,36 @@ describe('Taboola Adapter', function () { }); }) - describe('userData', function () { - // todo: add UT for getUserSyncs + describe('getUserSyncs', function () { + const usersyncUrl = 'https://trc.taboola.com/sg/prebidJS/1/cm'; + + it('should not return user sync if pixelEnabled is false', function () { + const res = spec.getUserSyncs({pixelEnabled: false}); + expect(res).to.be.an('array').that.is.empty; + }); + + it('should return user sync if pixelEnabled is true', function () { + const res = spec.getUserSyncs({pixelEnabled: true}); + expect(res).to.deep.equal([{type: 'image', url: usersyncUrl}]); + }); + + it('should pass consent tokens values', function() { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, {gdprApplies: true, consentString: 'GDPR_CONSENT'}, 'USP_CONSENT')).to.deep.equal([{ + type: 'image', url: `${usersyncUrl}?gdpr=1&gdpr_consent=GDPR_CONSENT&us_privacy=USP_CONSENT` + }]); + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, {gdprApplies: false, consentString: undefined}, undefined)).to.deep.equal([{ + type: 'image', url: `${usersyncUrl}?gdpr=0&gdpr_consent=` + }]); + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, {gdprApplies: false, consentString: undefined}, undefined)).to.deep.equal([{ + type: 'image', url: `${usersyncUrl}?gdpr=0&gdpr_consent=` + }]); + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, undefined, 'USP_CONSENT')).to.deep.equal([{ + type: 'image', url: `${usersyncUrl}?us_privacy=USP_CONSENT` + }]); + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, undefined, 'USP_CONSENT', 'GPP_STRING')).to.deep.equal([{ + type: 'image', url: `${usersyncUrl}?us_privacy=USP_CONSENT&gpp=GPP_STRING` + }]); + }); }) describe('internal functions', function () { diff --git a/test/spec/modules/targetVideoBidAdapter_spec.js b/test/spec/modules/targetVideoBidAdapter_spec.js index adbc982e509..8180183e6d7 100644 --- a/test/spec/modules/targetVideoBidAdapter_spec.js +++ b/test/spec/modules/targetVideoBidAdapter_spec.js @@ -58,7 +58,7 @@ describe('TargetVideo Bid Adapter', function() { 'uuid': '84ab500420319d', 'ads': [{ 'ad_type': 'video', - 'cpm': 0.500000, + 'cpm': 0.675000, 'notify_url': 'https://www.target-video.com/', 'rtb': { 'video': { @@ -87,7 +87,7 @@ describe('TargetVideo Bid Adapter', function() { const bid = bidResponse[0]; expect(bid).to.not.be.empty; - expect(bid.cpm).to.equal(0.675); + expect(bid.cpm).to.equal(0.5); expect(bid.width).to.equal(300); expect(bid.height).to.equal(250); expect(bid.ad).to.include('') diff --git a/test/spec/modules/topicsFpdModule_spec.js b/test/spec/modules/topicsFpdModule_spec.js index 3781768497b..958489f2728 100644 --- a/test/spec/modules/topicsFpdModule_spec.js +++ b/test/spec/modules/topicsFpdModule_spec.js @@ -1,5 +1,15 @@ -import {getTopics, getTopicsData, processFpd} from '../../../modules/topicsFpdModule.js'; -import {deepClone} from '../../../src/utils.js'; +import { + getTopics, + getTopicsData, + processFpd, + hasGDPRConsent, + getCachedTopics, + receiveMessage, + topicStorageName +} from '../../../modules/topicsFpdModule.js'; +import {deepClone, safeJSONParse} from '../../../src/utils.js'; +import {gdprDataHandler} from 'src/adapterManager.js'; +import {getCoreStorageManager} from 'src/storageManager.js'; describe('getTopicsData', () => { function makeTopic(topic, modelv, taxv = '1') { @@ -7,14 +17,14 @@ describe('getTopicsData', () => { topic, taxonomyVersion: taxv, modelVersion: modelv - } + }; } function byTaxClass(segments) { return segments.reduce((memo, segment) => { memo[`${segment.ext.segtax}:${segment.ext.segclass}`] = segment; return memo; - }, {}) + }, {}); } [ @@ -144,16 +154,16 @@ describe('getTopicsData', () => { Object.entries(byTaxClass(actual)).forEach(([key, datum]) => { sinon.assert.match(datum, expected[key]); expect(datum.name).to.equal('mockName'); - }) + }); }); it('should not set name if null', () => { getTopicsData(null, topics).forEach((data) => { expect(data.hasOwnProperty('name')).to.be.false; - }) - }) - }) - }) + }); + }); + }); + }); }); describe('getTopics', () => { @@ -167,11 +177,13 @@ describe('getTopics', () => { 'document that throws on featurePolicy': { browsingTopics: sinon.stub(), get featurePolicy() { - throw new Error() + throw new Error(); } }, 'document that throws on browsingTopics': { - browsingTopics: sinon.stub().callsFake(() => { throw new Error(); }), + browsingTopics: sinon.stub().callsFake(() => { + throw new Error(); + }), featurePolicy: { allowsFeature: sinon.stub().returns(true) } @@ -181,11 +193,11 @@ describe('getTopics', () => { return getTopics(doc).then((topics) => { expect(topics).to.eql([]); }); - }) + }); }); it('should call `document.browsingTopics` when allowed', () => { - const topics = ['t1', 't2'] + const topics = ['t1', 't2']; return getTopics({ browsingTopics: sinon.stub().returns(Promise.resolve(topics)), featurePolicy: { @@ -193,9 +205,9 @@ describe('getTopics', () => { } }).then((actual) => { expect(actual).to.eql(topics); - }) - }) -}) + }); + }); +}); describe('processFpd', () => { const mockData = [ @@ -237,3 +249,184 @@ describe('processFpd', () => { }); }); }); + +describe('Topics Module GDPR consent check', () => { + let gdprDataHdlrStub; + beforeEach(() => { + gdprDataHdlrStub = sinon.stub(gdprDataHandler, 'getConsentData'); + }); + + afterEach(() => { + gdprDataHdlrStub.restore(); + }); + + it('should return false when GDPR is applied but consent string is not present', () => { + const consentString = ''; + const consentConfig = { + consentString: consentString, + gdprApplies: true, + vendorData: {} + }; + gdprDataHdlrStub.returns(consentConfig); + expect(hasGDPRConsent()).to.equal(false); + }); + + it('should return true when GDPR doesn\'t apply', () => { + const consentString = 'CPi8wgAPi8wgAADABBENCrCsAP_AAH_AAAAAISNB7D=='; + const consentConfig = { + consentString: consentString, + gdprApplies: false, + vendorData: {} + }; + + gdprDataHdlrStub.returns(consentConfig); + expect(hasGDPRConsent()).to.equal(true); + }); + + it('should return true when GDPR is applied and purpose consent is true for all purpose[1,2,3,4]', () => { + const consentString = 'CPi8wgAPi8wgAADABBENCrCsAP_AAH_AAAAAISNB7D=='; + const consentConfig = { + consentString: consentString, + gdprApplies: true, + vendorData: { + metadata: consentString, + gdprApplies: true, + purpose: { + consents: { + 1: true, + 2: true, + 3: true, + 4: true + } + } + } + }; + + gdprDataHdlrStub.returns(consentConfig); + expect(hasGDPRConsent()).to.equal(true); + }); + + it('should return false when GDPR is applied and purpose consent is false for one of the purpose[1,2,3,4]', () => { + const consentString = 'CPi8wgAPi8wgAADABBENCrCsAP_AAH_AAAAAISNB7D=='; + const consentConfig = { + consentString: consentString, + gdprApplies: true, + vendorData: { + metadata: consentString, + gdprApplies: true, + purpose: { + consents: { + 1: true, + 2: true, + 3: true, + 4: false + } + } + } + }; + + gdprDataHdlrStub.returns(consentConfig); + expect(hasGDPRConsent()).to.equal(false); + }); +}); + +describe('getCachedTopics()', () => { + const storage = getCoreStorageManager('topicsFpd'); + const expected = [{ + ext: { + segtax: 600, + segclass: '2206021246' + }, + segment: [{ + 'id': '243' + }, { + 'id': '265' + }], + name: 'ads.pubmatic.com' + }]; + const consentString = 'CPi8wgAPi8wgAADABBENCrCsAP_AAH_AAAAAISNB7D=='; + const consentConfig = { + consentString: consentString, + gdprApplies: true, + vendorData: { + metadata: consentString, + gdprApplies: true, + purpose: { + consents: { + 1: true, + 2: true, + 3: true, + 4: true + } + } + } + }; + const mockData = [ + { + name: 'domain', + segment: [{id: 123}] + }, + { + name: 'domain', + segment: [{id: 321}], + } + ]; + + const evt = { + data: '{"segment":{"domain":"ads.pubmatic.com","topics":[{"configVersion":"chrome.1","modelVersion":"2206021246","taxonomyVersion":"1","topic":165,"version":"chrome.1:1:2206021246"}],"bidder":"pubmatic"},"date":1669743901858}', + origin: 'https://ads.pubmatic.com' + }; + + let gdprDataHdlrStub; + beforeEach(() => { + gdprDataHdlrStub = sinon.stub(gdprDataHandler, 'getConsentData'); + }); + + afterEach(() => { + storage.removeDataFromLocalStorage(topicStorageName); + gdprDataHdlrStub.restore(); + }); + + it('should return segments for bidder if GDPR consent is true and there is cached segments stored which is not expired', () => { + const storedSegments = JSON.stringify( + [['pubmatic', { + '2206021246': { + 'ext': {'segtax': 600, 'segclass': '2206021246'}, + 'segment': [{'id': '243'}, {'id': '265'}], + 'name': 'ads.pubmatic.com' + }, + 'lastUpdated': new Date().getTime() + }]] + ); + storage.setDataInLocalStorage(topicStorageName, storedSegments); + gdprDataHdlrStub.returns(consentConfig); + assert.deepEqual(getCachedTopics(), expected); + }); + + it('should return empty segments for bidder if GDPR consent is true and there is cached segments stored which is expired', () => { + let storedSegments = '[["pubmatic",{"2206021246":{"ext":{"segtax":600,"segclass":"2206021246"},"segment":[{"id":"243"},{"id":"265"}],"name":"ads.pubmatic.com"},"lastUpdated":10}]]'; + storage.setDataInLocalStorage(topicStorageName, storedSegments); + gdprDataHdlrStub.returns(consentConfig); + assert.deepEqual(getCachedTopics(), []); + }); + + it('should stored segments if receiveMessage event is triggerred with segment data', () => { + return processFpd({}, {global: {}}, {data: Promise.resolve(mockData)}) + .then(({global}) => { + receiveMessage(evt); + let segments = new Map(safeJSONParse(storage.getDataFromLocalStorage(topicStorageName))); + expect(segments.has('pubmatic')).to.equal(true); + }); + }); + + it('should update stored segments if receiveMessage event is triggerred with segment data', () => { + let storedSegments = '[["pubmatic",{"2206021246":{"ext":{"segtax":600,"segclass":"2206021246"},"segment":[{"id":"243"},{"id":"265"}],"name":"ads.pubmatic.com"},"lastUpdated":1669719242027}]]'; + storage.setDataInLocalStorage(topicStorageName, storedSegments); + return processFpd({}, {global: {}}, {data: Promise.resolve(mockData)}) + .then(({global}) => { + receiveMessage(evt); + let segments = new Map(safeJSONParse(storage.getDataFromLocalStorage(topicStorageName))); + expect(segments.get('pubmatic')[2206021246].segment.length).to.equal(1); + }); + }); +}); diff --git a/test/spec/modules/tripleliftBidAdapter_spec.js b/test/spec/modules/tripleliftBidAdapter_spec.js index e485ae3998f..221ffb8371f 100644 --- a/test/spec/modules/tripleliftBidAdapter_spec.js +++ b/test/spec/modules/tripleliftBidAdapter_spec.js @@ -725,11 +725,11 @@ describe('triplelift adapter', function () { it('should add amxRtbId to the payload if included', function () { const id = 'Ok9JQkBM-UFlAXEZQ-UUNBQlZOQzgrUFhW-UUNBQkRQTUBPQVpVWVxNXlZUUF9AUFhAUF9PXFY/'; - bidRequests[0].userIdAsEids = [{ source: 'amxrtb.com', uids: [{ id }] }]; + bidRequests[0].userIdAsEids = [{ source: 'amxdt.net', uids: [{ id }] }]; const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest); const payload = request.data; expect(payload).to.exist; - expect(payload.user).to.deep.equal({ext: {eids: [{source: 'amxrtb.com', uids: [{id, ext: {rtiPartner: 'amxrtb.com'}}]}]}}); + expect(payload.user).to.deep.equal({ext: {eids: [{source: 'amxdt.net', uids: [{id, ext: {rtiPartner: 'amxdt.net'}}]}]}}); }); it('should add tdid, idl_env and criteoId to the payload if both are included', function () { @@ -979,6 +979,13 @@ describe('triplelift adapter', function () { expect(url).to.match(new RegExp('(?:' + prebid.version + ')')) expect(url).to.match(/(?:referrer)/); }); + it('should use refererInfo.page for referrer', function () { + bidderRequest.refererInfo.page = 'https://topmostlocation.com?foo=bar' + const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest); + const url = request.url; + expect(url).to.match(/(\?|&)referrer=https%3A%2F%2Ftopmostlocation.com%3Ffoo%3Dbar/); + delete bidderRequest.refererInfo.page + }); it('should return us_privacy param when CCPA info is available', function() { bidderRequest.uspConsent = '1YYY'; const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest); @@ -1161,6 +1168,19 @@ describe('triplelift adapter', function () { } }) }); + it('should add gpp consent data to bid request object if gpp data exists', function() { + bidderRequest.ortb2 = { + regs: { + 'gpp': 'BOJ/P2HOJ/P2HABABMAAAAAZ+A==', + 'gpp_sid': [7] + } + } + const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest); + expect(request.data.regs).to.deep.equal({ + 'gpp': 'BOJ/P2HOJ/P2HABABMAAAAAZ+A==', + 'gpp_sid': [7] + }) + }); }); describe('interpretResponse', function () { @@ -1417,6 +1437,13 @@ describe('triplelift adapter', function () { expect(result[0].meta.advertiserDomains[1]).to.equal('internetalerts.org'); expect(result[1].meta).to.not.have.key('advertiserDomains'); }); + + it('should include networkId in the meta field if available', function () { + let result = tripleliftAdapterSpec.interpretResponse(response, {bidderRequest}); + expect(result[1].meta.networkId).to.equal('10092'); + expect(result[2].meta.networkId).to.equal('5989'); + expect(result[3].meta.networkId).to.equal('5989'); + }); }); describe('getUserSyncs', function() { diff --git a/test/spec/modules/ttdBidAdapter_spec.js b/test/spec/modules/ttdBidAdapter_spec.js index 60c00f4e4b9..9869d072657 100644 --- a/test/spec/modules/ttdBidAdapter_spec.js +++ b/test/spec/modules/ttdBidAdapter_spec.js @@ -2,6 +2,9 @@ import { expect } from 'chai'; import { spec } from 'modules/ttdBidAdapter'; import { deepClone } from 'src/utils.js'; import { config } from 'src/config'; +import { detectReferer } from 'src/refererDetection.js'; + +import { buildWindowTree } from '../../helpers/refererDetectionHelper'; describe('ttdBidAdapter', function () { function testBuildRequests(bidRequests, bidderRequestBase) { @@ -200,20 +203,15 @@ describe('ttdBidAdapter', function () { '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)(); const baseBidderRequest = { 'bidderCode': 'ttd', 'auctionId': 'e7b34fa3-8654-424e-8c49-03e509e53d8c', 'bidderRequestId': '18084284054531', 'auctionStart': 1540945362095, 'timeout': 3000, - 'refererInfo': { - 'page': 'https://www.example.com/test', - 'reachedTop': true, - 'numIframes': 0, - 'stack': [ - 'https://www.example.com/test' - ] - }, + 'refererInfo': baseBidderRequestReferer, 'start': 1540945362099, 'doneCbCallCount': 0 }; @@ -291,6 +289,11 @@ describe('ttdBidAdapter', function () { expect(requestBody.site.page).to.equal('https://www.example.com/test'); }); + it('ensure top most location is used', function () { + const requestBody = testBuildRequests(baseBannerBidRequests, baseBidderRequest).data; + expect(requestBody.site.page).to.equal('https://www.example.com/test'); + }); + it('sets the banner pos correctly if sent', function () { let clonedBannerRequests = deepClone(baseBannerBidRequests); clonedBannerRequests[0].mediaTypes.banner.pos = 1; @@ -310,6 +313,43 @@ describe('ttdBidAdapter', function () { expect(requestBody.imp[0].banner.expdir).to.equal(expdir); }); + it('merges first party site data', function () { + const ortb2 = { + site: { + publisher: { + domain: 'https://foo.bar', + } + } + }; + const baseBidderRequestWithoutRefererDomain = { + ...baseBidderRequest, + refererInfo: { + ...baseBannerBidRequests.referer, + domain: null + } + } + const requestBody = testBuildRequests( + baseBannerBidRequests, {...baseBidderRequestWithoutRefererDomain, ortb2} + ).data; + config.resetConfig(); + expect(requestBody.site.publisher).to.deep.equal({domain: 'https://foo.bar', id: '13144370'}); + }); + + it('referer domain overrides first party site data publisher domain', function () { + const ortb2 = { + site: { + publisher: { + domain: 'https://foo.bar', + } + } + }; + const requestBody = testBuildRequests( + baseBannerBidRequests, {...baseBidderRequest, ortb2} + ).data; + config.resetConfig(); + expect(requestBody.site.publisher.domain).to.equal(baseBidderRequest.refererInfo.domain); + }); + it('sets keywords properly if sent', function () { const ortb2 = { site: { @@ -387,6 +427,20 @@ describe('ttdBidAdapter', function () { expect(requestBody.regs.coppa).to.equal(1); }); + it('adds gpp consent info to the request', function () { + const ortb2 = { + regs: { + gpp: 'somegppstring', + gpp_sid: [6, 7] + } + }; + let clonedBidderRequest = {...deepClone(baseBidderRequest), ortb2}; + const requestBody = testBuildRequests(baseBannerBidRequests, clonedBidderRequest).data; + config.resetConfig(); + expect(requestBody.regs.gpp).to.equal('somegppstring'); + expect(requestBody.regs.gpp_sid).to.eql([6, 7]); + }); + it('adds schain info to the request', function () { const schain = { 'ver': '1.0', diff --git a/test/spec/modules/uid2IdSystem_spec.js b/test/spec/modules/uid2IdSystem_spec.js new file mode 100644 index 00000000000..b33e8cda501 --- /dev/null +++ b/test/spec/modules/uid2IdSystem_spec.js @@ -0,0 +1,310 @@ +import {coreStorage, init, setSubmoduleRegistry, requestBidsHook} from 'modules/userId/index.js'; +import {config} from 'src/config.js'; +import * as utils from 'src/utils.js'; +import { uid2IdSubmodule } from 'modules/uid2IdSystem.js'; +import 'src/prebid.js'; +import { getGlobal } from 'src/prebidGlobal.js'; +import { server } from 'test/mocks/xhr.js'; +import { configureTimerInterceptors } from 'test/mocks/timers.js'; +import {hook} from 'src/hook.js'; +import {uninstall as uninstallGdprEnforcement} from 'modules/gdprEnforcement.js'; + +let expect = require('chai').expect; + +const clearTimersAfterEachTest = true; +const debugOutput = () => {}; + +const expireCookieDate = 'Thu, 01 Jan 1970 00:00:01 GMT'; +const msIn12Hours = 60 * 60 * 12 * 1000; +const moduleCookieName = '__uid2_advertising_token'; +const publisherCookieName = '__UID2_SERVER_COOKIE'; +const auctionDelayMs = 10; +const legacyConfigParams = null; +const serverCookieConfigParams = { uid2ServerCookie: publisherCookieName } +const getFutureCookieExpiry = () => new Date(Date.now() + msIn12Hours).toUTCString(); +const setPublisherCookie = (token) => coreStorage.setCookie(publisherCookieName, JSON.stringify(token), getFutureCookieExpiry()); + +const makePrebidIdentityContainer = (token) => ({uid2: {id: token}}); +const makePrebidConfig = (params = null, extraSettings = {}, debug = false) => ({ + userSync: { auctionDelay: auctionDelayMs, userIds: [{name: 'uid2', params}] }, debug, ...extraSettings +}); + +const initialToken = `initial-advertising-token`; +const legacyToken = 'legacy-advertising-token'; +const refreshedToken = 'refreshed-advertising-token'; +const makeUid2Token = (token = initialToken, shouldRefresh = false, expired = false) => ({ + advertising_token: token, + refresh_token: 'fake-refresh-token', + identity_expires: expired ? Date.now() - 1000 : Date.now() + 60 * 60 * 1000, + refresh_from: shouldRefresh ? Date.now() - 1000 : Date.now() + 60 * 1000, + refresh_expires: Date.now() + 24 * 60 * 60 * 1000, // 24 hours + refresh_response_key: 'wR5t6HKMfJ2r4J7fEGX9Gw==', +}); +const expectInitialToken = (bid) => expect(bid?.userId ?? {}).to.deep.include(makePrebidIdentityContainer(initialToken)); +const expectRefreshedToken = (bid) => expect(bid?.userId ?? {}).to.deep.include(makePrebidIdentityContainer(refreshedToken)); +const expectNoIdentity = (bid) => expect(bid).to.not.haveOwnProperty('userId'); +const expectGlobalToHaveRefreshedIdentity = () => expect(getGlobal().getUserIds()).to.deep.include(makePrebidIdentityContainer(refreshedToken)); +const expectGlobalToHaveNoUid2 = () => expect(getGlobal().getUserIds()).to.not.haveOwnProperty('uid2'); +const expectLegacyToken = (bid) => expect(bid.userId).to.deep.include(makePrebidIdentityContainer(legacyToken)); +const expectNoLegacyToken = (bid) => expect(bid.userId).to.not.deep.include(makePrebidIdentityContainer(legacyToken)); +const expectModuleCookieEmptyOrMissing = () => expect(coreStorage.getCookie(moduleCookieName)).to.be.null; +const expectModuleCookieToContain = (initialIdentity, latestIdentity) => { + const cookie = JSON.parse(coreStorage.getCookie(moduleCookieName)); + if (initialIdentity) expect(cookie.originalToken.advertising_token).to.equal(initialIdentity); + if (latestIdentity) expect(cookie.latestToken.advertising_token).to.equal(latestIdentity); +} + +const apiUrl = 'https://prod.uidapi.com/v2/token/refresh'; +const headers = { 'Content-Type': 'application/json' }; +const makeSuccessResponseBody = () => btoa(JSON.stringify({ status: 'success', body: { ...makeUid2Token(), advertising_token: refreshedToken } })); +const configureUid2Response = (httpStatus, response) => server.respondWith('POST', apiUrl, (xhr) => xhr.respond(httpStatus, headers, response)); +const configureUid2ApiSuccessResponse = () => configureUid2Response(200, makeSuccessResponseBody()); +const configureUid2ApiFailResponse = () => configureUid2Response(500, 'Error'); + +const respondAfterDelay = (delay) => new Promise((resolve) => setTimeout(() => { + server.respond(); + setTimeout(() => resolve()); +}, delay)); + +const runAuction = async () => { + const adUnits = [{ + code: 'adUnit-code', + mediaTypes: {banner: {}, native: {}}, + sizes: [[300, 200], [300, 600]], + bids: [{bidder: 'sampleBidder', params: {placementId: 'banner-only-bidder'}}] + }]; + return new Promise(function(resolve) { + requestBidsHook(function() { + resolve(adUnits[0].bids[0]); + }, {adUnits}); + }); +} + +// Runs the provided test twice - once with a successful API mock, once with one which returns a server error +const testApiSuccessAndFailure = (act, testDescription, failTestDescription, only = false) => { + const testFn = only ? it.only : it; + testFn(`API responds successfully: ${testDescription}`, async function() { + configureUid2ApiSuccessResponse(); + await act(true); + }); + testFn(`API responds with an error: ${failTestDescription ?? testDescription}`, async function() { + configureUid2ApiFailResponse(); + await act(false); + }); +} +describe(`UID2 module`, function () { + let suiteSandbox, testSandbox, timerSpy, fullTestTitle, restoreSubtleToUndefined = false; + before(function () { + timerSpy = configureTimerInterceptors(debugOutput); + hook.ready(); + uninstallGdprEnforcement(); + + suiteSandbox = sinon.sandbox.create(); + // I'm unable to find an authoritative source, but apparently subtle isn't available in some test stacks for security reasons. + // I've confirmed it's available in Firefox since v34 (it seems to be unavailable on BrowserStack in Firefox v106). + if (typeof window.crypto.subtle === 'undefined') { + restoreSubtleToUndefined = true; + window.crypto.subtle = { importKey: () => {}, decrypt: () => {} }; + } + suiteSandbox.stub(window.crypto.subtle, 'importKey').callsFake(() => Promise.resolve()); + suiteSandbox.stub(window.crypto.subtle, 'decrypt').callsFake((settings, key, data) => Promise.resolve(new Uint8Array([...settings.iv, ...data]))); + }); + + after(function () { + suiteSandbox.restore(); + timerSpy.restore(); + if (restoreSubtleToUndefined) window.crypto.subtle = undefined; + }); + + const getFullTestTitle = (test) => `${test.parent.title ? getFullTestTitle(test.parent) + ' | ' : ''}${test.title}`; + beforeEach(function () { + debugOutput(`----------------- START TEST ------------------`); + fullTestTitle = getFullTestTitle(this.test.ctx.currentTest); + debugOutput(fullTestTitle); + testSandbox = sinon.sandbox.create(); + testSandbox.stub(utils, 'logWarn'); + + init(config); + setSubmoduleRegistry([uid2IdSubmodule]); + }); + + afterEach(async function() { + $$PREBID_GLOBAL$$.requestBids.removeAll(); + config.resetConfig(); + testSandbox.restore(); + if (timerSpy.timers.length > 0) { + if (clearTimersAfterEachTest) { + debugOutput(`Cancelling ${timerSpy.timers.length} still-active timers.`); + timerSpy.clearAllActiveTimers(); + } else { + debugOutput(`Waiting on ${timerSpy.timers.length} still-active timers...`, timerSpy.timers); + await timerSpy.waitAllActiveTimers(); + } + } + coreStorage.setCookie(moduleCookieName, '', expireCookieDate); + coreStorage.setCookie(publisherCookieName, '', expireCookieDate); + + debugOutput('----------------- END TEST ------------------'); + }); + + describe('Configuration', function() { + it('When no baseUrl is provided in config, the module calls the production endpoint', function() { + const uid2Token = makeUid2Token(initialToken, true, true); + config.setConfig(makePrebidConfig({uid2Token})); + expect(server.requests[0]?.url).to.have.string('https://prod.uidapi.com/'); + }); + + it('When a baseUrl is provided in config, the module calls the provided endpoint', function() { + const uid2Token = makeUid2Token(initialToken, true, true); + config.setConfig(makePrebidConfig({uid2Token, uid2ApiBase: 'https://operator-integ.uidapi.com'})); + expect(server.requests[0]?.url).to.have.string('https://operator-integ.uidapi.com/'); + }); + }); + + it('When a legacy value is provided directly in configuration, it is passed on', async function() { + const valueConfig = makePrebidConfig(); + valueConfig.userSync.userIds[0].value = {uid2: {id: legacyToken}} + config.setConfig(valueConfig); + const bid = await runAuction(); + + expectLegacyToken(bid); + }); + + // These tests cover 'legacy' cookies - i.e. cookies set with just the uid2 advertising token, which was how some previous integrations worked. + // Some users might still have this cookie, and the module should use that token if a newer one isn't provided. + // This should cover older integrations where the server is setting this legacy cookie and expecting the module to pass it on. + describe('When a legacy cookie exists', function () { + // Creates a test which sets the legacy cookie, configures the UID2 module with provided params, runs an + const createLegacyTest = function(params, bidAssertions) { + return async function() { + coreStorage.setCookie(moduleCookieName, legacyToken, getFutureCookieExpiry()); + config.setConfig(makePrebidConfig(params)); + + const bid = await runAuction(); + bidAssertions.forEach(function(assertion) { assertion(bid); }); + } + }; + + it('and a legacy config is used, it should provide the legacy cookie', + createLegacyTest(legacyConfigParams, [expectLegacyToken])); + it('and a server cookie config is used without a valid server cookie, it should provide the legacy cookie', + createLegacyTest(serverCookieConfigParams, [expectLegacyToken])); + it('and a server cookie is used with a valid server cookie, it should provide the server cookie', + async function() { setPublisherCookie(makeUid2Token()); await createLegacyTest(serverCookieConfigParams, [expectInitialToken, expectNoLegacyToken])(); }); + it('and a token is provided in config, it should provide the config token', + createLegacyTest({uid2Token: makeUid2Token()}, [expectInitialToken, expectNoLegacyToken])); + }); + + // This setup runs all of the functional tests with both types of config - the full token response in params, or a server cookie with the cookie name provided + let scenarios = [ + { + name: 'Token provided in config call', + setConfig: (token, extraConfig = {}) => config.setConfig(makePrebidConfig({uid2Token: token}, extraConfig)), + }, + { + name: 'Token provided in server-set cookie', + setConfig: (token, extraConfig) => { + setPublisherCookie(token); + config.setConfig(makePrebidConfig(serverCookieConfigParams, extraConfig)); + }, + } + ] + + scenarios.forEach(function(scenario) { + describe(scenario.name, function() { + describe(`When an expired token which can be refreshed is provided`, function() { + describe('When the refresh is available in time', function() { + testApiSuccessAndFailure(async function(apiSucceeds) { + scenario.setConfig(makeUid2Token(initialToken, true, true)); + respondAfterDelay(auctionDelayMs / 10); + const bid = await runAuction(); + + if (apiSucceeds) expectRefreshedToken(bid); + else expectNoIdentity(bid); + }, 'it should be used in the auction', 'the auction should have no uid2'); + + testApiSuccessAndFailure(async function(apiSucceeds) { + scenario.setConfig(makeUid2Token(initialToken, true, true)); + respondAfterDelay(auctionDelayMs / 10); + + await runAuction(); + if (apiSucceeds) { + expectModuleCookieToContain(initialToken, refreshedToken); + } else { + expectModuleCookieEmptyOrMissing(); + } + }, 'the refreshed token should be stored in the module cookie', 'the module cookie should not be set'); + }); + describe(`when the response doesn't arrive before the auction timer`, function() { + testApiSuccessAndFailure(async function() { + scenario.setConfig(makeUid2Token(initialToken, true, true)); + const bid = await runAuction(); + expectNoIdentity(bid); + }, 'it should run the auction'); + + testApiSuccessAndFailure(async function(apiSucceeds) { + scenario.setConfig(makeUid2Token(initialToken, true, true)); + const promise = respondAfterDelay(auctionDelayMs * 2); + + const bid = await runAuction(); + expectNoIdentity(bid); + expectGlobalToHaveNoUid2(); + await promise; + if (apiSucceeds) expectGlobalToHaveRefreshedIdentity(); + else expectGlobalToHaveNoUid2(); + }, 'it should update the userId after the auction', 'there should be no global identity'); + }) + describe('and there is a refreshed token in the module cookie', function() { + it('the refreshed value from the cookie is used', async function() { + const initialIdentity = makeUid2Token(initialToken, true, true); + const refreshedIdentity = makeUid2Token(refreshedToken); + const moduleCookie = {originalToken: initialIdentity, latestToken: refreshedIdentity}; + coreStorage.setCookie(moduleCookieName, JSON.stringify(moduleCookie), getFutureCookieExpiry()); + scenario.setConfig(initialIdentity); + + const bid = await runAuction(); + expectRefreshedToken(bid); + }); + }) + }); + + describe(`When a current token is provided`, function() { + beforeEach(function() { + scenario.setConfig(makeUid2Token()); + }); + + it('it should use the token in the auction', async function() { + const bid = await runAuction(); + expectInitialToken(bid); + }); + }); + + describe(`When a current token which should be refreshed is provided, and the auction is set to run immediately`, function() { + beforeEach(function() { + scenario.setConfig(makeUid2Token(initialToken, true), {auctionDelay: 0, syncDelay: 1}); + }); + testApiSuccessAndFailure(async function() { + respondAfterDelay(10); + const bid = await runAuction(); + expectInitialToken(bid); + }, 'it should not be refreshed before the auction runs'); + + testApiSuccessAndFailure(async function(success) { + const promise = respondAfterDelay(1); + await runAuction(); + await promise; + if (success) { + expectModuleCookieToContain(initialToken, refreshedToken); + } else { + expectModuleCookieToContain(initialToken, initialToken); + } + }, 'the refreshed token should be stored in the module cookie after the auction runs', 'the module cookie should only have the original token'); + + it('it should use the current token in the auction', async function() { + const bid = await runAuction(); + expectInitialToken(bid); + }); + }); + }); + }); +}); diff --git a/test/spec/modules/userId_spec.js b/test/spec/modules/userId_spec.js index 4e9be5417e2..bf27ef0ff81 100644 --- a/test/spec/modules/userId_spec.js +++ b/test/spec/modules/userId_spec.js @@ -9,7 +9,7 @@ import { setSubmoduleRegistry, syncDelay, PBJS_USER_ID_OPTOUT_NAME, - findRootDomain, + findRootDomain, requestDataDeletion, } from 'modules/userId/index.js'; import {createEidsArray} from 'modules/userId/eids.js'; import {config} from 'src/config.js'; @@ -897,7 +897,7 @@ describe('User ID', function () { storage: {name: 'intentIqId', type: 'cookie'} }, { name: 'hadronId', - storage: {name: 'hadronId', type: 'cookie'} + storage: {name: 'hadronId', type: 'html5'} }, { name: 'zeotapIdPlus' }, { @@ -1298,7 +1298,7 @@ describe('User ID', function () { expect(bid).to.have.deep.nested.property('userId.amxId'); expect(bid.userId.amxId).to.equal('test_amxid_id'); expect(bid.userIdAsEids[0]).to.deep.equal({ - source: 'amxrtb.com', + source: 'amxdt.net', uids: [{ id: 'test_amxid_id', atype: 1, @@ -1872,8 +1872,8 @@ describe('User ID', function () { it('test hook from hadronId html5', function (done) { // simulate existing browser local storage values - localStorage.setItem('hadronId', JSON.stringify({'hadronId': 'random-ls-identifier'})); - localStorage.setItem('hadronId_exp', ''); + localStorage.setItem('hadronId', JSON.stringify({'hadronId': 'testHadronId1'})); + localStorage.setItem('hadronId_exp', (new Date(Date.now() + 5000)).toUTCString()); init(config); setSubmoduleRegistry([hadronIdSubmodule]); @@ -1883,15 +1883,15 @@ describe('User ID', function () { adUnits.forEach(unit => { unit.bids.forEach(bid => { expect(bid).to.have.deep.nested.property('userId.hadronId'); - expect(bid.userId.hadronId).to.equal('random-ls-identifier'); + expect(bid.userId.hadronId).to.equal('testHadronId1'); expect(bid.userIdAsEids[0]).to.deep.equal({ source: 'audigent.com', - uids: [{id: 'random-ls-identifier', atype: 1}] + uids: [{id: 'testHadronId1', atype: 1}] }); }); }); localStorage.removeItem('hadronId'); - localStorage.removeItem('hadronId_exp', ''); + localStorage.removeItem('hadronId_exp'); done(); }, {adUnits}); }); @@ -2125,7 +2125,9 @@ describe('User ID', function () { coreStorage.setCookie('netId', JSON.stringify({'netId': 'testnetId'}), (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('intentIqId', 'testintentIqId', (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('IDP', btoa(JSON.stringify('zeotapId')), (new Date(Date.now() + 5000).toUTCString())); - coreStorage.setCookie('hadronId', JSON.stringify({'hadronId': 'testHadronId'}), (new Date(Date.now() + 5000).toUTCString())); + // hadronId only supports localStorage + localStorage.setItem('hadronId', JSON.stringify({'hadronId': 'testHadronId1'})); + localStorage.setItem('hadronId_exp', (new Date(Date.now() + 5000)).toUTCString()); coreStorage.setCookie('storage_criteo', JSON.stringify({'criteoId': 'test_bidid'}), (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('mwol', JSON.stringify({eid: 'XX-YY-ZZ-123'}), (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('uid2id', 'Sample_AD_Token', (new Date(Date.now() + 5000).toUTCString())); @@ -2149,7 +2151,7 @@ describe('User ID', function () { ['netId', 'netId', 'cookie'], ['intentIqId', 'intentIqId', 'cookie'], ['zeotapIdPlus', 'IDP', 'cookie'], - ['hadronId', 'hadronId', 'cookie'], + ['hadronId', 'hadronId', 'html5'], ['criteo', 'storage_criteo', 'cookie'], ['mwOpenLinkId', 'mwol', 'cookie'], ['tapadId', 'tapad_id', 'cookie'], @@ -2192,7 +2194,7 @@ describe('User ID', function () { expect(bid.userId.IDP).to.equal('zeotapId'); // also check that hadronId id was copied to bid expect(bid).to.have.deep.nested.property('userId.hadronId'); - expect(bid.userId.hadronId).to.equal('testHadronId'); + expect(bid.userId.hadronId).to.equal('testHadronId1'); // also check that criteo id was copied to bid expect(bid).to.have.deep.nested.property('userId.criteoId'); expect(bid.userId.criteoId).to.equal('test_bidid'); @@ -2231,7 +2233,8 @@ describe('User ID', function () { coreStorage.setCookie('netId', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('intentIqId', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('IDP', '', EXPIRED_COOKIE_DATE); - coreStorage.setCookie('hadronId', '', EXPIRED_COOKIE_DATE); + localStorage.removeItem('hadronId'); + localStorage.removeItem('hadronId_exp'); coreStorage.setCookie('storage_criteo', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('mwol', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('uid2id', '', EXPIRED_COOKIE_DATE); @@ -2284,7 +2287,8 @@ describe('User ID', function () { coreStorage.setCookie('netId', JSON.stringify({'netId': 'testnetId'}), new Date(Date.now() + 5000).toUTCString()); coreStorage.setCookie('intentIqId', 'testintentIqId', (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('IDP', btoa(JSON.stringify('zeotapId')), (new Date(Date.now() + 5000).toUTCString())); - coreStorage.setCookie('hadronId', JSON.stringify({'hadronId': 'testHadronId'}), (new Date(Date.now() + 5000).toUTCString())); + localStorage.setItem('hadronId', JSON.stringify({'hadronId': 'testHadronId1'})); + localStorage.setItem('hadronId_exp', (new Date(Date.now() + 5000)).toUTCString()); coreStorage.setCookie('admixerId', 'testadmixerId', new Date(Date.now() + 5000).toUTCString()); coreStorage.setCookie('deepintentId', 'testdeepintentId', new Date(Date.now() + 5000).toUTCString()); coreStorage.setCookie('MOCKID', JSON.stringify({'MOCKID': '123456778'}), new Date(Date.now() + 5000).toUTCString()); @@ -2320,7 +2324,7 @@ describe('User ID', function () { }, { name: 'zeotapIdPlus' }, { - name: 'hadronId', storage: {name: 'hadronId', type: 'cookie'} + name: 'hadronId', storage: {name: 'hadronId', type: 'html5'} }, { name: 'admixerId', storage: {name: 'admixerId', type: 'cookie'} }, { @@ -2388,7 +2392,7 @@ describe('User ID', function () { expect(bid.userId.IDP).to.equal('zeotapId'); // also check that hadronId id data was copied to bid expect(bid).to.have.deep.nested.property('userId.hadronId'); - expect(bid.userId.hadronId).to.equal('testHadronId'); + expect(bid.userId.hadronId).to.equal('testHadronId1'); expect(bid.userId.uid2).to.deep.equal({ id: 'Sample_AD_Token' }); @@ -2420,7 +2424,8 @@ describe('User ID', function () { coreStorage.setCookie('netId', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('intentIqId', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('IDP', '', EXPIRED_COOKIE_DATE); - coreStorage.setCookie('hadronId', '', EXPIRED_COOKIE_DATE); + localStorage.removeItem('hadronId'); + localStorage.removeItem('hadronId_exp'); coreStorage.setCookie('dmdId', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('admixerId', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('deepintentId', '', EXPIRED_COOKIE_DATE); @@ -2703,45 +2708,70 @@ describe('User ID', function () { }); }); - describe('findRootDomain', function () { - let sandbox; + describe('requestDataDeletion', () => { + function idMod(name, value) { + return { + name, + getId() { + return {id: value} + }, + decode(d) { + return {[name]: d} + }, + onDataDeletionRequest: sinon.stub() + } + } + let mod1, mod2, mod3, cfg1, cfg2, cfg3; - beforeEach(function () { + beforeEach(() => { init(config); - setSubmoduleRegistry([sharedIdSystemSubmodule]); + mod1 = idMod('id1', 'val1'); + mod2 = idMod('id2', 'val2'); + mod3 = idMod('id3', 'val3'); + cfg1 = getStorageMock('id1', 'id1', 'cookie'); + cfg2 = getStorageMock('id2', 'id2', 'html5'); + cfg3 = {name: 'id3', value: {id3: 'val3'}}; + setSubmoduleRegistry([mod1, mod2, mod3]); config.setConfig({ + auctionDelay: 1, userSync: { - syncDelay: 0, - userIds: [ - { - name: 'pubCommonId', - value: { pubcid: '11111' }, - }, - ], - }, + userIds: [cfg1, cfg2, cfg3] + } }); - sandbox = sinon.createSandbox(); - sandbox - .stub(coreStorage, 'getCookie') - .onFirstCall() - .returns(null) // .co.uk - .onSecondCall() - .returns('writeable'); // realdomain.co.uk; - }); - - afterEach(function () { - sandbox.restore(); - }); - - it('should just find the root domain', function () { - var domain = findRootDomain('sub.realdomain.co.uk'); - expect(domain).to.be.eq('realdomain.co.uk'); - }); - - it('should find the full domain when no subdomain is present', function () { - var domain = findRootDomain('realdomain.co.uk'); - expect(domain).to.be.eq('realdomain.co.uk'); - }); + return getGlobal().refreshUserIds(); + }); + + it('deletes stored IDs', () => { + expect(coreStorage.getCookie('id1')).to.exist; + expect(coreStorage.getDataFromLocalStorage('id2')).to.exist; + requestDataDeletion(sinon.stub()); + expect(coreStorage.getCookie('id1')).to.not.exist; + expect(coreStorage.getDataFromLocalStorage('id2')).to.not.exist; + }); + + it('invokes onDataDeletionRequest', () => { + requestDataDeletion(sinon.stub()); + sinon.assert.calledWith(mod1.onDataDeletionRequest, cfg1, {id1: 'val1'}); + sinon.assert.calledWith(mod2.onDataDeletionRequest, cfg2, {id2: 'val2'}) + sinon.assert.calledWith(mod3.onDataDeletionRequest, cfg3, {id3: 'val3'}) + }); + + describe('does not choke when onDataDeletionRequest', () => { + Object.entries({ + 'is missing': () => { delete mod1.onDataDeletionRequest }, + 'throws': () => { mod1.onDataDeletionRequest.throws(new Error()) } + }).forEach(([t, setup]) => { + it(t, () => { + setup(); + const next = sinon.stub(); + const arg = {random: 'value'}; + requestDataDeletion(next, arg); + sinon.assert.calledOnce(mod2.onDataDeletionRequest); + sinon.assert.calledOnce(mod3.onDataDeletionRequest); + sinon.assert.calledWith(next, arg); + }) + }) + }) }); }); diff --git a/test/spec/modules/vidazooBidAdapter_spec.js b/test/spec/modules/vidazooBidAdapter_spec.js index d30b9f31417..24d565805d3 100644 --- a/test/spec/modules/vidazooBidAdapter_spec.js +++ b/test/spec/modules/vidazooBidAdapter_spec.js @@ -13,10 +13,13 @@ import { getUniqueDealId, getNextDealId, getVidazooSessionId, + webSessionId } from 'modules/vidazooBidAdapter.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'; const SUB_DOMAIN = 'openrtb'; @@ -37,20 +40,78 @@ const BID = { 'transactionId': 'c881914b-a3b5-4ecf-ad9c-1c2f37c6aabf', 'sizes': [[300, 250], [300, 600]], 'bidderRequestId': '1fdb5ff1b6eaa7', + 'auctionId': 'auction_id', + 'bidRequestsCount': 4, + 'bidderRequestsCount': 3, + 'bidderWinsCount': 1, 'requestId': 'b0777d85-d061-450e-9bc7-260dd54bbb7a', - 'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc' + 'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc', + 'mediaTypes': [BANNER], + 'ortb2Imp': { + 'ext': { + 'gpid': '1234567890' + } + } }; +const VIDEO_BID = { + 'bidId': '2d52001cabd527', + 'adUnitCode': '63550ad1ff6642d368cba59dh5884270560', + 'bidderRequestId': '12a8ae9ada9c13', + 'transactionId': '56e184c6-bde9-497b-b9b9-cf47a61381ee', + 'auctionId': 'auction_id', + 'bidRequestsCount': 4, + 'bidderRequestsCount': 3, + 'bidderWinsCount': 1, + 'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc', + 'params': { + 'subDomain': SUB_DOMAIN, + 'cId': '635509f7ff6642d368cb9837', + 'pId': '59ac17c192832d0011283fe3', + 'bidFloor': 0.1 + }, + 'sizes': [[545, 307]], + 'mediaTypes': { + 'video': { + 'playerSize': [[545, 307]], + 'context': 'instream', + 'mimes': [ + 'video/mp4', + 'application/javascript' + ], + 'protocols': [2, 3, 5, 6], + 'maxduration': 60, + 'minduration': 0, + 'startdelay': 0, + 'linearity': 1, + 'api': [2], + 'placement': 1 + } + } +} + const BIDDER_REQUEST = { 'gdprConsent': { 'consentString': 'consent_string', 'gdprApplies': true }, + 'gppString': 'gpp_string', + 'gppSid': [7], 'uspConsent': 'consent_string', 'refererInfo': { 'page': 'https://www.greatsite.com', 'ref': 'https://www.somereferrer.com' - } + }, + 'ortb2': { + 'site': { + 'cat': ['IAB2'], + 'pagecat': ['IAB2-2'] + }, + 'regs': { + 'gpp': 'gpp_string', + 'gpp_sid': [7] + } + }, }; const SERVER_RESPONSE = { @@ -75,6 +136,23 @@ const SERVER_RESPONSE = { } }; +const VIDEO_SERVER_RESPONSE = { + body: { + 'cid': '635509f7ff6642d368cb9837', + 'results': [{ + 'ad': '', + 'advertiserDomains': ['vidazoo.com'], + 'exp': 60, + 'width': 545, + 'height': 307, + 'mediaType': 'video', + 'creativeId': '12610997325162499419', + 'price': 2, + 'cookies': [] + }] + } +} + const REQUEST = { data: { width: 300, @@ -113,6 +191,11 @@ describe('VidazooBidAdapter', function () { it('exists and is a string', function () { expect(adapter.code).to.exist.and.to.be.a('string'); }); + + it('exists and contains media types', function () { + expect(adapter.supportedMediaTypes).to.exist.and.to.be.an('array').with.length(2); + expect(adapter.supportedMediaTypes).to.contain.members([BANNER, VIDEO]); + }); }); describe('validate bid requests', function () { @@ -150,14 +233,83 @@ describe('VidazooBidAdapter', function () { before(function () { $$PREBID_GLOBAL$$.bidderSettings = { vidazoo: { - storageAllowed: true + storageAllowed: true, } }; sandbox = sinon.sandbox.create(); sandbox.stub(Date, 'now').returns(1000); }); - it('should build request for each size', function () { + it('should build video request', function () { + const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.page); + config.setConfig({ + bidderTimeout: 3000 + }); + const requests = adapter.buildRequests([VIDEO_BID], BIDDER_REQUEST); + expect(requests).to.have.length(1); + expect(requests[0]).to.deep.equal({ + method: 'POST', + url: `${createDomain(SUB_DOMAIN)}/prebid/multi/635509f7ff6642d368cb9837`, + data: { + adUnitCode: '63550ad1ff6642d368cba59dh5884270560', + bidFloor: 0.1, + bidId: '2d52001cabd527', + bidderVersion: adapter.version, + cat: ['IAB2'], + pagecat: ['IAB2-2'], + cb: 1000, + dealId: 1, + gdpr: 1, + gdprConsent: 'consent_string', + usPrivacy: 'consent_string', + gppString: 'gpp_string', + gppSid: [7], + auctionId: 'auction_id', + bidRequestsCount: 4, + bidderRequestsCount: 3, + bidderWinsCount: 1, + bidderTimeout: 3000, + transactionId: '56e184c6-bde9-497b-b9b9-cf47a61381ee', + bidderRequestId: '12a8ae9ada9c13', + gpid: '', + prebidVersion: version, + ptrace: '1000', + publisherId: '59ac17c192832d0011283fe3', + url: 'https%3A%2F%2Fwww.greatsite.com', + referrer: 'https://www.somereferrer.com', + res: `${window.top.screen.width}x${window.top.screen.height}`, + schain: VIDEO_BID.schain, + sessionId: '', + sizes: ['545x307'], + uniqueDealId: `${hashUrl}_${Date.now().toString()}`, + uqs: getTopWindowQueryParams(), + isStorageAllowed: true, + webSessionId: webSessionId, + mediaTypes: { + video: { + api: [2], + context: 'instream', + linearity: 1, + maxduration: 60, + mimes: [ + 'video/mp4', + 'application/javascript' + ], + minduration: 0, + placement: 1, + playerSize: [[545, 307]], + protocols: [2, 3, 5, 6], + startdelay: 0 + } + } + } + }); + }); + + it('should build banner request for each size', function () { + config.setConfig({ + bidderTimeout: 3000 + }); const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.page); const requests = adapter.buildRequests([BID], BIDDER_REQUEST); expect(requests).to.have.length(1); @@ -168,6 +320,15 @@ describe('VidazooBidAdapter', function () { gdprConsent: 'consent_string', gdpr: 1, usPrivacy: 'consent_string', + gppString: 'gpp_string', + gppSid: [7], + auctionId: 'auction_id', + bidRequestsCount: 4, + bidderRequestsCount: 3, + bidderWinsCount: 1, + bidderTimeout: 3000, + transactionId: 'c881914b-a3b5-4ecf-ad9c-1c2f37c6aabf', + bidderRequestId: '1fdb5ff1b6eaa7', sizes: ['300x250', '300x600'], url: 'https%3A%2F%2Fwww.greatsite.com', referrer: 'https://www.somereferrer.com', @@ -176,16 +337,23 @@ describe('VidazooBidAdapter', function () { bidId: '2d52001cabd527', adUnitCode: 'div-gpt-ad-12345-0', publisherId: '59ac17c192832d0011283fe3', - dealId: 1, + dealId: 2, sessionId: '', uniqueDealId: `${hashUrl}_${Date.now().toString()}`, bidderVersion: adapter.version, prebidVersion: version, schain: BID.schain, + ptrace: '1000', res: `${window.top.screen.width}x${window.top.screen.height}`, + mediaTypes: [BANNER], uqs: getTopWindowQueryParams(), 'ext.param1': 'loremipsum', 'ext.param2': 'dolorsitamet', + isStorageAllowed: true, + gpid: '1234567890', + cat: ['IAB2'], + pagecat: ['IAB2-2'], + webSessionId: webSessionId } }); }); @@ -195,6 +363,7 @@ describe('VidazooBidAdapter', function () { sandbox.restore(); }); }); + describe('getUserSyncs', function () { it('should have valid user sync with iframeEnabled', function () { const result = adapter.getUserSyncs({iframeEnabled: true}, [SERVER_RESPONSE]); @@ -239,7 +408,7 @@ describe('VidazooBidAdapter', function () { expect(responses).to.be.empty; }); - it('should return an array of interpreted responses', function () { + it('should return an array of interpreted banner responses', function () { const responses = adapter.interpretResponse(SERVER_RESPONSE, REQUEST); expect(responses).to.have.length(1); expect(responses[0]).to.deep.equal({ @@ -258,6 +427,26 @@ describe('VidazooBidAdapter', function () { }); }); + it('should return an array of interpreted video responses', function () { + const responses = adapter.interpretResponse(VIDEO_SERVER_RESPONSE, REQUEST); + expect(responses).to.have.length(1); + expect(responses[0]).to.deep.equal({ + requestId: '2d52001cabd527', + cpm: 2, + width: 545, + height: 307, + mediaType: 'video', + creativeId: '12610997325162499419', + currency: 'USD', + netRevenue: true, + ttl: 60, + vastXml: '', + meta: { + advertiserDomains: ['vidazoo.com'] + } + }); + }); + it('should take default TTL', function () { const serverResponse = utils.deepClone(SERVER_RESPONSE); delete serverResponse.body.results[0].exp; diff --git a/test/spec/modules/videoModule/adQueue_spec.js b/test/spec/modules/videoModule/adQueue_spec.js new file mode 100644 index 00000000000..4002e0b6dcc --- /dev/null +++ b/test/spec/modules/videoModule/adQueue_spec.js @@ -0,0 +1,172 @@ +import { expect } from 'chai'; +import { AdQueueCoordinator } from '../../../../modules/videoModule/adQueue.js'; +import { AD_BREAK_END, SETUP_COMPLETE } from '../../../../libraries/video/constants/events.js' + +const testId = 'testId'; +describe('Ad Queue Coordinator', function () { + const mockVideoCoreFactory = function () { + return { + onEvents: sinon.spy(), + offEvents: sinon.spy(), + setAdTagUrl: sinon.spy(), + } + }; + + const mockEventsFactory = function () { + return { + emit: sinon.spy() + }; + }; + + describe('Before Provider Setup Complete', function () { + it('should push ad to queue', function () { + const mockVideoCore = mockVideoCoreFactory(); + const mockEvents = mockEventsFactory(); + const coordinator = AdQueueCoordinator(mockVideoCore, mockEvents); + coordinator.registerProvider(testId); + coordinator.queueAd('testAdTag', testId, { param: {} }); + + expect(mockEvents.emit.calledOnce).to.be.true; + let emitArgs = mockEvents.emit.firstCall.args; + expect(emitArgs[0]).to.be.equal('videoAuctionAdLoadQueued'); + expect(mockVideoCore.setAdTagUrl.called).to.be.false; + }); + }); + + describe('After Provider Setup Complete', function () { + it('should load from ad queue', function () { + const mockVideoCore = mockVideoCoreFactory(); + const mockEvents = mockEventsFactory(); + let setupComplete; + mockVideoCore.onEvents = function(events, callback, id) { + if (events[0] === SETUP_COMPLETE && id === testId) { + setupComplete = callback; + } + }; + const coordinator = AdQueueCoordinator(mockVideoCore, mockEvents); + coordinator.registerProvider(testId); + coordinator.queueAd('testAdTag', testId, { param: {} }); + + expect(mockEvents.emit.calledOnce).to.be.true; + let emitArgs = mockEvents.emit.firstCall.args; + expect(emitArgs[0]).to.be.equal('videoAuctionAdLoadQueued'); + + setupComplete('', { divId: testId }); + expect(mockEvents.emit.calledTwice).to.be.true; + emitArgs = mockEvents.emit.secondCall.args; + expect(emitArgs[0]).to.be.equal('videoAuctionAdLoadAttempt'); + expect(mockVideoCore.setAdTagUrl.calledOnce).to.be.true; + }); + + it('should load ads without queueing', function () { + const mockVideoCore = mockVideoCoreFactory(); + const mockEvents = mockEventsFactory(); + let setupComplete; + mockVideoCore.onEvents = function(events, callback, id) { + if (events[0] === SETUP_COMPLETE && id === testId) { + setupComplete = callback; + } + }; + const coordinator = AdQueueCoordinator(mockVideoCore, mockEvents); + coordinator.registerProvider(testId); + + setupComplete('', { divId: testId }); + + coordinator.queueAd('testAdTag', testId, { param: {} }); + expect(mockEvents.emit.calledOnce).to.be.true; + let emitArgs = mockEvents.emit.firstCall.args; + expect(emitArgs[0]).to.be.equal('videoAuctionAdLoadAttempt'); + expect(mockVideoCore.setAdTagUrl.calledOnce).to.be.true; + }); + }); + + describe('On Ad Break End', function () { + it('should load from queue', function () { + const mockVideoCore = mockVideoCoreFactory(); + const mockEvents = mockEventsFactory(); + let setupComplete; + let adBreakEnd; + + mockVideoCore.onEvents = function(events, callback, id) { + if (events[0] === SETUP_COMPLETE && id === testId) { + setupComplete = callback; + } + + if (events[0] === AD_BREAK_END && id === testId) { + adBreakEnd = callback; + } + }; + + const coordinator = AdQueueCoordinator(mockVideoCore, mockEvents); + coordinator.registerProvider(testId); + coordinator.queueAd('testAdTag', testId); + coordinator.queueAd('testAdTag2', testId); + coordinator.queueAd('testAdTag3', testId); + + mockEvents.emit.resetHistory(); + + setupComplete('', { divId: testId }); + + expect(mockEvents.emit.calledOnce).to.be.true; + let emitArgs = mockEvents.emit.firstCall.args; + expect(emitArgs[0]).to.be.equal('videoAuctionAdLoadAttempt'); + expect(mockVideoCore.setAdTagUrl.calledOnce).to.be.true; + let setAdTagArgs = mockVideoCore.setAdTagUrl.firstCall.args; + expect(setAdTagArgs[0]).to.be.equal('testAdTag'); + + adBreakEnd('', { divId: testId }); + + expect(mockEvents.emit.calledTwice).to.be.true; + emitArgs = mockEvents.emit.secondCall.args; + expect(emitArgs[0]).to.be.equal('videoAuctionAdLoadAttempt'); + expect(mockVideoCore.setAdTagUrl.calledTwice).to.be.true; + setAdTagArgs = mockVideoCore.setAdTagUrl.secondCall.args; + expect(setAdTagArgs[0]).to.be.equal('testAdTag2'); + + adBreakEnd('', { divId: testId }); + + expect(mockEvents.emit.calledThrice).to.be.true; + emitArgs = mockEvents.emit.thirdCall.args; + expect(emitArgs[0]).to.be.equal('videoAuctionAdLoadAttempt'); + expect(mockVideoCore.setAdTagUrl.calledThrice).to.be.true; + setAdTagArgs = mockVideoCore.setAdTagUrl.thirdCall.args; + expect(setAdTagArgs[0]).to.be.equal('testAdTag3'); + + adBreakEnd('', { divId: testId }); + + expect(mockEvents.emit.calledThrice).to.be.true; + expect(mockVideoCore.setAdTagUrl.calledThrice).to.be.true; + }); + + it('should stop responding to AdBreakEnd when queue is empty', function () { + const mockVideoCore = mockVideoCoreFactory(); + let setupComplete; + let adBreakEnd; + + mockVideoCore.onEvents = function(events, callback, id) { + if (events[0] === SETUP_COMPLETE && id === testId) { + setupComplete = callback; + } + + if (events[0] === AD_BREAK_END && id === testId) { + adBreakEnd = callback; + } + }; + + const coordinator = AdQueueCoordinator(mockVideoCore, mockEventsFactory()); + coordinator.registerProvider(testId); + coordinator.queueAd('testAdTag', testId); + coordinator.queueAd('testAdTag2', testId); + coordinator.queueAd('testAdTag3', testId); + + setupComplete('', { divId: testId }); + adBreakEnd('', { divId: testId }); + adBreakEnd('', { divId: testId }); + expect(mockVideoCore.setAdTagUrl.calledThrice).to.be.true; + adBreakEnd('', { divId: testId }); + expect(mockVideoCore.setAdTagUrl.calledThrice).to.be.true; + adBreakEnd('', { divId: testId }); + expect(mockVideoCore.setAdTagUrl.calledThrice).to.be.true; + }); + }); +}); diff --git a/test/spec/modules/videoModule/pbVideo_spec.js b/test/spec/modules/videoModule/pbVideo_spec.js index cfd34ebd706..41780a007dd 100644 --- a/test/spec/modules/videoModule/pbVideo_spec.js +++ b/test/spec/modules/videoModule/pbVideo_spec.js @@ -14,12 +14,15 @@ let gamSubmoduleMock; let gamSubmoduleFactoryMock; let videoImpressionVerifierFactoryMock; let videoImpressionVerifierMock; +let adQueueCoordinatorMock; +let adQueueCoordinatorFactoryMock; function resetTestVars() { ortbVideoMock = {}; ortbContentMock = {}; videoCoreMock = { registerProvider: sinon.spy(), + initProvider: sinon.spy(), onEvents: sinon.spy(), getOrtbVideo: () => ortbVideoMock, getOrtbContent: () => ortbContentMock, @@ -54,9 +57,16 @@ function resetTestVars() { }; videoImpressionVerifierFactoryMock = () => videoImpressionVerifierMock; + + adQueueCoordinatorMock = { + registerProvider: sinon.spy(), + queueAd: sinon.spy() + }; + + adQueueCoordinatorFactoryMock = () => adQueueCoordinatorMock; } -let pbVideoFactory = (videoCore, getConfig, pbGlobal, pbEvents, videoEvents, gamSubmoduleFactory, videoImpressionVerifierFactory) => { +let pbVideoFactory = (videoCore, getConfig, pbGlobal, pbEvents, videoEvents, gamSubmoduleFactory, videoImpressionVerifierFactory, adQueueCoordinator) => { const pbVideo = PbVideo( videoCore || videoCoreMock, getConfig || getConfigMock, @@ -64,7 +74,8 @@ let pbVideoFactory = (videoCore, getConfig, pbGlobal, pbEvents, videoEvents, gam pbEvents || pbEventsMock, videoEvents || videoEventsMock, gamSubmoduleFactory || gamSubmoduleFactoryMock, - videoImpressionVerifierFactory || videoImpressionVerifierFactoryMock + videoImpressionVerifierFactory || videoImpressionVerifierFactoryMock, + adQueueCoordinator || adQueueCoordinatorMock ); pbVideo.init(); return pbVideo; @@ -207,6 +218,7 @@ describe('Prebid Video', function () { beforeEach(() => { gamSubmoduleMock.getAdTagUrl.resetHistory(); videoCoreMock.setAdTagUrl.resetHistory(); + adQueueCoordinatorMock.queueAd.resetHistory(); }); let beforeBidRequestCallback; @@ -250,10 +262,10 @@ describe('Prebid Video', function () { pbVideoFactory(null, getConfig, pbGlobal, pbEvents, null, gamSubmoduleFactory); beforeBidRequestCallback(() => {}, {}); auctionEndCallback(auctionResults); - expect(videoCoreMock.setAdTagUrl.calledOnce).to.be.true; - expect(videoCoreMock.setAdTagUrl.args[0][0]).to.be.equal(expectedAdTag); - expect(videoCoreMock.setAdTagUrl.args[0][1]).to.be.equal(expectedDivId); - expect(videoCoreMock.setAdTagUrl.args[0][2]).to.have.property('adUnitCode', expectedAdUnitCode); + expect(adQueueCoordinatorMock.queueAd.calledOnce).to.be.true; + expect(adQueueCoordinatorMock.queueAd.args[0][0]).to.be.equal(expectedAdTag); + expect(adQueueCoordinatorMock.queueAd.args[0][1]).to.be.equal(expectedDivId); + expect(adQueueCoordinatorMock.queueAd.args[0][2]).to.have.property('adUnitCode', expectedAdUnitCode); }); it('should load ad tag from highest bid when ad server is not configured', function () { @@ -275,11 +287,11 @@ describe('Prebid Video', function () { pbVideoFactory(null, () => ({ providers: [] }), pbGlobal, pbEvents); beforeBidRequestCallback(() => {}, {}); auctionEndCallback(auctionResults); - expect(videoCoreMock.setAdTagUrl.calledOnce).to.be.true; - expect(videoCoreMock.setAdTagUrl.args[0][0]).to.be.equal(expectedVastUrl); - expect(videoCoreMock.setAdTagUrl.args[0][1]).to.be.equal(expectedDivId); - expect(videoCoreMock.setAdTagUrl.args[0][2]).to.have.property('adUnitCode', expectedAdUnitCode); - expect(videoCoreMock.setAdTagUrl.args[0][2]).to.have.property('adXml', expectedVastXml); + expect(adQueueCoordinatorMock.queueAd.calledOnce).to.be.true; + expect(adQueueCoordinatorMock.queueAd.args[0][0]).to.be.equal(expectedVastUrl); + expect(adQueueCoordinatorMock.queueAd.args[0][1]).to.be.equal(expectedDivId); + expect(adQueueCoordinatorMock.queueAd.args[0][2]).to.have.property('adUnitCode', expectedAdUnitCode); + expect(adQueueCoordinatorMock.queueAd.args[0][2]).to.have.property('adXml', expectedVastXml); }); }); diff --git a/test/spec/modules/videoModule/shared/parentModule_spec.js b/test/spec/modules/videoModule/shared/parentModule_spec.js index 1e8e7fda380..e3e4cfb7f3f 100644 --- a/test/spec/modules/videoModule/shared/parentModule_spec.js +++ b/test/spec/modules/videoModule/shared/parentModule_spec.js @@ -62,7 +62,6 @@ describe('Submodule Builder', function () { it('should instantiate the submodule, when supported', function () { const submodule = submoduleBuilder.build(vendorCode2); - expect(initSpy.calledOnce).to.be.true; expect(submodule).to.be.equal(submodule2); }); diff --git a/test/spec/modules/videoModule/submodules/jwplayerVideoProvider_spec.js b/test/spec/modules/videoModule/submodules/jwplayerVideoProvider_spec.js index 399c115b820..e08353f5b8d 100644 --- a/test/spec/modules/videoModule/submodules/jwplayerVideoProvider_spec.js +++ b/test/spec/modules/videoModule/submodules/jwplayerVideoProvider_spec.js @@ -14,7 +14,7 @@ import { SETUP_COMPLETE, SETUP_FAILED, PLAY, AD_IMPRESSION, videoEvents } from 'libraries/video/constants/events.js'; -import { PLAYBACK_MODE } from 'libraries/video/constants/enums.js'; +import { PLAYBACK_MODE } from 'libraries/video/constants/constants.js'; function getPlayerMock() { return makePlayerFactoryMock({ @@ -66,7 +66,28 @@ function getUtilsMock() { const sharedUtils = { videoEvents }; +function addDiv() { + const div = document.createElement('div'); + div.setAttribute('id', 'test'); + document.body.appendChild(div); +} + +function removeDiv() { + const div = document.getElementById('test'); + if (div) { + div.remove(); + } +} + describe('JWPlayerProvider', function () { + beforeEach(() => { + addDiv(); + }); + + afterEach(() => { + removeDiv(); + }); + describe('init', function () { let config; let adState; @@ -75,7 +96,7 @@ describe('JWPlayerProvider', function () { let utilsMock; beforeEach(() => { - config = {}; + config = { divId: 'test' }; adState = adStateFactory(); timeState = timeStateFactory(); callbackStorage = callbackStorageFactory(); @@ -104,7 +125,21 @@ describe('JWPlayerProvider', function () { expect(payload.errorCode).to.be.equal(-2); }); - it('should instantiate the player when uninstantied', function () { + it('should trigger failure when div is missing', function () { + removeDiv(); + let jwplayerMock = () => {}; + const provider = JWPlayerProvider(config, jwplayerMock, adState, timeState, callbackStorage, utilsMock, sharedUtils); + const setupFailed = sinon.spy(); + provider.onEvent(SETUP_FAILED, setupFailed, {}); + provider.init(); + expect(setupFailed.calledOnce).to.be.true; + const payload = setupFailed.args[0][1]; + expect(payload.errorCode).to.be.equal(-3); + addDiv(); + addDiv(); + }); + + it('should instantiate the player when uninstantiated', function () { const player = getPlayerMock(); config.playerConfig = {}; const setupSpy = player.setup = sinon.spy(); @@ -113,7 +148,7 @@ describe('JWPlayerProvider', function () { expect(setupSpy.calledOnce).to.be.true; }); - it('should trigger setup complete when player is already instantied', function () { + it('should trigger setup complete when player is already instantiated', function () { const player = getPlayerMock(); player.getState = () => 'idle'; const provider = JWPlayerProvider(config, makePlayerFactoryMock(player), adState, timeState, callbackStorage, utilsMock, sharedUtils); @@ -151,7 +186,7 @@ describe('JWPlayerProvider', function () { const test_playback_method = PLAYBACK_METHODS.CLICK_TO_PLAY; const test_skip = 0; - const config = {}; + const config = { divId: 'test' }; const player = getPlayerMock(); const utils = getUtilsMock(); @@ -230,9 +265,9 @@ describe('JWPlayerProvider', function () { duration: test_duration, playbackMode: test_playback_mode }) - } + }; - const provider = JWPlayerProvider({}, makePlayerFactoryMock(player), adStateFactory(), timeState, {}, utils, sharedUtils); + const provider = JWPlayerProvider({ divId: 'test' }, makePlayerFactoryMock(player), adStateFactory(), timeState, {}, utils, sharedUtils); provider.init(); let content = provider.getOrtbContent(); @@ -260,7 +295,7 @@ describe('JWPlayerProvider', function () { it('should call playAd', function () { const player = getPlayerMock(); const playAdSpy = player.playAd = sinon.spy(); - const provider = JWPlayerProvider({}, makePlayerFactoryMock(player), {}, {}, {}, {}, sharedUtils); + const provider = JWPlayerProvider({ divId: 'test' }, makePlayerFactoryMock(player), {}, {}, {}, {}, sharedUtils); provider.init(); provider.setAdTagUrl('tag'); expect(playAdSpy.called).to.be.true; @@ -273,7 +308,7 @@ describe('JWPlayerProvider', function () { it('should register event listener on player', function () { const player = getPlayerMock(); const onSpy = player.on = sinon.spy(); - const provider = JWPlayerProvider({}, makePlayerFactoryMock(player), adStateFactory(), timeStateFactory(), callbackStorageFactory(), getUtilsMock(), sharedUtils); + const provider = JWPlayerProvider({ divId: 'test' }, makePlayerFactoryMock(player), adStateFactory(), timeStateFactory(), callbackStorageFactory(), getUtilsMock(), sharedUtils); provider.init(); const callback = () => {}; provider.onEvent(PLAY, callback, {}); @@ -285,7 +320,7 @@ describe('JWPlayerProvider', function () { it('should remove event listener on player', function () { const player = getPlayerMock(); const offSpy = player.off = sinon.spy(); - const provider = JWPlayerProvider({}, makePlayerFactoryMock(player), adStateFactory(), timeStateFactory(), callbackStorageFactory(), utils, sharedUtils); + const provider = JWPlayerProvider({ divId: 'test' }, makePlayerFactoryMock(player), adStateFactory(), timeStateFactory(), callbackStorageFactory(), utils, sharedUtils); provider.init(); const callback = () => {}; provider.onEvent(AD_IMPRESSION, callback, {}); @@ -301,7 +336,7 @@ describe('JWPlayerProvider', function () { const player = getPlayerMock(); const removeSpy = player.remove = sinon.spy(); player.remove = removeSpy; - const provider = JWPlayerProvider({}, makePlayerFactoryMock(player), adStateFactory(), timeStateFactory(), callbackStorageFactory(), getUtilsMock(), sharedUtils); + const provider = JWPlayerProvider({ divId: 'test' }, makePlayerFactoryMock(player), adStateFactory(), timeStateFactory(), callbackStorageFactory(), getUtilsMock(), sharedUtils); provider.init(); provider.destroy(); provider.destroy(); diff --git a/test/spec/modules/viqeoBidAdapter_spec.js b/test/spec/modules/viqeoBidAdapter_spec.js new file mode 100644 index 00000000000..8f597318af9 --- /dev/null +++ b/test/spec/modules/viqeoBidAdapter_spec.js @@ -0,0 +1,124 @@ +import {expect} from 'chai'; +import {spec} from 'modules/viqeoBidAdapter'; + +describe('viqeoBidAdapter', function () { + it('minimal params', function () { + expect(spec.isBidRequestValid({ + bidder: 'viqeo', + params: { + user: { + buyeruid: '1', + }, + playerOptions: { + videoId: 'ed584da454c7205ca7e4', + profileId: 1382, + }, + }})).to.equal(true); + }); + it('minimal params no playerOptions', function () { + expect(spec.isBidRequestValid({ + bidder: 'viqeo', + params: { + currency: 'EUR', + }})).to.equal(false); + }); + it('build request check data', function () { + const bidRequestData = [{ + bidId: 'id1', + bidder: 'viqeo', + params: { + user: { + buyeruid: '1', + }, + currency: 'EUR', + floor: 0.5, + playerOptions: { + videoId: 'ed584da454c7205ca7e4', + profileId: 1382, + }, + }, + mediaTypes: { + video: { playerSize: [[240, 400]] } + }, + }]; + const request = spec.buildRequests(bidRequestData); + const requestData = request[0].data; + expect(requestData.id).to.equal('id1') + expect(requestData.imp[0].bidfloorcur).to.equal('EUR'); + expect(requestData.imp[0].bidfloor).to.equal(0.5); + expect(requestData.imp[0].video.w).to.equal(240); + expect(requestData.imp[0].video.h).to.equal(400); + expect(requestData.user.buyeruid).to.equal('1'); + }); + it('build request check url', function () { + const bidRequestData = [{ + bidder: 'viqeo', + params: { + playerOptions: { + videoId: 'ed584da454c7205ca7e4', + profileId: 1382, + }, + sspId: 42, + }, + mediaTypes: { + video: { playerSize: [[240, 400]] } + }, + }]; + const request = spec.buildRequests(bidRequestData); + expect(request[0].url).to.equal('https://ads.betweendigital.com/openrtb_bid/?sspId=42') + }); + it('response_params common case', function () { + const bidRequestData = { + bids: [{ + bidId: 'id1', + params: {}, + mediaTypes: { + video: { playerSize: [[240, 400]] } + }, + }], + }; + const serverResponse = { + body: { + id: 'id1', + cur: 'EUR', + seatbid: [{ + bid: [{ + cpm: 0.5, + ttl: 3600, + netRevenue: true, + creativeId: 'test1', + adm: '', + }], + }], + } + }; + const bids = spec.interpretResponse(serverResponse, bidRequestData); + expect(bids).to.have.lengthOf(1); + }); + it('should set flooPrice to getFloor.floor value if it is greater than params.floor', function() { + const bidRequestData = [{ + bidId: 'id1', + bidder: 'viqeo', + params: { + currency: 'EUR', + floor: 0.5, + playerOptions: { + videoId: 'ed584da454c7205ca7e4', + profileId: 1382, + }, + }, + mediaTypes: { + video: { playerSize: [[240, 400]] } + }, + getFloor: () => { + return { + currency: 'EUR', + floor: 3.32 + } + }, + }]; + const request = spec.buildRequests(bidRequestData); + const requestData = request[0].data; + expect(requestData.imp[0].bidfloor).to.equal(3.32) + }); +}); diff --git a/test/spec/modules/visiblemeasuresBidAdapter_spec.js b/test/spec/modules/visiblemeasuresBidAdapter_spec.js new file mode 100644 index 00000000000..93eeb7b556c --- /dev/null +++ b/test/spec/modules/visiblemeasuresBidAdapter_spec.js @@ -0,0 +1,400 @@ +import { expect } from 'chai'; +import { spec } from '../../../modules/visiblemeasuresBidAdapter.js'; +import { BANNER, VIDEO, NATIVE } from '../../../src/mediaTypes.js'; +import { getUniqueIdentifierStr } from '../../../src/utils.js'; + +const bidder = 'visiblemeasures' +const adUrl = 'https://us-e.visiblemeasures.com/pbjs'; +const syncUrl = 'https://cs.visiblemeasures.com'; + +describe('VisibleMeasuresBidAdapter', function () { + const bids = [ + { + bidId: getUniqueIdentifierStr(), + bidder: bidder, + mediaTypes: { + [BANNER]: { + sizes: [[300, 250]] + } + }, + params: { + placementId: 'testBanner', + } + }, + { + bidId: getUniqueIdentifierStr(), + bidder: bidder, + mediaTypes: { + [VIDEO]: { + playerSize: [[300, 300]], + minduration: 5, + maxduration: 60 + } + }, + params: { + placementId: 'testVideo', + } + }, + { + bidId: getUniqueIdentifierStr(), + bidder: bidder, + mediaTypes: { + [NATIVE]: { + native: { + title: { + required: true + }, + body: { + required: true + }, + icon: { + required: true, + size: [64, 64] + } + } + } + }, + params: { + placementId: 'testNative', + } + } + ]; + + const invalidBid = { + bidId: getUniqueIdentifierStr(), + bidder: bidder, + mediaTypes: { + [BANNER]: { + sizes: [[300, 250]] + } + }, + params: { + + } + } + + const bidderRequest = { + uspConsent: '1---', + gdprConsent: 'COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw', + refererInfo: { + referer: 'https://test.com' + } + }; + + describe('isBidRequestValid', function () { + it('Should return true if there are bidId, params and key parameters present', function () { + expect(spec.isBidRequestValid(bids[0])).to.be.true; + }); + it('Should return false if at least one of parameters is not present', function () { + expect(spec.isBidRequestValid(invalidBid)).to.be.false; + }); + }); + + describe('buildRequests', function () { + let serverRequest = spec.buildRequests(bids, bidderRequest); + + it('Creates a ServerRequest object with method, URL and data', function () { + expect(serverRequest).to.exist; + expect(serverRequest.method).to.exist; + expect(serverRequest.url).to.exist; + expect(serverRequest.data).to.exist; + }); + + it('Returns POST method', function () { + expect(serverRequest.method).to.equal('POST'); + }); + + it('Returns valid URL', function () { + expect(serverRequest.url).to.equal(adUrl); + }); + + it('Returns general data valid', function () { + let data = serverRequest.data; + expect(data).to.be.an('object'); + expect(data).to.have.all.keys('deviceWidth', + 'deviceHeight', + 'language', + 'secure', + 'host', + 'page', + 'placements', + 'coppa', + 'ccpa', + 'gdpr', + 'tmax' + ); + expect(data.deviceWidth).to.be.a('number'); + expect(data.deviceHeight).to.be.a('number'); + expect(data.language).to.be.a('string'); + expect(data.secure).to.be.within(0, 1); + 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.ccpa).to.be.a('string'); + expect(data.tmax).to.be.a('number'); + expect(data.placements).to.have.lengthOf(3); + }); + + it('Returns valid placements', function () { + const { placements } = serverRequest.data; + for (let i = 0, len = placements.length; i < len; i++) { + const placement = placements[i]; + expect(placement.placementId).to.be.oneOf(['testBanner', 'testVideo', 'testNative']); + expect(placement.adFormat).to.be.oneOf([BANNER, VIDEO, NATIVE]); + expect(placement.bidId).to.be.a('string'); + expect(placement.schain).to.be.an('object'); + expect(placement.bidfloor).to.exist.and.to.equal(0); + expect(placement.type).to.exist.and.to.equal('publisher'); + + if (placement.adFormat === BANNER) { + expect(placement.sizes).to.be.an('array'); + } + switch (placement.adFormat) { + case BANNER: + expect(placement.sizes).to.be.an('array'); + break; + case VIDEO: + expect(placement.playerSize).to.be.an('array'); + expect(placement.minduration).to.be.an('number'); + expect(placement.maxduration).to.be.an('number'); + break; + case NATIVE: + expect(placement.native).to.be.an('object'); + break; + } + } + }); + + it('Returns data with gdprConsent and without uspConsent', function () { + delete bidderRequest.uspConsent; + serverRequest = spec.buildRequests(bids, bidderRequest); + let data = serverRequest.data; + expect(data.gdpr).to.exist; + expect(data.gdpr).to.be.a('string'); + expect(data.gdpr).to.equal(bidderRequest.gdprConsent); + expect(data.ccpa).to.not.exist; + delete bidderRequest.gdprConsent; + }); + + it('Returns data with uspConsent and without gdprConsent', function () { + bidderRequest.uspConsent = '1---'; + delete bidderRequest.gdprConsent; + serverRequest = spec.buildRequests(bids, bidderRequest); + let data = serverRequest.data; + expect(data.ccpa).to.exist; + expect(data.ccpa).to.be.a('string'); + expect(data.ccpa).to.equal(bidderRequest.uspConsent); + expect(data.gdpr).to.not.exist; + }); + + it('Returns empty data if no valid requests are passed', function () { + serverRequest = spec.buildRequests([], bidderRequest); + let data = serverRequest.data; + expect(data.placements).to.be.an('array').that.is.empty; + }); + }); + + describe('interpretResponse', function () { + it('Should interpret banner response', function () { + const banner = { + body: [{ + mediaType: 'banner', + width: 300, + height: 250, + cpm: 0.4, + ad: 'Test', + requestId: '23fhj33i987f', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1', + meta: { + advertiserDomains: ['google.com'], + advertiserId: 1234 + } + }] + }; + let bannerResponses = spec.interpretResponse(banner); + expect(bannerResponses).to.be.an('array').that.is.not.empty; + let dataItem = bannerResponses[0]; + expect(dataItem).to.have.all.keys('requestId', 'cpm', 'width', 'height', 'ad', 'ttl', 'creativeId', + 'netRevenue', 'currency', 'dealId', 'mediaType', 'meta'); + expect(dataItem.requestId).to.equal(banner.body[0].requestId); + expect(dataItem.cpm).to.equal(banner.body[0].cpm); + expect(dataItem.width).to.equal(banner.body[0].width); + expect(dataItem.height).to.equal(banner.body[0].height); + expect(dataItem.ad).to.equal(banner.body[0].ad); + expect(dataItem.ttl).to.equal(banner.body[0].ttl); + expect(dataItem.creativeId).to.equal(banner.body[0].creativeId); + expect(dataItem.netRevenue).to.be.true; + expect(dataItem.currency).to.equal(banner.body[0].currency); + expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains'); + }); + it('Should interpret video response', function () { + const video = { + body: [{ + vastUrl: 'test.com', + mediaType: 'video', + cpm: 0.5, + requestId: '23fhj33i987f', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1', + meta: { + advertiserDomains: ['google.com'], + advertiserId: 1234 + } + }] + }; + let videoResponses = spec.interpretResponse(video); + expect(videoResponses).to.be.an('array').that.is.not.empty; + + let dataItem = videoResponses[0]; + expect(dataItem).to.have.all.keys('requestId', 'cpm', 'vastUrl', 'ttl', 'creativeId', + 'netRevenue', 'currency', 'dealId', 'mediaType', 'meta'); + expect(dataItem.requestId).to.equal('23fhj33i987f'); + expect(dataItem.cpm).to.equal(0.5); + expect(dataItem.vastUrl).to.equal('test.com'); + expect(dataItem.ttl).to.equal(120); + expect(dataItem.creativeId).to.equal('2'); + expect(dataItem.netRevenue).to.be.true; + expect(dataItem.currency).to.equal('USD'); + expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains'); + }); + it('Should interpret native response', function () { + const native = { + body: [{ + mediaType: 'native', + native: { + clickUrl: 'test.com', + title: 'Test', + image: 'test.com', + impressionTrackers: ['test.com'], + }, + ttl: 120, + cpm: 0.4, + requestId: '23fhj33i987f', + creativeId: '2', + netRevenue: true, + currency: 'USD', + meta: { + advertiserDomains: ['google.com'], + advertiserId: 1234 + } + }] + }; + let nativeResponses = spec.interpretResponse(native); + expect(nativeResponses).to.be.an('array').that.is.not.empty; + + let dataItem = nativeResponses[0]; + expect(dataItem).to.have.keys('requestId', 'cpm', 'ttl', 'creativeId', 'netRevenue', 'currency', 'mediaType', 'native', 'meta'); + expect(dataItem.native).to.have.keys('clickUrl', 'impressionTrackers', 'title', 'image') + expect(dataItem.requestId).to.equal('23fhj33i987f'); + expect(dataItem.cpm).to.equal(0.4); + expect(dataItem.native.clickUrl).to.equal('test.com'); + expect(dataItem.native.title).to.equal('Test'); + expect(dataItem.native.image).to.equal('test.com'); + expect(dataItem.native.impressionTrackers).to.be.an('array').that.is.not.empty; + expect(dataItem.native.impressionTrackers[0]).to.equal('test.com'); + expect(dataItem.ttl).to.equal(120); + expect(dataItem.creativeId).to.equal('2'); + expect(dataItem.netRevenue).to.be.true; + expect(dataItem.currency).to.equal('USD'); + expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains'); + }); + it('Should return an empty array if invalid banner response is passed', function () { + const invBanner = { + body: [{ + width: 300, + cpm: 0.4, + ad: 'Test', + requestId: '23fhj33i987f', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1' + }] + }; + + let serverResponses = spec.interpretResponse(invBanner); + expect(serverResponses).to.be.an('array').that.is.empty; + }); + it('Should return an empty array if invalid video response is passed', function () { + const invVideo = { + body: [{ + mediaType: 'video', + cpm: 0.5, + requestId: '23fhj33i987f', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1' + }] + }; + let serverResponses = spec.interpretResponse(invVideo); + expect(serverResponses).to.be.an('array').that.is.empty; + }); + it('Should return an empty array if invalid native response is passed', function () { + const invNative = { + body: [{ + mediaType: 'native', + clickUrl: 'test.com', + title: 'Test', + impressionTrackers: ['test.com'], + ttl: 120, + requestId: '23fhj33i987f', + creativeId: '2', + netRevenue: true, + currency: 'USD', + }] + }; + let serverResponses = spec.interpretResponse(invNative); + expect(serverResponses).to.be.an('array').that.is.empty; + }); + it('Should return an empty array if invalid response is passed', function () { + const invalid = { + body: [{ + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1' + }] + }; + let serverResponses = spec.interpretResponse(invalid); + expect(serverResponses).to.be.an('array').that.is.empty; + }); + }); + + describe('getUserSyncs', function() { + it('Should return array of objects with proper sync config , include GDPR', function() { + const syncData = spec.getUserSyncs({}, {}, { + consentString: 'ALL', + gdprApplies: true, + }, {}); + expect(syncData).to.be.an('array').which.is.not.empty; + expect(syncData[0]).to.be.an('object') + expect(syncData[0].type).to.be.a('string') + expect(syncData[0].type).to.equal('image') + expect(syncData[0].url).to.be.a('string') + expect(syncData[0].url).to.equal(`${syncUrl}/image?pbjs=1&gdpr=1&gdpr_consent=ALL&coppa=0`) + }); + it('Should return array of objects with proper sync config , include CCPA', function() { + const syncData = spec.getUserSyncs({}, {}, {}, { + consentString: '1---' + }); + expect(syncData).to.be.an('array').which.is.not.empty; + expect(syncData[0]).to.be.an('object') + expect(syncData[0].type).to.be.a('string') + expect(syncData[0].type).to.equal('image') + expect(syncData[0].url).to.be.a('string') + expect(syncData[0].url).to.equal(`${syncUrl}/image?pbjs=1&ccpa_consent=1---&coppa=0`) + }); + }); +}); diff --git a/test/spec/modules/yahoosspBidAdapter_spec.js b/test/spec/modules/yahoosspBidAdapter_spec.js index 32bc94b73fa..a326b22ecb4 100644 --- a/test/spec/modules/yahoosspBidAdapter_spec.js +++ b/test/spec/modules/yahoosspBidAdapter_spec.js @@ -3,6 +3,7 @@ import { config } from 'src/config.js'; import { BANNER, VIDEO } from 'src/mediaTypes.js'; import { spec } from 'modules/yahoosspBidAdapter.js'; import {createEidsArray} from '../../../modules/userId/eids'; +import {deepClone} from '../../../src/utils'; const DEFAULT_BID_ID = '84ab500420319d'; const DEFAULT_BID_DCN = '2093845709823475'; @@ -713,7 +714,7 @@ describe('YahooSSP Bid Adapter:', () => { }); }); - describe('GDPR & Consent:', () => { + describe('GDPR & Consent & GPP:', () => { it('should return request objects that do not send cookies if purpose 1 consent is not provided', () => { const { validBidRequests, bidderRequest } = generateBuildRequestMock({}); bidderRequest.gdprConsent = { @@ -731,6 +732,20 @@ describe('YahooSSP Bid Adapter:', () => { const options = spec.buildRequests(validBidRequests, bidderRequest)[0].options; expect(options.withCredentials).to.be.false; }); + + it('adds the ortb2 gpp consent info to the request', function () { + const { validBidRequests, bidderRequest } = generateBuildRequestMock({}); + const ortb2 = { + regs: { + gpp: 'somegppstring', + gpp_sid: [6, 7] + } + }; + let clonedBidderRequest = {...bidderRequest, ortb2}; + const data = spec.buildRequests(validBidRequests, clonedBidderRequest)[0].data; + expect(data.regs.ext.gpp).to.equal('somegppstring'); + expect(data.regs.ext.gpp_sid).to.eql([6, 7]); + }); }); describe('Endpoint & Impression Request Mode:', () => { @@ -857,7 +872,7 @@ describe('YahooSSP Bid Adapter:', () => { expect(data.user.ext.eids).to.deep.equal([ {source: 'admixer.net', uids: [{id: 'admixerId_FROM_USER_ID_MODULE', atype: 3}]}, {source: 'adtelligent.com', uids: [{id: 'adtelligentId_FROM_USER_ID_MODULE', atype: 3}]}, - {source: 'amxrtb.com', uids: [{id: 'amxId_FROM_USER_ID_MODULE', atype: 1}]}, + {source: 'amxdt.net', uids: [{id: 'amxId_FROM_USER_ID_MODULE', atype: 1}]}, {source: 'britepool.com', uids: [{id: 'britepoolid_FROM_USER_ID_MODULE', atype: 3}]}, {source: 'deepintent.com', uids: [{id: 'deepintentId_FROM_USER_ID_MODULE', atype: 3}]}, {source: 'epsilon.com', uids: [{id: 'publinkId_FROM_USER_ID_MODULE', atype: 3}]}, diff --git a/test/spec/modules/yandexBidAdapter_spec.js b/test/spec/modules/yandexBidAdapter_spec.js index eee53771a80..df91100b966 100644 --- a/test/spec/modules/yandexBidAdapter_spec.js +++ b/test/spec/modules/yandexBidAdapter_spec.js @@ -1,15 +1,14 @@ -import {assert, expect} from 'chai'; -import {spec} from 'modules/yandexBidAdapter.js'; -import {parseUrl} from 'src/utils.js'; -import {BANNER} from '../../../src/mediaTypes'; +import { assert, expect } from 'chai'; +import { spec } from 'modules/yandexBidAdapter.js'; +import { parseUrl } from 'src/utils.js'; +import { BANNER } from '../../../src/mediaTypes'; describe('Yandex adapter', function () { function getBidConfig() { return { bidder: 'yandex', params: { - pageId: 123, - impId: 1, + placementId: '123-1', }, }; } @@ -32,7 +31,7 @@ describe('Yandex adapter', function () { describe('isBidRequestValid', function () { it('should return true when required params found', function () { - const bid = getBidConfig(); + const bid = getBidRequest(); assert(spec.isBidRequestValid(bid)); }); @@ -40,18 +39,28 @@ describe('Yandex adapter', function () { expect(spec.isBidRequestValid({})).to.be.false; }); - it('should return false when required params.pageId are not passed', function () { + it('should return false when required params.placementId are not passed', function () { + const bid = getBidConfig(); + delete bid.params.placementId; + + expect(spec.isBidRequestValid(bid)).to.be.false; + }); + + it('should return false when required params.placementId are not valid', function () { const bid = getBidConfig(); - delete bid.params.pageId; + bid.params.placementId = '123'; - expect(spec.isBidRequestValid(bid)).to.be.false + expect(spec.isBidRequestValid(bid)).to.be.false; }); - it('should return false when required params.impId are not passed', function () { + it('should return true when passed deprecated placement config', function () { const bid = getBidConfig(); - delete bid.params.impId; + delete bid.params.placementId; + + bid.params.pageId = 123; + bid.params.impId = 1; - expect(spec.isBidRequestValid(bid)).to.be.false + expect(spec.isBidRequestValid(bid)); }); }); diff --git a/test/spec/modules/yieldlabBidAdapter_spec.js b/test/spec/modules/yieldlabBidAdapter_spec.js index 4c39fe5fe29..e5151cf789c 100644 --- a/test/spec/modules/yieldlabBidAdapter_spec.js +++ b/test/spec/modules/yieldlabBidAdapter_spec.js @@ -1,7 +1,7 @@ import { config } from 'src/config.js'; -import { expect } from 'chai' -import { spec } from 'modules/yieldlabBidAdapter.js' -import { newBidder } from 'src/adapters/bidderFactory.js' +import { expect } from 'chai'; +import { spec } from 'modules/yieldlabBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; const DEFAULT_REQUEST = () => ({ bidder: 'yieldlab', @@ -11,11 +11,11 @@ const DEFAULT_REQUEST = () => ({ targeting: { key1: 'value1', key2: 'value2', - notDoubleEncoded: 'value3,value4' + notDoubleEncoded: 'value3,value4', }, customParams: { extraParam: true, - foo: 'bar' + foo: 'bar', }, extId: 'abc', iabContent: { @@ -31,8 +31,8 @@ const DEFAULT_REQUEST = () => ({ cat: ['cat1', 'cat2,ppp', 'cat3|||//'], context: '7', keywords: ['k1,', 'k2..'], - live: '0' - } + live: '0', + }, }, bidderRequestId: '143346cf0f1731', auctionId: '2e41f65424c87c', @@ -43,8 +43,14 @@ const DEFAULT_REQUEST = () => ({ source: 'netid.de', uids: [{ id: 'fH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg', - atype: 1 - }] + atype: 1, + }], + }, { + source: 'digitrust.de', + uids: [{ + id: 'd8aa10fa-d86c-451d-aad8-5f16162a9e64', + atype: 2, + }], }], schain: { ver: '1.0', @@ -53,32 +59,107 @@ const DEFAULT_REQUEST = () => ({ { asi: 'indirectseller.com', sid: '1', - hp: 1 + hp: 1, }, { asi: 'indirectseller2.com', name: 'indirectseller2 name with comma , and bang !', sid: '2', - hp: 1 - } - ] - } -}) + hp: 1, + }, + ], + }, +}); const VIDEO_REQUEST = () => Object.assign(DEFAULT_REQUEST(), { mediaTypes: { video: { playerSize: [[640, 480]], - context: 'instream' - } - } -}) + context: 'instream', + }, + }, +}); const NATIVE_REQUEST = () => Object.assign(DEFAULT_REQUEST(), { mediaTypes: { - native: {} - } -}) + native: {}, + }, +}); + +const IAB_REQUEST = () => Object.assign(DEFAULT_REQUEST(), { + params: { + adslotId: '1111', + supplyId: '2222', + iabContent: { + id: 'foo', + episode: '99', + title: 'bar', + series: 'baz', + season: 's01', + artist: 'foobar', + genre: 'barbaz', + isrc: 'CC-XXX-YY-NNNNN', + url: 'https://foo.test', + cat: ['cat1', 'cat2,ppp', 'cat3|||//'], + context: '2', + keywords: ['k1', 'k2', 'k3', 'k4'], + live: '0', + album: 'foo', + cattax: '3', + prodq: 2, + contentrating: 'foo', + userrating: 'bar', + qagmediarating: 2, + sourcerelationship: 1, + len: 12345, + language: 'en', + embeddable: 0, + producer: { + id: 'foo', + name: 'bar', + cattax: 532, + cat: [1, 'foo', true], + domain: 'producer.test', + }, + data: { + id: 'foo', + name: 'bar', + segment: [{ + name: 'foo', + value: 'bar', + ext: { + foo: { + bar: 'bar', + }, + }, + }, { + name: 'foo2', + value: 'bar2', + ext: { + test: { + nums: { + int: 123, + float: 123.123, + }, + bool: true, + string: 'foo2', + }, + }, + }], + }, + network: { + id: 'foo', + name: 'bar', + domain: 'network.test', + }, + channel: { + id: 'bar', + name: 'foo', + domain: 'channel.test', + }, + }, + }, +}); const RESPONSE = { advertiser: 'yieldlab', @@ -88,177 +169,231 @@ const RESPONSE = { price: 1, pid: 2222, adsize: '728x90', - adtype: 'BANNER' -} + adtype: 'BANNER', +}; const NATIVE_RESPONSE = Object.assign({}, RESPONSE, { adtype: 'NATIVE', native: { link: { - url: 'https://www.yieldlab.de' + url: 'https://www.yieldlab.de', }, assets: [ { id: 1, title: { - text: 'This is a great headline' - } + text: 'This is a great headline', + }, }, { id: 2, img: { url: 'https://localhost:8080/yl-logo100x100.jpg', w: 100, - h: 100 - } + h: 100, + }, }, { id: 3, data: { - value: 'Native body value' - } - } + value: 'Native body value', + }, + }, ], imptrackers: [ 'http://localhost:8080/ve?d=ODE9ZSY2MTI1MjAzNjMzMzYxPXN0JjA0NWUwZDk0NTY5Yi05M2FiLWUwZTQtOWFjNy1hYWY0MzFiZj1kaXQmMj12', 'http://localhost:8080/md/1111/9efa4e76-2030-4f04-bb9f-322541f8d611?mdata=false&pvid=false&ids=x:1', - 'http://localhost:8080/imp?s=13216&d=2171514&a=12548955&ts=1633363025216&tid=fb134faa-7ca9-4e0e-ba39-b96549d0e540&l=0' - ] - } -}) + 'http://localhost:8080/imp?s=13216&d=2171514&a=12548955&ts=1633363025216&tid=fb134faa-7ca9-4e0e-ba39-b96549d0e540&l=0', + ], + }, +}); const VIDEO_RESPONSE = Object.assign({}, RESPONSE, { - adtype: 'VIDEO' -}) + adtype: 'VIDEO', +}); const PVID_RESPONSE = Object.assign({}, VIDEO_RESPONSE, { - pvid: '43513f11-55a0-4a83-94e5-0ebc08f54a2c' -}) + pvid: '43513f11-55a0-4a83-94e5-0ebc08f54a2c', +}); const REQPARAMS = { json: true, - ts: 1234567890 -} + ts: 1234567890, +}; const REQPARAMS_GDPR = Object.assign({}, REQPARAMS, { gdpr: true, - consent: 'BN5lERiOMYEdiAKAWXEND1AAAAE6DABACMA' -}) + consent: 'BN5lERiOMYEdiAKAWXEND1AAAAE6DABACMA', +}); const REQPARAMS_IAB_CONTENT = Object.assign({}, REQPARAMS, { - iab_content: 'id%3Afoo_id%2Cepisode%3A99%2Ctitle%3Afoo_title%252Cbar_title%2Cseries%3Afoo_series%2Cseason%3As1%2Cartist%3Afoo%2520bar%2Cgenre%3Abaz%2Cisrc%3ACC-XXX-YY-NNNNN%2Curl%3Ahttp%253A%252F%252Ffoo_url.de%2Ccat%3Acat1%7Ccat2%252Cppp%7Ccat3%257C%257C%257C%252F%252F%2Ccontext%3A7%2Ckeywords%3Ak1%252C%7Ck2..%2Clive%3A0' -}) + iab_content: 'id%3Afoo_id%2Cepisode%3A99%2Ctitle%3Afoo_title%252Cbar_title%2Cseries%3Afoo_series%2Cseason%3As1%2Cartist%3Afoo%2520bar%2Cgenre%3Abaz%2Cisrc%3ACC-XXX-YY-NNNNN%2Curl%3Ahttp%253A%252F%252Ffoo_url.de%2Ccat%3Acat1%7Ccat2%252Cppp%7Ccat3%257C%257C%257C%252F%252F%2Ccontext%3A7%2Ckeywords%3Ak1%252C%7Ck2..%2Clive%3A0', +}); describe('yieldlabBidAdapter', () => { describe('instantiation from spec', () => { it('is working properly', () => { - const yieldlabBidAdapter = newBidder(spec) - expect(yieldlabBidAdapter.callBids).to.exist.and.to.be.a('function') - }) - }) + const yieldlabBidAdapter = newBidder(spec); + expect(yieldlabBidAdapter.callBids).to.exist.and.to.be.a('function'); + }); + }); describe('isBidRequestValid', () => { it('should return true when all required parameters are found', () => { const request = { params: { adslotId: '1111', - supplyId: '2222' - } - } - expect(spec.isBidRequestValid(request)).to.equal(true) - }) + supplyId: '2222', + }, + }; + expect(spec.isBidRequestValid(request)).to.equal(true); + }); it('should return false when required parameters are missing', () => { - expect(spec.isBidRequestValid({})).to.equal(false) - }) - }) + expect(spec.isBidRequestValid({})).to.equal(false); + }); + }); describe('buildRequests', () => { - const bidRequests = [DEFAULT_REQUEST()] + const bidRequests = [DEFAULT_REQUEST()]; describe('default functionality', () => { - let request + let request; before(() => { - request = spec.buildRequests(bidRequests) - }) + request = spec.buildRequests(bidRequests); + }); it('sends bid request to ENDPOINT via GET', () => { - expect(request.method).to.equal('GET') - }) + expect(request.method).to.equal('GET'); + }); it('returns a list of valid requests', () => { - expect(request.validBidRequests).to.eql(bidRequests) - }) + expect(request.validBidRequests).to.eql(bidRequests); + }); it('passes single-encoded targeting to bid request', () => { - expect(request.url).to.include('t=key1%3Dvalue1%26key2%3Dvalue2%26notDoubleEncoded%3Dvalue3%2Cvalue4') - }) + expect(request.url).to.include('t=key1%3Dvalue1%26key2%3Dvalue2%26notDoubleEncoded%3Dvalue3%2Cvalue4'); + }); it('passes userids to bid request', () => { - expect(request.url).to.include('ids=netid.de%3AfH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg') - }) + expect(request.url).to.include('ids=netid.de%3AfH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg%2Cdigitrust.de%3Ad8aa10fa-d86c-451d-aad8-5f16162a9e64'); + }); + + it('passes atype to bid request', () => { + expect(request.url).to.include('atypes=netid.de%3A1%2Cdigitrust.de%3A2'); + }); it('passes extra params to bid request', () => { - expect(request.url).to.include('extraParam=true&foo=bar') - }) + expect(request.url).to.include('extraParam=true&foo=bar'); + }); it('passes unencoded schain string to bid request', () => { - expect(request.url).to.include('schain=1.0,1!indirectseller.com,1,1,,,,!indirectseller2.com,2,1,,indirectseller2%20name%20with%20comma%20%2C%20and%20bang%20%21,,') - }) + expect(request.url).to.include('schain=1.0,1!indirectseller.com,1,1,,,,!indirectseller2.com,2,1,,indirectseller2%20name%20with%20comma%20%2C%20and%20bang%20%21,,'); + }); it('passes iab_content string to bid request', () => { - expect(request.url).to.include('iab_content=id%3Afoo_id%2Cepisode%3A99%2Ctitle%3Afoo_title%252Cbar_title%2Cseries%3Afoo_series%2Cseason%3As1%2Cartist%3Afoo%2520bar%2Cgenre%3Abaz%2Cisrc%3ACC-XXX-YY-NNNNN%2Curl%3Ahttp%253A%252F%252Ffoo_url.de%2Ccat%3Acat1%7Ccat2%252Cppp%7Ccat3%257C%257C%257C%252F%252F%2Ccontext%3A7%2Ckeywords%3Ak1%252C%7Ck2..%2Clive%3A0') - }) + expect(request.url).to.include('iab_content=id%3Afoo_id%2Cepisode%3A99%2Ctitle%3Afoo_title%252Cbar_title%2Cseries%3Afoo_series%2Cseason%3As1%2Cartist%3Afoo%2520bar%2Cgenre%3Abaz%2Cisrc%3ACC-XXX-YY-NNNNN%2Curl%3Ahttp%253A%252F%252Ffoo_url.de%2Ccat%3Acat1%7Ccat2%252Cppp%7Ccat3%257C%257C%257C%252F%252F%2Ccontext%3A7%2Ckeywords%3Ak1%252C%7Ck2..%2Clive%3A0'); + }); it('passes correct size to bid request', () => { - expect(request.url).to.include('728x90') - }) + expect(request.url).to.include('728x90'); + }); it('passes external id to bid request', () => { - expect(request.url).to.include('id=abc') - }) - }) + expect(request.url).to.include('id=abc'); + }); + }); describe('iab_content handling', () => { const siteConfig = { ortb2: { site: { content: { - id: 'id_from_config' - } - } - } - } + id: 'id_from_config', + }, + }, + }, + }; beforeEach(() => { - config.setConfig(siteConfig) - }) + config.setConfig(siteConfig); + }); afterEach(() => { - config.resetConfig() - }) + config.resetConfig(); + }); it('generates iab_content string from bidder params', () => { - const request = spec.buildRequests(bidRequests) - expect(request.url).to.include('iab_content=id%3Afoo_id%2Cepisode%3A99%2Ctitle%3Afoo_title%252Cbar_title%2Cseries%3Afoo_series%2Cseason%3As1%2Cartist%3Afoo%2520bar%2Cgenre%3Abaz%2Cisrc%3ACC-XXX-YY-NNNNN%2Curl%3Ahttp%253A%252F%252Ffoo_url.de%2Ccat%3Acat1%7Ccat2%252Cppp%7Ccat3%257C%257C%257C%252F%252F%2Ccontext%3A7%2Ckeywords%3Ak1%252C%7Ck2..%2Clive%3A0') - }) + const request = spec.buildRequests(bidRequests); + expect(request.url).to.include('iab_content=id%3Afoo_id%2Cepisode%3A99%2Ctitle%3Afoo_title%252Cbar_title%2Cseries%3Afoo_series%2Cseason%3As1%2Cartist%3Afoo%2520bar%2Cgenre%3Abaz%2Cisrc%3ACC-XXX-YY-NNNNN%2Curl%3Ahttp%253A%252F%252Ffoo_url.de%2Ccat%3Acat1%7Ccat2%252Cppp%7Ccat3%257C%257C%257C%252F%252F%2Ccontext%3A7%2Ckeywords%3Ak1%252C%7Ck2..%2Clive%3A0'); + }); it('generates iab_content string from first party data if not provided in bidder params', () => { - const requestWithoutIabContent = DEFAULT_REQUEST() - delete requestWithoutIabContent.params.iabContent - - const request = spec.buildRequests([{...requestWithoutIabContent, ...siteConfig}]) - expect(request.url).to.include('iab_content=id%3Aid_from_config') - }) - }) + const requestWithoutIabContent = DEFAULT_REQUEST(); + delete requestWithoutIabContent.params.iabContent; + + const request = spec.buildRequests([{...requestWithoutIabContent, ...siteConfig}]); + expect(request.url).to.include('iab_content=id%3Aid_from_config'); + }); + + it('flattens the iabContent, encodes the values, joins the keywords into one value, and than encodes the iab_content request param ', () => { + const expectedIabContentValue = encodeURIComponent( + 'id:foo,' + + 'episode:99,' + + 'title:bar,' + + 'series:baz,' + + 'season:s01,' + + 'artist:foobar,' + + 'genre:barbaz,' + + 'isrc:CC-XXX-YY-NNNNN,' + + 'url:https%3A%2F%2Ffoo.test,' + + 'cat:cat1|cat2%2Cppp|cat3%7C%7C%7C%2F%2F,' + + 'context:2,' + + 'keywords:k1|k2|k3|k4,' + + 'live:0,' + + 'album:foo,' + + 'cattax:3,' + + 'prodq:2,' + + 'contentrating:foo,' + + 'userrating:bar,' + + 'qagmediarating:2,' + + 'sourcerelationship:1,' + + 'len:12345,' + + 'language:en,' + + 'embeddable:0,' + + 'producer.id:foo,' + + 'producer.name:bar,' + + 'producer.cattax:532,' + + 'cat:1|foo|true,' + + 'producer.domain:producer.test,' + + 'data.id:foo,data.name:bar,' + + 'data.segment.0.name:foo,' + + 'data.segment.0.value:bar,' + + 'data.segment.0.ext.foo.bar:bar,' + + 'data.segment.1.name:foo2,' + + 'data.segment.1.value:bar2,' + + 'data.segment.1.ext.test.nums.int:123,' + + 'data.segment.1.ext.test.nums.float:123.123,' + + 'data.segment.1.ext.test.bool:true,' + + 'data.segment.1.ext.test.string:foo2,' + + 'network.id:foo,network.name:bar,' + + 'network.domain:network.test,' + + 'channel.id:bar,' + + 'channel.name:foo,' + + 'channel.domain:channel.test' + ); + const request = spec.buildRequests([IAB_REQUEST()], REQPARAMS); + expect(request.url).to.include('iab_content=' + expectedIabContentValue); + }); + }); it('passes unencoded schain string to bid request when complete == 0', () => { - const schainRequest = DEFAULT_REQUEST() + const schainRequest = DEFAULT_REQUEST(); schainRequest.schain.complete = 0; // - const request = spec.buildRequests([schainRequest]) - expect(request.url).to.include('schain=1.0,0!indirectseller.com,1,1,,,,!indirectseller2.com,2,1,,indirectseller2%20name%20with%20comma%20%2C%20and%20bang%20%21,,') - }) + const request = spec.buildRequests([schainRequest]); + expect(request.url).to.include('schain=1.0,0!indirectseller.com,1,1,,,,!indirectseller2.com,2,1,,indirectseller2%20name%20with%20comma%20%2C%20and%20bang%20%21,,'); + }); it('passes encoded referer to bid request', () => { const refererRequest = spec.buildRequests(bidRequests, { @@ -267,123 +402,123 @@ describe('yieldlabBidAdapter', () => { numIframes: 0, reachedTop: true, page: 'https://www.yieldlab.de/test?with=querystring', - stack: ['https://www.yieldlab.de/test?with=querystring'] - } - }) + stack: ['https://www.yieldlab.de/test?with=querystring'], + }, + }); - expect(refererRequest.url).to.include('pubref=https%3A%2F%2Fwww.yieldlab.de%2Ftest%3Fwith%3Dquerystring') - }) + expect(refererRequest.url).to.include('pubref=https%3A%2F%2Fwww.yieldlab.de%2Ftest%3Fwith%3Dquerystring'); + }); it('passes gdpr flag and consent if present', () => { const gdprRequest = spec.buildRequests(bidRequests, { gdprConsent: { consentString: 'BN5lERiOMYEdiAKAWXEND1AAAAE6DABACMA', - gdprApplies: true - } - }) + gdprApplies: true, + }, + }); - expect(gdprRequest.url).to.include('consent=BN5lERiOMYEdiAKAWXEND1AAAAE6DABACMA') - expect(gdprRequest.url).to.include('gdpr=true') - }) + expect(gdprRequest.url).to.include('consent=BN5lERiOMYEdiAKAWXEND1AAAAE6DABACMA'); + expect(gdprRequest.url).to.include('gdpr=true'); + }); describe('sizes handling', () => { it('passes correct size to bid request for mediaType banner', () => { const bannerRequest = DEFAULT_REQUEST(); bannerRequest.mediaTypes = { banner: { - sizes: [[123, 456]] - } - } + sizes: [[123, 456]], + }, + }; // when mediaTypes is present it has precedence over the sizes field (728, 90) - let request = spec.buildRequests([bannerRequest], REQPARAMS) - expect(request.url).to.include('sizes') - expect(request.url).to.include('123x456') + let request = spec.buildRequests([bannerRequest], REQPARAMS); + expect(request.url).to.include('sizes'); + expect(request.url).to.include('123x456'); - bannerRequest.mediaTypes.banner.sizes = [123, 456] - request = spec.buildRequests([bannerRequest], REQPARAMS) - expect(request.url).to.include('123x456') + bannerRequest.mediaTypes.banner.sizes = [123, 456]; + request = spec.buildRequests([bannerRequest], REQPARAMS); + expect(request.url).to.include('123x456'); - bannerRequest.mediaTypes.banner.sizes = [[123, 456], [320, 240]] - request = spec.buildRequests([bannerRequest], REQPARAMS) - expect(request.url).to.include('123x456') - expect(request.url).to.include('320x240') - }) + bannerRequest.mediaTypes.banner.sizes = [[123, 456], [320, 240]]; + request = spec.buildRequests([bannerRequest], REQPARAMS); + expect(request.url).to.include('123x456'); + expect(request.url).to.include('320x240'); + }); it('passes correct sizes to bid request when mediaType is not present', () => { // information is taken from the top level sizes field const sizesRequest = DEFAULT_REQUEST(); - let request = spec.buildRequests([sizesRequest], REQPARAMS) - expect(request.url).to.include('sizes') - expect(request.url).to.include('728x90') + let request = spec.buildRequests([sizesRequest], REQPARAMS); + expect(request.url).to.include('sizes'); + expect(request.url).to.include('728x90'); - sizesRequest.sizes = [[728, 90]] - request = spec.buildRequests([sizesRequest], REQPARAMS) - expect(request.url).to.include('728x90') + sizesRequest.sizes = [[728, 90]]; + request = spec.buildRequests([sizesRequest], REQPARAMS); + expect(request.url).to.include('728x90'); - sizesRequest.sizes = [[728, 90], [320, 240]] - request = spec.buildRequests([sizesRequest], REQPARAMS) - expect(request.url).to.include('728x90') - }) + sizesRequest.sizes = [[728, 90], [320, 240]]; + request = spec.buildRequests([sizesRequest], REQPARAMS); + expect(request.url).to.include('728x90'); + }); it('does not pass the sizes parameter for mediaType video', () => { const videoRequest = VIDEO_REQUEST(); - let request = spec.buildRequests([videoRequest], REQPARAMS) - expect(request.url).to.not.include('sizes') - }) + let request = spec.buildRequests([videoRequest], REQPARAMS); + expect(request.url).to.not.include('sizes'); + }); it('does not pass the sizes parameter for mediaType native', () => { const nativeRequest = NATIVE_REQUEST(); - let request = spec.buildRequests([nativeRequest], REQPARAMS) - expect(request.url).to.not.include('sizes') - }) - }) - }) + let request = spec.buildRequests([nativeRequest], REQPARAMS); + expect(request.url).to.not.include('sizes'); + }); + }); + }); describe('interpretResponse', () => { - let bidRequest + let bidRequest; before(() => { - bidRequest = DEFAULT_REQUEST() - }) + bidRequest = DEFAULT_REQUEST(); + }); it('handles nobid responses', () => { - expect(spec.interpretResponse({body: {}}, {validBidRequests: []}).length).to.equal(0) - expect(spec.interpretResponse({body: []}, {validBidRequests: []}).length).to.equal(0) - }) + expect(spec.interpretResponse({body: {}}, {validBidRequests: []}).length).to.equal(0); + expect(spec.interpretResponse({body: []}, {validBidRequests: []}).length).to.equal(0); + }); it('should get correct bid response', () => { - const result = spec.interpretResponse({body: [RESPONSE]}, {validBidRequests: [bidRequest], queryParams: REQPARAMS}) - - expect(result[0].requestId).to.equal('2d925f27f5079f') - expect(result[0].cpm).to.equal(0.01) - expect(result[0].width).to.equal(728) - expect(result[0].height).to.equal(90) - expect(result[0].creativeId).to.equal('1111') - expect(result[0].dealId).to.equal(2222) - expect(result[0].currency).to.equal('EUR') - expect(result[0].netRevenue).to.equal(false) - expect(result[0].ttl).to.equal(300) - expect(result[0].referrer).to.equal('') - expect(result[0].meta.advertiserDomains).to.equal('yieldlab') - expect(result[0].ad).to.include('', + privacyLink: 'https://privacy-link.example', ext: { foo: 'foo-value', baz: 'baz-value', @@ -98,9 +100,18 @@ const ortbBid = { privacy: 'https://privacy-link.example', ver: '1.2' } - }, + } }; +const completeNativeBid = { + adId: '123', + transactionId: 'au', + native: { + ...bid.native, + ...ortbBid.native + } +} + const ortbRequest = { assets: [ { @@ -224,6 +235,14 @@ describe('native.js', function () { expect(targeting.hb_native_baz).to.equal('hb_native_baz:123'); }); + it('sends placeholdes targetings with ortb native response', function () { + const targeting = getNativeTargeting(completeNativeBid); + + expect(targeting[CONSTANTS.NATIVE_KEYS.title]).to.equal('Native Creative'); + expect(targeting[CONSTANTS.NATIVE_KEYS.body]).to.equal('Cool description great stuff'); + expect(targeting[CONSTANTS.NATIVE_KEYS.clickUrl]).to.equal('https://www.link.example'); + }); + it('should only include native targeting keys with values', function () { const adUnit = { transactionId: 'au', @@ -302,6 +321,10 @@ describe('native.js', function () { required: false, sendTargetingKeys: false, }, + privacyLink: { + required: false, + sendTargetingKeys: false, + }, ext: { foo: { required: false, @@ -348,6 +371,7 @@ describe('native.js', function () { CONSTANTS.NATIVE_KEYS.icon, CONSTANTS.NATIVE_KEYS.sponsoredBy, CONSTANTS.NATIVE_KEYS.clickUrl, + CONSTANTS.NATIVE_KEYS.privacyLink, CONSTANTS.NATIVE_KEYS.rendererUrl, ]); @@ -380,6 +404,7 @@ describe('native.js', function () { CONSTANTS.NATIVE_KEYS.icon, CONSTANTS.NATIVE_KEYS.sponsoredBy, CONSTANTS.NATIVE_KEYS.clickUrl, + CONSTANTS.NATIVE_KEYS.privacyLink, ]); expect(bid.native.adTemplate).to.deep.equal( @@ -437,9 +462,9 @@ describe('native.js', function () { adId: '123', }; - const message = getAllAssetsMessage(messageRequest, bid, {getNativeReq: () => null}); + const message = getAllAssetsMessage(messageRequest, bid); - expect(message.assets.length).to.equal(9); + expect(message.assets.length).to.equal(10); expect(message.assets).to.deep.include({ key: 'body', value: bid.native.body, @@ -485,7 +510,7 @@ describe('native.js', function () { adId: '123', }; - const message = getAllAssetsMessage(messageRequest, bidWithUndefinedFields, {getNativeReq: () => null}); + const message = getAllAssetsMessage(messageRequest, bidWithUndefinedFields); expect(message.assets.length).to.equal(4); expect(message.assets).to.deep.include({ @@ -506,16 +531,16 @@ describe('native.js', function () { }); }); - it('creates native all asset message with OpenRTB format', function () { + it('creates native all asset message with complete format', function () { const messageRequest = { message: 'Prebid Native', action: 'allAssetRequest', adId: '123', }; - const message = getAllAssetsMessage(messageRequest, ortbBid, {getNativeReq: () => ortbRequest}); + const message = getAllAssetsMessage(messageRequest, completeNativeBid); - expect(message.assets.length).to.equal(8); + expect(message.assets.length).to.equal(10); expect(message.assets).to.deep.include({ key: 'body', value: bid.native.body, @@ -548,6 +573,14 @@ describe('native.js', function () { key: 'privacyLink', value: ortbBid.native.ortb.privacy, }); + expect(message.assets).to.deep.include({ + key: 'foo', + value: bid.native.ext.foo, + }); + expect(message.assets).to.deep.include({ + key: 'baz', + value: bid.native.ext.baz, + }); }); const SAMPLE_ORTB_REQUEST = toOrtbNativeRequest({ @@ -555,60 +588,39 @@ describe('native.js', function () { body: 'vbody' }); const SAMPLE_ORTB_RESPONSE = { - native: { - ortb: { - link: { - url: 'url' - }, - assets: [ - { - id: 0, - title: { - text: 'vtitle' - } - }, - { - id: 1, - data: { - value: 'vbody' - } - } - ] + link: { + url: 'url' + }, + assets: [ + { + id: 0, + title: { + text: 'vtitle' + } + }, + { + id: 1, + data: { + value: 'vbody' + } } - } + ], + eventtrackers: [ + { event: 1, method: 1, url: 'https://sampleurl.com' }, + { event: 1, method: 2, url: 'https://sampleurljs.com' } + ] } - describe('getAllAssetsMessage', () => { + describe('toLegacyResponse', () => { it('returns assets in legacy format for ortb responses', () => { - const actual = getAllAssetsMessage({}, SAMPLE_ORTB_RESPONSE, {getNativeReq: () => SAMPLE_ORTB_REQUEST}); - expect(actual.assets).to.eql([ - { - key: 'clickUrl', - value: 'url' - }, - { - key: 'title', - value: 'vtitle' - }, - { - key: 'body', - value: 'vbody' - }, - ]) + const actual = toLegacyResponse(SAMPLE_ORTB_RESPONSE, SAMPLE_ORTB_REQUEST); + expect(actual.body).to.equal('vbody'); + expect(actual.title).to.equal('vtitle'); + expect(actual.clickUrl).to.equal('url'); + expect(actual.javascriptTrackers).to.equal(''); + expect(actual.impressionTrackers.length).to.equal(1); + expect(actual.impressionTrackers[0]).to.equal('https://sampleurl.com'); }); }); - describe('getAssetsMessage', () => { - Object.entries({ - 'hb_native_title': {key: 'title', value: 'vtitle'}, - 'hb_native_body': {key: 'body', value: 'vbody'} - }).forEach(([tkey, assetVal]) => { - it(`returns ${tkey} asset in legacy format for ortb responses`, () => { - const actual = getAssetMessage({ - assets: [tkey] - }, SAMPLE_ORTB_RESPONSE, {getNativeReq: () => SAMPLE_ORTB_REQUEST}) - expect(actual.assets).to.eql([assetVal]) - }) - }) - }) }); describe('validate native openRTB', function () { diff --git a/test/spec/ortb2.5StrictTranslator/dsl_spec.js b/test/spec/ortb2.5StrictTranslator/dsl_spec.js new file mode 100644 index 00000000000..c9b4575bcd2 --- /dev/null +++ b/test/spec/ortb2.5StrictTranslator/dsl_spec.js @@ -0,0 +1,137 @@ +import {Arr, ERR_ENUM, ERR_TYPE, ERR_UNKNOWN_FIELD, IntEnum, Obj} from '../../../libraries/ortb2.5StrictTranslator/dsl.js'; +import {deepClone} from '../../../src/utils.js'; + +describe('DSL', () => { + const spec = (() => { + const inner = Obj(['p21', 'p22'], { + enum: IntEnum(10, 20), + enumArray: Arr(IntEnum(10, 20)) + }); + return Obj(['p11', 'p12'], { + inner, + innerArray: Arr(inner) + }); + })(); + + let onError; + + function scan(obj) { + spec(null, null, null, obj, onError); + } + + beforeEach(() => { + onError = sinon.stub(); + }); + + it('checks object type', () => { + scan(null); + sinon.assert.calledWith(onError, ERR_TYPE, null, null, null, null); + }); + it('ignores known fields and ext', () => { + scan({p11: 1, p12: 2, ext: {e1: 1, e2: 2}}); + sinon.assert.notCalled(onError); + }); + it('detects unknown fields', () => { + const obj = {p11: 1, unk: 2}; + scan(obj); + sinon.assert.calledOnce(onError); + sinon.assert.calledWith(onError, ERR_UNKNOWN_FIELD, 'unk', obj, 'unk', 2); + }); + describe('when nested', () => { + describe('directly', () => { + it('detects unknown fields', () => { + const obj = {inner: {p21: 1, unk: 2}}; + scan(obj); + sinon.assert.calledOnce(onError); + sinon.assert.calledWith(onError, ERR_UNKNOWN_FIELD, 'inner.unk', obj.inner, 'unk', 2); + }); + it('accepts enum values in range', () => { + scan({inner: {enum: 12}}); + sinon.assert.notCalled(onError); + }); + [Infinity, NaN, -Infinity].forEach(val => { + it(`does not accept ${val} in enum`, () => { + const obj = {inner: {enum: val}}; + scan(obj); + sinon.assert.calledOnce(onError); + sinon.assert.calledWith(onError, ERR_ENUM, 'inner.enum', obj.inner, 'enum', val); + }); + }); + it('accepts arrays of enums that are in range', () => { + scan({inner: {enumArray: [12, 13]}}); + sinon.assert.notCalled(onError); + }) + it('detects enum values out of range', () => { + const obj = {inner: {enum: -1}}; + scan(obj); + sinon.assert.calledOnce(onError); + sinon.assert.calledWith(onError, ERR_ENUM, 'inner.enum', obj.inner, 'enum', -1); + }); + it('detects enum values that are not numbers', () => { + const obj = {inner: {enum: 'err'}}; + scan(obj); + sinon.assert.calledOnce(onError); + sinon.assert.calledWith(onError, ERR_TYPE, 'inner.enum', obj.inner, 'enum', 'err'); + }) + it('detects arrays of enums that are out of range', () => { + const obj = {inner: {enumArray: [12, 13, -1, 14]}}; + scan(obj); + sinon.assert.calledOnce(onError); + sinon.assert.calledWith(onError, ERR_ENUM, 'inner.enumArray.2', obj.inner.enumArray, 2, -1); + }); + it('detects when enum arrays are not arrays', () => { + const obj = {inner: {enumArray: 'err'}}; + scan(obj); + sinon.assert.calledOnce(onError); + sinon.assert.calledWith(onError, ERR_TYPE, 'inner.enumArray', obj.inner, 'enumArray', 'err'); + }); + it('detects items within enum arrays that are not numbers', () => { + const obj = {inner: {enumArray: [12, 'err', 13]}}; + scan(obj); + sinon.assert.calledOnce(onError); + sinon.assert.calledWith(onError, ERR_TYPE, 'inner.enumArray.1', obj.inner.enumArray, 1, 'err'); + }) + }); + describe('into arrays', () => { + it('detects if inner array is not an array', () => { + const obj = {innerArray: 'err', inner: {p21: 1}}; + scan(obj); + sinon.assert.calledOnce(onError); + sinon.assert.calledWith(onError, ERR_TYPE, 'innerArray', obj, 'innerArray', 'err'); + }); + it('detects when elements of inner array are not objects', () => { + const obj = {innerArray: [{p21: 1}, 'err', {ext: {r: 1}}]}; + scan(obj); + sinon.assert.calledOnce(onError); + sinon.assert.calledWith(onError, ERR_TYPE, 'innerArray.1', obj.innerArray, 1, 'err'); + }); + const oos = { + innerArray: [ + {p22: 2, unk: 3, enumArray: [-1, 12, 'err']}, + {p21: 1, enum: -1, ext: {e: 1}}, + ] + }; + it('detects invalid properties within inner array', () => { + const obj = deepClone(oos); + scan(obj); + sinon.assert.calledWith(onError, ERR_UNKNOWN_FIELD, 'innerArray.0.unk', obj.innerArray[0], 'unk', 3); + sinon.assert.calledWith(onError, ERR_ENUM, 'innerArray.0.enumArray.0', obj.innerArray[0].enumArray, 0, -1); + sinon.assert.calledWith(onError, ERR_TYPE, 'innerArray.0.enumArray.2', obj.innerArray[0].enumArray, 2, 'err'); + sinon.assert.calledWith(onError, ERR_ENUM, 'innerArray.1.enum', obj.innerArray[1], 'enum', -1); + }); + it('can remove all invalid properties during scan', () => { + onError.callsFake((errno, path, obj, field) => { + Array.isArray(obj) ? obj.splice(field, 1) : delete obj[field]; + }); + const obj = deepClone(oos); + scan(obj); + expect(obj).to.eql({ + innerArray: [ + {p22: 2, enumArray: [12]}, + {p21: 1, ext: {e: 1}} + ] + }); + }) + }) + }) +}); diff --git a/test/spec/ortb2.5StrictTranslator/spec_spec.js b/test/spec/ortb2.5StrictTranslator/spec_spec.js new file mode 100644 index 00000000000..a54b551bf61 --- /dev/null +++ b/test/spec/ortb2.5StrictTranslator/spec_spec.js @@ -0,0 +1,358 @@ +import {BidRequest} from '../../../libraries/ortb2.5StrictTranslator/spec.js'; + +// sample requests taken from ORTB 2.5 spec: https://www.iab.com/wp-content/uploads/2016/03/OpenRTB-API-Specification-Version-2-5-FINAL.pdf +const SAMPLE_REQUESTS = [ + { + 'id': '80ce30c53c16e6ede735f123ef6e32361bfc7b22', + 'at': 1, + 'cur': ['USD'], + 'imp': [ + { + 'id': '1', + 'bidfloor': 0.03, + 'banner': { + 'h': 250, 'w': 300, 'pos': 0 + } + } + ], + 'site': { + 'id': '102855', + 'cat': ['IAB3-1'], + 'domain': 'www.foobar.com', + 'page': 'http://www.foobar.com/1234.html ', + 'publisher': { + 'id': '8953', + 'name': 'foobar.com', + 'cat': ['IAB3-1'], + 'domain': 'foobar.com' + } + }, + 'device': { + 'ua': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.13 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2', + 'ip': '123.145.167.10' + }, + 'user': { + 'id': '55816b39711f9b5acf3b90e313ed29e51665623f' + } + }, + { + 'id': '123456789316e6ede735f123ef6e32361bfc7b22', + 'at': 2, + 'cur': ['USD'], + 'imp': [ + { + 'id': '1', + 'bidfloor': 0.03, + 'iframebuster': ['vendor1.com', 'vendor2.com'], + 'banner': { + 'h': 250, + 'w': 300, + 'pos': 0, + 'battr': [13], + 'expdir': [2, 4] + } + } + ], + 'site': { + 'id': '102855', + 'cat': ['IAB3-1'], + 'domain': 'www.foobar.com', + 'page': 'http://www.foobar.com/1234.html', + 'publisher': { + 'id': '8953', + 'name': 'foobar.com', + 'cat': ['IAB3-1'], + 'domain': 'foobar.com' + } + }, + 'device': { + 'ua': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.13 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2', + 'ip': '123.145.167.10' + }, + 'user': { + 'id': '55816b39711f9b5acf3b90e313ed29e51665623f', + 'buyeruid': '545678765467876567898765678987654', + 'data': [ + { + 'id': '6', + 'name': 'Data Provider 1', + 'segment': [ + { + 'id': '12341318394918', 'name': 'auto intenders' + }, + { + 'id': '1234131839491234', 'name': 'auto enthusiasts' + }, + { + 'id': '23423424', + 'name': 'data-provider1-age', + 'value': '30-40' + } + ] + } + ] + } + }, + { + 'id': 'IxexyLDIIk', + 'at': 2, + 'bcat': ['IAB25', 'IAB7-39', 'IAB8-18', 'IAB8-5', 'IAB9-9'], + 'badv': ['apple.com', 'go-text.me', 'heywire.com'], + 'imp': [ + { + 'id': '1', + 'bidfloor': 0.5, + 'instl': 0, + 'tagid': 'agltb3B1Yi1pbmNyDQsSBFNpdGUY7fD0FAw', + 'banner': { + 'w': 728, + 'h': 90, + 'pos': 1, + 'btype': [4], + 'battr': [14], + 'api': [3] + } + } + ], + 'app': { + 'id': 'agltb3B1Yi1pbmNyDAsSA0FwcBiJkfIUDA', + 'name': 'Yahoo Weather', + 'cat': ['IAB15', 'IAB15-10'], + 'ver': '1.0.2', + 'bundle': '12345', + 'storeurl': 'https://itunes.apple.com/id628677149', + 'publisher': { + 'id': 'agltb3B1Yi1pbmNyDAsSA0FwcBiJkfTUCV', + 'name': 'yahoo', + 'domain': 'www.yahoo.com' + } + }, + 'device': { + 'dnt': 0, + 'ua': 'Mozilla/5.0 (iPhone; CPU iPhone OS 6_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3', + 'ip': '123.145.167.189', + 'ifa': 'AA000DFE74168477C70D291f574D344790E0BB11', + 'carrier': 'VERIZON', + 'language': 'en', + 'make': 'Apple', + 'model': 'iPhone', + 'os': 'iOS', + 'osv': '6.1', + 'js': 1, + 'connectiontype': 3, + 'devicetype': 1, + 'geo': { + 'lat': 35.012345, + 'lon': -115.12345, + 'country': 'USA', + 'metro': '803', + 'region': 'CA', + 'city': 'Los Angeles', + 'zip': '90049' + } + }, + 'user': { + 'id': 'ffffffd5135596709273b3a1a07e466ea2bf4fff', + 'yob': 1984, + 'gender': 'M' + } + }, + { + 'id': '1234567893', + 'at': 2, + 'tmax': 120, + 'imp': [ + { + 'id': '1', + 'bidfloor': 0.03, + 'video': { + 'w': 640, + 'h': 480, + 'pos': 1, + 'startdelay': 0, + 'minduration': 5, + 'maxduration': 30, + 'maxextended': 30, + 'minbitrate': 300, + 'maxbitrate': 1500, + 'api': [1, 2], + 'protocols': [2, 3], + 'mimes': [ + 'video/x-flv', + 'video/mp4', + 'application/x-shockwave-flash', + 'application/javascript' + ], + 'linearity': 1, + 'boxingallowed': 1, + 'playbackmethod': [1, 3], + 'delivery': [2], + 'battr': [13, 14], + 'companionad': [ + { + 'id': '1234567893-1', + 'w': 300, + 'h': 250, + 'pos': 1, + 'battr': [13, 14], + 'expdir': [2, 4] + }, + { + 'id': '1234567893-2', + 'w': 728, + 'h': 90, + 'pos': 1, + 'battr': [13, 14] + } + ], + 'companiontype': [1, 2] + } + } + ], + 'site': { + 'id': '1345135123', + 'name': 'Site ABCD', + 'domain': 'siteabcd.com', + 'cat': ['IAB2-1', 'IAB2-2'], + 'page': 'http://siteabcd.com/page.htm', + 'ref': 'http://referringsite.com/referringpage.htm', + 'privacypolicy': 1, + 'publisher': { + 'id': 'pub12345', 'name': 'Publisher A' + }, + 'content': { + 'id': '1234567', + 'series': 'All About Cars', + 'season': '2', + 'episode': 23, + 'title': 'Car Show', + 'cat': ['IAB2-2'], + 'keywords': 'keyword-a,keyword-b,keyword-c' + } + }, + 'device': { + 'ip': '64.124.253.1', + 'ua': 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16', + 'os': 'OS X', + 'flashver': '10.1', + 'js': 1 + }, + 'user': { + 'id': '456789876567897654678987656789', + 'buyeruid': '545678765467876567898765678987654', + 'data': [ + { + 'id': '6', + 'name': 'Data Provider 1', + 'segment': [ + { + 'id': '12341318394918', 'name': 'auto intenders' + }, + { + 'id': '1234131839491234', 'name': 'auto enthusiasts' + } + ] + } + ] + } + }, + { + 'id': '80ce30c53c16e6ede735f123ef6e32361bfc7b22', + 'at': 1, + 'cur': ['USD'], + 'imp': [ + { + 'id': '1', + 'bidfloor': 0.03, + 'banner': { + 'h': 250, 'w': 300, 'pos': 0 + }, + 'pmp': { + 'private_auction': 1, + 'deals': [ + { + 'id': 'AB-Agency1-0001', + 'at': 1, + 'bidfloor': 2.5, + 'wseat': ['Agency1'] + }, + { + 'id': 'XY-Agency2-0001', + 'at': 2, + 'bidfloor': 2, + 'wseat': ['Agency2'] + } + ] + } + } + ], + 'site': { + 'id': '102855', + 'domain': 'www.foobar.com', + 'cat': ['IAB3-1'], + 'page': 'http://www.foobar.com/1234.html', + 'publisher': { + 'id': '8953', + 'name': 'foobar.com', + 'cat': ['IAB3-1'], + 'domain': 'foobar.com' + } + }, + 'device': { + 'ua': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.13 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2', + 'ip': '123.145.167.10' + }, + 'user': { + 'id': '55816b39711f9b5acf3b90e313ed29e51665623f' + } + }, +]; + +if (FEATURES.NATIVE) { + SAMPLE_REQUESTS.push({ + 'id': '80ce30c53c16e6ede735f123ef6e32361bfc7b22', + 'at': 1, + 'cur': ['USD'], + 'imp': [ + { + 'id': '1', + 'bidfloor': 0.03, + 'native': { + 'request': '{"native":{"ver":"1.0","assets":[ ... ]}}', + 'ver': '1.0', + 'api': [3], + 'battr': [13, 14] + } + } + ], + 'site': { + 'id': '102855', + 'cat': ['IAB3-1'], + 'domain': 'www.foobar.com', + 'page': 'http://www.foobar.com/1234.html ', + 'publisher': { + 'id': '8953', + 'name': 'foobar.com', + 'cat': ['IAB3-1'], + 'domain': 'foobar.com' + } + }, + 'device': { + 'ua': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.13 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2', + 'ip': '123.145.167.10' + }, + 'user': { + 'id': '55816b39711f9b5acf3b90e313ed29e51665623f' + } + }); +} + +describe('BidRequest spec', () => { + SAMPLE_REQUESTS.forEach((req, i) => { + it(`accepts sample #${i}`, () => { + const onError = sinon.stub(); + BidRequest(null, null, null, req, onError); + sinon.assert.notCalled(onError); + }); + }); +}); diff --git a/test/spec/ortb2.5StrictTranslator/translator_spec.js b/test/spec/ortb2.5StrictTranslator/translator_spec.js new file mode 100644 index 00000000000..4bda3d96235 --- /dev/null +++ b/test/spec/ortb2.5StrictTranslator/translator_spec.js @@ -0,0 +1,16 @@ +import {toOrtb25Strict} from '../../../libraries/ortb2.5StrictTranslator/translator.js'; + +describe('toOrtb25Strict', () => { + let translator; + beforeEach(() => { + translator = sinon.stub().callsFake((o) => o); + }) + it('uses provided translator', () => { + translator.reset(); + translator.callsFake(() => ({id: 'test'})); + expect(toOrtb25Strict(null, translator)).to.eql({id: 'test'}); + }); + it('removes fields out of spec', () => { + expect(toOrtb25Strict({unk: 'field', imp: ['err', {}]}, translator)).to.eql({imp: [{}]}); + }); +}); diff --git a/test/spec/ortb2.5Translator/translator_spec.js b/test/spec/ortb2.5Translator/translator_spec.js new file mode 100644 index 00000000000..db20a8f59be --- /dev/null +++ b/test/spec/ortb2.5Translator/translator_spec.js @@ -0,0 +1,64 @@ +import {EXT_PROMOTIONS, moveRule, splitPath, toOrtb25} from '../../../libraries/ortb2.5Translator/translator.js'; +import {deepAccess, deepClone, deepSetValue} from '../../../src/utils.js'; + +describe('ORTB 2.5 translation', () => { + describe('moveRule', () => { + const rule = moveRule('f1.f2.f3', (prefix, field) => `${prefix}.m1.m2.${field}`); + + function applyRule(rule, obj, del = true) { + obj = deepClone(obj); + const deleter = rule(obj); + if (typeof deleter === 'function' && del) { + deleter(); + } + return obj; + } + + it('returns undef when field is not present', () => { + expect(rule({})).to.eql(undefined); + }); + it('can copy field', () => { + expect(applyRule(rule, {f1: {f2: {f3: 'value'}}}, false)).to.eql({ + f1: { + f2: { + f3: 'value', + m1: {m2: {f3: 'value'}} + } + } + }); + }); + it('can move field', () => { + expect(applyRule(rule, {f1: {f2: {f3: 'value'}}}, true)).to.eql({f1: {f2: {m1: {m2: {f3: 'value'}}}}}); + }); + }); + describe('toOrtb25', () => { + EXT_PROMOTIONS.forEach(path => { + const newPath = (() => { + const [prefix, field] = splitPath(path); + return `${prefix}.ext.${field}`; + })(); + + it(`moves ${path} to ${newPath}`, () => { + const obj = {}; + deepSetValue(obj, path, 'val'); + toOrtb25(obj); + expect(deepAccess(obj, path)).to.eql(undefined); + expect(deepAccess(obj, newPath)).to.eql('val'); + }); + }); + it('moves kwarray into keywords', () => { + expect(toOrtb25({app: {keywords: 'k1,k2', kwarray: ['ka1', 'ka2']}})).to.eql({app: {keywords: 'k1,k2,ka1,ka2'}}); + }); + it('does not choke if kwarray is not an array', () => { + expect(toOrtb25({site: {keywords: 'k1,k2', kwarray: 'err'}})).to.eql({site: {keywords: 'k1,k2'}}); + }); + it('does not choke if keywords is not a string', () => { + expect(toOrtb25({user: {keywords: {}, kwarray: ['ka1', 'ka2']}})).to.eql({ + user: { + keywords: {}, + kwarray: ['ka1', 'ka2'] + } + }); + }); + }); +}); diff --git a/test/spec/ortbConverter/default_processors_spec.js b/test/spec/ortbConverter/default_processors_spec.js index 28a35390b86..48204b2c861 100644 --- a/test/spec/ortbConverter/default_processors_spec.js +++ b/test/spec/ortbConverter/default_processors_spec.js @@ -1,61 +1,23 @@ -import {setDevice, setSite} from '../../../libraries/ortbConverter/processors/default.js'; +import {onlyOneClientSection} from '../../../libraries/ortbConverter/processors/default.js'; -describe('setDevice', () => { - it('sets device.w, h, dnt, language, ua', () => { - const req = {}; - setDevice(req); - ['h', 'w', 'dnt', 'language', 'ua'].forEach(prop => expect(req.device[prop]).to.exist) - }); - - it('does not override FPD', () => { - const req = { - device: { - w: 'w', - h: 'h', - ext: {} - } - }; - setDevice(req); - sinon.assert.match(req.device, { - w: 'w', - h: 'h', - ext: {} +describe('onlyOneClientSection', () => { + [ + [['app'], 'app'], + [['site'], 'site'], + [['dooh'], 'dooh'], + [['app', 'site'], 'app'], + [['dooh', 'app', 'site'], 'dooh'], + [['dooh', 'site'], 'dooh'] + ].forEach(([sections, winner]) => { + it(`should leave only ${winner} in request when it contains ${sections.join(', ')}`, () => { + const req = Object.fromEntries(sections.map(s => [s, {foo: 'bar'}])); + onlyOneClientSection(req); + expect(Object.keys(req)).to.eql([winner]); }) }); -}); - -describe('setSite', () => { - const refererInfo = { - page: 'page.com', - ref: 'ref.com', - domain: 'domain.com' - }; - - it('sets site, domain, ref from refererInfo', () => { - const req = { - site: { - ext: {} - } - }; - setSite(req, {refererInfo}); - sinon.assert.match(req.site, refererInfo); - expect(req.site.ext).to.eql({}); - }); - - it('does not override FPD', () => { - const req = { - site: { - ref: 'other ref' - } - } - setSite(req, {refererInfo}); - expect(req.site.ref).to.eql('other ref'); - ['domain', 'page'].forEach(prop => expect(req.site[prop]).to.eql(refererInfo[prop])); - }); - - it('does not set null properties from refererInfo', () => { + it('should not choke if none of the sections are in the request', () => { const req = {}; - setSite(req, {refererInfo: {...refererInfo, ref: null}}); - expect(req.site.ref).to.not.exist; + onlyOneClientSection(req); + expect(req).to.eql({}); }); }); diff --git a/test/spec/ortbConverter/gdpr_spec.js b/test/spec/ortbConverter/gdpr_spec.js index 9851d7603b4..78fd1830438 100644 --- a/test/spec/ortbConverter/gdpr_spec.js +++ b/test/spec/ortbConverter/gdpr_spec.js @@ -1,33 +1,4 @@ -import {setOrtbAdditionalConsent, setOrtbGdpr} from '../../../modules/consentManagement.js'; - -describe('pbjs - ortb gpdr', () => { - it('sets gdpr properties from bidderRequest', () => { - const req = {}; - setOrtbGdpr(req, {gdprConsent: {gdprApplies: true, consentString: 'consent'}}); - expect(req.regs.ext.gdpr).to.eql(1); - expect(req.user.ext.consent).to.eql('consent'); - }); - - it('does not set it if missing', () => { - const req = {}; - setOrtbGdpr(req, {}); - expect(req).to.eql({}); - }); - - it('sets user.ext.consent, but not regs.ext.gdpr, if gpdrApplies is not a boolean', () => { - const req = {}; - setOrtbGdpr(req, { - gdprConsent: {consentString: 'mock-consent'} - }); - expect(req).to.eql({ - user: { - ext: { - consent: 'mock-consent' - } - } - }) - }); -}); +import {setOrtbAdditionalConsent} from '../../../modules/consentManagement.js'; describe('pbjs -> ortb addtlConsent', () => { it('sets ConsentedProvidersSettings', () => { diff --git a/test/spec/ortbConverter/pbsExtensions/adUnitCode_spec.js b/test/spec/ortbConverter/pbsExtensions/adUnitCode_spec.js new file mode 100644 index 00000000000..e17f9e856b0 --- /dev/null +++ b/test/spec/ortbConverter/pbsExtensions/adUnitCode_spec.js @@ -0,0 +1,23 @@ +import {setImpAdUnitCode} from '../../../../libraries/pbsExtensions/processors/adUnitCode.js'; + +describe('pbjs -> ortb adunit code to imp[].ext.prebid.adunitcode', () => { + function setImp(bidRequest) { + const imp = {}; + setImpAdUnitCode(imp, bidRequest); + return imp; + } + + it('it sets adunitcode in ext.prebid.adunitcode when adUnitCode is present', () => { + expect(setImp({bidder: 'mockBidder', adUnitCode: 'mockAdUnit'})).to.eql({ + 'ext': { + 'prebid': { + 'adunitcode': 'mockAdUnit' + } + } + }) + }); + + it('does not set adunitcode in ext.prebid.adunitcode if adUnit is undefined', () => { + expect(setImp({bidder: 'mockBidder'})).to.eql({}); + }); +}); diff --git a/test/spec/ortbConverter/usp_spec.js b/test/spec/ortbConverter/usp_spec.js deleted file mode 100644 index 01ff689cd97..00000000000 --- a/test/spec/ortbConverter/usp_spec.js +++ /dev/null @@ -1,15 +0,0 @@ -import {setOrtbUsp} from '../../../modules/consentManagementUsp.js'; - -describe('pbjs - ortb usp', () => { - it('sets regs.ext.us_privacy from bidderRequest', () => { - const req = {}; - setOrtbUsp(req, {uspConsent: '1NN'}); - expect(req.regs.ext.us_privacy).to.eql('1NN'); - }); - - it('does not set if missing', () => { - const req = {}; - setOrtbUsp(req, {}); - expect(req).to.eql({}); - }); -}) diff --git a/test/spec/refererDetection_spec.js b/test/spec/refererDetection_spec.js index 3f33d1646a1..a0ffc3eddbe 100644 --- a/test/spec/refererDetection_spec.js +++ b/test/spec/refererDetection_spec.js @@ -2,94 +2,7 @@ import {detectReferer, ensureProtocol, parseDomain} from 'src/refererDetection.j import {config} from 'src/config.js'; import {expect} from 'chai'; -/** - * Build a walkable linked list of window-like objects for testing. - * - * @param {Array} urls Array of URL strings starting from the top window. - * @param {string} [topReferrer] - * @param {string} [canonicalUrl] - * @param {boolean} [ancestorOrigins] - * @returns {Object} - */ -function buildWindowTree(urls, topReferrer = null, canonicalUrl = null, ancestorOrigins = false) { - /** - * Find the origin from a given fully-qualified URL. - * - * @param {string} url The fully qualified URL - * @returns {string|null} - */ - function getOrigin(url) { - const originRegex = new RegExp('^(https?://[^/]+/?)'); - - const result = originRegex.exec(url); - - if (result && result[0]) { - return result[0]; - } - - return null; - } - - const inaccessibles = []; - - let previousWindow, topWindow; - const topOrigin = getOrigin(urls[0]); - - const windowList = urls.map((url, index) => { - const thisOrigin = getOrigin(url), - sameOriginAsPrevious = index === 0 ? true : (getOrigin(urls[index - 1]) === thisOrigin), - sameOriginAsTop = thisOrigin === topOrigin; - - const win = { - location: { - href: url, - }, - document: { - referrer: index === 0 ? topReferrer : urls[index - 1] - } - }; - - if (topWindow == null) { - topWindow = win; - win.document.querySelector = function (selector) { - if (selector === 'link[rel=\'canonical\']') { - return { - href: canonicalUrl - }; - } - return null; - }; - } - - if (sameOriginAsPrevious) { - win.parent = previousWindow; - } else { - win.parent = inaccessibles[inaccessibles.length - 1]; - } - if (ancestorOrigins) { - win.location.ancestorOrigins = urls.slice(0, index).reverse().map(getOrigin); - } - win.top = sameOriginAsTop ? topWindow : inaccessibles[0]; - - const inWin = {parent: inaccessibles[inaccessibles.length - 1], top: inaccessibles[0]}; - if (index === 0) { - inWin.top = inWin; - } - ['document', 'location'].forEach((prop) => { - Object.defineProperty(inWin, prop, { - get: function () { - throw new Error('cross-origin access'); - } - }); - }); - inaccessibles.push(inWin); - previousWindow = win; - - return win; - }); - - return windowList[windowList.length - 1]; -} +import { buildWindowTree } from '../helpers/refererDetectionHelper'; describe('Referer detection', () => { afterEach(function () { @@ -128,11 +41,49 @@ describe('Referer detection', () => { numIframes: 0, stack: ['https://example.com/some/page'], canonicalUrl: 'https://example.com/canonical/page', - page: 'https://example.com/canonical/page', + page: 'https://example.com/some/page', ref: 'https://othersite.com/', domain: 'example.com' }); }); + + it('Should set page and canonical to pageUrl value set in config if present, even if canonical url is also present in head', () => { + config.setConfig({'pageUrl': 'https://www.set-from-config.com/path'}); + const testWindow = buildWindowTree(['https://example.com/some/page'], 'https://othersite.com/', 'https://example.com/canonical/page'), + result = detectReferer(testWindow)(); + + sinon.assert.match(result, { + topmostLocation: 'https://example.com/some/page', + location: 'https://example.com/some/page', + reachedTop: true, + isAmp: false, + numIframes: 0, + stack: ['https://example.com/some/page'], + canonicalUrl: 'https://www.set-from-config.com/path', + page: 'https://www.set-from-config.com/path', + ref: 'https://othersite.com/', + domain: 'www.set-from-config.com' + }); + }); + + it('Should set page with query params if canonical url is present without query params but the current page does have them', () => { + config.setConfig({'pageUrl': 'https://www.set-from-config.com/path'}); + const testWindow = buildWindowTree(['https://example.com/some/page?query1=123&query2=456'], 'https://othersite.com/', 'https://example.com/canonical/page'), + result = detectReferer(testWindow)(); + + sinon.assert.match(result, { + topmostLocation: 'https://example.com/some/page?query1=123&query2=456', + location: 'https://example.com/some/page?query1=123&query2=456', + reachedTop: true, + isAmp: false, + numIframes: 0, + stack: ['https://example.com/some/page?query1=123&query2=456'], + canonicalUrl: 'https://www.set-from-config.com/path', + page: 'https://www.set-from-config.com/path?query1=123&query2=456', + ref: 'https://othersite.com/', + domain: 'www.set-from-config.com' + }); + }); }); describe('Friendly iframes', () => { @@ -174,7 +125,7 @@ describe('Referer detection', () => { 'https://example.com/third/page' ], canonicalUrl: 'https://example.com/canonical/page', - page: 'https://example.com/canonical/page', + page: 'https://example.com/some/page', ref: 'https://othersite.com/', domain: 'example.com' }); @@ -317,7 +268,7 @@ describe('Referer detection', () => { 'https://ad-iframe.ampproject.org/ad' ], canonicalUrl: 'https://example.com/some/page/', - page: 'https://example.com/some/page/', + page: 'https://example.com/some/page/amp/', ref: null, domain: 'example.com' }); @@ -344,7 +295,7 @@ describe('Referer detection', () => { 'https://ad-iframe.ampproject.org/ad' ], canonicalUrl: 'https://example.com/some/page/', - page: 'https://example.com/some/page/', + page: 'https://example.com/some/page/amp/', ref: null, domain: 'example.com' }); @@ -384,7 +335,7 @@ describe('Referer detection', () => { 'https://ad-iframe.ampproject.org/ad' ], canonicalUrl: 'https://example.com/some/page/', - page: 'https://example.com/some/page/', + page: 'https://example.com/some/page/amp/', ref: null, domain: 'example.com', }); @@ -412,7 +363,7 @@ describe('Referer detection', () => { 'https://ad-iframe.ampproject.org/ad' ], canonicalUrl: 'https://example.com/some/page/', - page: 'https://example.com/some/page/', + page: 'https://example.com/some/page/amp/', ref: null, domain: 'example.com' }); @@ -441,7 +392,7 @@ describe('Referer detection', () => { 'https://ad-iframe.ampproject.org/ad' ], canonicalUrl: 'https://example.com/some/page/', - page: 'https://example.com/some/page/', + page: 'https://example.com/some/page/amp/', ref: null, domain: 'example.com', }); diff --git a/test/spec/unit/core/adapterManager_spec.js b/test/spec/unit/core/adapterManager_spec.js index 6e37da4e85f..06366e8cc5c 100644 --- a/test/spec/unit/core/adapterManager_spec.js +++ b/test/spec/unit/core/adapterManager_spec.js @@ -20,6 +20,7 @@ import { setSizeConfig } from 'src/sizeMapping.js'; import {find, includes} from 'src/polyfill.js'; import s2sTesting from 'modules/s2sTesting.js'; import {hook} from '../../../../src/hook.js'; +import {auctionManager} from '../../../../src/auctionManager.js'; var events = require('../../../../src/events'); const CONFIG = { @@ -1756,6 +1757,153 @@ describe('adapterManager tests', function () { requests.appnexus.bids.forEach((bid) => expect(bid.ortb2).to.eql(requests.appnexus.ortb2)); }); + it('should merge in bid-level ortb2Imp with adUnit-level ortb2Imp', () => { + const adUnit = { + ...adUnits[1], + ortb2Imp: {oneone: {twoone: 'val'}, onetwo: 'val'} + }; + adUnit.bids[0].ortb2Imp = {oneone: {twotwo: 'val'}, onethree: 'val', onetwo: 'val2'}; + const reqs = Object.fromEntries( + adapterManager.makeBidRequests([adUnit], 123, 'auction-id', 123, [], {}) + .map((req) => [req.bidderCode, req]) + ); + sinon.assert.match(reqs[adUnit.bids[0].bidder].bids[0].ortb2Imp, { + oneone: { + twoone: 'val', + twotwo: 'val', + }, + onetwo: 'val2', + onethree: 'val' + }) + sinon.assert.match(reqs[adUnit.bids[1].bidder].bids[0].ortb2Imp, adUnit.ortb2Imp) + }) + + it('picks ortb2Imp from "module" when only one s2sConfig is set', () => { + config.setConfig({ + s2sConfig: [ + { + enabled: true, + adapter: 'mockS2S1', + } + ] + }); + const adUnit = { + code: 'mockau', + ortb2Imp: { + p1: 'adUnit' + }, + bids: [ + { + module: 'pbsBidAdapter', + ortb2Imp: { + p2: 'module' + } + } + ] + }; + const req = adapterManager.makeBidRequests([adUnit], 123, 'auction-id', 123, [], {})[0]; + [req.adUnitsS2SCopy[0].ortb2Imp, req.bids[0].ortb2Imp].forEach(imp => { + sinon.assert.match(imp, { + p1: 'adUnit', + p2: 'module' + }); + }); + }); + + describe('with named s2s configs', () => { + beforeEach(() => { + config.setConfig({ + s2sConfig: [ + { + enabled: true, + adapter: 'mockS2S1', + configName: 'one', + bidders: ['A'] + }, + { + enabled: true, + adapter: 'mockS2S2', + configName: 'two', + bidders: ['B'] + } + ] + }) + }); + + it('generates requests for "module" bids', () => { + const adUnit = { + code: 'mockau', + ortb2Imp: { + p1: 'adUnit' + }, + bids: [ + { + module: 'pbsBidAdapter', + params: {configName: 'one'}, + ortb2Imp: { + p2: 'one' + } + }, + { + module: 'pbsBidAdapter', + params: {configName: 'two'}, + ortb2Imp: { + p2: 'two' + } + } + ] + }; + const reqs = adapterManager.makeBidRequests([adUnit], 123, 'auction-id', 123, [], {}); + [reqs[0].adUnitsS2SCopy[0].ortb2Imp, reqs[0].bids[0].ortb2Imp].forEach(imp => { + sinon.assert.match(imp, { + p1: 'adUnit', + p2: 'one' + }) + }); + [reqs[1].adUnitsS2SCopy[0].ortb2Imp, reqs[1].bids[0].ortb2Imp].forEach(imp => { + sinon.assert.match(imp, { + p1: 'adUnit', + p2: 'two' + }) + }); + }); + + it('applies module-level ortb2Imp to "normal" s2s requests', () => { + const adUnit = { + code: 'mockau', + ortb2Imp: { + p1: 'adUnit' + }, + bids: [ + { + module: 'pbsBidAdapter', + params: {configName: 'one'}, + ortb2Imp: { + p2: 'one' + } + }, + { + bidder: 'A', + ortb2Imp: { + p3: 'bidderA' + } + } + ] + }; + const reqs = adapterManager.makeBidRequests([adUnit], 123, 'auction-id', 123, [], {}); + expect(reqs.length).to.equal(1); + sinon.assert.match(reqs[0].adUnitsS2SCopy[0].ortb2Imp, { + p1: 'adUnit', + p2: 'one' + }) + sinon.assert.match(reqs[0].bids[0].ortb2Imp, { + p1: 'adUnit', + p2: 'one', + p3: 'bidderA' + }) + }); + }); + describe('when calling the s2s adapter', () => { beforeEach(() => { config.setConfig({ @@ -2543,4 +2691,105 @@ describe('adapterManager tests', function () { }) }); }); + + describe('callDataDeletionRequest', () => { + function delMethodForBidder(bidderCode) { + const del = sinon.stub(); + adapterManager.registerBidAdapter({ + callBids: sinon.stub(), + getSpec() { + return { + onDataDeletionRequest: del + } + } + }, bidderCode); + return del; + } + + function delMethodForAnalytics(provider) { + const del = sinon.stub(); + adapterManager.registerAnalyticsAdapter({ + code: provider, + adapter: { + enableAnalytics: sinon.stub(), + onDataDeletionRequest: del, + }, + }) + return del; + } + + Object.entries({ + 'bid adapters': delMethodForBidder, + 'analytics adapters': delMethodForAnalytics + }).forEach(([t, getDelMethod]) => { + describe(t, () => { + it('invokes onDataDeletionRequest', () => { + const del = getDelMethod('mockAdapter'); + adapterManager.callDataDeletionRequest(); + sinon.assert.calledOnce(del); + }); + + it('does not choke if onDeletionRequest throws', () => { + const del1 = getDelMethod('mockAdapter1'); + const del2 = getDelMethod('mockAdapter2'); + del1.throws(new Error()); + adapterManager.callDataDeletionRequest(); + sinon.assert.calledOnce(del1); + sinon.assert.calledOnce(del2); + }); + }) + }) + + describe('for bid adapters', () => { + let bidderRequests; + + beforeEach(() => { + bidderRequests = []; + sinon.stub(auctionManager, 'getBidsRequested').callsFake(() => bidderRequests); + }) + afterEach(() => { + auctionManager.getBidsRequested.restore(); + }) + + it('does not invoke onDataDeletionRequest on aliases', () => { + const del = delMethodForBidder('mockBidder'); + adapterManager.aliasBidAdapter('mockBidder', 'mockBidderAlias'); + adapterManager.aliasBidAdapter('mockBidderAlias2', 'mockBidderAlias'); + adapterManager.callDataDeletionRequest(); + sinon.assert.calledOnce(del); + }); + + it('passes known bidder requests', () => { + const del1 = delMethodForBidder('mockBidder1'); + const del2 = delMethodForBidder('mockBidder2'); + adapterManager.aliasBidAdapter('mockBidder1', 'mockBidder1Alias'); + adapterManager.aliasBidAdapter('mockBidder1Alias', 'mockBidder1Alias2') + bidderRequests = [ + { + bidderCode: 'mockBidder1', + id: 0 + }, + { + bidderCode: 'mockBidder2', + id: 1, + }, + { + bidderCode: 'mockBidder1Alias', + id: 2, + }, + { + bidderCode: 'someOtherBidder', + id: 3 + }, + { + bidderCode: 'mockBidder1Alias2', + id: 4 + } + ]; + adapterManager.callDataDeletionRequest(); + sinon.assert.calledWith(del1, [bidderRequests[0], bidderRequests[2], bidderRequests[4]]); + sinon.assert.calledWith(del2, [bidderRequests[1]]); + }) + }) + }); }); diff --git a/test/spec/unit/core/storageManager_spec.js b/test/spec/unit/core/storageManager_spec.js index cb38aed9e47..58bf8c9eb25 100644 --- a/test/spec/unit/core/storageManager_spec.js +++ b/test/spec/unit/core/storageManager_spec.js @@ -8,6 +8,7 @@ import { import { config } from 'src/config.js'; import * as utils from 'src/utils.js'; import {hook} from '../../../../src/hook.js'; +import {VENDORLESS_GVLID} from '../../../../src/consentHandler.js'; describe('storage manager', function() { before(() => { @@ -73,7 +74,7 @@ describe('storage manager', function() { it('should respect (vendorless) consent enforcement', () => { storage.localStorageIsEnabled(); - expect(validateHook.args[0][1]).to.eql(true); // isVendorless should be set to true + expect(validateHook.args[0][1]).to.equal(VENDORLESS_GVLID); // gvlid should be set to VENDORLESS_GVLID }); it('should respect the deviceAccess flag', () => { diff --git a/test/spec/unit/core/targeting_spec.js b/test/spec/unit/core/targeting_spec.js index 448f1b36e3a..f9fe2e398b0 100644 --- a/test/spec/unit/core/targeting_spec.js +++ b/test/spec/unit/core/targeting_spec.js @@ -269,6 +269,40 @@ describe('targeting tests', function () { bidCacheFilterFunction = undef; }); + describe('isBidNotExpired', () => { + let clock; + beforeEach(() => { + clock = sandbox.useFakeTimers(0); + }); + + Object.entries({ + 'bid.ttlBuffer': (bid, ttlBuffer) => { + bid.ttlBuffer = ttlBuffer + }, + 'setConfig({ttlBuffer})': (_, ttlBuffer) => { + config.setConfig({ttlBuffer}) + }, + }).forEach(([t, setup]) => { + describe(`respects ${t}`, () => { + [0, 2].forEach(ttlBuffer => { + it(`when ttlBuffer is ${ttlBuffer}`, () => { + const bid = { + responseTimestamp: 0, + ttl: 10, + } + setup(bid, ttlBuffer); + + expect(filters.isBidNotExpired(bid)).to.be.true; + clock.tick((bid.ttl - ttlBuffer) * 1000 - 100); + expect(filters.isBidNotExpired(bid)).to.be.true; + clock.tick(101); + expect(filters.isBidNotExpired(bid)).to.be.false; + }); + }); + }); + }); + }); + describe('getAllTargeting', function () { let amBidsReceivedStub; let amGetAdUnitsStub; diff --git a/test/spec/unit/pbjs_api_spec.js b/test/spec/unit/pbjs_api_spec.js index e83608325d8..0867cb0e399 100644 --- a/test/spec/unit/pbjs_api_spec.js +++ b/test/spec/unit/pbjs_api_spec.js @@ -23,6 +23,8 @@ import $$PREBID_GLOBAL$$ from 'src/prebid.js'; import {resetAuctionState} from 'src/auction.js'; import {stubAuctionIndex} from '../../helpers/indexStub.js'; import {createBid} from '../../../src/bidfactory.js'; +import {enrichFPD} from '../../../src/fpd/enrichment.js'; +import {mockFpdEnrichments} from '../../helpers/fpd.js'; var assert = require('chai').assert; var expect = require('chai').expect; @@ -195,7 +197,7 @@ window.apntag = { } describe('Unit: Prebid Module', function () { - let bidExpiryStub + let bidExpiryStub, sandbox; before(() => { hook.ready(); @@ -205,12 +207,15 @@ describe('Unit: Prebid Module', function () { }); beforeEach(function () { + sandbox = sinon.sandbox.create(); + mockFpdEnrichments(sandbox); bidExpiryStub = sinon.stub(filters, 'isBidNotExpired').callsFake(() => true); configObj.setConfig({ useBidCache: true }); resetAuctionState(); }); afterEach(function() { + sandbox.restore(); $$PREBID_GLOBAL$$.adUnits = []; bidExpiryStub.restore(); configObj.setConfig({ useBidCache: false }); @@ -1459,7 +1464,7 @@ describe('Unit: Prebid Module', function () { describe('requestBids', function () { let logMessageSpy; - let makeRequestsStub; + let makeRequestsStub, createAuctionStub; let adUnits; let clock; before(function () { @@ -1615,6 +1620,19 @@ describe('Unit: Prebid Module', function () { }); describe('returns a promise that resolves', () => { + function delayHook(next, ...args) { + setTimeout(() => next(...args)) + } + + beforeEach(() => { + // make sure the return value works correctly when hooks give up priority + $$PREBID_GLOBAL$$.requestBids.before(delayHook) + }); + + afterEach(() => { + $$PREBID_GLOBAL$$.requestBids.getHooks({hook: delayHook}).remove(); + }); + Object.entries({ 'immediately, without bidsBackHandler': (req) => $$PREBID_GLOBAL$$.requestBids(req), 'after bidsBackHandler': (() => { @@ -1665,11 +1683,24 @@ describe('Unit: Prebid Module', function () { sinon.assert.match(bids[bid.adUnitCode].bids[0], bid) done(); }); - completeAuction([bid]); + // `completeAuction` won't work until we're out of `delayHook` + // and the mocked auction has been set up; + // setTimeout here takes us after the setTimeout in `delayHook` + setTimeout(() => completeAuction([bid])); }) }) }) }) + + it('should transfer ttlBuffer to adUnit.ttlBuffer', () => { + $$PREBID_GLOBAL$$.requestBids({ + ttlBuffer: 123, + adUnits: [adUnits[0], {...adUnits[0], ttlBuffer: 0}] + }); + sinon.assert.calledWithMatch(auctionModule.newAuction, { + adUnits: sinon.match((units) => units[0].ttlBuffer === 123 && units[1].ttlBuffer === 0) + }) + }); }) describe('requestBids', function () { @@ -1723,39 +1754,72 @@ describe('Unit: Prebid Module', function () { configObj.resetConfig(); }); - it('passing global and auction-level FPD as ortb2Fragments.global', () => { - configObj.setConfig({ - ortb2: { + describe('with FPD', () => { + let globalFPD, auctionFPD, mergedFPD; + beforeEach(() => { + globalFPD = { 'k1': 'v1', 'k2': { 'k3': 'v3', 'k4': 'v4' } - } - }); - $$PREBID_GLOBAL$$.requestBids({ - ortb2: { + }; + auctionFPD = { 'k5': 'v5', 'k2': { 'k3': 'override', 'k7': 'v7' } + }; + mergedFPD = { + 'k1': 'v1', + 'k5': 'v5', + 'k2': { + 'k3': 'override', + 'k4': 'v4', + 'k7': 'v7' + } + }; + }); + + it('merged from setConfig and requestBids', () => { + configObj.setConfig({ortb2: globalFPD}); + $$PREBID_GLOBAL$$.requestBids({ortb2: auctionFPD}); + sinon.assert.calledWith(startAuctionStub, sinon.match({ + ortb2Fragments: {global: mergedFPD} + })); + }); + + it('enriched through enrichFPD', () => { + function enrich(next, fpd) { + next.bail(fpd.then(ortb2 => { + ortb2.enrich = true; + return ortb2; + })) } + enrichFPD.before(enrich); + try { + configObj.setConfig({ortb2: globalFPD}); + $$PREBID_GLOBAL$$.requestBids({ortb2: auctionFPD}); + sinon.assert.calledWith(startAuctionStub, sinon.match({ + ortb2Fragments: {global: {...mergedFPD, enrich: true}} + })); + } finally { + enrichFPD.getHooks({hook: enrich}).remove(); + } + }) + }); + + it('filtering adUnits by adUnitCodes', () => { + $$PREBID_GLOBAL$$.requestBids({ + adUnits: [{code: 'one'}, {code: 'two'}], + adUnitCodes: 'two' }); sinon.assert.calledWith(startAuctionStub, sinon.match({ - ortb2Fragments: { - global: { - 'k1': 'v1', - 'k5': 'v5', - 'k2': { - 'k3': 'override', - 'k4': 'v4', - 'k7': 'v7' - } - } - } - })) + adUnits: [{code: 'two'}] + })); }); + it('passing bidder-specific FPD as ortb2Fragments.bidder', () => { configObj.setBidderConfig({ bidders: ['bidderA', 'bidderC'], @@ -1815,6 +1879,7 @@ describe('Unit: Prebid Module', function () { mediaTypes: {banner: {sizes: [[300, 250]]}}, bids: [{bidder: 'bd'}] }], + adUnitCodes: ['au'], ortb2Fragments }); sinon.assert.calledWith(newAuctionStub, sinon.match({ @@ -2952,6 +3017,20 @@ describe('Unit: Prebid Module', function () { }); }); + describe('aliasRegistry', function () { + it('should return the same value as adapterManager.aliasRegistry by default', function () { + const adapterManagerAliasRegistry = adapterManager.aliasRegistry; + const pbjsAliasRegistry = $$PREBID_GLOBAL$$.aliasRegistry; + assert.equal(adapterManagerAliasRegistry, pbjsAliasRegistry); + }); + + it('should return undefined if the aliasRegistry config option is set to private', function () { + configObj.setConfig({ aliasRegistry: 'private' }); + const pbjsAliasRegistry = $$PREBID_GLOBAL$$.aliasRegistry; + assert.equal(pbjsAliasRegistry, undefined); + }); + }); + describe('setPriceGranularity', function () { it('should log error when not passed granularity', function () { const logErrorSpy = sinon.spy(utils, 'logError'); diff --git a/test/spec/unit/utils/cpm_spec.js b/test/spec/unit/utils/cpm_spec.js new file mode 100644 index 00000000000..9d104b04d09 --- /dev/null +++ b/test/spec/unit/utils/cpm_spec.js @@ -0,0 +1,64 @@ +import {adjustCpm} from '../../../../src/utils/cpm.js'; + +describe('adjustCpm', () => { + const bidderCode = 'mockBidder'; + let adjustmentFn, bs, index; + beforeEach(() => { + bs = { + get: sinon.stub() + } + index = { + getBidRequest: sinon.stub() + } + adjustmentFn = sinon.stub().callsFake((cpm) => cpm * 2); + }) + + it('throws when neither bidRequest nor bidResponse are provided', () => { + expect(() => adjustCpm(1)).to.throw(); + }) + + it('always provides an object as bidResponse for the adjustment fn', () => { + bs.get.callsFake(() => adjustmentFn); + adjustCpm(1, null, {bidder: bidderCode}, {index, bs}); + sinon.assert.calledWith(adjustmentFn, 1, {}); + }); + + describe('when no bidRequest is provided', () => { + Object.entries({ + 'unavailable': undefined, + 'found': {foo: 'bar'} + }).forEach(([t, req]) => { + describe(`and it is ${t} in the index`, () => { + beforeEach(() => { + bs.get.callsFake(() => adjustmentFn); + index.getBidRequest.callsFake(() => req) + }); + + it('provides it to the adjustment fn', () => { + const bidResponse = {bidderCode}; + adjustCpm(1, bidResponse, undefined, {index, bs}); + sinon.assert.calledWith(index.getBidRequest, bidResponse); + sinon.assert.calledWith(adjustmentFn, 1, bidResponse, req); + }) + }) + }) + }); + + Object.entries({ + 'bidResponse': [{bidderCode}], + 'bidRequest': [null, {bidder: bidderCode}], + }).forEach(([t, [bidResp, bidReq]]) => { + describe(`when passed ${t}`, () => { + beforeEach(() => { + bs.get.callsFake((bidder) => { if (bidder === bidderCode) return adjustmentFn }); + }); + it('retrieves the correct bidder code', () => { + expect(adjustCpm(1, bidResp, bidReq, {bs, index})).to.eql(2); + }); + it('passes them to the adjustment fn', () => { + adjustCpm(1, bidResp, bidReq, {bs, index}); + sinon.assert.calledWith(adjustmentFn, 1, bidResp == null ? sinon.match.any : bidResp, bidReq); + }); + }); + }) +});