prebid.js 7.20.0 → 7.22.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.
- package/dist/1plusXRtdProvider.js +1 -1
- package/dist/33acrossBidAdapter.js +1 -1
- package/dist/adagioBidAdapter.js +1 -1
- package/dist/adbookpspBidAdapter.js +1 -1
- package/dist/adgenerationBidAdapter.js +1 -1
- package/dist/adrelevantisBidAdapter.js +1 -1
- package/dist/adtrgtmeBidAdapter.js +1 -1
- package/dist/adxcgBidAdapter.js +1 -1
- package/dist/adyoulikeBidAdapter.js +1 -1
- package/dist/ajaBidAdapter.js +1 -1
- package/dist/amxBidAdapter.js +1 -1
- package/dist/amxIdSystem.js +1 -1
- package/dist/appierAnalyticsAdapter.js +1 -1
- package/dist/appnexusBidAdapter.js +1 -1
- package/dist/asoBidAdapter.js +1 -1
- package/dist/audiencerunBidAdapter.js +1 -1
- package/dist/axonixBidAdapter.js +1 -1
- package/dist/bidglassBidAdapter.js +1 -1
- package/dist/big-richmediaBidAdapter.js +1 -1
- package/dist/bluebillywigBidAdapter.js +1 -1
- package/dist/bridgewellBidAdapter.js +1 -1
- package/dist/brightMountainMediaBidAdapter.js +1 -1
- package/dist/brightcomBidAdapter.js +1 -1
- package/dist/carodaBidAdapter.js +1 -1
- package/dist/concertBidAdapter.js +1 -1
- package/dist/connectadBidAdapter.js +1 -1
- package/dist/consumableBidAdapter.js +1 -1
- package/dist/conversantBidAdapter.js +1 -1
- package/dist/craftBidAdapter.js +1 -1
- package/dist/criteoBidAdapter.js +1 -1
- package/dist/dacIdSystem.js +1 -1
- package/dist/dspxBidAdapter.js +1 -1
- package/dist/eplanningBidAdapter.js +1 -1
- package/dist/finativeBidAdapter.js +1 -1
- package/dist/freewheel-sspBidAdapter.js +1 -1
- package/dist/ftrackIdSystem.js +1 -1
- package/dist/glimpseBidAdapter.js +1 -1
- package/dist/gmosspBidAdapter.js +1 -1
- package/dist/goldbachBidAdapter.js +1 -1
- package/dist/gridBidAdapter.js +1 -1
- package/dist/gridNMBidAdapter.js +1 -1
- package/dist/gumgumBidAdapter.js +1 -1
- package/dist/h12mediaBidAdapter.js +1 -1
- package/dist/iasRtdProvider.js +1 -1
- package/dist/id5IdSystem.js +1 -1
- package/dist/impactifyBidAdapter.js +1 -1
- package/dist/improvedigitalBidAdapter.js +1 -1
- package/dist/inmarBidAdapter.js +1 -1
- package/dist/insticatorBidAdapter.js +1 -1
- package/dist/ixBidAdapter.js +1 -1
- package/dist/jixieBidAdapter.js +1 -1
- package/dist/justpremiumBidAdapter.js +1 -1
- package/dist/konduitAnalyticsAdapter.js +1 -1
- package/dist/kueezBidAdapter.js +1 -1
- package/dist/lassoBidAdapter.js +1 -1
- package/dist/lifestreetBidAdapter.js +1 -1
- package/dist/liveyieldAnalyticsAdapter.js +1 -1
- package/dist/logicadBidAdapter.js +1 -1
- package/dist/loglyliftBidAdapter.js +1 -1
- package/dist/magniteAnalyticsAdapter.js +1 -1
- package/dist/malltvAnalyticsAdapter.js +1 -1
- package/dist/marsmediaBidAdapter.js +1 -1
- package/dist/mediafuseBidAdapter.js +1 -1
- package/dist/mediakeysBidAdapter.js +1 -1
- package/dist/medianetAnalyticsAdapter.js +1 -1
- package/dist/medianetBidAdapter.js +1 -1
- package/dist/mediasquareBidAdapter.js +1 -1
- package/dist/mgidBidAdapter.js +1 -1
- package/dist/minutemediaBidAdapter.js +1 -1
- package/dist/not-for-prod/prebid.js +127 -127
- package/dist/oguryBidAdapter.js +1 -1
- package/dist/onetagBidAdapter.js +1 -1
- package/dist/ooloAnalyticsAdapter.js +1 -1
- package/dist/outbrainBidAdapter.js +1 -1
- package/dist/parrableIdSystem.js +1 -1
- package/dist/pixfutureBidAdapter.js +1 -1
- package/dist/prebid-core.js +1 -1
- package/dist/prebidServerBidAdapter.js +1 -1
- package/dist/publinkIdSystem.js +1 -1
- package/dist/pubmaticBidAdapter.js +1 -1
- package/dist/pubwiseAnalyticsAdapter.js +1 -1
- package/dist/pubwiseBidAdapter.js +1 -1
- package/dist/pulsepointBidAdapter.js +1 -1
- package/dist/pxyzBidAdapter.js +1 -1
- package/dist/quantcastBidAdapter.js +1 -1
- package/dist/readpeakBidAdapter.js +1 -1
- package/dist/relaidoBidAdapter.js +1 -1
- package/dist/rhythmoneBidAdapter.js +1 -1
- package/dist/riseBidAdapter.js +1 -1
- package/dist/rubiconAnalyticsAdapter.js +1 -1
- package/dist/rubiconBidAdapter.js +1 -1
- package/dist/seedingAllianceBidAdapter.js +1 -1
- package/dist/seedtagBidAdapter.js +1 -1
- package/dist/sharethroughAnalyticsAdapter.js +1 -1
- package/dist/sharethroughBidAdapter.js +1 -1
- package/dist/shinezBidAdapter.js +1 -1
- package/dist/smaatoBidAdapter.js +1 -1
- package/dist/smartadserverBidAdapter.js +1 -1
- package/dist/smartxBidAdapter.js +1 -1
- package/dist/smilewantedBidAdapter.js +1 -1
- package/dist/sonobiBidAdapter.js +1 -1
- package/dist/sovrnAnalyticsAdapter.js +1 -1
- package/dist/sovrnBidAdapter.js +1 -1
- package/dist/sspBCBidAdapter.js +1 -1
- package/dist/sublimeBidAdapter.js +1 -1
- package/dist/synacormediaBidAdapter.js +1 -1
- package/dist/targetVideoBidAdapter.js +1 -1
- package/dist/teadsBidAdapter.js +1 -1
- package/dist/trionBidAdapter.js +1 -1
- package/dist/tripleliftBidAdapter.js +1 -1
- package/dist/ttdBidAdapter.js +1 -1
- package/dist/ucfunnelAnalyticsAdapter.js +1 -1
- package/dist/underdogmediaBidAdapter.js +1 -1
- package/dist/undertoneBidAdapter.js +1 -1
- package/dist/userId.js +1 -1
- package/dist/vidazooBidAdapter.js +1 -1
- package/dist/videobyteBidAdapter.js +1 -1
- package/dist/visxBidAdapter.js +1 -1
- package/dist/vuukleBidAdapter.js +1 -1
- package/dist/weboramaRtdProvider.js +1 -1
- package/dist/widespaceBidAdapter.js +1 -1
- package/dist/winrBidAdapter.js +1 -1
- package/dist/yahoosspBidAdapter.js +1 -1
- package/dist/yieldmoBidAdapter.js +1 -1
- package/dist/yieldoneAnalyticsAdapter.js +1 -1
- package/dist/yieldoneBidAdapter.js +1 -1
- package/integrationExamples/gpt/weboramaRtdProvider_example.html +10 -51
- package/modules/1plusXRtdProvider.js +32 -5
- package/modules/33acrossBidAdapter.js +18 -11
- package/modules/adyoulikeBidAdapter.js +12 -6
- package/modules/asoBidAdapter.js +11 -6
- package/modules/asoBidAdapter.md +5 -6
- package/modules/brightcomBidAdapter.js +30 -10
- package/modules/dacIdSystem.js +145 -27
- package/modules/dacIdSystem.md +7 -2
- package/modules/fledgeForGpt.md +101 -23
- package/modules/freewheel-sspBidAdapter.js +48 -7
- package/modules/freewheel-sspBidAdapter.md +1 -1
- package/modules/ftrackIdSystem.js +28 -9
- package/modules/gridBidAdapter.js +1 -0
- package/modules/iasRtdProvider.js +21 -6
- package/modules/iasRtdProvider.md +1 -1
- package/modules/ixBidAdapter.js +9 -4
- package/modules/medianetAnalyticsAdapter.js +26 -22
- package/modules/medianetBidAdapter.js +5 -1
- package/modules/mediasquareBidAdapter.js +42 -3
- package/modules/mgidBidAdapter.js +8 -1
- package/modules/oguryBidAdapter.js +6 -2
- package/modules/prebidServerBidAdapter/index.js +1 -1
- package/modules/pubmaticBidAdapter.js +27 -3
- package/modules/pubwiseBidAdapter.js +14 -12
- package/modules/pulsepointBidAdapter.js +11 -6
- package/modules/smaatoBidAdapter.js +54 -5
- package/modules/smaatoBidAdapter.md +78 -0
- package/modules/teadsBidAdapter.js +26 -8
- package/modules/ttdBidAdapter.js +8 -0
- package/modules/userId/eids.js +7 -11
- package/modules/weboramaRtdProvider.js +800 -643
- package/modules/weboramaRtdProvider.md +32 -0
- package/modules/yieldoneBidAdapter.js +7 -4
- package/package.json +3 -3
- package/src/adapters/bidderFactory.js +11 -9
- package/src/auction.js +3 -3
- package/test/spec/auctionmanager_spec.js +29 -20
- package/test/spec/modules/1plusXRtdProvider_spec.js +30 -14
- package/test/spec/modules/33acrossBidAdapter_spec.js +44 -1
- package/test/spec/modules/adyoulikeBidAdapter_spec.js +1 -1
- package/test/spec/modules/asoBidAdapter_spec.js +2 -2
- package/test/spec/modules/brightcomBidAdapter_spec.js +94 -1
- package/test/spec/modules/dacIdSystem_spec.js +93 -11
- package/test/spec/modules/eids_spec.js +11 -7
- package/test/spec/modules/freewheel-sspBidAdapter_spec.js +25 -4
- package/test/spec/modules/ftrackIdSystem_spec.js +200 -90
- package/test/spec/modules/iasRtdProvider_spec.js +57 -1
- package/test/spec/modules/ixBidAdapter_spec.js +12 -0
- package/test/spec/modules/medianetAnalyticsAdapter_spec.js +50 -8
- package/test/spec/modules/medianetBidAdapter_spec.js +76 -0
- package/test/spec/modules/mediasquareBidAdapter_spec.js +4 -2
- package/test/spec/modules/mgidBidAdapter_spec.js +50 -0
- package/test/spec/modules/oguryBidAdapter_spec.js +33 -17
- package/test/spec/modules/prebidServerBidAdapter_spec.js +24 -0
- package/test/spec/modules/pubmaticBidAdapter_spec.js +60 -5
- package/test/spec/modules/pubwiseBidAdapter_spec.js +6 -4
- package/test/spec/modules/pulsepointBidAdapter_spec.js +123 -0
- package/test/spec/modules/smaatoBidAdapter_spec.js +307 -36
- package/test/spec/modules/teadsBidAdapter_spec.js +119 -6
- package/test/spec/modules/weboramaRtdProvider_spec.js +382 -0
- package/test/spec/modules/yieldoneBidAdapter_spec.js +2 -3
- package/test/spec/unit/core/bidderFactory_spec.js +0 -4
|
@@ -7,83 +7,98 @@
|
|
|
7
7
|
* @requires module:modules/realTimeData
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
/**
|
|
10
|
+
/** profile metadata
|
|
11
11
|
* @typedef dataCallbackMetadata
|
|
12
|
-
* @property {
|
|
13
|
-
* @property {
|
|
14
|
-
* @property {
|
|
12
|
+
* @property {boolean} user if true it is user-centric data
|
|
13
|
+
* @property {string} source describe the source of data, if 'contextual' or 'wam'
|
|
14
|
+
* @property {boolean} isDefault if true it the default profile defined in the configuration
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/** profile from contextual, wam or sfbx
|
|
18
|
+
* @typedef {Object.<string,string[]>} Profile
|
|
15
19
|
*/
|
|
16
20
|
|
|
17
21
|
/** onData callback type
|
|
18
22
|
* @callback dataCallback
|
|
19
|
-
* @param {
|
|
23
|
+
* @param {Profile} data profile data
|
|
20
24
|
* @param {dataCallbackMetadata} meta metadata
|
|
21
25
|
* @returns {void}
|
|
22
26
|
*/
|
|
23
27
|
|
|
24
28
|
/** setPrebidTargeting callback type
|
|
25
29
|
* @callback setPrebidTargetingCallback
|
|
26
|
-
* @param {
|
|
27
|
-
* @param {
|
|
30
|
+
* @param {string} adUnitCode
|
|
31
|
+
* @param {Profile} data
|
|
28
32
|
* @param {dataCallbackMetadata} metadata
|
|
29
|
-
* @returns {
|
|
33
|
+
* @returns {boolean}
|
|
30
34
|
*/
|
|
31
35
|
|
|
32
36
|
/** sendToBidders callback type
|
|
33
37
|
* @callback sendToBiddersCallback
|
|
34
38
|
* @param {Object} bid
|
|
35
|
-
* @param {
|
|
36
|
-
* @param {
|
|
39
|
+
* @param {string} adUnitCode
|
|
40
|
+
* @param {Profile} data
|
|
37
41
|
* @param {dataCallbackMetadata} metadata
|
|
38
|
-
* @returns {
|
|
42
|
+
* @returns {boolean}
|
|
39
43
|
*/
|
|
40
44
|
|
|
41
45
|
/**
|
|
42
46
|
* @typedef {Object} ModuleParams
|
|
43
|
-
* @property {?setPrebidTargetingCallback|?
|
|
44
|
-
* @property {?sendToBiddersCallback|?
|
|
47
|
+
* @property {?setPrebidTargetingCallback|?boolean|?Object} setPrebidTargeting if true, will set the GAM targeting (default undefined)
|
|
48
|
+
* @property {?sendToBiddersCallback|?boolean|?Object} sendToBidders if true, will send the contextual profile to all bidders, else expects a list of allowed bidders (default undefined)
|
|
45
49
|
* @property {?dataCallback} onData callback
|
|
46
50
|
* @property {?WeboCtxConf} weboCtxConf site-centric contextual configuration
|
|
47
51
|
* @property {?WeboUserDataConf} weboUserDataConf user-centric wam configuration
|
|
48
52
|
* @property {?SfbxLiteDataConf} sfbxLiteDataConf site-centric lite configuration
|
|
49
53
|
*/
|
|
50
54
|
|
|
55
|
+
/**
|
|
56
|
+
* @callback assetIDcallback
|
|
57
|
+
* @returns {string} should return asset identifier using the form datasource:docId
|
|
58
|
+
*/
|
|
51
59
|
/**
|
|
52
60
|
* @typedef {Object} WeboCtxConf
|
|
53
61
|
* @property {string} token required token to be used on bigsea contextual API requests
|
|
54
62
|
* @property {?string} targetURL specify the target url instead use the referer
|
|
55
|
-
* @property {?
|
|
56
|
-
* @property {?
|
|
63
|
+
* @property {?assetIDcallback|?string} assetID specifies the assert identifier using the form datasource:docId or via callback
|
|
64
|
+
* @property {?setPrebidTargetingCallback|?boolean|?Object} setPrebidTargeting if true, will set the GAM targeting (default undefined)
|
|
65
|
+
* @property {?sendToBiddersCallback|?boolean|?Object} sendToBidders if true, will send the contextual profile to all bidders, else expects a list of allowed bidders (default undefined)
|
|
57
66
|
* @property {?dataCallback} onData callback
|
|
58
|
-
* @property {?
|
|
59
|
-
* @property {?
|
|
67
|
+
* @property {?Profile} defaultProfile to be used if the profile is not found
|
|
68
|
+
* @property {?boolean} enabled if false, will ignore this configuration
|
|
60
69
|
* @property {?string} baseURLProfileAPI to be used to point to a different domain than ctx.weborama.com
|
|
61
70
|
*/
|
|
62
71
|
|
|
63
72
|
/**
|
|
64
73
|
* @typedef {Object} WeboUserDataConf
|
|
65
74
|
* @property {?number} accountId wam account id
|
|
66
|
-
* @property {?setPrebidTargetingCallback|?
|
|
67
|
-
* @property {?sendToBiddersCallback|?
|
|
68
|
-
* @property {?
|
|
75
|
+
* @property {?setPrebidTargetingCallback|?boolean|?Object} setPrebidTargeting if true, will set the GAM targeting (default undefined)
|
|
76
|
+
* @property {?sendToBiddersCallback|?boolean|?Object} sendToBidders if true, will send the contextual profile to all bidders, else expects a list of allowed bidders (default undefined)
|
|
77
|
+
* @property {?Profile} defaultProfile to be used if the profile is not found
|
|
69
78
|
* @property {?dataCallback} onData callback
|
|
70
79
|
* @property {?string} localStorageProfileKey can be used to customize the local storage key (default is 'webo_wam2gam_entry')
|
|
71
|
-
* @property {?
|
|
80
|
+
* @property {?boolean} enabled if false, will ignore this configuration
|
|
72
81
|
*/
|
|
73
82
|
|
|
74
83
|
/**
|
|
75
84
|
* @typedef {Object} SfbxLiteDataConf
|
|
76
|
-
* @property {?setPrebidTargetingCallback|?
|
|
77
|
-
* @property {?sendToBiddersCallback|?
|
|
78
|
-
* @property {?
|
|
85
|
+
* @property {?setPrebidTargetingCallback|?boolean|?Object} setPrebidTargeting if true, will set the GAM targeting (default undefined)
|
|
86
|
+
* @property {?sendToBiddersCallback|?boolean|?Object} sendToBidders if true, will send the contextual profile to all bidders, else expects a list of allowed bidders (default undefined)
|
|
87
|
+
* @property {?Profile} defaultProfile to be used if the profile is not found
|
|
79
88
|
* @property {?dataCallback} onData callback
|
|
80
89
|
* @property {?string} localStorageProfileKey can be used to customize the local storage key (default is '_lite')
|
|
81
|
-
* @property {?
|
|
90
|
+
* @property {?boolean} enabled if false, will ignore this configuration
|
|
82
91
|
*/
|
|
92
|
+
|
|
93
|
+
/** common configuration between contextual, wam and sfbx
|
|
94
|
+
* @typedef {WeboCtxConf|WeboUserDataConf|SfbxLiteDataConf} CommonConf
|
|
95
|
+
*/
|
|
96
|
+
|
|
83
97
|
import {
|
|
84
98
|
getGlobal
|
|
85
99
|
} from '../src/prebidGlobal.js';
|
|
86
100
|
import {
|
|
101
|
+
deepClone,
|
|
87
102
|
deepSetValue,
|
|
88
103
|
isEmpty,
|
|
89
104
|
isFn,
|
|
@@ -93,8 +108,9 @@ import {
|
|
|
93
108
|
isStr,
|
|
94
109
|
isBoolean,
|
|
95
110
|
isPlainObject,
|
|
96
|
-
|
|
97
|
-
|
|
111
|
+
logWarn,
|
|
112
|
+
mergeDeep,
|
|
113
|
+
tryAppendQueryString
|
|
98
114
|
} from '../src/utils.js';
|
|
99
115
|
import {
|
|
100
116
|
submodule
|
|
@@ -127,431 +143,869 @@ const WEBO_CTX_CONF_SECTION = 'weboCtxConf';
|
|
|
127
143
|
const WEBO_USER_DATA_CONF_SECTION = 'weboUserDataConf';
|
|
128
144
|
/** @type {string} */
|
|
129
145
|
const SFBX_LITE_DATA_CONF_SECTION = 'sfbxLiteDataConf';
|
|
130
|
-
|
|
146
|
+
/** @type {string} */
|
|
147
|
+
const WEBO_CTX_SOURCE_LABEL = 'contextual';
|
|
148
|
+
/** @type {string} */
|
|
149
|
+
const WEBO_USER_DATA_SOURCE_LABEL = 'wam';
|
|
150
|
+
/** @type {string} */
|
|
151
|
+
const SFBX_LITE_DATA_SOURCE_LABEL = 'lite';
|
|
131
152
|
/** @type {number} */
|
|
132
153
|
const GVLID = 284;
|
|
133
|
-
|
|
154
|
+
|
|
134
155
|
export const storage = getStorageManager({
|
|
135
156
|
gvlid: GVLID,
|
|
136
157
|
moduleName: SUBMODULE_NAME
|
|
137
158
|
});
|
|
138
159
|
|
|
139
|
-
/**
|
|
140
|
-
|
|
160
|
+
/**
|
|
161
|
+
* @typedef {Object} Component
|
|
162
|
+
* @property {boolean} initialized
|
|
163
|
+
* @property {?Profile} data
|
|
164
|
+
* @property {boolean} user if true it is user-centric data
|
|
165
|
+
* @property {string} source describe the source of data, if 'contextual' or 'wam'
|
|
166
|
+
* @property {buildProfileHandlerCallbackBuilder} callbackBuilder
|
|
167
|
+
*/
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* @typedef {Object} Components
|
|
171
|
+
* @property {Component} WeboCtx
|
|
172
|
+
* @property {Component} WeboUserData
|
|
173
|
+
* @property {Component} SfbxLiteData
|
|
174
|
+
*/
|
|
141
175
|
|
|
142
|
-
/**
|
|
143
|
-
|
|
176
|
+
/**
|
|
177
|
+
* @classdesc Weborama Real Time Data Provider
|
|
178
|
+
* @class
|
|
179
|
+
*/
|
|
180
|
+
class WeboramaRtdProvider {
|
|
181
|
+
#components;
|
|
182
|
+
name = SUBMODULE_NAME;
|
|
183
|
+
/**
|
|
184
|
+
* @param {Components} components
|
|
185
|
+
*/
|
|
186
|
+
constructor(components) {
|
|
187
|
+
this.#components = components;
|
|
188
|
+
}
|
|
189
|
+
/** Initialize module
|
|
190
|
+
* @method
|
|
191
|
+
* @param {Object} moduleConfig
|
|
192
|
+
* @param {?ModuleParams} moduleConfig.params
|
|
193
|
+
* @return {boolean} true if module was initialized with success
|
|
194
|
+
*/
|
|
195
|
+
init(moduleConfig) {
|
|
196
|
+
/** @type {Object} */
|
|
197
|
+
const globalDefaults = {
|
|
198
|
+
setPrebidTargeting: true,
|
|
199
|
+
sendToBidders: true,
|
|
200
|
+
onData: () => {
|
|
201
|
+
/* do nothing */
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
/** @type {ModuleParams} */
|
|
205
|
+
const moduleParams = Object.assign({}, globalDefaults, moduleConfig?.params || {});
|
|
144
206
|
|
|
145
|
-
|
|
146
|
-
let _weboUserDataUserProfile = null;
|
|
207
|
+
// reset profiles
|
|
147
208
|
|
|
148
|
-
|
|
149
|
-
|
|
209
|
+
this.#components.WeboCtx.data = null;
|
|
210
|
+
this.#components.WeboUserData.data = null;
|
|
211
|
+
this.#components.SfbxLiteData.data = null;
|
|
150
212
|
|
|
151
|
-
|
|
152
|
-
|
|
213
|
+
this.#components.WeboCtx.initialized = this.#initSubSection(moduleParams, WEBO_CTX_CONF_SECTION, 'token');
|
|
214
|
+
this.#components.WeboUserData.initialized = this.#initSubSection(moduleParams, WEBO_USER_DATA_CONF_SECTION);
|
|
215
|
+
this.#components.SfbxLiteData.initialized = this.#initSubSection(moduleParams, SFBX_LITE_DATA_CONF_SECTION);
|
|
153
216
|
|
|
154
|
-
|
|
155
|
-
|
|
217
|
+
return Object.values(this.#components).some((c) => c.initialized);
|
|
218
|
+
}
|
|
156
219
|
|
|
157
|
-
/**
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
220
|
+
/** function that will allow RTD sub-modules to modify the AdUnit object for each auction
|
|
221
|
+
* @method
|
|
222
|
+
* @param {Object} reqBidsConfigObj
|
|
223
|
+
* @param {doneCallback} onDone
|
|
224
|
+
* @param {Object} moduleConfig
|
|
225
|
+
* @param {?ModuleParams} moduleConfig.params
|
|
226
|
+
* @returns {void}
|
|
227
|
+
*/
|
|
228
|
+
getBidRequestData(reqBidsConfigObj, onDone, moduleConfig) {
|
|
229
|
+
/** @type {ModuleParams} */
|
|
230
|
+
const moduleParams = moduleConfig?.params || {};
|
|
231
|
+
|
|
232
|
+
if (!this.#components.WeboCtx.initialized) {
|
|
233
|
+
this.#handleBidRequestData(reqBidsConfigObj, moduleParams);
|
|
163
234
|
|
|
164
|
-
|
|
165
|
-
_weboUserDataUserProfile = null;
|
|
166
|
-
_sfbxLiteDataProfile = null;
|
|
235
|
+
onDone();
|
|
167
236
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
_sfbxLiteDataInitialized = initSubSection(moduleParams, SFBX_LITE_DATA_CONF_SECTION);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
171
239
|
|
|
172
|
-
|
|
173
|
-
}
|
|
240
|
+
/** @type {WeboCtxConf} */
|
|
241
|
+
const weboCtxConf = moduleParams.weboCtxConf || {};
|
|
174
242
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
* @param {string} subSection subsection name to initialize
|
|
178
|
-
* @param {[]string} requiredFields
|
|
179
|
-
* @return {Boolean} true if module subsection was initialized with success
|
|
180
|
-
*/
|
|
181
|
-
function initSubSection(moduleParams, subSection, ...requiredFields) {
|
|
182
|
-
const weboSectionConf = moduleParams[subSection] || {enabled: false};
|
|
243
|
+
this.#fetchContextualProfile(weboCtxConf, (data) => {
|
|
244
|
+
logMessage('fetchContextualProfile on getBidRequestData is done');
|
|
183
245
|
|
|
184
|
-
|
|
185
|
-
|
|
246
|
+
this.#setWeboContextualProfile(data);
|
|
247
|
+
}, () => {
|
|
248
|
+
this.#handleBidRequestData(reqBidsConfigObj, moduleParams);
|
|
186
249
|
|
|
187
|
-
|
|
250
|
+
onDone();
|
|
251
|
+
});
|
|
188
252
|
}
|
|
189
253
|
|
|
190
|
-
|
|
254
|
+
/** function that provides ad server targeting data to RTD-core
|
|
255
|
+
* @method
|
|
256
|
+
* @param {string[]} adUnitsCodes
|
|
257
|
+
* @param {Object} moduleConfig
|
|
258
|
+
* @param {?ModuleParams} moduleConfig.params
|
|
259
|
+
* @returns {Object} target data
|
|
260
|
+
*/
|
|
261
|
+
getTargetingData(adUnitsCodes, moduleConfig) {
|
|
262
|
+
/** @type {ModuleParams} */
|
|
263
|
+
const moduleParams = moduleConfig?.params || {};
|
|
264
|
+
|
|
265
|
+
const profileHandlers = this.#buildProfileHandlers(moduleParams);
|
|
266
|
+
|
|
267
|
+
if (isEmpty(profileHandlers)) {
|
|
268
|
+
logMessage('no data to set targeting');
|
|
269
|
+
return {};
|
|
270
|
+
}
|
|
191
271
|
|
|
192
|
-
|
|
193
|
-
|
|
272
|
+
try {
|
|
273
|
+
return adUnitsCodes.reduce((data, adUnitCode) => {
|
|
274
|
+
data[adUnitCode] = profileHandlers.reduce((targeting, ph) => {
|
|
275
|
+
// logMessage(`check if should set targeting for adunit '${adUnitCode}'`);
|
|
276
|
+
const [data, metadata] = this.#copyDataAndMetadata(ph);
|
|
277
|
+
if (ph.setTargeting(adUnitCode, data, metadata)) {
|
|
278
|
+
// logMessage(`set targeting for adunit '${adUnitCode}', source '${metadata.source}'`);
|
|
279
|
+
|
|
280
|
+
mergeDeep(targeting, data);
|
|
281
|
+
}
|
|
194
282
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
throw `missing required field "{field}" on {section}`;
|
|
198
|
-
}
|
|
199
|
-
});
|
|
200
|
-
} catch (e) {
|
|
201
|
-
logError(`unable to initialize: error on ${subSection} configuration: ${e}`);
|
|
202
|
-
return false;
|
|
203
|
-
}
|
|
283
|
+
return targeting;
|
|
284
|
+
}, {});
|
|
204
285
|
|
|
205
|
-
|
|
286
|
+
return data;
|
|
287
|
+
}, {});
|
|
288
|
+
} catch (e) {
|
|
289
|
+
logError(`unable to format weborama rtd targeting data:`, e);
|
|
206
290
|
|
|
207
|
-
|
|
208
|
-
}
|
|
291
|
+
return {};
|
|
292
|
+
}
|
|
293
|
+
}
|
|
209
294
|
|
|
210
|
-
/**
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
}
|
|
295
|
+
/** Initialize subsection module
|
|
296
|
+
* @method
|
|
297
|
+
* @private
|
|
298
|
+
* @param {ModuleParams} moduleParams
|
|
299
|
+
* @param {string} subSection subsection name to initialize
|
|
300
|
+
* @param {string[]} requiredFields
|
|
301
|
+
* @return {boolean} true if module subsection was initialized with success
|
|
302
|
+
*/
|
|
303
|
+
#initSubSection(moduleParams, subSection, ...requiredFields) {
|
|
304
|
+
/** @type {CommonConf} */
|
|
305
|
+
const weboSectionConf = moduleParams[subSection] || { enabled: false };
|
|
306
|
+
|
|
307
|
+
if (weboSectionConf.enabled === false) {
|
|
308
|
+
delete moduleParams[subSection];
|
|
217
309
|
|
|
218
|
-
|
|
219
|
-
* @param {ModuleParams} moduleParams
|
|
220
|
-
* @param {WeboCtxConf|WeboUserDataConf|SfbxLiteDataConf} submoduleParams
|
|
221
|
-
* @return {void}
|
|
222
|
-
*/
|
|
223
|
-
function normalizeConf(moduleParams, submoduleParams) {
|
|
224
|
-
// handle defaults
|
|
225
|
-
Object.entries(globalDefaults).forEach(([propertyName, globalDefaultValue]) => {
|
|
226
|
-
if (!submoduleParams.hasOwnProperty(propertyName)) {
|
|
227
|
-
const hasModuleParam = moduleParams.hasOwnProperty(propertyName);
|
|
228
|
-
submoduleParams[propertyName] = (hasModuleParam) ? moduleParams[propertyName] : globalDefaultValue;
|
|
310
|
+
return false;
|
|
229
311
|
}
|
|
230
|
-
})
|
|
231
312
|
|
|
232
|
-
|
|
233
|
-
|
|
313
|
+
try {
|
|
314
|
+
this.#normalizeConf(moduleParams, weboSectionConf);
|
|
234
315
|
|
|
235
|
-
|
|
236
|
-
|
|
316
|
+
requiredFields.forEach(field => {
|
|
317
|
+
if (!(field in weboSectionConf)) {
|
|
318
|
+
throw `missing required field '${field}''`;
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
} catch (e) {
|
|
322
|
+
logError(`unable to initialize: error on ${subSection} configuration:`, e);
|
|
323
|
+
return false;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
logMessage(`weborama ${subSection} initialized with success`);
|
|
237
327
|
|
|
238
|
-
|
|
239
|
-
throw 'onData parameter should be a callback';
|
|
328
|
+
return true;
|
|
240
329
|
}
|
|
241
330
|
|
|
242
|
-
|
|
331
|
+
/** normalize submodule configuration
|
|
332
|
+
* @method
|
|
333
|
+
* @private
|
|
334
|
+
* @param {ModuleParams} moduleParams
|
|
335
|
+
* @param {CommonConf} submoduleParams
|
|
336
|
+
* @return {void}
|
|
337
|
+
* @throws will throw an error in case of invalid configuration
|
|
338
|
+
*/
|
|
339
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
340
|
+
#normalizeConf(moduleParams, submoduleParams) {
|
|
341
|
+
submoduleParams.defaultProfile = submoduleParams.defaultProfile || {};
|
|
243
342
|
|
|
244
|
-
|
|
245
|
-
throw 'defaultProfile is not valid';
|
|
246
|
-
}
|
|
247
|
-
}
|
|
343
|
+
const { setPrebidTargeting, sendToBidders, onData } = moduleParams;
|
|
248
344
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
*/
|
|
253
|
-
function coerceSetPrebidTargeting(submoduleParams) {
|
|
254
|
-
const setPrebidTargeting = submoduleParams.setPrebidTargeting;
|
|
345
|
+
submoduleParams.setPrebidTargeting ??= setPrebidTargeting;
|
|
346
|
+
submoduleParams.sendToBidders ??= sendToBidders;
|
|
347
|
+
submoduleParams.onData ??= onData;
|
|
255
348
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
}
|
|
349
|
+
// handle setPrebidTargeting
|
|
350
|
+
this.#coerceSetPrebidTargeting(submoduleParams);
|
|
259
351
|
|
|
260
|
-
|
|
261
|
-
|
|
352
|
+
// handle sendToBidders
|
|
353
|
+
this.#coerceSendToBidders(submoduleParams);
|
|
262
354
|
|
|
263
|
-
submoduleParams.
|
|
355
|
+
if (!isFn(submoduleParams.onData)) {
|
|
356
|
+
throw 'onData parameter should be a callback';
|
|
357
|
+
}
|
|
264
358
|
|
|
265
|
-
|
|
359
|
+
if (!isValidProfile(submoduleParams.defaultProfile)) {
|
|
360
|
+
throw 'defaultProfile is not valid';
|
|
361
|
+
}
|
|
266
362
|
}
|
|
267
363
|
|
|
268
|
-
|
|
269
|
-
|
|
364
|
+
/** coerce setPrebidTargeting to a callback
|
|
365
|
+
* @method
|
|
366
|
+
* @private
|
|
367
|
+
* @param {CommonConf} submoduleParams
|
|
368
|
+
* @return {void}
|
|
369
|
+
* @throws will throw an error in case of invalid configuration
|
|
370
|
+
*/
|
|
371
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
372
|
+
#coerceSetPrebidTargeting(submoduleParams) {
|
|
373
|
+
try {
|
|
374
|
+
submoduleParams.setPrebidTargeting = this.#wrapValidatorCallback(submoduleParams.setPrebidTargeting);
|
|
375
|
+
} catch (e) {
|
|
376
|
+
throw `invalid setPrebidTargeting: ${e}`;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
270
379
|
|
|
271
|
-
|
|
380
|
+
/** coerce sendToBidders to a callback
|
|
381
|
+
* @method
|
|
382
|
+
* @private
|
|
383
|
+
* @param {CommonConf} submoduleParams
|
|
384
|
+
* @return {void}
|
|
385
|
+
* @throws will throw an error in case of invalid configuration
|
|
386
|
+
*/
|
|
387
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
388
|
+
#coerceSendToBidders(submoduleParams) {
|
|
389
|
+
let sendToBidders = submoduleParams.sendToBidders;
|
|
390
|
+
|
|
391
|
+
if (isPlainObject(sendToBidders)) {
|
|
392
|
+
const sendToBiddersMap = Object.entries(sendToBidders).reduce((map, [key, value]) => {
|
|
393
|
+
map[key] = this.#wrapValidatorCallback(value);
|
|
394
|
+
return map;
|
|
395
|
+
}, {});
|
|
272
396
|
|
|
273
|
-
|
|
274
|
-
|
|
397
|
+
submoduleParams.sendToBidders = (bid, adUnitCode) => {
|
|
398
|
+
const bidder = bid.bidder;
|
|
399
|
+
if (!(bidder in sendToBiddersMap)) {
|
|
400
|
+
return false;
|
|
401
|
+
}
|
|
275
402
|
|
|
276
|
-
|
|
277
|
-
const allowedAdUnitCodes = setPrebidTargeting;
|
|
403
|
+
const validatorCallback = sendToBiddersMap[bidder];
|
|
278
404
|
|
|
279
|
-
|
|
405
|
+
try {
|
|
406
|
+
return validatorCallback(adUnitCode);
|
|
407
|
+
} catch (e) {
|
|
408
|
+
throw `invalid sendToBidders[${bidder}]: ${e}`;
|
|
409
|
+
}
|
|
410
|
+
};
|
|
280
411
|
|
|
281
|
-
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
try {
|
|
416
|
+
submoduleParams.sendToBidders = this.#wrapValidatorCallback(submoduleParams.sendToBidders,
|
|
417
|
+
(bid) => bid.bidder);
|
|
418
|
+
} catch (e) {
|
|
419
|
+
throw `invalid sendToBidders: ${e}`;
|
|
420
|
+
}
|
|
282
421
|
}
|
|
283
422
|
|
|
284
|
-
|
|
285
|
-
}
|
|
423
|
+
/**
|
|
424
|
+
* @typedef {Object} AdUnit
|
|
425
|
+
* @property {Object[]} bids
|
|
426
|
+
*/
|
|
427
|
+
/** function that handles bid request data
|
|
428
|
+
* @method
|
|
429
|
+
* @private
|
|
430
|
+
* @param {Object} reqBidsConfigObj
|
|
431
|
+
* @param {AdUnit[]} reqBidsConfigObj.adUnits
|
|
432
|
+
* @param {Object} reqBidsConfigObj.ortb2Fragments
|
|
433
|
+
* @param {Object} reqBidsConfigObj.ortb2Fragments.bidder
|
|
434
|
+
* @param {ModuleParams} moduleParams
|
|
435
|
+
* @returns {void}
|
|
436
|
+
*/
|
|
437
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
438
|
+
#handleBidRequestData(reqBidsConfigObj, moduleParams) {
|
|
439
|
+
const profileHandlers = this.#buildProfileHandlers(moduleParams);
|
|
440
|
+
|
|
441
|
+
if (isEmpty(profileHandlers)) {
|
|
442
|
+
logMessage('no data to send to bidders');
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
286
445
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
446
|
+
const adUnits = reqBidsConfigObj.adUnits || getGlobal().adUnits;
|
|
447
|
+
|
|
448
|
+
try {
|
|
449
|
+
adUnits.forEach(
|
|
450
|
+
adUnit => adUnit.bids?.forEach(
|
|
451
|
+
bid => profileHandlers.forEach(ph => {
|
|
452
|
+
// logMessage(`check if bidder '${bid.bidder}' and adunit '${adUnit.code} are share ${ph.metadata.source} data`);
|
|
453
|
+
|
|
454
|
+
const [data, metadata] = this.#copyDataAndMetadata(ph);
|
|
455
|
+
if (ph.sendToBidders(bid, adUnit.code, data, metadata)) {
|
|
456
|
+
// logMessage(`handling bidder '${bid.bidder}' with ${ph.metadata.source} data`);
|
|
457
|
+
|
|
458
|
+
this.#handleBid(reqBidsConfigObj, bid, data, ph.metadata);
|
|
459
|
+
}
|
|
460
|
+
})
|
|
461
|
+
)
|
|
462
|
+
);
|
|
463
|
+
} catch (e) {
|
|
464
|
+
logError('unable to send data to bidders:', e);
|
|
465
|
+
}
|
|
293
466
|
|
|
294
|
-
|
|
295
|
-
|
|
467
|
+
profileHandlers.forEach(ph => {
|
|
468
|
+
try {
|
|
469
|
+
const [data, metadata] = this.#copyDataAndMetadata(ph);
|
|
470
|
+
ph.onData(data, metadata);
|
|
471
|
+
} catch (e) {
|
|
472
|
+
logError(`error while execute onData callback with ${ph.metadata.source}-based data:`, e);
|
|
473
|
+
}
|
|
474
|
+
});
|
|
296
475
|
}
|
|
297
476
|
|
|
298
|
-
|
|
299
|
-
|
|
477
|
+
/** onSuccess callback type
|
|
478
|
+
* @callback successCallback
|
|
479
|
+
* @param {?Object} data
|
|
480
|
+
* @returns {void}
|
|
481
|
+
*/
|
|
482
|
+
|
|
483
|
+
/** onDone callback type
|
|
484
|
+
* @callback doneCallback
|
|
485
|
+
* @returns {void}
|
|
486
|
+
*/
|
|
487
|
+
|
|
488
|
+
/** Fetch Bigsea Contextual Profile
|
|
489
|
+
* @method
|
|
490
|
+
* @private
|
|
491
|
+
* @param {WeboCtxConf} weboCtxConf
|
|
492
|
+
* @param {successCallback} onSuccess callback
|
|
493
|
+
* @param {doneCallback} onDone callback
|
|
494
|
+
* @returns {void}
|
|
495
|
+
*/
|
|
496
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
497
|
+
#fetchContextualProfile(weboCtxConf, onSuccess, onDone) {
|
|
498
|
+
const token = weboCtxConf.token;
|
|
499
|
+
const baseURLProfileAPI = weboCtxConf.baseURLProfileAPI || BASE_URL_CONTEXTUAL_PROFILE_API;
|
|
500
|
+
|
|
501
|
+
let path = '/profile';
|
|
502
|
+
let queryString = '';
|
|
503
|
+
queryString = tryAppendQueryString(queryString, 'token', token);
|
|
504
|
+
|
|
505
|
+
if (weboCtxConf.assetID) {
|
|
506
|
+
path = '/document-profile';
|
|
507
|
+
|
|
508
|
+
let assetID = weboCtxConf.assetID;
|
|
509
|
+
if (isFn(assetID)) {
|
|
510
|
+
try {
|
|
511
|
+
assetID = weboCtxConf.assetID();
|
|
512
|
+
} catch (e) {
|
|
513
|
+
logError('unexpected error while fetching asset id from callback', e);
|
|
300
514
|
|
|
301
|
-
|
|
515
|
+
onDone();
|
|
302
516
|
|
|
303
|
-
|
|
304
|
-
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
305
520
|
|
|
306
|
-
|
|
307
|
-
|
|
521
|
+
if (!assetID) {
|
|
522
|
+
logError('missing asset id');
|
|
308
523
|
|
|
309
|
-
|
|
524
|
+
onDone();
|
|
310
525
|
|
|
311
|
-
|
|
312
|
-
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
313
528
|
|
|
314
|
-
|
|
315
|
-
|
|
529
|
+
queryString = tryAppendQueryString(queryString, 'assetId', assetID);
|
|
530
|
+
}
|
|
316
531
|
|
|
317
|
-
|
|
532
|
+
const targetURL = weboCtxConf.targetURL || document.URL;
|
|
533
|
+
queryString = tryAppendQueryString(queryString, 'url', targetURL);
|
|
318
534
|
|
|
319
|
-
|
|
320
|
-
}
|
|
535
|
+
const urlProfileAPI = `https://${baseURLProfileAPI}/api${path}?${queryString}`;
|
|
321
536
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
537
|
+
const success = (response, req) => {
|
|
538
|
+
if (req.status === 200) {
|
|
539
|
+
const data = JSON.parse(response);
|
|
540
|
+
onSuccess(data);
|
|
541
|
+
} else {
|
|
542
|
+
throw `unexpected http status response ${req.status} with response ${response}`;
|
|
328
543
|
}
|
|
329
544
|
|
|
330
|
-
|
|
545
|
+
onDone();
|
|
546
|
+
};
|
|
331
547
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
}
|
|
548
|
+
const error = (e, req) => {
|
|
549
|
+
logError(`unable to get weborama data`, e, req);
|
|
335
550
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
}
|
|
551
|
+
onDone();
|
|
552
|
+
};
|
|
339
553
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
554
|
+
const callback = {
|
|
555
|
+
success,
|
|
556
|
+
error,
|
|
557
|
+
};
|
|
343
558
|
|
|
344
|
-
|
|
559
|
+
const options = {
|
|
560
|
+
method: 'GET',
|
|
561
|
+
withCredentials: false,
|
|
345
562
|
};
|
|
346
563
|
|
|
347
|
-
|
|
564
|
+
ajax(urlProfileAPI, callback, null, options);
|
|
348
565
|
}
|
|
349
566
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
567
|
+
/** set bigsea contextual profile on module state
|
|
568
|
+
* @method
|
|
569
|
+
* @private
|
|
570
|
+
* @param {?Object} data
|
|
571
|
+
* @returns {void}
|
|
572
|
+
*/
|
|
573
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
574
|
+
#setWeboContextualProfile(data) {
|
|
575
|
+
if (data && isPlainObject(data) && isValidProfile(data) && !isEmpty(data)) {
|
|
576
|
+
this.#components.WeboCtx.data = data;
|
|
577
|
+
}
|
|
360
578
|
}
|
|
361
579
|
|
|
362
|
-
|
|
580
|
+
/** function that provides data handlers based on the configuration
|
|
581
|
+
* @method
|
|
582
|
+
* @private
|
|
583
|
+
* @param {ModuleParams} moduleParams
|
|
584
|
+
* @returns {ProfileHandler[]}
|
|
585
|
+
*/
|
|
586
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
587
|
+
#buildProfileHandlers(moduleParams) {
|
|
588
|
+
const steps = [{
|
|
589
|
+
component: this.#components.WeboCtx,
|
|
590
|
+
conf: moduleParams?.weboCtxConf,
|
|
591
|
+
}, {
|
|
592
|
+
component: this.#components.WeboUserData,
|
|
593
|
+
conf: moduleParams?.weboUserDataConf,
|
|
594
|
+
}, {
|
|
595
|
+
component: this.#components.SfbxLiteData,
|
|
596
|
+
conf: moduleParams?.sfbxLiteDataConf,
|
|
597
|
+
}];
|
|
598
|
+
|
|
599
|
+
return steps.filter(step => step.component.initialized).reduce((ph, { component, conf }) => {
|
|
600
|
+
const user = component.user;
|
|
601
|
+
const source = component.source;
|
|
602
|
+
const callback = component.callbackBuilder(component /* equivalent to this */);
|
|
603
|
+
const profileHandler = this.#buildProfileHandler(conf, callback, user, source);
|
|
604
|
+
if (profileHandler) {
|
|
605
|
+
ph.push(profileHandler);
|
|
606
|
+
} else {
|
|
607
|
+
logMessage(`skip ${source} profile: no data`);
|
|
608
|
+
}
|
|
363
609
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
610
|
+
return ph;
|
|
611
|
+
}, []);
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
/**
|
|
615
|
+
* @typedef {Object} ProfileHandler
|
|
616
|
+
* @property {Profile} data
|
|
617
|
+
* @property {dataCallbackMetadata} metadata
|
|
618
|
+
* @property {setPrebidTargetingCallback} setTargeting
|
|
619
|
+
* @property {sendToBiddersCallback} sendToBidders
|
|
620
|
+
* @property {dataCallback} onData
|
|
621
|
+
*/
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* @callback buildProfileHandlerCallbackBuilder
|
|
625
|
+
* @param {Component} component
|
|
626
|
+
* @returns {buildProfileHandlerCallback}
|
|
627
|
+
*/
|
|
628
|
+
|
|
629
|
+
/**
|
|
630
|
+
* @callback buildProfileHandlerCallback
|
|
631
|
+
* @param {CommonConf} dataConf
|
|
632
|
+
* @returns {[Profile,boolean]} profile + is default flag
|
|
633
|
+
*/
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* return specific profile handler
|
|
637
|
+
* @method
|
|
638
|
+
* @private
|
|
639
|
+
* @param {CommonConf} dataConf
|
|
640
|
+
* @param {buildProfileHandlerCallback} callback
|
|
641
|
+
* @param {boolean} user
|
|
642
|
+
* @param {string} source
|
|
643
|
+
* @returns {ProfileHandler}
|
|
644
|
+
*/
|
|
645
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
646
|
+
#buildProfileHandler(dataConf, callback, user, source) {
|
|
647
|
+
if (!dataConf) {
|
|
648
|
+
return;
|
|
369
649
|
}
|
|
370
650
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
651
|
+
const [data, isDefault] = callback(dataConf);
|
|
652
|
+
if (isEmpty(data)) {
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
return {
|
|
657
|
+
data: data,
|
|
658
|
+
metadata: {
|
|
659
|
+
user: user,
|
|
660
|
+
source: source,
|
|
661
|
+
isDefault: !!isDefault,
|
|
662
|
+
},
|
|
663
|
+
setTargeting: dataConf.setPrebidTargeting,
|
|
664
|
+
sendToBidders: dataConf.sendToBidders,
|
|
665
|
+
onData: dataConf.onData,
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
/** handle individual bid
|
|
669
|
+
* @method
|
|
670
|
+
* @private
|
|
671
|
+
* @param {Object} reqBidsConfigObj
|
|
672
|
+
* @param {Object} reqBidsConfigObj.ortb2Fragments
|
|
673
|
+
* @param {Object} reqBidsConfigObj.ortb2Fragments.bidder
|
|
674
|
+
* @param {Object} bid
|
|
675
|
+
* @param {string} bid.bidder
|
|
676
|
+
* @param {Profile} profile
|
|
677
|
+
* @param {dataCallbackMetadata} metadata
|
|
678
|
+
* @returns {void}
|
|
679
|
+
*/
|
|
680
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
681
|
+
#handleBid(reqBidsConfigObj, bid, profile, metadata) {
|
|
682
|
+
this.#handleBidViaORTB2(reqBidsConfigObj, bid.bidder, profile, metadata);
|
|
683
|
+
|
|
684
|
+
/** @type {Object.<string,string>} */
|
|
685
|
+
const bidderAliasRegistry = adapterManager.aliasRegistry || {};
|
|
686
|
+
|
|
687
|
+
/** @type {string} */
|
|
688
|
+
const bidder = bidderAliasRegistry[bid.bidder] || bid.bidder;
|
|
689
|
+
|
|
690
|
+
switch (bidder) {
|
|
691
|
+
case 'appnexus':
|
|
692
|
+
this.#handleAppnexusBid(bid, profile);
|
|
693
|
+
break;
|
|
694
|
+
case 'pubmatic':
|
|
695
|
+
this.#handlePubmaticBid(bid, profile);
|
|
696
|
+
break;
|
|
697
|
+
case 'smartadserver':
|
|
698
|
+
this.#handleSmartadserverBid(bid, profile);
|
|
699
|
+
break;
|
|
700
|
+
case 'rubicon':
|
|
701
|
+
this.#handleRubiconBid(bid, profile, metadata);
|
|
702
|
+
break;
|
|
376
703
|
}
|
|
377
704
|
}
|
|
378
705
|
|
|
379
|
-
|
|
380
|
-
|
|
706
|
+
/** function that handles bid request data
|
|
707
|
+
* @method
|
|
708
|
+
* @private
|
|
709
|
+
* @param {ProfileHandler} ph profile handler
|
|
710
|
+
* @returns {[Profile,dataCallbackMetadata]} deeply copy data + metadata
|
|
711
|
+
*/
|
|
712
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
713
|
+
#copyDataAndMetadata(ph) {
|
|
714
|
+
return [deepClone(ph.data), deepClone(ph.metadata)];
|
|
715
|
+
}
|
|
381
716
|
|
|
382
|
-
/**
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
717
|
+
/** handle appnexus/xandr bid
|
|
718
|
+
* @method
|
|
719
|
+
* @private
|
|
720
|
+
* @param {Object} bid
|
|
721
|
+
* @param {Object} bid.params
|
|
722
|
+
* @param {Object} bid.params.keyword
|
|
723
|
+
* @param {Profile} profile
|
|
724
|
+
* @returns {void}
|
|
725
|
+
*/
|
|
726
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
727
|
+
#handleAppnexusBid(bid, profile) {
|
|
728
|
+
const base = 'params.keywords';
|
|
729
|
+
this.#assignProfileToObject(bid, base, profile);
|
|
730
|
+
}
|
|
389
731
|
|
|
390
|
-
|
|
732
|
+
/** handle pubmatic bid
|
|
733
|
+
* @method
|
|
734
|
+
* @private
|
|
735
|
+
* @param {Object} bid
|
|
736
|
+
* @param {Object} bid.params
|
|
737
|
+
* @param {string} bid.params.dctr
|
|
738
|
+
* @param {Profile} profile
|
|
739
|
+
* @returns {void}
|
|
740
|
+
*/
|
|
741
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
742
|
+
#handlePubmaticBid(bid, profile) {
|
|
743
|
+
const sep = '|';
|
|
744
|
+
const subsep = ',';
|
|
745
|
+
|
|
746
|
+
bid.params ||= {};
|
|
747
|
+
|
|
748
|
+
const data = bid.params.dctr || '';
|
|
749
|
+
const target = new Set(data.split(sep).filter((x) => x.length > 0));
|
|
750
|
+
|
|
751
|
+
Object.entries(profile).forEach(([key, values]) => {
|
|
752
|
+
const value = values.join(subsep);
|
|
753
|
+
const keyword = `${key}=${value}`;
|
|
754
|
+
target.add(keyword);
|
|
755
|
+
});
|
|
391
756
|
|
|
392
|
-
|
|
393
|
-
logMessage('no data to set targeting');
|
|
394
|
-
return {};
|
|
757
|
+
bid.params.dctr = Array.from(target).join(sep);
|
|
395
758
|
}
|
|
396
759
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
760
|
+
/** handle smartadserver bid
|
|
761
|
+
* @method
|
|
762
|
+
* @private
|
|
763
|
+
* @param {Object} bid
|
|
764
|
+
* @param {Object} bid.params
|
|
765
|
+
* @param {string} bid.params.target
|
|
766
|
+
* @param {Profile} profile
|
|
767
|
+
* @returns {void}
|
|
768
|
+
*/
|
|
769
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
770
|
+
#handleSmartadserverBid(bid, profile) {
|
|
771
|
+
const sep = ';';
|
|
772
|
+
|
|
773
|
+
bid.params ||= {};
|
|
774
|
+
|
|
775
|
+
const data = bid.params.target || '';
|
|
776
|
+
const target = new Set(data.split(sep).filter((x) => x.length > 0));
|
|
777
|
+
|
|
778
|
+
Object.entries(profile).forEach(([key, values]) => {
|
|
779
|
+
values.forEach(value => {
|
|
780
|
+
const keyword = `${key}=${value}`;
|
|
781
|
+
target.add(keyword);
|
|
782
|
+
})
|
|
783
|
+
});
|
|
411
784
|
|
|
412
|
-
|
|
413
|
-
} catch (e) {
|
|
414
|
-
logError('unable to format weborama rtd targeting data', e);
|
|
415
|
-
return {};
|
|
785
|
+
bid.params.target = Array.from(target).join(sep);
|
|
416
786
|
}
|
|
417
|
-
}
|
|
418
787
|
|
|
419
|
-
/**
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
source: 'contextual',
|
|
435
|
-
isDefault: !!isDefault,
|
|
436
|
-
},
|
|
437
|
-
setTargeting: weboCtxConf.setPrebidTargeting,
|
|
438
|
-
sendToBidders: weboCtxConf.sendToBidders,
|
|
439
|
-
onData: weboCtxConf.onData,
|
|
440
|
-
})
|
|
788
|
+
/** handle rubicon bid
|
|
789
|
+
* @method
|
|
790
|
+
* @private
|
|
791
|
+
* @param {Object} bid
|
|
792
|
+
* @param {string} bid.bidder
|
|
793
|
+
* @param {Profile} profile
|
|
794
|
+
* @param {dataCallbackMetadata} metadata
|
|
795
|
+
* @returns {void}
|
|
796
|
+
*/
|
|
797
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
798
|
+
#handleRubiconBid(bid, profile, metadata) {
|
|
799
|
+
if (isBoolean(metadata.user)) {
|
|
800
|
+
const section = metadata.user ? 'visitor' : 'inventory';
|
|
801
|
+
const base = `params.${section}`;
|
|
802
|
+
this.#assignProfileToObject(bid, base, profile);
|
|
441
803
|
} else {
|
|
442
|
-
logMessage('
|
|
804
|
+
logMessage(`SKIP bidder '${bid.bidder}', data from '${metadata.source}' is not defined as user or site-centric`);
|
|
443
805
|
}
|
|
444
806
|
}
|
|
445
807
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
})
|
|
808
|
+
/** handle generic bid via ortb2 arbitrary data
|
|
809
|
+
* @method
|
|
810
|
+
* @private
|
|
811
|
+
* @param {Object} reqBidsConfigObj
|
|
812
|
+
* @param {Object} reqBidsConfigObj.ortb2Fragments
|
|
813
|
+
* @param {Object} reqBidsConfigObj.ortb2Fragments.bidder
|
|
814
|
+
* @param {string} bidder
|
|
815
|
+
* @param {Profile} profile
|
|
816
|
+
* @param {dataCallbackMetadata} metadata
|
|
817
|
+
* @returns {void}
|
|
818
|
+
*/
|
|
819
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
820
|
+
#handleBidViaORTB2(reqBidsConfigObj, bidder, profile, metadata) {
|
|
821
|
+
if (isBoolean(metadata.user)) {
|
|
822
|
+
logMessage(`bidder '${bidder}' is not directly supported, trying set data via bidder ortb2 fpd`);
|
|
823
|
+
const section = metadata.user ? 'user' : 'site';
|
|
824
|
+
const base = `${bidder}.${section}.ext.data`;
|
|
825
|
+
|
|
826
|
+
this.#assignProfileToObject(reqBidsConfigObj.ortb2Fragments?.bidder, base, profile);
|
|
461
827
|
} else {
|
|
462
|
-
logMessage(
|
|
828
|
+
logMessage(`SKIP unsupported bidder '${bidder}', data from '${metadata.source}' is not defined as user or site-centric`);
|
|
463
829
|
}
|
|
464
830
|
}
|
|
465
831
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
} else {
|
|
482
|
-
logMessage('skip sfbx lite profile: no data');
|
|
483
|
-
}
|
|
832
|
+
/**
|
|
833
|
+
* assign profile to object
|
|
834
|
+
* @method
|
|
835
|
+
* @private
|
|
836
|
+
* @param {Object} destination
|
|
837
|
+
* @param {string} base
|
|
838
|
+
* @param {Profile} profile
|
|
839
|
+
* @returns {void}
|
|
840
|
+
*/
|
|
841
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
842
|
+
#assignProfileToObject(destination, base, profile) {
|
|
843
|
+
Object.entries(profile).forEach(([key, values]) => {
|
|
844
|
+
const path = `${base}.${key}`;
|
|
845
|
+
deepSetValue(destination, path, values);
|
|
846
|
+
})
|
|
484
847
|
}
|
|
485
848
|
|
|
486
|
-
|
|
849
|
+
/**
|
|
850
|
+
* @callback validatorCallback
|
|
851
|
+
* @param {string} target
|
|
852
|
+
* @returns {boolean}
|
|
853
|
+
*/
|
|
854
|
+
|
|
855
|
+
/**
|
|
856
|
+
* @callback coerceCallback
|
|
857
|
+
* @param {*} input
|
|
858
|
+
* @returns {*}
|
|
859
|
+
*/
|
|
860
|
+
|
|
861
|
+
/**
|
|
862
|
+
* wrap value into validator
|
|
863
|
+
* @method
|
|
864
|
+
* @private
|
|
865
|
+
* @param {*} value
|
|
866
|
+
* @param {coerceCallback} coerce
|
|
867
|
+
* @returns {validatorCallback}
|
|
868
|
+
* @throws will throw an error in case of unsupported type
|
|
869
|
+
*/
|
|
870
|
+
// eslint-disable-next-line no-dupe-class-members
|
|
871
|
+
#wrapValidatorCallback(value, coerce = (x) => x) {
|
|
872
|
+
if (isFn(value)) {
|
|
873
|
+
return value;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
if (isBoolean(value)) {
|
|
877
|
+
return (_) => value;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
if (isStr(value)) {
|
|
881
|
+
return (target) => {
|
|
882
|
+
return value == coerce(target);
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
if (isArray(value)) {
|
|
887
|
+
return (target) => {
|
|
888
|
+
return value.includes(coerce(target));
|
|
889
|
+
};
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
throw `unexpected format: ${typeof value} (expects function, boolean, string or array)`;
|
|
893
|
+
}
|
|
487
894
|
}
|
|
488
895
|
|
|
489
|
-
/**
|
|
490
|
-
*
|
|
491
|
-
* @
|
|
896
|
+
/**
|
|
897
|
+
* check if profile is valid
|
|
898
|
+
* @param {*} profile
|
|
899
|
+
* @returns {boolean}
|
|
492
900
|
*/
|
|
493
|
-
function
|
|
494
|
-
if (
|
|
495
|
-
return
|
|
901
|
+
export function isValidProfile(profile) {
|
|
902
|
+
if (!isPlainObject(profile)) {
|
|
903
|
+
return false;
|
|
496
904
|
}
|
|
497
905
|
|
|
498
|
-
|
|
906
|
+
return Object.values(profile).every((field) => isArray(field) && field.every(isStr));
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
/**
|
|
910
|
+
* bind callback with component
|
|
911
|
+
* @param {Component} component
|
|
912
|
+
* @returns {buildProfileHandlerCallback}
|
|
913
|
+
*/
|
|
914
|
+
function getContextualProfile(component /* equivalent to this */) {
|
|
915
|
+
/** return contextual profile
|
|
916
|
+
* @param {WeboCtxConf} weboCtxConf
|
|
917
|
+
* @returns {[Profile,boolean]} contextual profile + isDefault boolean flag
|
|
918
|
+
*/
|
|
919
|
+
return function (weboCtxConf) {
|
|
920
|
+
if (component.data) {
|
|
921
|
+
return [component.data, false];
|
|
922
|
+
}
|
|
499
923
|
|
|
500
|
-
|
|
924
|
+
const defaultContextualProfile = weboCtxConf.defaultProfile || {};
|
|
925
|
+
|
|
926
|
+
return [defaultContextualProfile, true];
|
|
927
|
+
}
|
|
501
928
|
}
|
|
502
929
|
|
|
503
|
-
/**
|
|
504
|
-
*
|
|
505
|
-
* @
|
|
930
|
+
/**
|
|
931
|
+
* bind callback with component
|
|
932
|
+
* @param {Component} component
|
|
933
|
+
* @returns {buildProfileHandlerCallback}
|
|
506
934
|
*/
|
|
507
|
-
function getWeboUserDataProfile(
|
|
508
|
-
return
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
935
|
+
function getWeboUserDataProfile(component /* equivalent to this */) {
|
|
936
|
+
/** return weboUserData profile
|
|
937
|
+
* @param {WeboUserDataConf} weboUserDataConf
|
|
938
|
+
* @returns {[Profile,boolean]} weboUserData profile + isDefault boolean flag
|
|
939
|
+
*/
|
|
940
|
+
return function (weboUserDataConf) {
|
|
941
|
+
return getDataFromLocalStorage(weboUserDataConf,
|
|
942
|
+
() => component.data,
|
|
943
|
+
(data) => component.data = data,
|
|
944
|
+
DEFAULT_LOCAL_STORAGE_USER_PROFILE_KEY,
|
|
945
|
+
LOCAL_STORAGE_USER_TARGETING_SECTION,
|
|
946
|
+
WEBO_USER_DATA_SOURCE_LABEL);
|
|
947
|
+
}
|
|
514
948
|
}
|
|
515
949
|
|
|
516
|
-
/**
|
|
517
|
-
*
|
|
518
|
-
* @
|
|
950
|
+
/**
|
|
951
|
+
* bind callback with component
|
|
952
|
+
* @param {Component} component
|
|
953
|
+
* @returns {buildProfileHandlerCallback}
|
|
519
954
|
*/
|
|
520
|
-
function getSfbxLiteDataProfile(
|
|
521
|
-
return
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
955
|
+
function getSfbxLiteDataProfile(component /* equivalent to this */) {
|
|
956
|
+
/** return weboUserData profile
|
|
957
|
+
* @param {SfbxLiteDataConf} sfbxLiteDataConf
|
|
958
|
+
* @returns {[Profile,boolean]} sfbxLiteData profile + isDefault boolean flag
|
|
959
|
+
*/
|
|
960
|
+
return function getSfbxLiteDataProfile(sfbxLiteDataConf) {
|
|
961
|
+
return getDataFromLocalStorage(sfbxLiteDataConf,
|
|
962
|
+
() => component.data,
|
|
963
|
+
(data) => component.data = data,
|
|
964
|
+
DEFAULT_LOCAL_STORAGE_LITE_PROFILE_KEY,
|
|
965
|
+
LOCAL_STORAGE_LITE_TARGETING_SECTION,
|
|
966
|
+
SFBX_LITE_DATA_SOURCE_LABEL);
|
|
967
|
+
}
|
|
527
968
|
}
|
|
528
969
|
|
|
970
|
+
/**
|
|
971
|
+
* @callback cacheGetCallback
|
|
972
|
+
* @returns {Profile}
|
|
973
|
+
*/
|
|
974
|
+
/**
|
|
975
|
+
* @callback cacheSetCallback
|
|
976
|
+
* @param {Profile} profile
|
|
977
|
+
* @returns {void}
|
|
978
|
+
*/
|
|
979
|
+
|
|
529
980
|
/** return generic webo data profile
|
|
530
981
|
* @param {WeboUserDataConf|SfbxLiteDataConf} weboDataConf
|
|
531
982
|
* @param {cacheGetCallback} cacheGet
|
|
532
983
|
* @param {cacheSetCallback} cacheSet
|
|
533
|
-
* @param {
|
|
534
|
-
* @param {
|
|
535
|
-
* @param {
|
|
536
|
-
* @returns {
|
|
984
|
+
* @param {string} defaultLocalStorageProfileKey
|
|
985
|
+
* @param {string} targetingSection
|
|
986
|
+
* @param {string} source
|
|
987
|
+
* @returns {[Profile,boolean]} webo (user|lite) data profile + isDefault boolean flag
|
|
537
988
|
*/
|
|
538
989
|
function getDataFromLocalStorage(weboDataConf, cacheGet, cacheSet, defaultLocalStorageProfileKey, targetingSection, source) {
|
|
539
990
|
const defaultProfile = weboDataConf.defaultProfile || {};
|
|
540
991
|
|
|
541
|
-
if (storage.localStorageIsEnabled() && !cacheGet()) {
|
|
992
|
+
if (storage.hasLocalStorage() && storage.localStorageIsEnabled() && !cacheGet()) {
|
|
542
993
|
const localStorageProfileKey = weboDataConf.localStorageProfileKey || defaultLocalStorageProfileKey;
|
|
543
994
|
|
|
544
995
|
const entry = storage.getDataFromLocalStorage(localStorageProfileKey);
|
|
545
996
|
if (entry) {
|
|
546
997
|
const data = JSON.parse(entry);
|
|
547
|
-
if (data && isPlainObject(data) && data
|
|
998
|
+
if (data && isPlainObject(data) && targetingSection in data) {
|
|
999
|
+
/** @type {profile} */
|
|
548
1000
|
const profile = data[targetingSection];
|
|
549
1001
|
const valid = isValidProfile(profile);
|
|
550
1002
|
if (!valid) {
|
|
551
1003
|
logWarn(`found invalid ${source} profile on local storage key ${localStorageProfileKey}, section ${targetingSection}`);
|
|
1004
|
+
|
|
1005
|
+
return;
|
|
552
1006
|
}
|
|
553
1007
|
|
|
554
|
-
if (
|
|
1008
|
+
if (!isEmpty(data)) {
|
|
555
1009
|
cacheSet(profile);
|
|
556
1010
|
}
|
|
557
1011
|
}
|
|
@@ -566,328 +1020,31 @@ function getDataFromLocalStorage(weboDataConf, cacheGet, cacheSet, defaultLocalS
|
|
|
566
1020
|
|
|
567
1021
|
return [defaultProfile, true];
|
|
568
1022
|
}
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
setWeboContextualProfile(data);
|
|
593
|
-
}, () => {
|
|
594
|
-
handleBidRequestData(reqBidsConfigObj, moduleParams);
|
|
595
|
-
|
|
596
|
-
onDone();
|
|
597
|
-
});
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
/** function that handles bid request data
|
|
601
|
-
* @param {Object} reqBids
|
|
602
|
-
* @param {ModuleParams} moduleParams
|
|
603
|
-
* @returns {void}
|
|
604
|
-
*/
|
|
605
|
-
function handleBidRequestData(reqBids, moduleParams) {
|
|
606
|
-
const profileHandlers = buildProfileHandlers(moduleParams);
|
|
607
|
-
|
|
608
|
-
if (isEmpty(profileHandlers)) {
|
|
609
|
-
logMessage('no data to send to bidders');
|
|
610
|
-
return;
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
const adUnits = reqBids.adUnits || getGlobal().adUnits;
|
|
614
|
-
|
|
615
|
-
try {
|
|
616
|
-
adUnits.filter(
|
|
617
|
-
adUnit => adUnit.hasOwnProperty('bids')
|
|
618
|
-
).forEach(
|
|
619
|
-
adUnit => adUnit.bids.forEach(
|
|
620
|
-
bid => profileHandlers.forEach(ph => {
|
|
621
|
-
// logMessage(`check if bidder '${bid.bidder}' and adunit '${adUnit.code} are share ${ph.metadata.source} data`);
|
|
622
|
-
|
|
623
|
-
const cph = copyProfileHandler(ph);
|
|
624
|
-
if (ph.sendToBidders(bid, adUnit.code, cph.data, cph.metadata)) {
|
|
625
|
-
// logMessage(`handling bidder '${bid.bidder}' with ${ph.metadata.source} data`);
|
|
626
|
-
|
|
627
|
-
handleBid(reqBids, bid, cph.data, ph.metadata);
|
|
628
|
-
}
|
|
629
|
-
})
|
|
630
|
-
)
|
|
631
|
-
);
|
|
632
|
-
} catch (e) {
|
|
633
|
-
logError('unable to send data to bidders:', e);
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
profileHandlers.forEach(ph => {
|
|
637
|
-
try {
|
|
638
|
-
const cph = copyProfileHandler(ph);
|
|
639
|
-
ph.onData(cph.data, cph.metadata);
|
|
640
|
-
} catch (e) {
|
|
641
|
-
logError(`error while executure onData callback with ${ph.metadata.source}-based data:`, e);
|
|
642
|
-
}
|
|
643
|
-
});
|
|
644
|
-
}
|
|
645
|
-
/** function that handles bid request data
|
|
646
|
-
* @param {Object} ph profile handler
|
|
647
|
-
*@returns {Object} of deeply copy data and metadata
|
|
648
|
-
*/
|
|
649
|
-
function copyProfileHandler(ph) {
|
|
650
|
-
return {
|
|
651
|
-
data: deepClone(ph.data),
|
|
652
|
-
metadata: deepClone(ph.metadata),
|
|
653
|
-
};
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
/** @type {string} */
|
|
657
|
-
const APPNEXUS = 'appnexus';
|
|
658
|
-
|
|
659
|
-
/** @type {string} */
|
|
660
|
-
const PUBMATIC = 'pubmatic';
|
|
661
|
-
|
|
662
|
-
/** @type {string} */
|
|
663
|
-
const RUBICON = 'rubicon';
|
|
664
|
-
|
|
665
|
-
/** @type {string} */
|
|
666
|
-
const SMARTADSERVER = 'smartadserver';
|
|
667
|
-
|
|
668
|
-
/** @type {Object} */
|
|
669
|
-
const bidderAliasRegistry = adapterManager.aliasRegistry || {};
|
|
670
|
-
|
|
671
|
-
/** handle individual bid
|
|
672
|
-
* @param reqBids
|
|
673
|
-
* @param {Object} bid
|
|
674
|
-
* @param {Object} profile
|
|
675
|
-
* @param {Object} metadata
|
|
676
|
-
* @returns {void}
|
|
677
|
-
*/
|
|
678
|
-
function handleBid(reqBids, bid, profile, metadata) {
|
|
679
|
-
const bidder = bidderAliasRegistry[bid.bidder] || bid.bidder;
|
|
680
|
-
|
|
681
|
-
switch (bidder) {
|
|
682
|
-
// TODO: these special cases should not be necessary - all adapters should look into FPD, not just their params
|
|
683
|
-
case APPNEXUS:
|
|
684
|
-
handleAppnexusBid(bid, profile);
|
|
685
|
-
|
|
686
|
-
break;
|
|
687
|
-
|
|
688
|
-
case PUBMATIC:
|
|
689
|
-
handlePubmaticBid(bid, profile);
|
|
690
|
-
|
|
691
|
-
break;
|
|
692
|
-
|
|
693
|
-
case SMARTADSERVER:
|
|
694
|
-
handleSmartadserverBid(bid, profile);
|
|
695
|
-
|
|
696
|
-
break;
|
|
697
|
-
case RUBICON:
|
|
698
|
-
handleRubiconBid(bid, profile, metadata);
|
|
699
|
-
|
|
700
|
-
break;
|
|
701
|
-
default:
|
|
702
|
-
handleBidViaORTB2(reqBids, bid, profile, metadata);
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
/** handle appnexus/xandr bid
|
|
707
|
-
* @param {Object} bid
|
|
708
|
-
* @param {Object} profile
|
|
709
|
-
* @returns {void}
|
|
710
|
-
*/
|
|
711
|
-
function handleAppnexusBid(bid, profile) {
|
|
712
|
-
const base = 'params.keywords';
|
|
713
|
-
assignProfileToObject(bid, base, profile);
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
/** handle pubmatic bid
|
|
717
|
-
* @param {Object} bid
|
|
718
|
-
* @param {Object} profile
|
|
719
|
-
* @returns {void}
|
|
720
|
-
*/
|
|
721
|
-
function handlePubmaticBid(bid, profile) {
|
|
722
|
-
const sep = '|';
|
|
723
|
-
const subsep = ',';
|
|
724
|
-
const target = [];
|
|
725
|
-
|
|
726
|
-
bid.params ||= {};
|
|
727
|
-
|
|
728
|
-
const data = bid.params.dctr;
|
|
729
|
-
if (data) {
|
|
730
|
-
data.split(sep).forEach(t => target.push(t));
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
Object.keys(profile).forEach(key => {
|
|
734
|
-
const value = profile[key].join(subsep);
|
|
735
|
-
const keyword = `${key}=${value}`;
|
|
736
|
-
if (target.indexOf(keyword) === -1) {
|
|
737
|
-
target.push(keyword);
|
|
738
|
-
}
|
|
739
|
-
});
|
|
740
|
-
|
|
741
|
-
bid.params.dctr = target.join(sep);
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
/** handle smartadserver bid
|
|
745
|
-
* @param {Object} bid
|
|
746
|
-
* @param {Object} profile
|
|
747
|
-
* @returns {void}
|
|
748
|
-
*/
|
|
749
|
-
function handleSmartadserverBid(bid, profile) {
|
|
750
|
-
const sep = ';';
|
|
751
|
-
const target = [];
|
|
752
|
-
|
|
753
|
-
bid.params ||= {};
|
|
754
|
-
|
|
755
|
-
const data = bid.params.target;
|
|
756
|
-
if (data) {
|
|
757
|
-
data.split(sep).forEach(t => target.push(t));
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
Object.keys(profile).forEach(key => {
|
|
761
|
-
profile[key].forEach(value => {
|
|
762
|
-
const keyword = `${key}=${value}`;
|
|
763
|
-
if (target.indexOf(keyword) === -1) {
|
|
764
|
-
target.push(keyword);
|
|
765
|
-
}
|
|
766
|
-
});
|
|
767
|
-
});
|
|
768
|
-
|
|
769
|
-
bid.params.target = target.join(sep);
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
/** handle rubicon bid
|
|
773
|
-
* @param {Object} bid
|
|
774
|
-
* @param {Object} profile
|
|
775
|
-
* @param {Object} metadata
|
|
776
|
-
* @returns {void}
|
|
777
|
-
*/
|
|
778
|
-
function handleRubiconBid(bid, profile, metadata) {
|
|
779
|
-
if (isBoolean(metadata.user)) {
|
|
780
|
-
const section = (metadata.user) ? 'visitor' : 'inventory';
|
|
781
|
-
const base = `params.${section}`;
|
|
782
|
-
assignProfileToObject(bid, base, profile);
|
|
783
|
-
} else {
|
|
784
|
-
logMessage(`SKIP bidder '${bid.bidder}', data from '${metadata.source}' is not defined as user or site-centric`);
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
/** handle generic bid via ortb2 arbitrary data
|
|
789
|
-
* @param reqBids
|
|
790
|
-
* @param {Object} bid
|
|
791
|
-
* @param {Object} profile
|
|
792
|
-
* @param {Object} metadata
|
|
793
|
-
* @returns {void}
|
|
794
|
-
*/
|
|
795
|
-
function handleBidViaORTB2(reqBids, bid, profile, metadata) {
|
|
796
|
-
if (isBoolean(metadata.user)) {
|
|
797
|
-
logMessage(`bidder '${bid.bidder}' is not directly supported, trying set data via bidder ortb2 fpd`);
|
|
798
|
-
const section = ((metadata.user) ? 'user' : 'site');
|
|
799
|
-
const base = `${bid.bidder}.${section}.ext.data`;
|
|
800
|
-
|
|
801
|
-
assignProfileToObject(reqBids.ortb2Fragments?.bidder, base, profile);
|
|
802
|
-
} else {
|
|
803
|
-
logMessage(`SKIP unsupported bidder '${bid.bidder}', data from '${metadata.source}' is not defined as user or site-centric`);
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
/**
|
|
808
|
-
* assign profile to object
|
|
809
|
-
* @param {Object} destination
|
|
810
|
-
* @param {string} base
|
|
811
|
-
* @param {Object} profile
|
|
812
|
-
* @returns {void}
|
|
813
|
-
*/
|
|
814
|
-
function assignProfileToObject(destination, base, profile) {
|
|
815
|
-
Object.keys(profile).forEach(key => {
|
|
816
|
-
const path = `${base}.${key}`;
|
|
817
|
-
deepSetValue(destination, path, profile[key])
|
|
818
|
-
})
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
/** set bigsea contextual profile on module state
|
|
822
|
-
* @param {null|Object} data
|
|
823
|
-
* @returns {void}
|
|
824
|
-
*/
|
|
825
|
-
export function setWeboContextualProfile(data) {
|
|
826
|
-
if (data && isPlainObject(data) && isValidProfile(data) && !isEmpty(data)) {
|
|
827
|
-
_weboContextualProfile = data;
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
|
|
831
|
-
/** onSuccess callback type
|
|
832
|
-
* @callback successCallback
|
|
833
|
-
* @param {null|Object} data
|
|
834
|
-
* @returns {void}
|
|
835
|
-
*/
|
|
836
|
-
|
|
837
|
-
/** onDone callback type
|
|
838
|
-
* @callback doneCallback
|
|
839
|
-
* @returns {void}
|
|
840
|
-
*/
|
|
841
|
-
|
|
842
|
-
/** Fetch Bigsea Contextual Profile
|
|
843
|
-
* @param {WeboCtxConf} weboCtxConf
|
|
844
|
-
* @param {successCallback} onSuccess callback
|
|
845
|
-
* @param {doneCallback} onDone callback
|
|
846
|
-
* @returns {void}
|
|
847
|
-
*/
|
|
848
|
-
function fetchContextualProfile(weboCtxConf, onSuccess, onDone) {
|
|
849
|
-
const targetURL = weboCtxConf.targetURL || document.URL;
|
|
850
|
-
const token = weboCtxConf.token;
|
|
851
|
-
const baseURLProfileAPI = weboCtxConf.baseURLProfileAPI || BASE_URL_CONTEXTUAL_PROFILE_API;
|
|
852
|
-
|
|
853
|
-
let queryString = '';
|
|
854
|
-
queryString = tryAppendQueryString(queryString, 'token', token);
|
|
855
|
-
queryString = tryAppendQueryString(queryString, 'url', targetURL);
|
|
856
|
-
|
|
857
|
-
const urlProfileAPI = `https://${baseURLProfileAPI}/api/profile?${queryString}`;
|
|
858
|
-
|
|
859
|
-
ajax(urlProfileAPI, {
|
|
860
|
-
success: (response, req) => {
|
|
861
|
-
if (req.status === 200) {
|
|
862
|
-
try {
|
|
863
|
-
const data = JSON.parse(response);
|
|
864
|
-
onSuccess(data);
|
|
865
|
-
onDone();
|
|
866
|
-
} catch (e) {
|
|
867
|
-
onDone();
|
|
868
|
-
logError('unable to parse weborama data', e);
|
|
869
|
-
throw e;
|
|
870
|
-
}
|
|
871
|
-
} else if (req.status === 204) {
|
|
872
|
-
onDone();
|
|
873
|
-
}
|
|
874
|
-
},
|
|
875
|
-
error: () => {
|
|
876
|
-
onDone();
|
|
877
|
-
logError('unable to get weborama data');
|
|
878
|
-
}
|
|
1023
|
+
/** @type {Components} */
|
|
1024
|
+
const components = {
|
|
1025
|
+
WeboCtx: {
|
|
1026
|
+
initialized: false,
|
|
1027
|
+
data: null,
|
|
1028
|
+
user: false,
|
|
1029
|
+
source: WEBO_CTX_SOURCE_LABEL,
|
|
1030
|
+
callbackBuilder: getContextualProfile,
|
|
1031
|
+
},
|
|
1032
|
+
WeboUserData: {
|
|
1033
|
+
initialized: false,
|
|
1034
|
+
data: null,
|
|
1035
|
+
user: true,
|
|
1036
|
+
source: WEBO_USER_DATA_SOURCE_LABEL,
|
|
1037
|
+
callbackBuilder: getWeboUserDataProfile,
|
|
1038
|
+
},
|
|
1039
|
+
SfbxLiteData: {
|
|
1040
|
+
initialized: false,
|
|
1041
|
+
data: null,
|
|
1042
|
+
user: false,
|
|
1043
|
+
source: SFBX_LITE_DATA_SOURCE_LABEL,
|
|
1044
|
+
callbackBuilder: getSfbxLiteDataProfile,
|
|
879
1045
|
},
|
|
880
|
-
null, {
|
|
881
|
-
method: 'GET',
|
|
882
|
-
withCredentials: false,
|
|
883
|
-
});
|
|
884
|
-
}
|
|
885
|
-
|
|
886
|
-
export const weboramaSubmodule = {
|
|
887
|
-
name: SUBMODULE_NAME,
|
|
888
|
-
init: init,
|
|
889
|
-
getTargetingData: getTargetingData,
|
|
890
|
-
getBidRequestData: getBidRequestData,
|
|
891
1046
|
};
|
|
892
1047
|
|
|
1048
|
+
export const weboramaSubmodule = new WeboramaRtdProvider(components);
|
|
1049
|
+
|
|
893
1050
|
submodule(MODULE_NAME, weboramaSubmodule);
|