prebid.js 6.8.0 → 6.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/.eslintrc.js +8 -1
  2. package/integrationExamples/gpt/weboramaRtdProvider_example.html +154 -115
  3. package/integrationExamples/gpt/x-domain/creative.html +13 -6
  4. package/modules/appnexusBidAdapter.js +3 -2
  5. package/modules/asealBidAdapter.js +58 -0
  6. package/modules/asealBidAdapter.md +52 -0
  7. package/modules/conversantBidAdapter.js +7 -0
  8. package/modules/improvedigitalBidAdapter.js +5 -0
  9. package/modules/lunamediahbBidAdapter.js +32 -4
  10. package/modules/oguryBidAdapter.js +6 -13
  11. package/modules/priceFloors.js +2 -1
  12. package/modules/richaudienceBidAdapter.js +7 -2
  13. package/modules/riseBidAdapter.js +17 -6
  14. package/modules/rubiconAnalyticsAdapter.js +5 -0
  15. package/modules/sortableAnalyticsAdapter.js +5 -4
  16. package/modules/weboramaRtdProvider.js +264 -34
  17. package/modules/weboramaRtdProvider.md +110 -40
  18. package/package.json +2 -1
  19. package/src/adloader.js +2 -1
  20. package/src/auction.js +59 -64
  21. package/src/bidderSettings.js +69 -0
  22. package/src/secureCreatives.js +26 -12
  23. package/src/targeting.js +3 -2
  24. package/src/utils.js +0 -7
  25. package/test/spec/auctionmanager_spec.js +33 -1
  26. package/test/spec/modules/asealBidAdapter_spec.js +144 -0
  27. package/test/spec/modules/conversantBidAdapter_spec.js +54 -2
  28. package/test/spec/modules/improvedigitalBidAdapter_spec.js +19 -0
  29. package/test/spec/modules/lunamediahbBidAdapter_spec.js +27 -1
  30. package/test/spec/modules/oguryBidAdapter_spec.js +62 -4
  31. package/test/spec/modules/riseBidAdapter_spec.js +30 -4
  32. package/test/spec/modules/rubiconAnalyticsAdapter_spec.js +31 -1
  33. package/test/spec/modules/sortableAnalyticsAdapter_spec.js +2 -3
  34. package/test/spec/modules/weboramaRtdProvider_spec.js +536 -20
  35. package/test/spec/unit/core/bidderSettings_spec.js +123 -0
  36. package/test/spec/unit/pbjs_api_spec.js +1 -6
  37. package/test/spec/unit/secureCreatives_spec.js +66 -32
@@ -21,40 +21,51 @@ Compile the Weborama RTD module into your Prebid build:
21
21
  Add the Weborama RTD provider to your Prebid config.
22
22
 
23
23
  ```javascript
24
- pbjs.setConfig(
25
- ...
26
- realTimeData: {
27
- auctionDelay: 1000,
28
- dataProviders: [
29
- {
24
+ var pbjs = pbjs || {};
25
+ pbjs.que = pbjs.que || [];
26
+
27
+ pbjs.que.push(function () {
28
+ pbjs.setConfig({
29
+ debug: true,
30
+ realTimeData: {
31
+ auctionDelay: 1000,
32
+ dataProviders: [{
30
33
  name: "weborama",
31
34
  waitForIt: true,
32
35
  params: {
33
- weboCtxConf: { // contextual configuration
34
- token: "<<provided by weborama>>", // mandatory
35
- targetURL: "...", // default is document.URL
36
- setPrebidTargeting: true, // default
37
- sendToBidders: true, // default
38
- defaultProfile: { // optional, default is none
39
- webo_ctx: ['foo'],
40
- webo_ds: ['bar']
41
- }
36
+ setPrebidTargeting: true, // optional
37
+ sendToBidders: true, // optional
38
+ onData: function(data, site){ // optional
39
+ var kind = (site)? 'site' : 'user';
40
+ console.log('onData', kind, data);
42
41
  },
43
- weboUserDataConf: { // user-centric configuration
44
- setPrebidTargeting: true, // default
45
- sendToBidders: true, // default
46
- defaultProfile: { // optional, default is none
47
- webo_cs: ['baz'],
48
- webo_audiences: ['bam']
49
- },
50
- localStorageProfileKey: 'webo_wam2gam_entry' // default
42
+ weboCtxConf: {
43
+ token: "to-be-defined", // mandatory
44
+ targetURL: "https://prebid.org", // default is document.URL
45
+ setPrebidTargeting: true, // override param.setPrebidTargeting or default true
46
+ sendToBidders: true, // override param.sendToBidders or default true
47
+ defaultProfile: { // optional
48
+ webo_ctx: ['moon'],
49
+ webo_ds: ['bar']
50
+ }
51
+ //, onData: function (data, ...) { ...}
52
+ },
53
+ weboUserDataConf: {
54
+ accountId: 12345, // optional, used for logging
55
+ setPrebidTargeting: true, // override param.setPrebidTargeting or default true
56
+ sendToBidders: true, // override param.sendToBidders or default true
57
+ defaultProfile: { // optional
58
+ webo_cs: ['Red'],
59
+ webo_audiences: ['bam']
60
+ },
61
+ localStorageProfileKey: 'webo_wam2gam_entry' // default
62
+ //, onData: function (data, ...) { ...}
51
63
  }
52
64
  }
53
- }
54
- ]
55
- }
56
- ...
57
- );
65
+ }]
66
+ }
67
+ });
68
+ });
58
69
  ```
59
70
 
60
71
  ### Parameter Descriptions for the Weborama Configuration Section
@@ -64,23 +75,82 @@ pbjs.setConfig(
64
75
  | name | String | Real time data module name | Mandatory. Always 'Weborama' |
65
76
  | waitForIt | Boolean | Mandatory. Required to ensure that the auction is delayed until prefetch is complete | Optional. Defaults to false but recommended to true |
66
77
  | params | Object | | Optional |
67
- | params.weboCtxConf | Object | Weborama Contextual Configuration | Optional |
68
- | params.weboCtxConf.token | String | Security Token provided by Weborama, unique per client | Mandatory |
69
- | params.weboCtxConf.targetURL | String | Url to be profiled in the contextual api | Optional. Defaults to `document.URL` |
70
- | params.weboCtxConf.setPrebidTargeting|Boolean|If true, will use the contextual profile to set the prebid (GPT/GAM or AST) targeting of all adunits managed by prebid.js| Optional. Default is *true*.|
71
- | params.weboCtxConf.sendToBidders|Boolean|If true, will send the contextual profile to all bidders (only smartadserver is supported now)| Optional. Default is *true*.|
72
- | params.weboCtxConf.defaultProfile | Object | default value of the profile to be used when there are no response from contextual api (such as timeout)| Optional. Default is `{}` |
73
- | params.weboUserDataConf | Object | WeboUserData Configuration | Optional |
74
- | params.weboUserDataConf.setPrebidTargeting|Boolean|If true, will use the contextual profile to set the prebid (GPT/GAM or AST) targeting of all adunits managed by prebid.js| Optional. Default is *true*.|
75
- | params.weboUserDataConf.sendToBidders|Boolean|If true, will send the contextual profile to all bidders (only smartadserver is supported now)| Optional. Default is *true*.|
76
- | params.weboUserDataConf.defaultProfile | Object | default value of the profile to be used when there are no response from contextual api (such as timeout)| Optional. Default is `{}` |
77
- | params.weboUserDataConf.localStorageProfileKey| String | can be used to customize the local storage key | Optional |
78
+ | params.setPrebidTargeting | Boolean | If true, may use the profile to set the prebid (GPT/GAM or AST) targeting of all adunits managed by prebid.js | Optional. Affects the `weboCtxConf` and `weboUserDataConf` sections |
79
+ | params.sendToBidders | Boolean | If true, may send the profile to all bidders | Optional. Affects the `weboCtxConf` and `weboUserDataConf` sections |
80
+ | params.weboCtxConf | Object | Weborama Contextual Configuration | Optional
81
+ | params.weboUserDataConf | Object | Weborama User-Centric Configuration | Optional |
82
+ | params.onData | Callback | If set, will receive the profile and site flag | Optional. Affects the `weboCtxConf` and `weboUserDataConf` sections |
83
+
84
+ #### Contextual Configuration
85
+
86
+ | Name |Type | Description | Notes |
87
+ | :------------ | :------------ | :------------ |:------------ |
88
+ | token | String | Security Token provided by Weborama, unique per client | Mandatory |
89
+ | targetURL | String | Url to be profiled in the contextual api | Optional. Defaults to `document.URL` |
90
+ | setPrebidTargeting|Boolean|If true, will use the contextual profile to set the prebid (GPT/GAM or AST) targeting of all adunits managed by prebid.js| Optional. Default is `params.setPrebidTargeting` (if any) or **true**.|
91
+ | sendToBidders|Boolean|If true, will send the contextual profile to all bidders| Optional. Default is `params.sendToBidders` (if any) or **true**.|
92
+ | defaultProfile | Object | default value of the profile to be used when there are no response from contextual api (such as timeout)| Optional. Default is `{}` |
93
+ | onData | Callback | If set, will receive the profile and site flag | Optional. Default is `params.onData` (if any) or log via prebid debug |
94
+ | enabled | Boolean| if false, will ignore this configuration| default true|
95
+
96
+ #### User-Centric Configuration
97
+
98
+ | Name |Type | Description | Notes |
99
+ | :------------ | :------------ | :------------ |:------------ |
100
+ | accountId|Number|WAM account id. If present, will be used on logging and statistics| Optional.|
101
+ | setPrebidTargeting|Boolean|If true, will use the user profile to set the prebid (GPT/GAM or AST) targeting of all adunits managed by prebid.js| Optional. Default is `params.setPrebidTargeting` (if any) or **true**.|
102
+ | sendToBidders|Boolean|If true, will send the user profile to all bidders| Optional. Default is `params.sendToBidders` (if any) or **true**.|
103
+ | onData | Callback | If set, will receive the profile and site flag | Optional. Default is `params.onData` (if any) or log via prebid debug |
104
+ | defaultProfile | Object | default value of the profile to be used when there are no response from contextual api (such as timeout)| Optional. Default is `{}` |
105
+ | localStorageProfileKey| String | can be used to customize the local storage key | Optional |
106
+ | enabled | Boolean| if false, will ignore this configuration| default true|
107
+
108
+ ### Supported Bidders
109
+
110
+ We currently support the following bidder adapters:
111
+ * SmartADServer SSP
112
+ * PubMatic SSP
113
+ * AppNexus SSP
114
+ * Rubicon SSP
115
+
116
+ We also set the bidder and global ortb2 `site` and `user` sections. The following bidders may support it, to be sure, check the `First Party Data Support` on the feature list for the particular bidder from here: https://docs.prebid.org/dev-docs/bidders
117
+
118
+ * Adagio
119
+ * AdformOpenRTB
120
+ * AdKernel
121
+ * AdMixer
122
+ * Adnuntius
123
+ * Adrelevantis
124
+ * adxcg
125
+ * AMX RTB
126
+ * Avocet
127
+ * BeOp
128
+ * Criteo
129
+ * Etarget
130
+ * Inmar
131
+ * Index Exchange
132
+ * Livewrapped
133
+ * Mediakeys
134
+ * NoBid
135
+ * OpenX
136
+ * Opt Out Advertising
137
+ * Ozone Project
138
+ * Proxistore
139
+ * Rise
140
+ * Smaato
141
+ * Sonobi
142
+ * TheMediaGrid
143
+ * TripleLift
144
+ * TrustX
145
+ * Yahoo SSP
146
+ * Yieldlab
147
+ * Zeta Global Ssp
78
148
 
79
149
  ### Testing
80
150
 
81
151
  To view an example of available segments returned by Weborama's backends:
82
152
 
83
- `gulp serve --modules=rtdModule,weboramaRtdProvider,smartadserverBidAdapter`
153
+ `gulp serve --notest --nolint --modules=rtdModule,weboramaRtdProvider,smartadserverBidAdapter,pubmaticBidAdapter,appnexusBidAdapter,rubiconBidAdapter,criteoBidAdapter`
84
154
 
85
155
  and then point your browser at:
86
156
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prebid.js",
3
- "version": "6.8.0",
3
+ "version": "6.9.0",
4
4
  "description": "Header Bidding Management Library",
5
5
  "main": "src/prebid.js",
6
6
  "scripts": {
@@ -30,6 +30,7 @@
30
30
  },
31
31
  "devDependencies": {
32
32
  "@babel/core": "^7.8.4",
33
+ "@babel/eslint-parser": "^7.16.5",
33
34
  "@babel/preset-env": "^7.8.4",
34
35
  "@jsdevtools/coverage-istanbul-loader": "^3.0.3",
35
36
  "@wdio/browserstack-service": "^6.1.4",
package/src/adloader.js CHANGED
@@ -8,7 +8,8 @@ const _approvedLoadExternalJSList = [
8
8
  'criteo',
9
9
  'outstream',
10
10
  'adagio',
11
- 'browsi'
11
+ 'browsi',
12
+ 'brandmetrics'
12
13
  ]
13
14
 
14
15
  /**
package/src/auction.js CHANGED
@@ -59,7 +59,7 @@
59
59
 
60
60
  import {
61
61
  flatten, timestamp, adUnitsFilter, deepAccess, getBidRequest, getValue, parseUrl, generateUUID,
62
- logMessage, bind, logError, logInfo, logWarn, isEmpty, _each, isFn, isEmptyStr, isAllowZeroCpmBidsEnabled
62
+ logMessage, bind, logError, logInfo, logWarn, isEmpty, _each, isFn, isEmptyStr
63
63
  } from './utils.js';
64
64
  import { getPriceBucketString } from './cpmBucketManager.js';
65
65
  import { getNativeTargeting } from './native.js';
@@ -72,6 +72,7 @@ import find from 'core-js-pure/features/array/find.js';
72
72
  import includes from 'core-js-pure/features/array/includes.js';
73
73
  import { OUTSTREAM } from './video.js';
74
74
  import { VIDEO } from './mediaTypes.js';
75
+ import {bidderSettings} from './bidderSettings.js';
75
76
 
76
77
  const { syncUsers } = userSync;
77
78
 
@@ -602,7 +603,7 @@ function getPreparedBidForAuction({adUnitCode, bid, bidderRequest, auctionId}) {
602
603
 
603
604
  function setupBidTargeting(bidObject, bidderRequest) {
604
605
  let keyValues;
605
- const cpmCheck = (isAllowZeroCpmBidsEnabled(bidObject.bidderCode)) ? bidObject.cpm >= 0 : bidObject.cpm > 0;
606
+ const cpmCheck = (bidderSettings.get(bidObject.bidderCode, 'allowZeroCpmBids') === true) ? bidObject.cpm >= 0 : bidObject.cpm > 0;
606
607
  if (bidObject.bidderCode && (cpmCheck || bidObject.dealId)) {
607
608
  let bidReq = find(bidderRequest.bids, bid => bid.adUnitCode === bidObject.adUnitCode && bid.bidId === bidObject.requestId);
608
609
  keyValues = getKeyValueTargetingPairs(bidObject.bidderCode, bidObject, bidReq);
@@ -650,18 +651,18 @@ export const getPriceGranularity = (mediaType, bidReq) => {
650
651
  */
651
652
  export const getPriceByGranularity = (granularity) => {
652
653
  return (bid, bidReq) => {
653
- granularity = granularity || getPriceGranularity(bid.mediaType, bidReq);
654
- if (granularity === CONSTANTS.GRANULARITY_OPTIONS.AUTO) {
654
+ const bidGranularity = granularity || getPriceGranularity(bid.mediaType, bidReq);
655
+ if (bidGranularity === CONSTANTS.GRANULARITY_OPTIONS.AUTO) {
655
656
  return bid.pbAg;
656
- } else if (granularity === CONSTANTS.GRANULARITY_OPTIONS.DENSE) {
657
+ } else if (bidGranularity === CONSTANTS.GRANULARITY_OPTIONS.DENSE) {
657
658
  return bid.pbDg;
658
- } else if (granularity === CONSTANTS.GRANULARITY_OPTIONS.LOW) {
659
+ } else if (bidGranularity === CONSTANTS.GRANULARITY_OPTIONS.LOW) {
659
660
  return bid.pbLg;
660
- } else if (granularity === CONSTANTS.GRANULARITY_OPTIONS.MEDIUM) {
661
+ } else if (bidGranularity === CONSTANTS.GRANULARITY_OPTIONS.MEDIUM) {
661
662
  return bid.pbMg;
662
- } else if (granularity === CONSTANTS.GRANULARITY_OPTIONS.HIGH) {
663
+ } else if (bidGranularity === CONSTANTS.GRANULARITY_OPTIONS.HIGH) {
663
664
  return bid.pbHg;
664
- } else if (granularity === CONSTANTS.GRANULARITY_OPTIONS.CUSTOM) {
665
+ } else if (bidGranularity === CONSTANTS.GRANULARITY_OPTIONS.CUSTOM) {
665
666
  return bid.pbCg;
666
667
  }
667
668
  }
@@ -677,6 +678,34 @@ export const getAdvertiserDomain = () => {
677
678
  }
678
679
  }
679
680
 
681
+ // factory for key value objs
682
+ function createKeyVal(key, value) {
683
+ return {
684
+ key,
685
+ val: (typeof value === 'function')
686
+ ? function (bidResponse, bidReq) {
687
+ return value(bidResponse, bidReq);
688
+ }
689
+ : function (bidResponse) {
690
+ return getValue(bidResponse, value);
691
+ }
692
+ };
693
+ }
694
+
695
+ function defaultAdserverTargeting() {
696
+ const TARGETING_KEYS = CONSTANTS.TARGETING_KEYS;
697
+ return [
698
+ createKeyVal(TARGETING_KEYS.BIDDER, 'bidderCode'),
699
+ createKeyVal(TARGETING_KEYS.AD_ID, 'adId'),
700
+ createKeyVal(TARGETING_KEYS.PRICE_BUCKET, getPriceByGranularity()),
701
+ createKeyVal(TARGETING_KEYS.SIZE, 'size'),
702
+ createKeyVal(TARGETING_KEYS.DEAL, 'dealId'),
703
+ createKeyVal(TARGETING_KEYS.SOURCE, 'source'),
704
+ createKeyVal(TARGETING_KEYS.FORMAT, 'mediaType'),
705
+ createKeyVal(TARGETING_KEYS.ADOMAIN, getAdvertiserDomain()),
706
+ ]
707
+ }
708
+
680
709
  /**
681
710
  * @param {string} mediaType
682
711
  * @param {string} bidderCode
@@ -684,40 +713,16 @@ export const getAdvertiserDomain = () => {
684
713
  * @returns {*}
685
714
  */
686
715
  export function getStandardBidderSettings(mediaType, bidderCode) {
687
- // factory for key value objs
688
- function createKeyVal(key, value) {
689
- return {
690
- key,
691
- val: (typeof value === 'function')
692
- ? function (bidResponse, bidReq) {
693
- return value(bidResponse, bidReq);
694
- }
695
- : function (bidResponse) {
696
- return getValue(bidResponse, value);
697
- }
698
- };
699
- }
700
716
  const TARGETING_KEYS = CONSTANTS.TARGETING_KEYS;
717
+ const standardSettings = Object.assign({}, bidderSettings.settingsFor(null));
701
718
 
702
- let bidderSettings = $$PREBID_GLOBAL$$.bidderSettings;
703
- if (!bidderSettings[CONSTANTS.JSON_MAPPING.BD_SETTING_STANDARD]) {
704
- bidderSettings[CONSTANTS.JSON_MAPPING.BD_SETTING_STANDARD] = {};
705
- }
706
- if (!bidderSettings[CONSTANTS.JSON_MAPPING.BD_SETTING_STANDARD][CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING]) {
707
- bidderSettings[CONSTANTS.JSON_MAPPING.BD_SETTING_STANDARD][CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING] = [
708
- createKeyVal(TARGETING_KEYS.BIDDER, 'bidderCode'),
709
- createKeyVal(TARGETING_KEYS.AD_ID, 'adId'),
710
- createKeyVal(TARGETING_KEYS.PRICE_BUCKET, getPriceByGranularity()),
711
- createKeyVal(TARGETING_KEYS.SIZE, 'size'),
712
- createKeyVal(TARGETING_KEYS.DEAL, 'dealId'),
713
- createKeyVal(TARGETING_KEYS.SOURCE, 'source'),
714
- createKeyVal(TARGETING_KEYS.FORMAT, 'mediaType'),
715
- createKeyVal(TARGETING_KEYS.ADOMAIN, getAdvertiserDomain()),
716
- ]
719
+ if (!standardSettings[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING]) {
720
+ standardSettings[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING] = defaultAdserverTargeting();
717
721
  }
718
722
 
719
723
  if (mediaType === 'video') {
720
- const adserverTargeting = bidderSettings[CONSTANTS.JSON_MAPPING.BD_SETTING_STANDARD][CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING];
724
+ const adserverTargeting = standardSettings[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING].slice();
725
+ standardSettings[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING] = adserverTargeting;
721
726
 
722
727
  // Adding hb_uuid + hb_cache_id
723
728
  [TARGETING_KEYS.UUID, TARGETING_KEYS.CACHE_ID].forEach(targetingKeyVal => {
@@ -727,7 +732,7 @@ export function getStandardBidderSettings(mediaType, bidderCode) {
727
732
  });
728
733
 
729
734
  // Adding hb_cache_host
730
- if (config.getConfig('cache.url') && (!bidderCode || deepAccess(bidderSettings, `${bidderCode}.sendStandardTargeting`) !== false)) {
735
+ if (config.getConfig('cache.url') && (!bidderCode || bidderSettings.get(bidderCode, 'sendStandardTargeting') !== false)) {
731
736
  const urlInfo = parseUrl(config.getConfig('cache.url'));
732
737
 
733
738
  if (typeof find(adserverTargeting, targetingKeyVal => targetingKeyVal.key === TARGETING_KEYS.CACHE_HOST) === 'undefined') {
@@ -738,7 +743,7 @@ export function getStandardBidderSettings(mediaType, bidderCode) {
738
743
  }
739
744
  }
740
745
  }
741
- return bidderSettings[CONSTANTS.JSON_MAPPING.BD_SETTING_STANDARD];
746
+ return standardSettings;
742
747
  }
743
748
 
744
749
  export function getKeyValueTargetingPairs(bidderCode, custBidObj, bidReq) {
@@ -747,19 +752,15 @@ export function getKeyValueTargetingPairs(bidderCode, custBidObj, bidReq) {
747
752
  }
748
753
 
749
754
  var keyValues = {};
750
- var bidderSettings = $$PREBID_GLOBAL$$.bidderSettings;
751
755
 
752
756
  // 1) set the keys from "standard" setting or from prebid defaults
753
- if (bidderSettings) {
754
- // initialize default if not set
755
- const standardSettings = getStandardBidderSettings(custBidObj.mediaType, bidderCode);
756
- setKeys(keyValues, standardSettings, custBidObj, bidReq);
757
-
758
- // 2) set keys from specific bidder setting override if they exist
759
- if (bidderCode && bidderSettings[bidderCode] && bidderSettings[bidderCode][CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING]) {
760
- setKeys(keyValues, bidderSettings[bidderCode], custBidObj, bidReq);
761
- custBidObj.sendStandardTargeting = bidderSettings[bidderCode].sendStandardTargeting;
762
- }
757
+ const standardSettings = getStandardBidderSettings(custBidObj.mediaType, bidderCode);
758
+ setKeys(keyValues, standardSettings, custBidObj, bidReq);
759
+
760
+ // 2) set keys from specific bidder setting override if they exist
761
+ if (bidderCode && bidderSettings.getOwn(bidderCode, CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING)) {
762
+ setKeys(keyValues, bidderSettings.ownSettingsFor(bidderCode), custBidObj, bidReq);
763
+ custBidObj.sendStandardTargeting = bidderSettings.get(bidderCode, 'sendStandardTargeting');
763
764
  }
764
765
 
765
766
  // set native key value targeting
@@ -811,19 +812,13 @@ function setKeys(keyValues, bidderSettings, custBidObj, bidReq) {
811
812
  export function adjustBids(bid) {
812
813
  let code = bid.bidderCode;
813
814
  let bidPriceAdjusted = bid.cpm;
814
- let bidCpmAdjustment;
815
- if ($$PREBID_GLOBAL$$.bidderSettings) {
816
- if (code && $$PREBID_GLOBAL$$.bidderSettings[code] && typeof $$PREBID_GLOBAL$$.bidderSettings[code].bidCpmAdjustment === 'function') {
817
- bidCpmAdjustment = $$PREBID_GLOBAL$$.bidderSettings[code].bidCpmAdjustment;
818
- } else if ($$PREBID_GLOBAL$$.bidderSettings[CONSTANTS.JSON_MAPPING.BD_SETTING_STANDARD] && typeof $$PREBID_GLOBAL$$.bidderSettings[CONSTANTS.JSON_MAPPING.BD_SETTING_STANDARD].bidCpmAdjustment === 'function') {
819
- bidCpmAdjustment = $$PREBID_GLOBAL$$.bidderSettings[CONSTANTS.JSON_MAPPING.BD_SETTING_STANDARD].bidCpmAdjustment;
820
- }
821
- if (bidCpmAdjustment) {
822
- try {
823
- bidPriceAdjusted = bidCpmAdjustment(bid.cpm, Object.assign({}, bid));
824
- } catch (e) {
825
- logError('Error during bid adjustment', 'bidmanager.js', e);
826
- }
815
+ const bidCpmAdjustment = bidderSettings.get(code || null, 'bidCpmAdjustment');
816
+
817
+ if (bidCpmAdjustment && typeof bidCpmAdjustment === 'function') {
818
+ try {
819
+ bidPriceAdjusted = bidCpmAdjustment(bid.cpm, Object.assign({}, bid));
820
+ } catch (e) {
821
+ logError('Error during bid adjustment', 'bidmanager.js', e);
827
822
  }
828
823
  }
829
824
 
@@ -0,0 +1,69 @@
1
+ import {deepAccess, mergeDeep} from './utils.js';
2
+ import {getGlobal} from './prebidGlobal.js';
3
+
4
+ const CONSTANTS = require('./constants.json');
5
+
6
+ export class ScopedSettings {
7
+ constructor(getSettings, defaultScope) {
8
+ this.getSettings = getSettings;
9
+ this.defaultScope = defaultScope;
10
+ }
11
+
12
+ /**
13
+ * Get setting value at `path` under the given scope, falling back to the default scope if needed.
14
+ * If `scope` is `null`, get the setting's default value.
15
+ * @param scope {String|null}
16
+ * @param path {String}
17
+ * @returns {*}
18
+ */
19
+ get(scope, path) {
20
+ let value = this.getOwn(scope, path);
21
+ if (typeof value === 'undefined') {
22
+ value = this.getOwn(null, path);
23
+ }
24
+ return value;
25
+ }
26
+
27
+ /**
28
+ * Get the setting value at `path` *without* falling back to the default value.
29
+ * @param scope {String}
30
+ * @param path {String}
31
+ * @returns {*}
32
+ */
33
+ getOwn(scope, path) {
34
+ scope = this.#resolveScope(scope);
35
+ return deepAccess(this.getSettings(), `${scope}.${path}`)
36
+ }
37
+
38
+ /**
39
+ * @returns {string[]} all existing scopes except the default one.
40
+ */
41
+ getScopes() {
42
+ return Object.keys(this.getSettings()).filter((scope) => scope !== this.defaultScope);
43
+ }
44
+
45
+ /**
46
+ * @returns all settings in the given scope, merged with the settings for the default scope.
47
+ */
48
+ settingsFor(scope) {
49
+ return mergeDeep({}, this.ownSettingsFor(null), this.ownSettingsFor(scope));
50
+ }
51
+
52
+ /**
53
+ * @returns all settings in the given scope, *without* any of the default settings.
54
+ */
55
+ ownSettingsFor(scope) {
56
+ scope = this.#resolveScope(scope);
57
+ return this.getSettings()[scope] || {};
58
+ }
59
+
60
+ #resolveScope(scope) {
61
+ if (scope == null) {
62
+ return this.defaultScope;
63
+ } else {
64
+ return scope;
65
+ }
66
+ }
67
+ }
68
+
69
+ export const bidderSettings = new ScopedSettings(() => getGlobal().bidderSettings || {}, CONSTANTS.JSON_MAPPING.BD_SETTING_STANDARD);
@@ -27,6 +27,24 @@ export function listenMessagesFromCreative() {
27
27
  window.addEventListener('message', receiveMessage, false);
28
28
  }
29
29
 
30
+ export function getReplier(ev) {
31
+ if (ev.origin == null && ev.ports.length === 0) {
32
+ return function () {
33
+ const msg = 'Cannot post message to a frame with null origin. Please update creatives to use MessageChannel, see https://github.com/prebid/Prebid.js/issues/7870'
34
+ logError(msg)
35
+ throw new Error(msg);
36
+ }
37
+ } else if (ev.ports.length > 0) {
38
+ return function (message) {
39
+ ev.ports[0].postMessage(JSON.stringify(message));
40
+ }
41
+ } else {
42
+ return function (message) {
43
+ ev.source.postMessage(JSON.stringify(message), ev.origin);
44
+ }
45
+ }
46
+ }
47
+
30
48
  export function receiveMessage(ev) {
31
49
  var key = ev.message ? 'message' : 'data';
32
50
  var data = {};
@@ -41,12 +59,12 @@ export function receiveMessage(ev) {
41
59
  return bid.adId === data.adId;
42
60
  });
43
61
  if (HANDLER_MAP.hasOwnProperty(data.message)) {
44
- HANDLER_MAP[data.message](ev, data, adObject);
62
+ HANDLER_MAP[data.message](getReplier(ev), data, adObject);
45
63
  }
46
64
  }
47
65
  }
48
66
 
49
- function handleRenderRequest(ev, data, adObject) {
67
+ function handleRenderRequest(reply, data, adObject) {
50
68
  if (adObject == null) {
51
69
  emitAdRenderFail({
52
70
  reason: constants.AD_RENDER_FAILED_REASON.CANNOT_FIND_AD,
@@ -64,7 +82,7 @@ function handleRenderRequest(ev, data, adObject) {
64
82
  }
65
83
 
66
84
  try {
67
- _sendAdToCreative(adObject, ev);
85
+ _sendAdToCreative(adObject, reply);
68
86
  } catch (e) {
69
87
  emitAdRenderFail({
70
88
  reason: constants.AD_RENDER_FAILED_REASON.EXCEPTION,
@@ -81,7 +99,7 @@ function handleRenderRequest(ev, data, adObject) {
81
99
  events.emit(BID_WON, adObject);
82
100
  }
83
101
 
84
- function handleNativeRequest(ev, data, adObject) {
102
+ function handleNativeRequest(reply, data, adObject) {
85
103
  // handle this script from native template in an ad server
86
104
  // window.parent.postMessage(JSON.stringify({
87
105
  // message: 'Prebid Native',
@@ -111,13 +129,9 @@ function handleNativeRequest(ev, data, adObject) {
111
129
  auctionManager.addWinningBid(adObject);
112
130
  events.emit(BID_WON, adObject);
113
131
  }
114
-
115
- function reply(message) {
116
- ev.source.postMessage(JSON.stringify(message), ev.origin);
117
- }
118
132
  }
119
133
 
120
- function handleEventRequest(ev, data, adObject) {
134
+ function handleEventRequest(reply, data, adObject) {
121
135
  if (adObject == null) {
122
136
  logError(`Cannot find ad '${data.adId}' for x-origin event request`);
123
137
  return;
@@ -147,21 +161,21 @@ function handleEventRequest(ev, data, adObject) {
147
161
  }
148
162
  }
149
163
 
150
- export function _sendAdToCreative(adObject, ev) {
164
+ export function _sendAdToCreative(adObject, reply) {
151
165
  const { adId, ad, adUrl, width, height, renderer, cpm } = adObject;
152
166
  // rendering for outstream safeframe
153
167
  if (isRendererRequired(renderer)) {
154
168
  executeRenderer(renderer, adObject);
155
169
  } else if (adId) {
156
170
  resizeRemoteCreative(adObject);
157
- ev.source.postMessage(JSON.stringify({
171
+ reply({
158
172
  message: 'Prebid Response',
159
173
  ad: replaceAuctionPrice(ad, cpm),
160
174
  adUrl: replaceAuctionPrice(adUrl, cpm),
161
175
  adId,
162
176
  width,
163
177
  height
164
- }), ev.origin);
178
+ });
165
179
  }
166
180
  }
167
181
 
package/src/targeting.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  uniques, isGptPubadsDefined, getHighestCpm, getOldestHighestCpmBid, groupBy, isAdUnitCodeMatchingSlot, timestamp,
3
- deepAccess, deepClone, logError, logWarn, logInfo, isFn, isArray, logMessage, isStr, isAllowZeroCpmBidsEnabled
3
+ deepAccess, deepClone, logError, logWarn, logInfo, isFn, isArray, logMessage, isStr,
4
4
  } from './utils.js';
5
5
  import { config } from './config.js';
6
6
  import { NATIVE_TARGETING_KEYS } from './native.js';
@@ -8,6 +8,7 @@ import { auctionManager } from './auctionManager.js';
8
8
  import { sizeSupported } from './sizeMapping.js';
9
9
  import { ADPOD } from './mediaTypes.js';
10
10
  import { hook } from './hook.js';
11
+ import { bidderSettings } from './bidderSettings.js';
11
12
  import includes from 'core-js-pure/features/array/includes.js';
12
13
  import find from 'core-js-pure/features/array/find.js';
13
14
 
@@ -459,7 +460,7 @@ export function newTargeting(auctionManager) {
459
460
  const adUnitCodes = getAdUnitCodes(adUnitCode);
460
461
  return bidsReceived
461
462
  .filter(bid => includes(adUnitCodes, bid.adUnitCode))
462
- .filter(bid => (isAllowZeroCpmBidsEnabled(bid.bidderCode)) ? bid.cpm >= 0 : bid.cpm > 0)
463
+ .filter(bid => (bidderSettings.get(bid.bidderCode, 'allowZeroCpmBids') === true) ? bid.cpm >= 0 : bid.cpm > 0)
463
464
  .map(bid => bid.adUnitCode)
464
465
  .filter(uniques)
465
466
  .map(adUnitCode => bidsReceived
package/src/utils.js CHANGED
@@ -1,6 +1,5 @@
1
1
  /* eslint-disable no-console */
2
2
  import { config } from './config.js';
3
- import { getGlobal } from './prebidGlobal.js';
4
3
  import clone from 'just-clone';
5
4
  import find from 'core-js-pure/features/array/find.js';
6
5
  import includes from 'core-js-pure/features/array/includes.js';
@@ -1343,9 +1342,3 @@ export function cyrb53Hash(str, seed = 0) {
1343
1342
  h2 = imul(h2 ^ (h2 >>> 16), 2246822507) ^ imul(h1 ^ (h1 >>> 13), 3266489909);
1344
1343
  return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString();
1345
1344
  }
1346
-
1347
- export function isAllowZeroCpmBidsEnabled(bidderCode) {
1348
- const bidderSettings = getGlobal().bidderSettings;
1349
- return ((bidderSettings[bidderCode] && bidderSettings[bidderCode].allowZeroCpmBids === true) ||
1350
- (bidderSettings.standard && bidderSettings.standard.allowZeroCpmBids === true));
1351
- }
@@ -3,7 +3,9 @@ import {
3
3
  auctionCallbacks,
4
4
  AUCTION_COMPLETED,
5
5
  adjustBids,
6
- getMediaTypeGranularity, addBidResponse,
6
+ getMediaTypeGranularity,
7
+ getPriceByGranularity,
8
+ addBidResponse
7
9
  } from 'src/auction.js';
8
10
  import CONSTANTS from 'src/constants.json';
9
11
  import * as auctionModule from 'src/auction.js';
@@ -1280,6 +1282,36 @@ describe('auctionmanager.js', function () {
1280
1282
  });
1281
1283
  });
1282
1284
 
1285
+ describe('getPriceByGranularity', () => {
1286
+ beforeEach(() => {
1287
+ config.setConfig({
1288
+ mediaTypePriceGranularity: {
1289
+ video: 'medium',
1290
+ banner: 'low'
1291
+ }
1292
+ });
1293
+ })
1294
+
1295
+ afterEach(() => {
1296
+ config.resetConfig();
1297
+ })
1298
+
1299
+ it('evaluates undef granularity on each call', () => {
1300
+ const gpbg = getPriceByGranularity();
1301
+ expect(gpbg({
1302
+ mediaType: 'video', pbMg: 'medium'
1303
+ }, {
1304
+ 'mediaTypes': {video: {id: '1'}}
1305
+ })).to.equal('medium');
1306
+ expect(gpbg({
1307
+ mediaType: 'banner',
1308
+ pbLg: 'low'
1309
+ }, {
1310
+ 'mediaTypes': {banner: {}}
1311
+ })).to.equal('low');
1312
+ });
1313
+ })
1314
+
1283
1315
  describe('auctionCallbacks', function() {
1284
1316
  let bids = TEST_BIDS;
1285
1317
  let bidRequests;