prebid.js 6.7.0 → 6.11.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 (160) hide show
  1. package/.eslintrc.js +8 -1
  2. package/integrationExamples/gpt/{haloRtdProvider_example.html → hadronRtdProvider_example.html} +9 -9
  3. package/integrationExamples/gpt/idImportLibrary_example.html +2 -2
  4. package/integrationExamples/gpt/userId_example.html +2 -2
  5. package/integrationExamples/gpt/weboramaRtdProvider_example.html +154 -115
  6. package/integrationExamples/gpt/x-domain/creative.html +63 -29
  7. package/modules/.submodules.json +3 -0
  8. package/modules/adagioBidAdapter.js +0 -8
  9. package/modules/adagioBidAdapter.md +1 -1
  10. package/modules/adkernelBidAdapter.js +2 -1
  11. package/modules/adnuntiusRtdProvider.js +96 -0
  12. package/modules/adnuntiusRtdProvider.md +41 -0
  13. package/modules/adotBidAdapter.js +516 -567
  14. package/modules/adotBidAdapter.md +6 -44
  15. package/modules/adpod.js +12 -14
  16. package/modules/adyoulikeBidAdapter.js +2 -0
  17. package/modules/appnexusBidAdapter.js +14 -2
  18. package/modules/asealBidAdapter.js +58 -0
  19. package/modules/asealBidAdapter.md +52 -0
  20. package/modules/brandmetricsRtdProvider.js +168 -0
  21. package/modules/brandmetricsRtdProvider.md +40 -0
  22. package/modules/conversantBidAdapter.js +7 -0
  23. package/modules/criteoBidAdapter.js +9 -0
  24. package/modules/currency.js +27 -5
  25. package/modules/displayioBidAdapter.js +157 -0
  26. package/modules/displayioBidAdapter.md +148 -0
  27. package/modules/dspxBidAdapter.js +69 -29
  28. package/modules/dspxBidAdapter.md +2 -1
  29. package/modules/e_volutionBidAdapter.js +158 -0
  30. package/modules/gridBidAdapter.js +15 -1
  31. package/modules/gumgumBidAdapter.js +52 -38
  32. package/modules/hadronIdSystem.js +96 -0
  33. package/modules/hadronIdSystem.md +35 -0
  34. package/modules/hadronRtdProvider.js +254 -0
  35. package/modules/hadronRtdProvider.md +126 -0
  36. package/modules/haloIdSystem.md +4 -35
  37. package/modules/haloRtdProvider.md +3 -126
  38. package/modules/imRtdProvider.js +10 -0
  39. package/modules/improvedigitalBidAdapter.js +5 -0
  40. package/modules/interactiveOffersBidAdapter.js +9 -6
  41. package/modules/iqzoneBidAdapter.js +10 -3
  42. package/modules/iqzoneBidAdapter.md +16 -0
  43. package/modules/ixBidAdapter.js +2 -6
  44. package/modules/kubientBidAdapter.js +50 -19
  45. package/modules/lunamediahbBidAdapter.js +32 -4
  46. package/modules/malltvBidAdapter.js +7 -3
  47. package/modules/malltvBidAdapter.md +64 -51
  48. package/modules/mass.js +3 -5
  49. package/modules/mediakeysBidAdapter.js +0 -5
  50. package/modules/medianetAnalyticsAdapter.js +1 -1
  51. package/modules/mediasquareBidAdapter.js +9 -1
  52. package/modules/nextMillenniumBidAdapter.js +1 -0
  53. package/modules/oguryBidAdapter.js +7 -14
  54. package/modules/prebidServerBidAdapter/index.js +61 -39
  55. package/modules/priceFloors.js +20 -12
  56. package/modules/pubmaticBidAdapter.js +1 -1
  57. package/modules/richaudienceBidAdapter.js +8 -3
  58. package/modules/riseBidAdapter.js +17 -6
  59. package/modules/rtbhouseBidAdapter.js +2 -0
  60. package/modules/rubiconAnalyticsAdapter.js +5 -0
  61. package/modules/rubiconBidAdapter.js +2 -2
  62. package/modules/sizeMappingV2.js +1 -8
  63. package/modules/sortableAnalyticsAdapter.js +5 -4
  64. package/modules/sovrnBidAdapter.js +93 -18
  65. package/modules/sovrnBidAdapter.md +80 -2
  66. package/modules/sspBCBidAdapter.js +53 -20
  67. package/modules/telariaBidAdapter.js +22 -29
  68. package/modules/trustpidSystem.js +197 -0
  69. package/modules/trustpidSystem.md +45 -0
  70. package/modules/undertoneBidAdapter.js +17 -1
  71. package/modules/userId/eids.js +16 -1
  72. package/modules/userId/eids.md +10 -2
  73. package/modules/userId/userId.md +17 -2
  74. package/modules/vibrantmediaBidAdapter.js +220 -0
  75. package/modules/vibrantmediaBidAdapter.md +92 -0
  76. package/modules/vidoomyBidAdapter.js +8 -0
  77. package/modules/vidoomyBidAdapter.md +4 -2
  78. package/modules/weboramaRtdProvider.js +264 -34
  79. package/modules/weboramaRtdProvider.md +110 -40
  80. package/modules/yahoosspBidAdapter.js +3 -1
  81. package/modules/yieldoneBidAdapter.js +6 -0
  82. package/package.json +2 -1
  83. package/src/adRendering.js +38 -0
  84. package/src/adapterManager.js +24 -19
  85. package/src/adapters/bidderFactory.js +14 -11
  86. package/src/adloader.js +2 -1
  87. package/src/auction.js +138 -115
  88. package/src/auctionIndex.js +85 -0
  89. package/src/auctionManager.js +3 -0
  90. package/src/bidderSettings.js +69 -0
  91. package/src/bidfactory.js +18 -6
  92. package/src/native.js +29 -21
  93. package/src/prebid.js +3 -19
  94. package/src/secureCreatives.js +128 -45
  95. package/src/targeting.js +11 -2
  96. package/src/utils.js +14 -17
  97. package/src/video.js +10 -11
  98. package/src/videoCache.js +10 -9
  99. package/test/fixtures/fixtures.js +2 -1
  100. package/test/helpers/indexStub.js +28 -0
  101. package/test/helpers/syncPromise.js +71 -0
  102. package/test/spec/auctionmanager_spec.js +268 -89
  103. package/test/spec/config_spec.js +24 -1
  104. package/test/spec/modules/adagioBidAdapter_spec.js +0 -10
  105. package/test/spec/modules/adnuntiusRtdProvider_spec.js +145 -0
  106. package/test/spec/modules/adotBidAdapter_spec.js +294 -3124
  107. package/test/spec/modules/adpod_spec.js +91 -156
  108. package/test/spec/modules/adyoulikeBidAdapter_spec.js +4 -0
  109. package/test/spec/modules/appnexusBidAdapter_spec.js +27 -0
  110. package/test/spec/modules/asealBidAdapter_spec.js +144 -0
  111. package/test/spec/modules/brandmetricsRtdProvider_spec.js +191 -0
  112. package/test/spec/modules/conversantBidAdapter_spec.js +54 -2
  113. package/test/spec/modules/criteoBidAdapter_spec.js +21 -0
  114. package/test/spec/modules/currency_spec.js +36 -15
  115. package/test/spec/modules/displayioBidAdapter_spec.js +239 -0
  116. package/test/spec/modules/dspxBidAdapter_spec.js +20 -15
  117. package/test/spec/modules/e_volutionBidAdapter_spec.js +242 -0
  118. package/test/spec/modules/eids_spec.js +2 -2
  119. package/test/spec/modules/gridBidAdapter_spec.js +18 -0
  120. package/test/spec/modules/gumgumBidAdapter_spec.js +49 -3
  121. package/test/spec/modules/hadronIdSystem_spec.js +57 -0
  122. package/test/spec/modules/hadronRtdProvider_spec.js +762 -0
  123. package/test/spec/modules/imRtdProvider_spec.js +30 -1
  124. package/test/spec/modules/improvedigitalBidAdapter_spec.js +19 -0
  125. package/test/spec/modules/iqzoneBidAdapter_spec.js +1 -0
  126. package/test/spec/modules/ixBidAdapter_spec.js +1 -1
  127. package/test/spec/modules/kubientBidAdapter_spec.js +182 -84
  128. package/test/spec/modules/lunamediahbBidAdapter_spec.js +27 -1
  129. package/test/spec/modules/mass_spec.js +2 -14
  130. package/test/spec/modules/mediakeysBidAdapter_spec.js +9 -5
  131. package/test/spec/modules/mediasquareBidAdapter_spec.js +25 -1
  132. package/test/spec/modules/oguryBidAdapter_spec.js +63 -5
  133. package/test/spec/modules/prebidServerBidAdapter_spec.js +43 -6
  134. package/test/spec/modules/priceFloors_spec.js +83 -24
  135. package/test/spec/modules/pubmaticBidAdapter_spec.js +40 -0
  136. package/test/spec/modules/riseBidAdapter_spec.js +30 -4
  137. package/test/spec/modules/rubiconAnalyticsAdapter_spec.js +31 -1
  138. package/test/spec/modules/rubiconBidAdapter_spec.js +1 -1
  139. package/test/spec/modules/sortableAnalyticsAdapter_spec.js +2 -3
  140. package/test/spec/modules/sovrnBidAdapter_spec.js +413 -333
  141. package/test/spec/modules/sspBCBidAdapter_spec.js +7 -7
  142. package/test/spec/modules/telariaBidAdapter_spec.js +1 -3
  143. package/test/spec/modules/trustpidSystem_spec.js +232 -0
  144. package/test/spec/modules/undertoneBidAdapter_spec.js +55 -2
  145. package/test/spec/modules/userId_spec.js +39 -39
  146. package/test/spec/modules/vibrantmediaBidAdapter_spec.js +1237 -0
  147. package/test/spec/modules/vidoomyBidAdapter_spec.js +7 -1
  148. package/test/spec/modules/weboramaRtdProvider_spec.js +536 -20
  149. package/test/spec/modules/yahoosspBidAdapter_spec.js +10 -0
  150. package/test/spec/modules/yieldoneBidAdapter_spec.js +33 -0
  151. package/test/spec/native_spec.js +62 -40
  152. package/test/spec/unit/core/adapterManager_spec.js +22 -0
  153. package/test/spec/unit/core/auctionIndex_spec.js +129 -0
  154. package/test/spec/unit/core/bidderFactory_spec.js +65 -12
  155. package/test/spec/unit/core/bidderSettings_spec.js +123 -0
  156. package/test/spec/unit/core/targeting_spec.js +93 -0
  157. package/test/spec/unit/pbjs_api_spec.js +80 -42
  158. package/test/spec/unit/secureCreatives_spec.js +143 -24
  159. package/test/spec/videoCache_spec.js +18 -19
  160. package/test/spec/video_spec.js +51 -61
@@ -17,32 +17,48 @@ const TIME_TO_LIVE = 60
17
17
  const DELAY_REQUEST_TIME = 1800000; // setting to 30 mins
18
18
 
19
19
  let invalidRequestIds = {};
20
- let browserParams = {};
21
20
  let pageViewId = null;
22
21
 
23
22
  // TODO: potential 0 values for browserParams sent to ad server
24
23
  function _getBrowserParams(topWindowUrl) {
25
- let topWindow
26
- let topScreen
27
- let topUrl
28
- let ggad
29
- let ns
30
- function getNetworkSpeed() {
31
- const connection = window.navigator && (window.navigator.connection || window.navigator.mozConnection || window.navigator.webkitConnection)
32
- const Mbps = connection && (connection.downlink || connection.bandwidth)
33
- return Mbps ? Math.round(Mbps * 1024) : null
24
+ const paramRegex = paramName => new RegExp(`[?#&](${paramName}=(.*?))($|&)`, 'i');
25
+
26
+ let browserParams = {};
27
+ let topWindow;
28
+ let topScreen;
29
+ let topUrl;
30
+ let ggad;
31
+ let ggdeal;
32
+ let ns;
33
+
34
+ function getNetworkSpeed () {
35
+ const connection = window.navigator && (window.navigator.connection || window.navigator.mozConnection || window.navigator.webkitConnection);
36
+ const Mbps = connection && (connection.downlink || connection.bandwidth);
37
+ return Mbps ? Math.round(Mbps * 1024) : null;
34
38
  }
35
- function getOgURL() {
36
- let ogURL = ''
37
- const ogURLSelector = "meta[property='og:url']"
38
- const head = document && document.getElementsByTagName('head')[0]
39
- const ogURLElement = head.querySelector(ogURLSelector)
40
- ogURL = ogURLElement ? ogURLElement.content : null
41
- return ogURL
39
+
40
+ function getOgURL () {
41
+ let ogURL = '';
42
+ const ogURLSelector = "meta[property='og:url']";
43
+ const head = document && document.getElementsByTagName('head')[0];
44
+ const ogURLElement = head.querySelector(ogURLSelector);
45
+ ogURL = ogURLElement ? ogURLElement.content : null;
46
+ return ogURL;
42
47
  }
43
- if (browserParams.vw) {
44
- // we've already initialized browserParams, just return it.
45
- return browserParams
48
+
49
+ function stripGGParams (url) {
50
+ const params = [
51
+ 'ggad',
52
+ 'ggdeal'
53
+ ];
54
+
55
+ return params.reduce((result, param) => {
56
+ const matches = url.match(paramRegex(param));
57
+ if (!matches) return result;
58
+ matches[1] && (result = result.replace(matches[1], ''));
59
+ matches[3] && (result = result.replace(matches[3], ''));
60
+ return result;
61
+ }, url);
46
62
  }
47
63
 
48
64
  try {
@@ -51,7 +67,7 @@ function _getBrowserParams(topWindowUrl) {
51
67
  topUrl = topWindowUrl || '';
52
68
  } catch (error) {
53
69
  logError(error);
54
- return browserParams
70
+ return browserParams;
55
71
  }
56
72
 
57
73
  browserParams = {
@@ -59,23 +75,25 @@ function _getBrowserParams(topWindowUrl) {
59
75
  vh: topWindow.innerHeight,
60
76
  sw: topScreen.width,
61
77
  sh: topScreen.height,
62
- pu: topUrl,
78
+ pu: stripGGParams(topUrl),
63
79
  ce: storage.cookiesAreEnabled(),
64
80
  dpr: topWindow.devicePixelRatio || 1,
65
81
  jcsi: JSON.stringify(JCSI),
66
82
  ogu: getOgURL()
67
- }
83
+ };
68
84
 
69
- ns = getNetworkSpeed()
85
+ ns = getNetworkSpeed();
70
86
  if (ns) {
71
- browserParams.ns = ns
87
+ browserParams.ns = ns;
72
88
  }
73
89
 
74
- ggad = (topUrl.match(/#ggad=(\w+)$/) || [0, 0])[1]
75
- if (ggad) {
76
- browserParams[isNaN(ggad) ? 'eAdBuyId' : 'adBuyId'] = ggad
77
- }
78
- return browserParams
90
+ ggad = (topUrl.match(paramRegex('ggad')) || [0, 0, 0])[2];
91
+ if (ggad) browserParams[isNaN(ggad) ? 'eAdBuyId' : 'adBuyId'] = ggad;
92
+
93
+ ggdeal = (topUrl.match(paramRegex('ggdeal')) || [0, 0, 0])[2];
94
+ if (ggdeal) browserParams.ggdeal = ggdeal;
95
+
96
+ return browserParams;
79
97
  }
80
98
 
81
99
  function getWrapperCode(wrapper, data) {
@@ -291,9 +309,9 @@ function buildRequests(validBidRequests, bidderRequest) {
291
309
  } = bidRequest;
292
310
  const { currency, floor } = _getFloor(mediaTypes, params.bidfloor, bidRequest);
293
311
  const eids = getEids(userId);
312
+ const gpid = deepAccess(ortb2Imp, 'ext.data.pbadslot') || deepAccess(ortb2Imp, 'ext.data.adserver.adslot');
294
313
  let sizes = [1, 1];
295
314
  let data = {};
296
- let gpid = '';
297
315
 
298
316
  const date = new Date();
299
317
  const lt = date.getTime();
@@ -309,12 +327,8 @@ function buildRequests(validBidRequests, bidderRequest) {
309
327
  // ADTS-134 Retrieve ID envelopes
310
328
  for (const eid in eids) data[eid] = eids[eid];
311
329
 
312
- // ADJS-1024 & ADSS-1297
313
- if (deepAccess(ortb2Imp, 'ext.data.pbadslot')) {
314
- gpid = deepAccess(ortb2Imp, 'ext.data.pbadslot')
315
- } else if (deepAccess(ortb2Imp, 'ext.data.adserver.name')) {
316
- gpid = ortb2Imp.ext.data.adserver.adslot
317
- }
330
+ // ADJS-1024 & ADSS-1297 & ADTS-175
331
+ gpid && (data.gpid = gpid);
318
332
 
319
333
  if (mediaTypes.banner) {
320
334
  sizes = mediaTypes.banner.sizes;
@@ -384,7 +398,7 @@ function buildRequests(validBidRequests, bidderRequest) {
384
398
  sizes,
385
399
  url: BID_ENDPOINT,
386
400
  method: 'GET',
387
- data: Object.assign(data, _getBrowserParams(topWindowUrl), _getDigiTrustQueryParams(userId), { gpid })
401
+ data: Object.assign(data, _getBrowserParams(topWindowUrl), _getDigiTrustQueryParams(userId))
388
402
  })
389
403
  });
390
404
  return bids;
@@ -0,0 +1,96 @@
1
+ /**
2
+ * This module adds HadronID to the User ID module
3
+ * The {@link module:modules/userId} module is required
4
+ * @module modules/hadronIdSystem
5
+ * @requires module:modules/userId
6
+ */
7
+
8
+ import {ajax} from '../src/ajax.js';
9
+ import {getStorageManager} from '../src/storageManager.js';
10
+ import {submodule} from '../src/hook.js';
11
+ import { isFn, isStr, isPlainObject, logError } from '../src/utils.js';
12
+
13
+ const MODULE_NAME = 'hadronId';
14
+ const AU_GVLID = 561;
15
+
16
+ export const storage = getStorageManager(AU_GVLID, 'hadron');
17
+
18
+ /**
19
+ * Param or default.
20
+ * @param {String} param
21
+ * @param {String} defaultVal
22
+ */
23
+ function paramOrDefault(param, defaultVal, arg) {
24
+ if (isFn(param)) {
25
+ return param(arg);
26
+ } else if (isStr(param)) {
27
+ return param;
28
+ }
29
+ return defaultVal;
30
+ }
31
+
32
+ /** @type {Submodule} */
33
+ export const hadronIdSubmodule = {
34
+ /**
35
+ * used to link submodule with config
36
+ * @type {string}
37
+ */
38
+ name: MODULE_NAME,
39
+ /**
40
+ * decode the stored id value for passing to bid requests
41
+ * @function
42
+ * @param {{value:string}} value
43
+ * @returns {{hadronId:Object}}
44
+ */
45
+ decode(value) {
46
+ let hadronId = storage.getDataFromLocalStorage('auHadronId');
47
+ if (isStr(hadronId)) {
48
+ return {hadronId: hadronId};
49
+ }
50
+ return (value && typeof value['hadronId'] === 'string') ? { 'hadronId': value['hadronId'] } : undefined;
51
+ },
52
+ /**
53
+ * performs action to obtain id and return a value in the callback's response argument
54
+ * @function
55
+ * @param {SubmoduleConfig} [config]
56
+ * @returns {IdResponse|undefined}
57
+ */
58
+ getId(config) {
59
+ if (!isPlainObject(config.params)) {
60
+ config.params = {};
61
+ }
62
+ const url = paramOrDefault(config.params.url,
63
+ `https://id.hadron.ad.gt/api/v1/pbhid`,
64
+ config.params.urlArg);
65
+
66
+ const resp = function (callback) {
67
+ let hadronId = storage.getDataFromLocalStorage('auHadronId');
68
+ if (isStr(hadronId)) {
69
+ const responseObj = {hadronId: hadronId};
70
+ callback(responseObj);
71
+ } else {
72
+ const callbacks = {
73
+ success: response => {
74
+ let responseObj;
75
+ if (response) {
76
+ try {
77
+ responseObj = JSON.parse(response);
78
+ } catch (error) {
79
+ logError(error);
80
+ }
81
+ }
82
+ callback(responseObj);
83
+ },
84
+ error: error => {
85
+ logError(`${MODULE_NAME}: ID fetch encountered an error`, error);
86
+ callback();
87
+ }
88
+ };
89
+ ajax(url, callbacks, undefined, {method: 'GET'});
90
+ }
91
+ };
92
+ return {callback: resp};
93
+ }
94
+ };
95
+
96
+ submodule('userId', hadronIdSubmodule);
@@ -0,0 +1,35 @@
1
+ ## Audigent Hadron User ID Submodule
2
+
3
+ Audigent Hadron ID Module. For assistance setting up your module please contact us at [prebid@audigent.com](prebid@audigent.com).
4
+
5
+ ### Prebid Params
6
+
7
+ Individual params may be set for the Audigent Hadron ID Submodule. At least one identifier must be set in the params.
8
+
9
+ ```
10
+ pbjs.setConfig({
11
+ usersync: {
12
+ userIds: [{
13
+ name: 'hadronId',
14
+ storage: {
15
+ name: 'hadronId',
16
+ type: 'html5'
17
+ }
18
+ }]
19
+ }
20
+ });
21
+ ```
22
+ ## Parameter Descriptions for the `usersync` Configuration Section
23
+ The below parameters apply only to the HadronID User ID Module integration.
24
+
25
+ | Param under usersync.userIds[] | Scope | Type | Description | Example |
26
+ | --- | --- | --- | --- | --- |
27
+ | name | Required | String | ID value for the HadronID module - `"hadronId"` | `"hadronId"` |
28
+ | storage | Required | Object | The publisher must specify the local storage in which to store the results of the call to get the user ID. This can be either cookie or HTML5 storage. | |
29
+ | storage.type | Required | String | This is where the results of the user ID will be stored. The recommended method is `localStorage` by specifying `html5`. | `"html5"` |
30
+ | storage.name | Required | String | The name of the cookie or html5 local storage where the user ID will be stored. | `"hadronid"` |
31
+ | storage.expires | Optional | Integer | How long (in days) the user ID information will be stored. | `365` |
32
+ | value | Optional | Object | Used only if the page has a separate mechanism for storing the Hadron ID. The value is an object containing the values to be sent to the adapters. In this scenario, no URL is called and nothing is added to local storage | `{"hadronId": "eb33b0cb-8d35-4722-b9c0-1a31d4064888"}` |
33
+ | params | Optional | Object | Used to store params for the id system |
34
+ | params.url | Optional | String | Set an alternate GET url for HadronId with this parameter |
35
+ | params.urlArg | Optional | Object | Optional url parameter for params.url |
@@ -0,0 +1,254 @@
1
+ /**
2
+ * This module adds the Audigent Hadron provider to the real time data module
3
+ * The {@link module:modules/realTimeData} module is required
4
+ * The module will fetch real-time data from Audigent
5
+ * @module modules/hadronRtdProvider
6
+ * @requires module:modules/realTimeData
7
+ */
8
+ import {ajax} from '../src/ajax.js';
9
+ import {config} from '../src/config.js';
10
+ import {getGlobal} from '../src/prebidGlobal.js';
11
+ import {getStorageManager} from '../src/storageManager.js';
12
+ import {submodule} from '../src/hook.js';
13
+ import {isFn, isStr, isArray, deepEqual, isPlainObject, logError} from '../src/utils.js';
14
+
15
+ const MODULE_NAME = 'realTimeData';
16
+ const SUBMODULE_NAME = 'hadron';
17
+ const AU_GVLID = 561;
18
+
19
+ export const HALOID_LOCAL_NAME = 'auHadronId';
20
+ export const RTD_LOCAL_NAME = 'auHadronRtd';
21
+ export const storage = getStorageManager(AU_GVLID, SUBMODULE_NAME);
22
+
23
+ /**
24
+ * Deep set an object unless value present.
25
+ * @param {Object} obj
26
+ * @param {String} path
27
+ * @param {Object} val
28
+ */
29
+ function set(obj, path, val) {
30
+ const keys = path.split('.');
31
+ const lastKey = keys.pop();
32
+ const lastObj = keys.reduce((obj, key) => obj[key] = obj[key] || {}, obj);
33
+ lastObj[lastKey] = lastObj[lastKey] || val;
34
+ }
35
+
36
+ /**
37
+ * Deep object merging with array deduplication.
38
+ * @param {Object} target
39
+ * @param {Object} sources
40
+ */
41
+ function mergeDeep(target, ...sources) {
42
+ if (!sources.length) return target;
43
+ const source = sources.shift();
44
+
45
+ if (isPlainObject(target) && isPlainObject(source)) {
46
+ for (const key in source) {
47
+ if (isPlainObject(source[key])) {
48
+ if (!target[key]) Object.assign(target, { [key]: {} });
49
+ mergeDeep(target[key], source[key]);
50
+ } else if (isArray(source[key])) {
51
+ if (!target[key]) {
52
+ Object.assign(target, { [key]: source[key] });
53
+ } else if (isArray(target[key])) {
54
+ source[key].forEach(obj => {
55
+ let e = 1;
56
+ for (let i = 0; i < target[key].length; i++) {
57
+ if (deepEqual(target[key][i], obj)) {
58
+ e = 0;
59
+ break;
60
+ }
61
+ }
62
+ if (e) {
63
+ target[key].push(obj);
64
+ }
65
+ });
66
+ }
67
+ } else {
68
+ Object.assign(target, { [key]: source[key] });
69
+ }
70
+ }
71
+ }
72
+
73
+ return mergeDeep(target, ...sources);
74
+ }
75
+
76
+ /**
77
+ * Lazy merge objects.
78
+ * @param {Object} target
79
+ * @param {Object} source
80
+ */
81
+ function mergeLazy(target, source) {
82
+ if (!isPlainObject(target)) {
83
+ target = {};
84
+ }
85
+
86
+ if (!isPlainObject(source)) {
87
+ source = {};
88
+ }
89
+
90
+ return mergeDeep(target, source);
91
+ }
92
+
93
+ /**
94
+ * Param or default.
95
+ * @param {String} param
96
+ * @param {String} defaultVal
97
+ */
98
+ function paramOrDefault(param, defaultVal, arg) {
99
+ if (isFn(param)) {
100
+ return param(arg);
101
+ } else if (isStr(param)) {
102
+ return param;
103
+ }
104
+ return defaultVal;
105
+ }
106
+
107
+ /**
108
+ * Add real-time data & merge segments.
109
+ * @param {Object} bidConfig
110
+ * @param {Object} rtd
111
+ * @param {Object} rtdConfig
112
+ */
113
+ export function addRealTimeData(bidConfig, rtd, rtdConfig) {
114
+ if (rtdConfig.params && rtdConfig.params.handleRtd) {
115
+ rtdConfig.params.handleRtd(bidConfig, rtd, rtdConfig, config);
116
+ } else {
117
+ if (isPlainObject(rtd.ortb2)) {
118
+ let ortb2 = config.getConfig('ortb2') || {};
119
+ config.setConfig({ortb2: mergeLazy(ortb2, rtd.ortb2)});
120
+ }
121
+
122
+ if (isPlainObject(rtd.ortb2b)) {
123
+ let bidderConfig = config.getBidderConfig();
124
+
125
+ Object.keys(rtd.ortb2b).forEach(bidder => {
126
+ let rtdOptions = rtd.ortb2b[bidder] || {};
127
+
128
+ let bidderOptions = {};
129
+ if (isPlainObject(bidderConfig[bidder])) {
130
+ bidderOptions = bidderConfig[bidder];
131
+ }
132
+
133
+ config.setBidderConfig({
134
+ bidders: [bidder],
135
+ config: mergeLazy(bidderOptions, rtdOptions)
136
+ });
137
+ });
138
+ }
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Real-time data retrieval from Audigent
144
+ * @param {Object} reqBidsConfigObj
145
+ * @param {function} onDone
146
+ * @param {Object} rtdConfig
147
+ * @param {Object} userConsent
148
+ */
149
+ export function getRealTimeData(bidConfig, onDone, rtdConfig, userConsent) {
150
+ if (rtdConfig && isPlainObject(rtdConfig.params) && rtdConfig.params.segmentCache) {
151
+ let jsonData = storage.getDataFromLocalStorage(RTD_LOCAL_NAME);
152
+
153
+ if (jsonData) {
154
+ let data = JSON.parse(jsonData);
155
+
156
+ if (data.rtd) {
157
+ addRealTimeData(bidConfig, data.rtd, rtdConfig);
158
+ onDone();
159
+ return;
160
+ }
161
+ }
162
+ }
163
+
164
+ const userIds = (getGlobal()).getUserIds();
165
+
166
+ let hadronId = storage.getDataFromLocalStorage(HALOID_LOCAL_NAME);
167
+ if (isStr(hadronId)) {
168
+ (getGlobal()).refreshUserIds({submoduleNames: 'hadronId'});
169
+ userIds.hadronId = hadronId;
170
+ getRealTimeDataAsync(bidConfig, onDone, rtdConfig, userConsent, userIds);
171
+ } else {
172
+ var script = document.createElement('script');
173
+ script.type = 'text/javascript';
174
+
175
+ window.pubHadronCb = (hadronId) => {
176
+ userIds.hadronId = hadronId;
177
+ getRealTimeDataAsync(bidConfig, onDone, rtdConfig, userConsent, userIds);
178
+ }
179
+
180
+ const hadronIdUrl = rtdConfig.params && rtdConfig.params.hadronIdUrl;
181
+ script.src = paramOrDefault(hadronIdUrl, 'https://id.hadron.ad.gt/api/v1/hadronid', userIds);
182
+ document.getElementsByTagName('head')[0].appendChild(script);
183
+ }
184
+ }
185
+
186
+ /**
187
+ * Async rtd retrieval from Audigent
188
+ * @param {function} onDone
189
+ * @param {Object} rtdConfig
190
+ * @param {Object} userConsent
191
+ * @param {Object} userIds
192
+ */
193
+ export function getRealTimeDataAsync(bidConfig, onDone, rtdConfig, userConsent, userIds) {
194
+ let reqParams = {};
195
+
196
+ if (isPlainObject(rtdConfig)) {
197
+ set(rtdConfig, 'params.requestParams.ortb2', config.getConfig('ortb2'));
198
+ reqParams = rtdConfig.params.requestParams;
199
+ }
200
+
201
+ if (isPlainObject(window.pubHadronPm)) {
202
+ reqParams.pubHadronPm = window.pubHadronPm;
203
+ }
204
+
205
+ const url = `https://seg.hadron.ad.gt/api/v1/rtd`;
206
+ ajax(url, {
207
+ success: function (response, req) {
208
+ if (req.status === 200) {
209
+ try {
210
+ const data = JSON.parse(response);
211
+ if (data && data.rtd) {
212
+ addRealTimeData(bidConfig, data.rtd, rtdConfig);
213
+ onDone();
214
+ storage.setDataInLocalStorage(RTD_LOCAL_NAME, JSON.stringify(data));
215
+ } else {
216
+ onDone();
217
+ }
218
+ } catch (err) {
219
+ logError('unable to parse audigent segment data');
220
+ onDone();
221
+ }
222
+ } else if (req.status === 204) {
223
+ // unrecognized partner config
224
+ onDone();
225
+ }
226
+ },
227
+ error: function () {
228
+ onDone();
229
+ logError('unable to get audigent segment data');
230
+ }
231
+ },
232
+ JSON.stringify({'userIds': userIds, 'config': reqParams}),
233
+ {contentType: 'application/json'}
234
+ );
235
+ }
236
+
237
+ /**
238
+ * Module init
239
+ * @param {Object} provider
240
+ * @param {Objkect} userConsent
241
+ * @return {boolean}
242
+ */
243
+ function init(provider, userConsent) {
244
+ return true;
245
+ }
246
+
247
+ /** @type {RtdSubmodule} */
248
+ export const hadronSubmodule = {
249
+ name: SUBMODULE_NAME,
250
+ getBidRequestData: getRealTimeData,
251
+ init: init
252
+ };
253
+
254
+ submodule(MODULE_NAME, hadronSubmodule);
@@ -0,0 +1,126 @@
1
+ ## Audigent Hadron Real-time Data Submodule
2
+
3
+ Audigent is a next-generation, 1st party data management platform and the
4
+ world’s first "data agency", powering the programmatic landscape and DTC
5
+ eCommerce with actionable 1st party audience and contextual data from the
6
+ world’s most influential retailers, lifestyle publishers, content creators,
7
+ athletes and artists.
8
+
9
+ The Hadron real-time data module in Prebid has been built so that publishers
10
+ can maximize the power of their first-party audiences and contextual data.
11
+ This module provides both an integrated cookieless Hadron identity with real-time
12
+ contextual and audience segmentation solution that seamlessly and easily
13
+ integrates into your existing Prebid deployment.
14
+
15
+ Users, devices, content, cohorts and other features are identified and utilized
16
+ to augment every bid request with targeted, 1st party data-derived segments
17
+ before being submitted to supply-side platforms. Enriching the bid request with
18
+ robust 1st party audience and contextual data, Audigent's Hadron RTD module
19
+ optimizes targeting, increases the number of bids, increases bid value,
20
+ and drives additional incremental revenue for publishers.
21
+
22
+ ### Publisher Usage
23
+
24
+ Compile the Hadron RTD module into your Prebid build:
25
+
26
+ `gulp build --modules=userId,unifiedIdSystem,rtdModule,hadronRtdProvider,appnexusBidAdapter`
27
+
28
+ Add the Hadron RTD provider to your Prebid config. In this example we will configure
29
+ publisher 1234 to retrieve segments from Audigent. See the
30
+ "Parameter Descriptions" below for more detailed information of the
31
+ configuration parameters. Please work with your Audigent Prebid support team
32
+ (prebid@audigent.com) on which version of Prebid.js supports different bidder
33
+ and segment configurations.
34
+
35
+ ```
36
+ pbjs.setConfig(
37
+ ...
38
+ realTimeData: {
39
+ auctionDelay: 5000,
40
+ dataProviders: [
41
+ {
42
+ name: "hadron",
43
+ waitForIt: true,
44
+ params: {
45
+ segmentCache: false,
46
+ requestParams: {
47
+ publisherId: 1234
48
+ }
49
+ }
50
+ }
51
+ ]
52
+ }
53
+ ...
54
+ }
55
+ ```
56
+
57
+ ### Parameter Descriptions for the Hadron Configuration Section
58
+
59
+ | Name |Type | Description | Notes |
60
+ | :------------ | :------------ | :------------ |:------------ |
61
+ | name | String | Real time data module name | Always 'hadron' |
62
+ | waitForIt | Boolean | Required to ensure that the auction is delayed until prefetch is complete | Optional. Defaults to false |
63
+ | params | Object | | |
64
+ | params.handleRtd | Function | A passable RTD handler that allows custom adunit and ortb2 logic to be configured. The function signature is (bidConfig, rtd, rtdConfig, pbConfig) => {}. | Optional |
65
+ | params.segmentCache | Boolean | This parameter tells the Hadron RTD module to attempt reading segments from a local storage cache instead of always requesting them from the Audigent server. | Optional. Defaults to false. |
66
+ | params.requestParams | Object | Publisher partner specific configuration options, such as optional publisher id and other segment query related metadata to be submitted to Audigent's backend with each request. Contact prebid@audigent.com for more information. | Optional |
67
+ | params.hadronIdUrl | String | Parameter to specify alternate hadronid endpoint url. | Optional |
68
+
69
+ ### Publisher Customized RTD Handling
70
+ As indicated above, it is possible to provide your own bid augmentation
71
+ functions rather than simply merging supplied data. This is useful if you
72
+ want to perform custom bid augmentation and logic with Hadron real-time data
73
+ prior to the bid request being sent. Simply add your custom logic to the
74
+ optional handleRtd parameter and provide your custom RTD handling logic there.
75
+
76
+ Please see the following example, which provides a function to modify bids for
77
+ a bid adapter called adBuzz and perform custom logic on bidder parameters.
78
+
79
+ ```
80
+ pbjs.setConfig(
81
+ ...
82
+ realTimeData: {
83
+ auctionDelay: auctionDelay,
84
+ dataProviders: [
85
+ {
86
+ name: "hadron",
87
+ waitForIt: true,
88
+ params: {
89
+ handleRtd: function(bidConfig, rtd, rtdConfig, pbConfig) {
90
+ var adUnits = bidConfig.adUnits;
91
+ for (var i = 0; i < adUnits.length; i++) {
92
+ var adUnit = adUnits[i];
93
+ for (var j = 0; j < adUnit.bids.length; j++) {
94
+ var bid = adUnit.bids[j];
95
+ if (bid.bidder == 'adBuzz' && rtd['adBuzz'][0].value != 'excludeSeg') {
96
+ bid.params.adBuzzCustomSegments.push(rtd['adBuzz'][0].id);
97
+ }
98
+ }
99
+ }
100
+ },
101
+ segmentCache: false,
102
+ requestParams: {
103
+ publisherId: 1234
104
+ }
105
+ }
106
+ }
107
+ ]
108
+ }
109
+ ...
110
+ }
111
+ ```
112
+
113
+ The handleRtd function can also be used to configure custom ortb2 data
114
+ processing. Please see the examples available in the hadronRtdProvider_spec.js
115
+ tests and work with your Audigent Prebid integration team (prebid@audigent.com)
116
+ on how to best configure your own Hadron RTD & Open RTB data handlers.
117
+
118
+ ### Testing
119
+
120
+ To view an example of available segments returned by Audigent's backends:
121
+
122
+ `gulp serve --modules=userId,unifiedIdSystem,rtdModule,hadronRtdProvider,appnexusBidAdapter`
123
+
124
+ and then point your browser at:
125
+
126
+ `http://localhost:9999/integrationExamples/gpt/hadronRtdProvider_example.html`