prebid.js 6.4.0 → 6.8.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 (147) hide show
  1. package/integrationExamples/gpt/amp/creative.html +11 -33
  2. package/integrationExamples/gpt/x-domain/creative.html +53 -26
  3. package/modules/.submodules.json +2 -1
  4. package/modules/adagioBidAdapter.js +0 -8
  5. package/modules/adagioBidAdapter.md +1 -1
  6. package/modules/adbookpspBidAdapter.js +27 -10
  7. package/modules/adhashBidAdapter.js +3 -3
  8. package/modules/adkernelBidAdapter.js +2 -1
  9. package/modules/admanBidAdapter.js +10 -4
  10. package/modules/adomikAnalyticsAdapter.js +23 -11
  11. package/modules/adqueryIdSystem.js +103 -0
  12. package/modules/adqueryIdSystem.md +35 -0
  13. package/modules/adyoulikeBidAdapter.js +13 -9
  14. package/modules/appnexusBidAdapter.js +11 -0
  15. package/modules/bliinkBidAdapter.js +3 -2
  16. package/modules/brandmetricsRtdProvider.js +168 -0
  17. package/modules/brandmetricsRtdProvider.md +40 -0
  18. package/modules/colossussspBidAdapter.js +12 -8
  19. package/modules/colossussspBidAdapter.md +15 -1
  20. package/modules/compassBidAdapter.js +10 -3
  21. package/modules/consentManagement.js +7 -1
  22. package/modules/consumableBidAdapter.md +1 -1
  23. package/modules/criteoBidAdapter.js +10 -1
  24. package/modules/criteoIdSystem.js +29 -7
  25. package/modules/currency.js +26 -1
  26. package/modules/displayioBidAdapter.js +157 -0
  27. package/modules/displayioBidAdapter.md +148 -0
  28. package/modules/docereeBidAdapter.js +10 -1
  29. package/modules/docereeBidAdapter.md +2 -0
  30. package/modules/e_volutionBidAdapter.js +158 -0
  31. package/modules/glimpseBidAdapter.js +66 -44
  32. package/modules/gnetBidAdapter.js +3 -3
  33. package/modules/gnetBidAdapter.md +4 -4
  34. package/modules/gptPreAuction.js +55 -7
  35. package/modules/gumgumBidAdapter.js +56 -42
  36. package/modules/idImportLibrary.js +45 -8
  37. package/modules/idImportLibrary.md +4 -0
  38. package/modules/improvedigitalBidAdapter.js +24 -2
  39. package/modules/interactiveOffersBidAdapter.js +9 -6
  40. package/modules/ixBidAdapter.js +29 -12
  41. package/modules/jwplayerRtdProvider.js +71 -6
  42. package/modules/jwplayerRtdProvider.md +27 -11
  43. package/modules/kargoBidAdapter.js +2 -2
  44. package/modules/limelightDigitalBidAdapter.js +2 -1
  45. package/modules/livewrappedAnalyticsAdapter.js +3 -1
  46. package/modules/loglyliftBidAdapter.js +79 -0
  47. package/modules/loglyliftBidAdapter.md +55 -0
  48. package/modules/nextMillenniumBidAdapter.js +3 -1
  49. package/modules/oguryBidAdapter.js +9 -2
  50. package/modules/onetagBidAdapter.js +4 -2
  51. package/modules/optimeraRtdProvider.js +8 -1
  52. package/modules/ozoneBidAdapter.js +21 -64
  53. package/modules/pilotxBidAdapter.js +147 -0
  54. package/modules/pilotxBidAdapter.md +50 -0
  55. package/modules/proxistoreBidAdapter.js +0 -2
  56. package/modules/pubmaticAnalyticsAdapter.js +16 -0
  57. package/modules/richaudienceBidAdapter.js +3 -2
  58. package/modules/riseBidAdapter.js +1 -1
  59. package/modules/rtbhouseBidAdapter.js +14 -4
  60. package/modules/rtdModule/index.js +14 -15
  61. package/modules/rubiconAnalyticsAdapter.js +3 -2
  62. package/modules/seedingAllianceBidAdapter.js +3 -3
  63. package/modules/sharethroughBidAdapter.js +12 -17
  64. package/modules/showheroes-bsBidAdapter.js +13 -2
  65. package/modules/sovrnBidAdapter.js +93 -18
  66. package/modules/sovrnBidAdapter.md +80 -2
  67. package/modules/synacormediaBidAdapter.js +31 -10
  68. package/modules/tappxBidAdapter.js +8 -5
  69. package/modules/teadsBidAdapter.js +1 -2
  70. package/modules/undertoneBidAdapter.js +17 -1
  71. package/modules/userId/eids.js +7 -1
  72. package/modules/userId/userId.md +8 -0
  73. package/modules/viewability.js +177 -0
  74. package/modules/viewability.md +87 -0
  75. package/modules/welectBidAdapter.js +106 -0
  76. package/modules/yahoosspBidAdapter.js +2 -0
  77. package/modules/yieldmoBidAdapter.js +23 -5
  78. package/modules/zeta_global_sspAnalyticsAdapter.js +97 -0
  79. package/modules/zeta_global_sspAnalyticsAdapter.md +24 -0
  80. package/package.json +1 -1
  81. package/src/adRendering.js +38 -0
  82. package/src/auction.js +44 -9
  83. package/src/config.js +27 -3
  84. package/src/hook.js +5 -1
  85. package/src/prebid.js +21 -21
  86. package/src/secureCreatives.js +114 -44
  87. package/src/utils.js +25 -4
  88. package/test/helpers/syncPromise.js +71 -0
  89. package/test/spec/auctionmanager_spec.js +148 -16
  90. package/test/spec/config_spec.js +279 -0
  91. package/test/spec/modules/adagioBidAdapter_spec.js +0 -10
  92. package/test/spec/modules/adbookpspBidAdapter_spec.js +17 -3
  93. package/test/spec/modules/adhashBidAdapter_spec.js +2 -2
  94. package/test/spec/modules/admanBidAdapter_spec.js +2 -2
  95. package/test/spec/modules/adomikAnalyticsAdapter_spec.js +3 -1
  96. package/test/spec/modules/adqueryIdSystem_spec.js +74 -0
  97. package/test/spec/modules/adyoulikeBidAdapter_spec.js +49 -0
  98. package/test/spec/modules/appnexusBidAdapter_spec.js +27 -0
  99. package/test/spec/modules/bliinkBidAdapter_spec.js +2 -0
  100. package/test/spec/modules/brandmetricsRtdProvider_spec.js +191 -0
  101. package/test/spec/modules/colossussspBidAdapter_spec.js +5 -2
  102. package/test/spec/modules/compassBidAdapter_spec.js +1 -0
  103. package/test/spec/modules/consentManagement_spec.js +20 -0
  104. package/test/spec/modules/criteoBidAdapter_spec.js +21 -0
  105. package/test/spec/modules/criteoIdSystem_spec.js +6 -3
  106. package/test/spec/modules/currency_spec.js +21 -6
  107. package/test/spec/modules/displayioBidAdapter_spec.js +239 -0
  108. package/test/spec/modules/docereeBidAdapter_spec.js +9 -1
  109. package/test/spec/modules/e_volutionBidAdapter_spec.js +242 -0
  110. package/test/spec/modules/eids_spec.js +15 -0
  111. package/test/spec/modules/glimpseBidAdapter_spec.js +0 -18
  112. package/test/spec/modules/gnetBidAdapter_spec.js +6 -6
  113. package/test/spec/modules/gptPreAuction_spec.js +177 -2
  114. package/test/spec/modules/gumgumBidAdapter_spec.js +46 -0
  115. package/test/spec/modules/idImportLibrary_spec.js +197 -10
  116. package/test/spec/modules/improvedigitalBidAdapter_spec.js +42 -0
  117. package/test/spec/modules/ixBidAdapter_spec.js +104 -62
  118. package/test/spec/modules/jwplayerRtdProvider_spec.js +195 -2
  119. package/test/spec/modules/kargoBidAdapter_spec.js +1 -1
  120. package/test/spec/modules/limelightDigitalBidAdapter_spec.js +75 -17
  121. package/test/spec/modules/livewrappedAnalyticsAdapter_spec.js +22 -0
  122. package/test/spec/modules/loglyliftBidAdapter_spec.js +172 -0
  123. package/test/spec/modules/nextMillenniumBidAdapter_spec.js +1 -1
  124. package/test/spec/modules/oguryBidAdapter_spec.js +10 -2
  125. package/test/spec/modules/optimeraRtdProvider_spec.js +14 -1
  126. package/test/spec/modules/ozoneBidAdapter_spec.js +43 -31
  127. package/test/spec/modules/pilotxBidAdapter_spec.js +244 -0
  128. package/test/spec/modules/pubmaticAnalyticsAdapter_spec.js +13 -1
  129. package/test/spec/modules/realTimeDataModule_spec.js +67 -5
  130. package/test/spec/modules/richaudienceBidAdapter_spec.js +40 -0
  131. package/test/spec/modules/riseBidAdapter_spec.js +1 -1
  132. package/test/spec/modules/rtbhouseBidAdapter_spec.js +20 -0
  133. package/test/spec/modules/rubiconAnalyticsAdapter_spec.js +30 -0
  134. package/test/spec/modules/sharethroughBidAdapter_spec.js +91 -6
  135. package/test/spec/modules/showheroes-bsBidAdapter_spec.js +2 -0
  136. package/test/spec/modules/sovrnBidAdapter_spec.js +413 -333
  137. package/test/spec/modules/synacormediaBidAdapter_spec.js +70 -0
  138. package/test/spec/modules/tappxBidAdapter_spec.js +0 -19
  139. package/test/spec/modules/teadsBidAdapter_spec.js +14 -59
  140. package/test/spec/modules/undertoneBidAdapter_spec.js +55 -2
  141. package/test/spec/modules/userId_spec.js +68 -19
  142. package/test/spec/modules/viewability_spec.js +280 -0
  143. package/test/spec/modules/welectBidAdapter_spec.js +211 -0
  144. package/test/spec/modules/yahoosspBidAdapter_spec.js +10 -0
  145. package/test/spec/modules/zeta_global_sspAnalyticsAdapter_spec.js +427 -0
  146. package/test/spec/unit/pbjs_api_spec.js +20 -2
  147. package/test/spec/unit/secureCreatives_spec.js +85 -0
@@ -0,0 +1,168 @@
1
+ /**
2
+ * This module adds brandmetrics provider to the real time data module
3
+ * The {@link module:modules/realTimeData} module is required
4
+ * The module will load load the brandmetrics script and set survey- targeting to ad units of specific bidders.
5
+ * @module modules/brandmetricsRtdProvider
6
+ * @requires module:modules/realTimeData
7
+ */
8
+ import { config } from '../src/config.js'
9
+ import { submodule } from '../src/hook.js'
10
+ import { deepSetValue, mergeDeep, logError, deepAccess } from '../src/utils.js'
11
+ import {loadExternalScript} from '../src/adloader.js'
12
+ const MODULE_NAME = 'brandmetrics'
13
+ const MODULE_CODE = MODULE_NAME
14
+ const RECEIVED_EVENTS = []
15
+ const GVL_ID = 422
16
+ const TCF_PURPOSES = [1, 7]
17
+
18
+ function init (config, userConsent) {
19
+ const hasConsent = checkConsent(userConsent)
20
+
21
+ if (hasConsent) {
22
+ const moduleConfig = getMergedConfig(config)
23
+ initializeBrandmetrics(moduleConfig.params.scriptId)
24
+ }
25
+ return hasConsent
26
+ }
27
+
28
+ /**
29
+ * Checks TCF and USP consents
30
+ * @param {Object} userConsent
31
+ * @returns {boolean}
32
+ */
33
+ function checkConsent (userConsent) {
34
+ let consent = false
35
+
36
+ if (userConsent && userConsent.gdpr && userConsent.gdpr.gdprApplies) {
37
+ const gdpr = userConsent.gdpr
38
+
39
+ if (gdpr.vendorData) {
40
+ const vendor = gdpr.vendorData.vendor
41
+ const purpose = gdpr.vendorData.purpose
42
+
43
+ let vendorConsent = false
44
+ if (vendor.consents) {
45
+ vendorConsent = vendor.consents[GVL_ID]
46
+ }
47
+
48
+ if (vendor.legitimateInterests) {
49
+ vendorConsent = vendorConsent || vendor.legitimateInterests[GVL_ID]
50
+ }
51
+
52
+ const purposes = TCF_PURPOSES.map(id => {
53
+ return (purpose.consents && purpose.consents[id]) || (purpose.legitimateInterests && purpose.legitimateInterests[id])
54
+ })
55
+ const purposesValid = purposes.filter(p => p === true).length === TCF_PURPOSES.length
56
+ consent = vendorConsent && purposesValid
57
+ }
58
+ } else if (userConsent.usp) {
59
+ const usp = userConsent.usp
60
+ consent = usp[1] !== 'N' && usp[2] !== 'Y'
61
+ }
62
+
63
+ return consent
64
+ }
65
+
66
+ /**
67
+ * Add event- listeners to hook in to brandmetrics events
68
+ * @param {Object} reqBidsConfigObj
69
+ * @param {function} callback
70
+ */
71
+ function processBrandmetricsEvents (reqBidsConfigObj, moduleConfig, callback) {
72
+ const callBidTargeting = (event) => {
73
+ if (event.available && event.conf) {
74
+ const targetingConf = event.conf.displayOption || {}
75
+ if (targetingConf.type === 'pbjs') {
76
+ setBidderTargeting(reqBidsConfigObj, moduleConfig, targetingConf.targetKey || 'brandmetrics_survey', event.survey.measurementId)
77
+ }
78
+ }
79
+ callback()
80
+ }
81
+
82
+ if (RECEIVED_EVENTS.length > 0) {
83
+ callBidTargeting(RECEIVED_EVENTS[RECEIVED_EVENTS.length - 1])
84
+ } else {
85
+ window._brandmetrics = window._brandmetrics || []
86
+ window._brandmetrics.push({
87
+ cmd: '_addeventlistener',
88
+ val: {
89
+ event: 'surveyloaded',
90
+ reEmitLast: true,
91
+ handler: (ev) => {
92
+ RECEIVED_EVENTS.push(ev)
93
+ if (RECEIVED_EVENTS.length === 1) {
94
+ // Call bid targeting only for the first received event, if called subsequently, last event from the RECEIVED_EVENTS array is used
95
+ callBidTargeting(ev)
96
+ }
97
+ },
98
+ }
99
+ })
100
+ }
101
+ }
102
+
103
+ /**
104
+ * Sets bid targeting of specific bidders
105
+ * @param {Object} reqBidsConfigObj
106
+ * @param {string} key Targeting key
107
+ * @param {string} val Targeting value
108
+ */
109
+ function setBidderTargeting (reqBidsConfigObj, moduleConfig, key, val) {
110
+ const bidders = deepAccess(moduleConfig, 'params.bidders')
111
+ if (bidders && bidders.length > 0) {
112
+ const ortb2 = {}
113
+ deepSetValue(ortb2, 'ortb2.user.ext.data.' + key, val)
114
+ config.setBidderConfig({
115
+ bidders: bidders,
116
+ config: ortb2
117
+ })
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Add the brandmetrics script to the page.
123
+ * @param {string} scriptId - The script- id provided by brandmetrics or brandmetrics partner
124
+ */
125
+ function initializeBrandmetrics(scriptId) {
126
+ if (scriptId) {
127
+ const path = 'https://cdn.brandmetrics.com/survey/script/'
128
+ const file = scriptId + '.js'
129
+ const url = path + file
130
+
131
+ loadExternalScript(url, MODULE_CODE)
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Merges a provided config with default values
137
+ * @param {Object} customConfig
138
+ * @returns
139
+ */
140
+ function getMergedConfig(customConfig) {
141
+ return mergeDeep({
142
+ waitForIt: false,
143
+ params: {
144
+ bidders: [],
145
+ scriptId: undefined,
146
+ }
147
+ }, customConfig)
148
+ }
149
+
150
+ /** @type {RtdSubmodule} */
151
+ export const brandmetricsSubmodule = {
152
+ name: MODULE_NAME,
153
+ getBidRequestData: function (reqBidsConfigObj, callback, customConfig) {
154
+ try {
155
+ const moduleConfig = getMergedConfig(customConfig)
156
+ if (moduleConfig.waitForIt) {
157
+ processBrandmetricsEvents(reqBidsConfigObj, moduleConfig, callback)
158
+ } else {
159
+ callback()
160
+ }
161
+ } catch (e) {
162
+ logError(e)
163
+ }
164
+ },
165
+ init: init
166
+ }
167
+
168
+ submodule('realTimeData', brandmetricsSubmodule)
@@ -0,0 +1,40 @@
1
+ # Brandmetrics Real-time Data Submodule
2
+ This module is intended to be used by brandmetrics (https://brandmetrics.com) partners and sets targeting keywords to bids if the browser is eligeble to see a brandmetrics survey.
3
+ The module hooks in to brandmetrics events and requires a brandmetrics script to be running. The module can optionally load and initialize brandmetrics by providing the 'scriptId'- parameter.
4
+
5
+ ## Usage
6
+ Compile the Brandmetrics RTD module into your Prebid build:
7
+ ```
8
+ gulp build --modules=rtdModule,brandmetricsRtdProvider
9
+ ```
10
+
11
+ > Note that the global RTD module, `rtdModule`, is a prerequisite of the Brandmetrics RTD module.
12
+
13
+ Enable the Brandmetrics RTD in your Prebid configuration, using the below format:
14
+
15
+ ```javascript
16
+ pbjs.setConfig({
17
+ ...,
18
+ realTimeData: {
19
+ auctionDelay: 500, // auction delay
20
+ dataProviders: [{
21
+ name: 'brandmetrics',
22
+ waitForIt: true // should be true if there's an `auctionDelay`,
23
+ params: {
24
+ scriptId: '00000000-0000-0000-0000-000000000000',
25
+ bidders: ['ozone']
26
+ }
27
+ }]
28
+ },
29
+ ...
30
+ })
31
+ ```
32
+
33
+ ## Parameters
34
+ | Name | Type | Description | Default |
35
+ | ----------------- | -------------------- | ------------------ | ------------------ |
36
+ | name | String | This should always be `brandmetrics` | - |
37
+ | waitForIt | Boolean | Should be `true` if there's an `auctionDelay` defined (recommended) | `false` |
38
+ | params | Object | | - |
39
+ | params.bidders | String[] | An array of bidders which should receive targeting keys. | `[]` |
40
+ | params.scriptId | String | A script- id GUID if the brandmetrics- script should be initialized. | `undefined` |
@@ -47,7 +47,10 @@ export const spec = {
47
47
  * @return boolean True if this is a valid bid, and false otherwise.
48
48
  */
49
49
  isBidRequestValid: (bid) => {
50
- return Boolean(bid.bidId && bid.params && !isNaN(bid.params.placement_id));
50
+ const validPlacamentId = bid.params && !isNaN(bid.params.placement_id);
51
+ const validGroupId = bid.params && !isNaN(bid.params.group_id);
52
+
53
+ return Boolean(bid.bidId && (validPlacamentId || validGroupId));
51
54
  },
52
55
 
53
56
  /**
@@ -61,13 +64,13 @@ export const spec = {
61
64
  const location = winTop.location;
62
65
  let placements = [];
63
66
  let request = {
64
- 'deviceWidth': winTop.screen.width,
65
- 'deviceHeight': winTop.screen.height,
66
- 'language': (navigator && navigator.language) ? navigator.language : '',
67
- 'secure': location.protocol === 'https:' ? 1 : 0,
68
- 'host': location.host,
69
- 'page': location.pathname,
70
- 'placements': placements,
67
+ deviceWidth: winTop.screen.width,
68
+ deviceHeight: winTop.screen.height,
69
+ language: (navigator && navigator.language) ? navigator.language : '',
70
+ secure: location.protocol === 'https:' ? 1 : 0,
71
+ host: location.host,
72
+ page: location.pathname,
73
+ placements: placements,
71
74
  };
72
75
 
73
76
  if (bidderRequest) {
@@ -85,6 +88,7 @@ export const spec = {
85
88
  let traff = bid.params.traffic || BANNER
86
89
  let placement = {
87
90
  placementId: bid.params.placement_id,
91
+ groupId: bid.params.group_id,
88
92
  bidId: bid.bidId,
89
93
  sizes: bid.mediaTypes[traff].sizes,
90
94
  traffic: traff,
@@ -26,5 +26,19 @@ Module that connects to Colossus SSP demand sources
26
26
  traffic: 'banner'
27
27
  }
28
28
  }]
29
- ];
29
+ }, {
30
+ code: 'placementid_1',
31
+ mediaTypes: {
32
+ banner: {
33
+ sizes: [[300, 250], [300,600]]
34
+ }
35
+ },
36
+ bids: [{
37
+ bidder: 'colossusssp',
38
+ params: {
39
+ group_id: 0,
40
+ traffic: 'banner'
41
+ }
42
+ }]
43
+ }];
30
44
  ```
@@ -28,16 +28,23 @@ function isBidResponseValid(bid) {
28
28
  function getPlacementReqData(bid) {
29
29
  const { params, bidId, mediaTypes } = bid;
30
30
  const schain = bid.schain || {};
31
- const { placementId } = params;
31
+ const { placementId, endpointId } = params;
32
32
  const bidfloor = getBidFloor(bid);
33
33
 
34
34
  const placement = {
35
- placementId,
36
35
  bidId,
37
36
  schain,
38
37
  bidfloor
39
38
  };
40
39
 
40
+ if (placementId) {
41
+ placement.placementId = placementId;
42
+ placement.type = 'publisher';
43
+ } else if (endpointId) {
44
+ placement.endpointId = endpointId;
45
+ placement.type = 'network';
46
+ }
47
+
41
48
  if (mediaTypes && mediaTypes[BANNER]) {
42
49
  placement.adFormat = BANNER;
43
50
  placement.sizes = mediaTypes[BANNER].sizes;
@@ -90,7 +97,7 @@ export const spec = {
90
97
 
91
98
  isBidRequestValid: (bid = {}) => {
92
99
  const { params, bidId, mediaTypes } = bid;
93
- let valid = Boolean(bidId && params && params.placementId);
100
+ let valid = Boolean(bidId && params && (params.placementId || params.endpointId));
94
101
 
95
102
  if (mediaTypes && mediaTypes[BANNER]) {
96
103
  valid = valid && Boolean(mediaTypes[BANNER] && mediaTypes[BANNER].sizes);
@@ -371,7 +371,13 @@ function processCmpData(consentObject, hookConfig) {
371
371
  * General timeout callback when interacting with CMP takes too long.
372
372
  */
373
373
  function cmpTimedOut(hookConfig) {
374
- cmpFailed('CMP workflow exceeded timeout threshold.', hookConfig);
374
+ if (cmpVersion === 2) {
375
+ logWarn(`No response from CMP, continuing auction...`)
376
+ storeConsentData(undefined);
377
+ exitModule(null, hookConfig)
378
+ } else {
379
+ cmpFailed('CMP workflow exceeded timeout threshold.', hookConfig);
380
+ }
375
381
  }
376
382
 
377
383
  /**
@@ -4,7 +4,7 @@ Module Name: Consumable Bid Adapter
4
4
 
5
5
  Module Type: Consumable Adapter
6
6
 
7
- Maintainer: naffis@consumable.com
7
+ Maintainer: prebid@consumable.com
8
8
 
9
9
  # Description
10
10
 
@@ -24,7 +24,7 @@ const LOG_PREFIX = 'Criteo: ';
24
24
  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
25
25
  */
26
26
  const FAST_BID_VERSION_PLACEHOLDER = '%FAST_BID_VERSION%';
27
- export const FAST_BID_VERSION_CURRENT = 116;
27
+ export const FAST_BID_VERSION_CURRENT = 117;
28
28
  const FAST_BID_VERSION_LATEST = 'latest';
29
29
  const FAST_BID_VERSION_NONE = 'none';
30
30
  const PUBLISHER_TAG_URL_TEMPLATE = 'https://static.criteo.net/js/ld/publishertag.prebid' + FAST_BID_VERSION_PLACEHOLDER + '.js';
@@ -281,6 +281,7 @@ function checkNativeSendId(bidRequest) {
281
281
  */
282
282
  function buildCdbRequest(context, bidRequests, bidderRequest) {
283
283
  let networkId;
284
+ let schain;
284
285
  const request = {
285
286
  publisher: {
286
287
  url: context.url,
@@ -288,6 +289,7 @@ function buildCdbRequest(context, bidRequests, bidderRequest) {
288
289
  },
289
290
  slots: bidRequests.map(bidRequest => {
290
291
  networkId = bidRequest.params.networkId || networkId;
292
+ schain = bidRequest.schain || schain;
291
293
  const slot = {
292
294
  impid: bidRequest.adUnitCode,
293
295
  transactionid: bidRequest.transactionId,
@@ -344,6 +346,13 @@ function buildCdbRequest(context, bidRequests, bidderRequest) {
344
346
  if (networkId) {
345
347
  request.publisher.networkid = networkId;
346
348
  }
349
+ if (schain) {
350
+ request.source = {
351
+ ext: {
352
+ schain: schain
353
+ }
354
+ }
355
+ };
347
356
  request.user = {
348
357
  ext: bidderRequest.userExt
349
358
  };
@@ -33,15 +33,37 @@ function getFromAllStorages(key) {
33
33
  return storage.getCookie(key) || storage.getDataFromLocalStorage(key);
34
34
  }
35
35
 
36
- function saveOnAllStorages(key, value) {
36
+ function saveOnAllStorages(key, value, hostname) {
37
37
  if (key && value) {
38
- storage.setCookie(key, value, expirationString);
39
38
  storage.setDataInLocalStorage(key, value);
39
+ setCookieOnAllDomains(key, value, expirationString, hostname, true);
40
40
  }
41
41
  }
42
42
 
43
- function deleteFromAllStorages(key) {
44
- storage.setCookie(key, '', pastDateString);
43
+ function setCookieOnAllDomains(key, value, expiration, hostname, stopOnSuccess) {
44
+ const subDomains = hostname.split('.');
45
+ for (let i = 0; i < subDomains.length; ++i) {
46
+ // Try to write the cookie on this subdomain (we want it to be stored only on the TLD+1)
47
+ const domain = subDomains.slice(subDomains.length - i - 1, subDomains.length).join('.');
48
+
49
+ try {
50
+ storage.setCookie(key, value, expiration, null, '.' + domain);
51
+
52
+ if (stopOnSuccess) {
53
+ // Try to read the cookie to check if we wrote it
54
+ const ck = storage.getCookie(key);
55
+ if (ck && ck === value) {
56
+ break;
57
+ }
58
+ }
59
+ } catch (error) {
60
+
61
+ }
62
+ }
63
+ }
64
+
65
+ function deleteFromAllStorages(key, hostname) {
66
+ setCookieOnAllDomains(key, '', pastDateString, hostname, true);
45
67
  storage.removeDataFromLocalStorage(key);
46
68
  }
47
69
 
@@ -89,15 +111,15 @@ function callCriteoUserSync(parsedCriteoData, gdprString, callback) {
89
111
  const urlsToCall = typeof jsonResponse.acwsUrl === 'string' ? [jsonResponse.acwsUrl] : jsonResponse.acwsUrl;
90
112
  urlsToCall.forEach(url => triggerPixel(url));
91
113
  } else if (jsonResponse.bundle) {
92
- saveOnAllStorages(bundleStorageKey, jsonResponse.bundle);
114
+ saveOnAllStorages(bundleStorageKey, jsonResponse.bundle, domain);
93
115
  }
94
116
 
95
117
  if (jsonResponse.bidId) {
96
- saveOnAllStorages(bididStorageKey, jsonResponse.bidId);
118
+ saveOnAllStorages(bididStorageKey, jsonResponse.bidId, domain);
97
119
  const criteoId = { criteoId: jsonResponse.bidId };
98
120
  callback(criteoId);
99
121
  } else {
100
- deleteFromAllStorages(bididStorageKey);
122
+ deleteFromAllStorages(bididStorageKey, domain);
101
123
  callback();
102
124
  }
103
125
  },
@@ -20,6 +20,25 @@ export var currencyRates = {};
20
20
  var bidderCurrencyDefault = {};
21
21
  var defaultRates;
22
22
 
23
+ export const ready = (() => {
24
+ let isDone, resolver, promise;
25
+ function reset() {
26
+ isDone = false;
27
+ resolver = null;
28
+ promise = new Promise((resolve) => {
29
+ resolver = resolve;
30
+ if (isDone) resolve();
31
+ })
32
+ }
33
+ function done() {
34
+ isDone = true;
35
+ if (resolver != null) { resolver() }
36
+ }
37
+ reset();
38
+
39
+ return {done, reset, promise: () => promise}
40
+ })();
41
+
23
42
  /**
24
43
  * Configuration function for currency
25
44
  * @param {string} [config.adServerCurrency = 'USD']
@@ -138,11 +157,15 @@ function initCurrency(url) {
138
157
  logInfo('currencyRates set to ' + JSON.stringify(currencyRates));
139
158
  currencyRatesLoaded = true;
140
159
  processBidResponseQueue();
160
+ ready.done();
141
161
  } catch (e) {
142
162
  errorSettingsRates('Failed to parse currencyRates response: ' + response);
143
163
  }
144
164
  },
145
- error: errorSettingsRates
165
+ error: function (...args) {
166
+ errorSettingsRates(...args);
167
+ ready.done();
168
+ }
146
169
  }
147
170
  );
148
171
  }
@@ -197,6 +220,8 @@ export function addBidResponseHook(fn, adUnitCode, bid) {
197
220
  bidResponseQueue.push(wrapFunction(fn, this, [adUnitCode, bid]));
198
221
  if (!currencySupportEnabled || currencyRatesLoaded) {
199
222
  processBidResponseQueue();
223
+ } else {
224
+ fn.bail(ready.promise());
200
225
  }
201
226
  }
202
227
 
@@ -0,0 +1,157 @@
1
+ import {registerBidder} from '../src/adapters/bidderFactory.js';
2
+ import {BANNER, VIDEO} from '../src/mediaTypes.js';
3
+
4
+ const BIDDER_VERSION = '1.0.0';
5
+ const BIDDER_CODE = 'displayio';
6
+ const GVLID = 999;
7
+ const BID_TTL = 300;
8
+ const SUPPORTED_AD_TYPES = [BANNER, VIDEO];
9
+ const DEFAULT_CURRENCY = 'USD';
10
+
11
+ export const spec = {
12
+ code: BIDDER_CODE,
13
+ gvlid: GVLID,
14
+ supportedMediaTypes: SUPPORTED_AD_TYPES,
15
+ isBidRequestValid: function(bid) {
16
+ return !!(bid.params && bid.params.placementId && bid.params.siteId &&
17
+ bid.params.adsSrvDomain && bid.params.cdnDomain);
18
+ },
19
+ buildRequests: function (bidRequests, bidderRequest) {
20
+ return bidRequests.map(bid => {
21
+ let url = '//' + bid.params.adsSrvDomain + '/srv?method=getPlacement&app=' +
22
+ bid.params.siteId + '&placement=' + bid.params.placementId;
23
+ const data = this._getPayload(bid, bidderRequest);
24
+ return {
25
+ method: 'POST',
26
+ headers: {'Content-Type': 'application/json;charset=utf-8'},
27
+ url,
28
+ data
29
+ };
30
+ });
31
+ },
32
+ interpretResponse: function (serverResponse, serverRequest) {
33
+ const ads = serverResponse.body.data.ads;
34
+ const bidResponses = [];
35
+ const { data } = serverRequest.data;
36
+ if (ads.length) {
37
+ const adData = ads[0].ad.data;
38
+ const bidResponse = {
39
+ requestId: data.id,
40
+ cpm: adData.ecpm,
41
+ width: adData.w,
42
+ height: adData.h,
43
+ netRevenue: true,
44
+ ttl: BID_TTL,
45
+ creativeId: adData.adId || 0,
46
+ currency: DEFAULT_CURRENCY,
47
+ referrer: data.data.ref,
48
+ mediaType: ads[0].ad.subtype,
49
+ ad: adData.markup,
50
+ placement: data.placement,
51
+ adData: adData
52
+ };
53
+ if (bidResponse.vastUrl === 'videoVast') {
54
+ bidResponse.vastUrl = adData.videos[0].url
55
+ }
56
+ bidResponses.push(bidResponse);
57
+ }
58
+ return bidResponses;
59
+ },
60
+ _getPayload: function (bid, bidderRequest) {
61
+ const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
62
+ const userSession = 'us_web_xxxxxxxxxxxx'.replace(/[x]/g, c => {
63
+ let r = Math.random() * 16 | 0;
64
+ let v = c === 'x' ? r : (r & 0x3 | 0x8);
65
+ return v.toString(16);
66
+ });
67
+ const { params } = bid;
68
+ const { siteId, placementId } = params;
69
+ const { refererInfo, uspConsent, gdprConsent } = bidderRequest;
70
+ const mediation = {consent: '-1', gdpr: '-1'};
71
+ if (gdprConsent) {
72
+ if (gdprConsent.consentString !== undefined) {
73
+ mediation.consent = gdprConsent.consentString;
74
+ }
75
+ if (gdprConsent.gdprApplies !== undefined) {
76
+ mediation.gdpr = gdprConsent.gdprApplies ? '1' : '0';
77
+ }
78
+ }
79
+ const payload = {
80
+ userSession,
81
+ data: {
82
+ id: bid.bidId,
83
+ action: 'getPlacement',
84
+ app: siteId,
85
+ placement: placementId,
86
+ data: {
87
+ pagecat: params.pageCategory ? params.pageCategory.split(',').map(k => k.trim()) : [],
88
+ keywords: params.keywords ? params.keywords.split(',').map(k => k.trim()) : [],
89
+ lang_content: document.documentElement.lang,
90
+ lang: window.navigator.language,
91
+ domain: window.location.hostname,
92
+ page: window.location.href,
93
+ ref: refererInfo.referer,
94
+ userids: _getUserIDs(),
95
+ geo: '',
96
+ },
97
+ complianceData: {
98
+ child: '-1',
99
+ us_privacy: uspConsent,
100
+ dnt: window.navigator.doNotTrack,
101
+ iabConsent: {},
102
+ mediation: {
103
+ consent: mediation.consent,
104
+ gdpr: mediation.gdpr,
105
+ }
106
+ },
107
+ integration: 'JS',
108
+ omidpn: 'Displayio',
109
+ mediationPlatform: 0,
110
+ prebidVersion: BIDDER_VERSION,
111
+ device: {
112
+ w: window.screen.width,
113
+ h: window.screen.height,
114
+ connection_type: connection ? connection.effectiveType : '',
115
+ }
116
+ }
117
+ }
118
+ if (navigator.permissions) {
119
+ navigator.permissions.query({ name: 'geolocation' })
120
+ .then((result) => {
121
+ if (result.state === 'granted') {
122
+ payload.data.data.geo = _getGeoData();
123
+ }
124
+ });
125
+ }
126
+ return payload
127
+ }
128
+ };
129
+
130
+ function _getUserIDs () {
131
+ let ids = {};
132
+ try {
133
+ ids = window.owpbjs.getUserIdsAsEids();
134
+ } catch (e) {}
135
+ return ids;
136
+ }
137
+
138
+ async function _getGeoData () {
139
+ let geoData = null;
140
+ const getCurrentPosition = () => {
141
+ return new Promise((resolve, reject) =>
142
+ navigator.geolocation.getCurrentPosition(resolve, reject)
143
+ );
144
+ }
145
+ try {
146
+ const position = await getCurrentPosition();
147
+ let {latitude, longitude, accuracy} = position.coords;
148
+ geoData = {
149
+ 'lat': latitude,
150
+ 'lng': longitude,
151
+ 'precision': accuracy
152
+ };
153
+ } catch (e) {}
154
+ return geoData
155
+ }
156
+
157
+ registerBidder(spec);