forked from prebid/Prebid.js
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathoptimeraRtdProvider.js
264 lines (240 loc) · 6.44 KB
/
optimeraRtdProvider.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
/**
* This module adds optimera provider to the real time data module
* The {@link module:modules/realTimeData} module is required
*
* The module will fetch targeting values from the Optimera server
* and apply the tageting to each ad request. These values are created
* from the Optimera Mesaurement script which is installed on the
* Publisher's site.
*
* @module modules/optimeraRtdProvider
* @requires module:modules/realTimeData
*/
/**
* @typedef {Object} ModuleParams
* @property {string} clientID
* @property {string} optimeraKeyName
* @property {string} device
* @property {string} apiVersion
*/
import { logInfo, logError } from '../src/utils.js';
import { submodule } from '../src/hook.js';
import { ajaxBuilder } from '../src/ajax.js';
/**
* @typedef {import('../modules/rtdModule/index.js').RtdSubmodule} RtdSubmodule
*/
/** @type {ModuleParams} */
let _moduleParams = {};
/**
* Default Optimera Key Name
* This can default to hb_deal_optimera for publishers
* who used the previous Optimera Bidder Adapter.
* @type {string}
*/
export let optimeraKeyName = 'hb_deal_optimera';
/**
* Optimera Score File Base URL.
* This is the base URL for the data endpoint request to fetch
* the targeting values.
* @type {string}
*/
export const scoresBaseURL = {
v0: 'https://dyv1bugovvq1g.cloudfront.net/',
v1: 'https://v1.oapi26b.com/',
};
/**
* Optimera Score File URL.
* @type {string}
*/
export let scoresURL;
/**
* Optimera Client ID.
* @type {string}
*/
export let clientID;
/**
* Optional device parameter.
* @type {string}
*/
export let device = 'default';
/**
* Optional apiVersion parameter.
* @type {string}
*/
export let apiVersion = 'v0';
/**
* Targeting object for all ad positions.
* @type {string}
*/
export let optimeraTargeting = {};
/**
* Flag to indicateo if a new score file should be fetched.
* @type {string}
*/
export let fetchScoreFile = true;
/**
* Make the request for the Score File.
*/
export function scoreFileRequest() {
logInfo('Fetch Optimera score file.');
const ajax = ajaxBuilder();
ajax(scoresURL,
{
success: (res, req) => {
if (req.status === 200) {
try {
setScores(res);
} catch (err) {
logError('Unable to parse Optimera Score File.', err);
}
} else if (req.status === 403) {
logError('Unable to fetch the Optimera Score File - 403');
}
},
error: () => {
logError('Unable to fetch the Optimera Score File.');
}
});
}
/**
* Apply the Optimera targeting to the ad slots.
*/
export function returnTargetingData(adUnits, config) {
const targeting = {};
try {
adUnits.forEach((adUnit) => {
if (optimeraTargeting[adUnit]) {
targeting[adUnit] = {};
targeting[adUnit][optimeraKeyName] = [optimeraTargeting[adUnit]];
}
});
} catch (err) {
logError('error', err);
}
logInfo('Apply Optimera targeting');
return targeting;
}
/**
* Fetch a new score file when an auction starts.
* Only fetch the new file if a new score file is needed.
*/
export function onAuctionInit(auctionDetails, config, userConsent) {
setScoresURL();
if (fetchScoreFile) {
scoreFileRequest();
}
}
/**
* Initialize the Module.
* moduleConfig.params.apiVersion can be either v0 or v1.
*/
export function init(moduleConfig) {
_moduleParams = moduleConfig.params;
if (_moduleParams && _moduleParams.clientID) {
clientID = _moduleParams.clientID;
if (_moduleParams.optimeraKeyName) {
optimeraKeyName = (_moduleParams.optimeraKeyName);
}
if (_moduleParams.device) {
device = _moduleParams.device;
}
if (_moduleParams.apiVersion) {
apiVersion = (_moduleParams.apiVersion.includes('v1', 'v0')) ? _moduleParams.apiVersion : 'v0';
}
setScoresURL();
scoreFileRequest();
return true;
}
if (!_moduleParams.clientID) {
logError('Optimera clientID is missing in the Optimera RTD configuration.');
}
return false;
}
/**
* Set the score file url.
*
* This fully-formed URL is for the data endpoint request to fetch
* the targeting values. This is not a js library, rather JSON
* which has the targeting values for the page.
*
* The score file url is based on the web page url. If the new score file URL
* has been updated, set the fetchScoreFile flag to true to is can be fetched.
*
*/
export function setScoresURL() {
const optimeraHost = window.location.host;
const optimeraPathName = window.location.pathname;
const baseUrl = scoresBaseURL[apiVersion] ? scoresBaseURL[apiVersion] : scoresBaseURL.v0;
let newScoresURL;
if (apiVersion === 'v1') {
newScoresURL = `${baseUrl}api/products/scores?c=${clientID}&h=${optimeraHost}&p=${optimeraPathName}&s=${device}`;
} else {
let encoded = encodeURIComponent(`${optimeraHost}${optimeraPathName}`)
.replaceAll('%2F', '/')
.replaceAll('%20', '+');
newScoresURL = `${baseUrl}${clientID}/${encoded}.js`;
}
if (scoresURL !== newScoresURL) {
scoresURL = newScoresURL;
fetchScoreFile = true;
} else {
fetchScoreFile = false;
}
}
/**
* Set the scores for the device if given.
* Add data and insights to the winddow.optimera object.
*
* @param {*} result
* @returns {string} JSON string of Optimera Scores.
*/
export function setScores(result) {
let scores = {};
try {
scores = JSON.parse(result);
if (device !== 'default' && scores.device[device]) {
scores = scores.device[device];
}
logInfo(scores);
window.optimera = window.optimera || {};
window.optimera.data = window.optimera.data || {};
window.optimera.insights = window.optimera.insights || {};
Object.keys(scores).map((key) => {
if (key !== 'insights') {
window.optimera.data[key] = scores[key];
}
});
if (scores.insights) {
window.optimera.insights = scores.insights;
}
} catch (e) {
logError('Optimera score file could not be parsed.');
}
optimeraTargeting = scores;
}
/** @type {RtdSubmodule} */
export const optimeraSubmodule = {
/**
* used to link submodule with realTimeData
* @type {string}
*/
name: 'optimeraRTD',
/**
* get data when an auction starts
* @function
*/
onAuctionInitEvent: onAuctionInit,
/**
* get data and send back to realTimeData module
* @function
*/
getTargetingData: returnTargetingData,
init,
};
/**
* Register the Sub Module.
*/
function registerSubModule() {
submodule('realTimeData', optimeraSubmodule);
}
registerSubModule();