prebid.js 5.20.1 → 5.20.2

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.
@@ -1,410 +1,362 @@
1
- import { logWarn, isStr, deepAccess, inIframe, checkCookieSupport, timestamp, getBidIdParameter, parseSizesInput, buildUrl, logMessage, isArray, deepSetValue, isPlainObject, triggerPixel, replaceAuctionPrice, isFn } from '../src/utils.js';
2
- import {config} from '../src/config.js'
3
- import {registerBidder} from '../src/adapters/bidderFactory.js'
4
- import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'
5
- import includes from 'core-js-pure/features/array/includes.js'
6
-
7
- /**
8
- * Adapter for requesting bids from adxcg.net
9
- * updated to latest prebid repo on 2017.10.20
10
- * updated for gdpr compliance on 2018.05.22 -requires gdpr compliance module
11
- * updated to pass aditional auction and impression level parameters. added pass for video targeting parameters
12
- * updated to fix native support for image width/height and icon 2019.03.17
13
- * updated support for userid - pubcid,ttid 2019.05.28
14
- * updated to support prebid 3.0 - remove non https, move to banner.xx.sizes, remove utils.getTopWindowLocation,remove utils.getTopWindowUrl(),remove utils.getTopWindowReferrer()
15
- * updated to support prebid 4.0 - standardized video params, updated video validation, add onBidWon, onTimeOut, use standardized getFloor
16
- */
17
-
18
- const BIDDER_CODE = 'adxcg'
19
- const SUPPORTED_AD_TYPES = [BANNER, VIDEO, NATIVE]
20
- const SOURCE = 'pbjs10'
21
- const VIDEO_TARGETING = ['id', 'minduration', 'maxduration', 'startdelay', 'skippable', 'playback_method', 'frameworks']
22
- const USER_PARAMS_AUCTION = ['forcedDspIds', 'forcedCampaignIds', 'forcedCreativeIds', 'gender', 'dnt', 'language']
23
- const USER_PARAMS_BID = ['lineparam1', 'lineparam2', 'lineparam3']
24
- const BIDADAPTERVERSION = 'r20210330PB40'
25
- const DEFAULT_MIN_FLOOR = 0;
1
+ // jshint esversion: 6, es3: false, node: true
2
+ 'use strict';
3
+
4
+ import {registerBidder} from '../src/adapters/bidderFactory.js';
5
+ import {NATIVE, BANNER, VIDEO} from '../src/mediaTypes.js';
6
+ import {
7
+ mergeDeep,
8
+ _map,
9
+ deepAccess,
10
+ getDNT,
11
+ parseSizesInput,
12
+ deepSetValue,
13
+ isStr,
14
+ isArray,
15
+ isPlainObject,
16
+ parseUrl,
17
+ replaceAuctionPrice, triggerPixel
18
+ } from '../src/utils.js';
19
+ import {config} from '../src/config.js';
20
+
21
+ const { getConfig } = config;
22
+
23
+ const BIDDER_CODE = 'adxcg';
24
+ const SECURE_BID_URL = 'https://pbc.adxcg.net/rtb/ortb/pbc?adExchangeId=1';
25
+
26
+ const NATIVE_ASSET_IDS = { 0: 'title', 2: 'icon', 3: 'image', 5: 'sponsoredBy', 4: 'body', 1: 'cta' };
27
+ const NATIVE_PARAMS = {
28
+ title: {
29
+ id: 0,
30
+ name: 'title'
31
+ },
32
+ icon: {
33
+ id: 2,
34
+ type: 1,
35
+ name: 'img'
36
+ },
37
+ image: {
38
+ id: 3,
39
+ type: 3,
40
+ name: 'img'
41
+ },
42
+ sponsoredBy: {
43
+ id: 5,
44
+ name: 'data',
45
+ type: 1
46
+ },
47
+ body: {
48
+ id: 4,
49
+ name: 'data',
50
+ type: 2
51
+ },
52
+ cta: {
53
+ id: 1,
54
+ type: 12,
55
+ name: 'data'
56
+ }
57
+ };
26
58
 
27
59
  export const spec = {
28
60
  code: BIDDER_CODE,
29
- supportedMediaTypes: SUPPORTED_AD_TYPES,
30
-
31
- /**
32
- * Determines whether or not the given bid request is valid.
33
- *
34
- * @param {object} bid The bid params to validate.
35
- * @return boolean True if this is a valid bid, and false otherwise.
36
- */
37
- isBidRequestValid: function (bid) {
38
- if (!bid || !bid.params) {
39
- logWarn(BIDDER_CODE + ': Missing bid parameters');
40
- return false
41
- }
61
+ supportedMediaTypes: [ NATIVE, BANNER, VIDEO ],
62
+ isBidRequestValid: (bid) => {
63
+ const params = bid.params || {};
64
+ const { adzoneid } = params;
65
+ return !!(adzoneid);
66
+ },
67
+ buildRequests: (validBidRequests, bidderRequest) => {
68
+ let app, site;
42
69
 
43
- if (!isStr(bid.params.adzoneid)) {
44
- logWarn(BIDDER_CODE + ': adzoneid must be specified as a string');
45
- return false
46
- }
70
+ const commonFpd = getConfig('ortb2') || {};
71
+ let { user } = commonFpd;
72
+
73
+ if (typeof getConfig('app') === 'object') {
74
+ app = getConfig('app') || {};
75
+ if (commonFpd.app) {
76
+ mergeDeep(app, commonFpd.app);
77
+ }
78
+ } else {
79
+ site = getConfig('site') || {};
80
+ if (commonFpd.site) {
81
+ mergeDeep(site, commonFpd.site);
82
+ }
47
83
 
48
- if (isBannerRequest(bid)) {
49
- const banneroAdUnit = deepAccess(bid, 'mediaTypes.banner');
50
- if (!banneroAdUnit.sizes) {
51
- logWarn(BIDDER_CODE + ': banner sizes must be specified');
52
- return false;
84
+ if (!site.page) {
85
+ site.page = bidderRequest.refererInfo.referer;
86
+ site.domain = parseUrl(bidderRequest.refererInfo.referer).hostname;
53
87
  }
54
88
  }
55
89
 
56
- if (isVideoRequest(bid)) {
57
- // prebid 4.0 use standardized Video parameters
58
- const videoAdUnit = deepAccess(bid, 'mediaTypes.video');
90
+ const device = getConfig('device') || {};
91
+ device.w = device.w || window.innerWidth;
92
+ device.h = device.h || window.innerHeight;
93
+ device.ua = device.ua || navigator.userAgent;
94
+ device.dnt = getDNT() ? 1 : 0;
95
+ device.language = (navigator && navigator.language) ? navigator.language.split('-')[0] : '';
96
+
97
+ const tid = validBidRequests[0].transactionId;
98
+ const test = setOnAny(validBidRequests, 'params.test');
99
+ const currency = getConfig('currency.adServerCurrency');
100
+ const cur = currency && [ currency ];
101
+ const eids = setOnAny(validBidRequests, 'userIdAsEids');
102
+ const schain = setOnAny(validBidRequests, 'schain');
103
+
104
+ const imp = validBidRequests.map((bid, id) => {
105
+ const floorInfo = bid.getFloor ? bid.getFloor({
106
+ currency: currency || 'USD'
107
+ }) : {};
108
+ const bidfloor = floorInfo.floor;
109
+ const bidfloorcur = floorInfo.currency;
110
+ const { adzoneid } = bid.params;
111
+
112
+ const imp = {
113
+ id: id + 1,
114
+ tagid: adzoneid,
115
+ secure: 1,
116
+ bidfloor,
117
+ bidfloorcur,
118
+ ext: {
119
+ }
120
+ };
59
121
 
60
- if (!Array.isArray(videoAdUnit.playerSize)) {
61
- logWarn(BIDDER_CODE + ': video playerSize must be an array of integers');
62
- return false;
63
- }
122
+ const assets = _map(bid.nativeParams, (bidParams, key) => {
123
+ const props = NATIVE_PARAMS[key];
124
+ const asset = {
125
+ required: bidParams.required & 1,
126
+ };
127
+ if (props) {
128
+ asset.id = props.id;
129
+ let wmin, hmin, w, h;
130
+ let aRatios = bidParams.aspect_ratios;
131
+
132
+ if (aRatios && aRatios[0]) {
133
+ aRatios = aRatios[0];
134
+ wmin = aRatios.min_width || 0;
135
+ hmin = aRatios.ratio_height * wmin / aRatios.ratio_width | 0;
136
+ }
64
137
 
65
- if (!videoAdUnit.context) {
66
- logWarn(BIDDER_CODE + ': video context must be specified');
67
- return false;
68
- }
138
+ if (bidParams.sizes) {
139
+ const sizes = flatten(bidParams.sizes);
140
+ w = sizes[0];
141
+ h = sizes[1];
142
+ }
69
143
 
70
- if (!Array.isArray(videoAdUnit.mimes) || videoAdUnit.mimes.length === 0) {
71
- logWarn(BIDDER_CODE + ': video mimes must be an array of strings');
72
- return false;
144
+ asset[props.name] = {
145
+ len: bidParams.len,
146
+ type: props.type,
147
+ wmin,
148
+ hmin,
149
+ w,
150
+ h
151
+ };
152
+
153
+ return asset;
154
+ }
155
+ }).filter(Boolean);
156
+
157
+ if (assets.length) {
158
+ imp.native = {
159
+ request: JSON.stringify({assets: assets})
160
+ };
73
161
  }
74
162
 
75
- if (!Array.isArray(videoAdUnit.protocols) || videoAdUnit.protocols.length === 0) {
76
- logWarn(BIDDER_CODE + ': video protocols must be an array of integers');
77
- return false;
163
+ const bannerParams = deepAccess(bid, 'mediaTypes.banner');
164
+
165
+ if (bannerParams && bannerParams.sizes) {
166
+ const sizes = parseSizesInput(bannerParams.sizes);
167
+ const format = sizes.map(size => {
168
+ const [ width, height ] = size.split('x');
169
+ const w = parseInt(width, 10);
170
+ const h = parseInt(height, 10);
171
+ return { w, h };
172
+ });
173
+
174
+ imp.banner = {
175
+ format
176
+ };
78
177
  }
79
- }
80
178
 
81
- return true
82
- },
179
+ const videoParams = deepAccess(bid, 'mediaTypes.video');
180
+ if (videoParams) {
181
+ imp.video = videoParams;
182
+ }
83
183
 
84
- /**
85
- * Make a server request from the list of BidRequests.
86
- *
87
- * an array of validBidRequests
88
- * Info describing the request to the server.
89
- */
90
- buildRequests: function (validBidRequests, bidderRequest) {
91
- let dt = new Date();
92
- let ratio = window.devicePixelRatio || 1;
93
- let iobavailable = window && window.IntersectionObserver && window.IntersectionObserverEntry && window.IntersectionObserverEntry.prototype && 'intersectionRatio' in window.IntersectionObserverEntry.prototype
94
-
95
- let bt = config.getConfig('bidderTimeout');
96
- if (window.PREBID_TIMEOUT) {
97
- bt = Math.min(window.PREBID_TIMEOUT, bt);
98
- }
184
+ return imp;
185
+ });
99
186
 
100
- let referrer = deepAccess(bidderRequest, 'refererInfo.referer');
101
- let page = deepAccess(bidderRequest, 'refererInfo.canonicalUrl') || config.getConfig('pageUrl') || deepAccess(window, 'location.href');
102
-
103
- // add common parameters
104
- let beaconParams = {
105
- renderformat: 'javascript',
106
- ver: BIDADAPTERVERSION,
107
- secure: '1',
108
- source: SOURCE,
109
- uw: window.screen.width,
110
- uh: window.screen.height,
111
- dpr: ratio,
112
- bt: bt,
113
- isinframe: inIframe(),
114
- cookies: checkCookieSupport() ? '1' : '0',
115
- tz: dt.getTimezoneOffset(),
116
- dt: timestamp(),
117
- iob: iobavailable ? '1' : '0',
118
- pbjs: '$prebid.version$',
119
- rndid: Math.floor(Math.random() * (999999 - 100000 + 1)) + 100000,
120
- ref: encodeURIComponent(referrer),
121
- url: encodeURIComponent(page)
187
+ const request = {
188
+ id: bidderRequest.auctionId,
189
+ site,
190
+ app,
191
+ user,
192
+ geo: { utcoffset: new Date().getTimezoneOffset() },
193
+ device,
194
+ source: { tid, fd: 1 },
195
+ ext: {
196
+ prebid: {
197
+ channel: {
198
+ name: 'pbjs',
199
+ version: '$prebid.version$'
200
+ }
201
+ }
202
+ },
203
+ cur,
204
+ imp
122
205
  };
123
206
 
124
- if (bidderRequest && bidderRequest.gdprConsent && bidderRequest.gdprConsent.gdprApplies) {
125
- beaconParams.gdpr = bidderRequest.gdprConsent.gdprApplies ? '1' : '0';
126
- beaconParams.gdpr_consent = bidderRequest.gdprConsent.consentString;
127
- }
128
-
129
- if (isStr(deepAccess(validBidRequests, '0.userId.pubcid'))) {
130
- beaconParams.pubcid = validBidRequests[0].userId.pubcid;
207
+ if (test) {
208
+ request.is_debug = !!test;
209
+ request.test = 1;
131
210
  }
132
-
133
- if (isStr(deepAccess(validBidRequests, '0.userId.tdid'))) {
134
- beaconParams.tdid = validBidRequests[0].userId.tdid;
211
+ if (deepAccess(bidderRequest, 'gdprConsent.gdprApplies') !== undefined) {
212
+ deepSetValue(request, 'user.ext.consent', bidderRequest.gdprConsent.consentString);
213
+ deepSetValue(request, 'regs.ext.gdpr', bidderRequest.gdprConsent.gdprApplies & 1);
135
214
  }
136
215
 
137
- if (isStr(deepAccess(validBidRequests, '0.userId.id5id.uid'))) {
138
- beaconParams.id5id = validBidRequests[0].userId.id5id.uid;
216
+ if (bidderRequest.uspConsent) {
217
+ deepSetValue(request, 'regs.ext.us_privacy', bidderRequest.uspConsent);
139
218
  }
140
219
 
141
- if (isStr(deepAccess(validBidRequests, '0.userId.idl_env'))) {
142
- beaconParams.idl_env = validBidRequests[0].userId.idl_env;
220
+ if (eids) {
221
+ deepSetValue(request, 'user.ext.eids', eids);
143
222
  }
144
223
 
145
- let biddercustom = config.getConfig(BIDDER_CODE);
146
- if (biddercustom) {
147
- Object.keys(biddercustom)
148
- .filter(param => includes(USER_PARAMS_AUCTION, param))
149
- .forEach(param => beaconParams[param] = encodeURIComponent(biddercustom[param]))
224
+ if (schain) {
225
+ deepSetValue(request, 'source.ext.schain', schain);
150
226
  }
151
227
 
152
- // per impression parameters
153
- let adZoneIds = [];
154
- let prebidBidIds = [];
155
- let sizes = [];
156
- let bidfloors = [];
157
-
158
- validBidRequests.forEach((bid, index) => {
159
- adZoneIds.push(getBidIdParameter('adzoneid', bid.params));
160
- prebidBidIds.push(bid.bidId);
161
-
162
- let bidfloor = getFloor(bid);
163
- bidfloors.push(bidfloor);
164
-
165
- // copy all custom parameters impression level parameters not supported above
166
- let customBidParams = getBidIdParameter('custom', bid.params) || {}
167
- if (customBidParams) {
168
- Object.keys(customBidParams)
169
- .filter(param => includes(USER_PARAMS_BID, param))
170
- .forEach(param => beaconParams[param + '.' + index] = encodeURIComponent(customBidParams[param]))
171
- }
172
-
173
- if (isBannerRequest(bid)) {
174
- sizes.push(parseSizesInput(bid.mediaTypes.banner.sizes).join('|'));
175
- }
176
-
177
- if (isNativeRequest(bid)) {
178
- sizes.push('0x0');
179
- }
180
-
181
- if (isVideoRequest(bid)) {
182
- if (bid.params.video) {
183
- Object.keys(bid.params.video)
184
- .filter(param => includes(VIDEO_TARGETING, param))
185
- .forEach(param => beaconParams['video.' + param + '.' + index] = encodeURIComponent(bid.params.video[param]))
186
- }
187
- // copy video standarized params
188
- beaconParams['video.context' + '.' + index] = deepAccess(bid, 'mediaTypes.video.context');
189
- sizes.push(parseSizesInput(bid.mediaTypes.video.playerSize).join('|'));
190
- beaconParams['video.mimes' + '.' + index] = deepAccess(bid, 'mediaTypes.video.mimes').join(',');
191
- beaconParams['video.protocols' + '.' + index] = deepAccess(bid, 'mediaTypes.video.protocols').join(',');
192
- }
193
- })
194
-
195
- beaconParams.adzoneid = adZoneIds.join(',');
196
- beaconParams.format = sizes.join(',');
197
- beaconParams.prebidBidIds = prebidBidIds.join(',');
198
- beaconParams.bidfloors = bidfloors.join(',');
199
-
200
- let adxcgRequestUrl = buildUrl({
201
- protocol: 'https',
202
- hostname: 'hbps.adxcg.net',
203
- pathname: '/get/adi',
204
- search: beaconParams
205
- });
206
-
207
- logMessage(`calling adi adxcg`);
208
228
  return {
209
- contentType: 'text/plain',
210
- method: 'GET',
211
- url: adxcgRequestUrl,
212
- withCredentials: true
229
+ method: 'POST',
230
+ url: SECURE_BID_URL,
231
+ data: JSON.stringify(request),
232
+ options: {
233
+ contentType: 'application/json'
234
+ },
235
+ bids: validBidRequests
213
236
  };
214
237
  },
215
- /**
216
- * Unpack the response from the server into a list of bids.
217
- *
218
- * @param {*} serverResponse A successful response from the server.
219
- * @return {bidRequests[]} An array of bids which were nested inside the server.
220
- */
221
- interpretResponse:
222
- function (serverResponse) {
223
- logMessage(`interpretResponse adxcg`);
224
- let bidsAll = [];
225
-
226
- if (!serverResponse || !serverResponse.body || !isArray(serverResponse.body.seatbid) || !serverResponse.body.seatbid.length) {
227
- logWarn(BIDDER_CODE + ': empty bid response');
228
- return bidsAll;
229
- }
230
-
231
- serverResponse.body.seatbid.forEach((bids) => {
232
- bids.bid.forEach((serverResponseOneItem) => {
233
- let bid = {}
234
- // parse general fields
235
- bid.requestId = serverResponseOneItem.impid;
236
- bid.cpm = serverResponseOneItem.price;
237
- bid.creativeId = parseInt(serverResponseOneItem.crid);
238
- bid.currency = serverResponseOneItem.currency ? serverResponseOneItem.currency : 'USD';
239
- bid.netRevenue = serverResponseOneItem.netRevenue ? serverResponseOneItem.netRevenue : true;
240
- bid.ttl = serverResponseOneItem.ttl ? serverResponseOneItem.ttl : 300;
241
- bid.width = serverResponseOneItem.w;
242
- bid.height = serverResponseOneItem.h;
243
- bid.burl = serverResponseOneItem.burl || '';
244
-
245
- if (serverResponseOneItem.dealid != null && serverResponseOneItem.dealid.trim().length > 0) {
246
- bid.dealId = serverResponseOneItem.dealid;
247
- }
238
+ interpretResponse: function(serverResponse, { bids }) {
239
+ if (!serverResponse.body) {
240
+ return;
241
+ }
242
+ const { seatbid, cur } = serverResponse.body;
243
+
244
+ const bidResponses = flatten(seatbid.map(seat => seat.bid)).reduce((result, bid) => {
245
+ result[bid.impid - 1] = bid;
246
+ return result;
247
+ }, []);
248
+
249
+ return bids.map((bid, id) => {
250
+ const bidResponse = bidResponses[id];
251
+ if (bidResponse) {
252
+ const mediaType = deepAccess(bidResponse, 'ext.crType');
253
+ const result = {
254
+ requestId: bid.bidId,
255
+ cpm: bidResponse.price,
256
+ creativeId: bidResponse.crid,
257
+ ttl: bidResponse.ttl ? bidResponse.ttl : 300,
258
+ netRevenue: bid.netRevenue === 'net',
259
+ currency: cur,
260
+ burl: bid.burl || '',
261
+ mediaType: mediaType,
262
+ width: bidResponse.w,
263
+ height: bidResponse.h,
264
+ dealId: bidResponse.dealid,
265
+ };
266
+
267
+ deepSetValue(result, 'meta.mediaType', mediaType);
268
+ if (isArray(bidResponse.adomain)) {
269
+ deepSetValue(result, 'meta.advertiserDomains', bidResponse.adomain);
270
+ }
248
271
 
249
- if (serverResponseOneItem.ext.crType === 'banner') {
250
- bid.ad = serverResponseOneItem.adm;
251
- } else if (serverResponseOneItem.ext.crType === 'video') {
252
- bid.vastUrl = serverResponseOneItem.nurl;
253
- bid.vastXml = serverResponseOneItem.adm;
254
- bid.mediaType = 'video';
255
- } else if (serverResponseOneItem.ext.crType === 'native') {
256
- bid.mediaType = 'native';
257
- bid.native = parseNative(JSON.parse(serverResponseOneItem.adm));
258
- } else {
259
- logWarn(BIDDER_CODE + ': unknown or undefined crType');
272
+ if (isPlainObject(bidResponse.ext)) {
273
+ if (isStr(bidResponse.ext.mediaType)) {
274
+ deepSetValue(result, 'meta.mediaType', mediaType);
260
275
  }
261
-
262
- // prebid 4.0 meta taxonomy
263
- if (isArray(serverResponseOneItem.adomain)) {
264
- deepSetValue(bid, 'meta.advertiserDomains', serverResponseOneItem.adomain);
276
+ if (isStr(bidResponse.ext.advertiser_id)) {
277
+ deepSetValue(result, 'meta.advertiserId', bidResponse.ext.advertiser_id);
265
278
  }
266
- if (isArray(serverResponseOneItem.cat)) {
267
- deepSetValue(bid, 'meta.secondaryCatIds', serverResponseOneItem.cat);
279
+ if (isStr(bidResponse.ext.advertiser_name)) {
280
+ deepSetValue(result, 'meta.advertiserName', bidResponse.ext.advertiser_name);
268
281
  }
269
- if (isPlainObject(serverResponseOneItem.ext)) {
270
- if (isStr(serverResponseOneItem.ext.advertiser_id)) {
271
- deepSetValue(bid, 'meta.mediaType', serverResponseOneItem.ext.mediaType);
272
- }
273
- if (isStr(serverResponseOneItem.ext.advertiser_id)) {
274
- deepSetValue(bid, 'meta.advertiserId', serverResponseOneItem.ext.advertiser_id);
275
- }
276
- if (isStr(serverResponseOneItem.ext.advertiser_name)) {
277
- deepSetValue(bid, 'meta.advertiserName', serverResponseOneItem.ext.advertiser_name);
278
- }
279
- if (isStr(serverResponseOneItem.ext.agency_name)) {
280
- deepSetValue(bid, 'meta.agencyName', serverResponseOneItem.ext.agency_name);
281
- }
282
+ if (isStr(bidResponse.ext.agency_name)) {
283
+ deepSetValue(result, 'meta.agencyName', bidResponse.ext.agency_name);
282
284
  }
283
- bidsAll.push(bid)
284
- })
285
- })
286
- return bidsAll
287
- },
285
+ }
286
+ if (mediaType === BANNER) {
287
+ result.ad = bidResponse.adm;
288
+ } else if (mediaType === NATIVE) {
289
+ result.native = parseNative(bidResponse);
290
+ result.width = 0;
291
+ result.height = 0;
292
+ } else if (mediaType === VIDEO) {
293
+ result.vastUrl = bidResponse.nurl;
294
+ result.vastXml = bidResponse.adm;
295
+ }
288
296
 
289
- onBidWon: (bid) => {
290
- if (bid.burl) {
291
- triggerPixel(replaceAuctionPrice(bid.burl, bid.originalCpm));
292
- }
297
+ return result;
298
+ }
299
+ }).filter(Boolean);
293
300
  },
301
+ getUserSyncs: (syncOptions, responses, gdprConsent, uspConsent) => {
302
+ const syncs = [];
303
+ let syncUrl = config.getConfig('adxcg.usersyncUrl');
304
+
305
+ let query = [];
306
+ if (syncOptions.pixelEnabled && syncUrl) {
307
+ if (gdprConsent) {
308
+ query.push('gdpr=' + (gdprConsent.gdprApplies & 1));
309
+ query.push('gdpr_consent=' + encodeURIComponent(gdprConsent.consentString || ''));
310
+ }
311
+ if (uspConsent) {
312
+ query.push('us_privacy=' + encodeURIComponent(uspConsent));
313
+ }
294
314
 
295
- onTimeout(timeoutData) {
296
- if (timeoutData == null) {
297
- return;
315
+ syncs.push({
316
+ type: 'image',
317
+ url: syncUrl + (query.length ? '?' + query.join('&') : '')
318
+ });
298
319
  }
299
-
300
- let beaconParams = {
301
- A: timeoutData.bidder,
302
- bid: timeoutData.bidId,
303
- a: timeoutData.adUnitCode,
304
- cn: timeoutData.timeout,
305
- aud: timeoutData.auctionId,
306
- };
307
- let adxcgRequestUrl = buildUrl({
308
- protocol: 'https',
309
- hostname: 'hbps.adxcg.net',
310
- pathname: '/event/timeout.gif',
311
- search: beaconParams
312
- });
313
- logWarn(BIDDER_CODE + ': onTimeout called');
314
- triggerPixel(adxcgRequestUrl);
320
+ return syncs;
315
321
  },
316
-
317
- getUserSyncs: function (syncOptions, serverResponses, gdprConsent) {
318
- let params = '';
319
- if (gdprConsent && 'gdprApplies' in gdprConsent) {
320
- if (gdprConsent.consentString) {
321
- if (typeof gdprConsent.gdprApplies === 'boolean') {
322
- params += `?gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`;
323
- } else {
324
- params += `?gdpr=0&gdpr_consent=${gdprConsent.consentString}`;
325
- }
326
- }
327
- }
328
-
329
- if (syncOptions.iframeEnabled) {
330
- return [{
331
- type: 'iframe',
332
- url: 'https://cdn.adxcg.net/pb-sync.html' + params
333
- }];
322
+ onBidWon: (bid) => {
323
+ // for native requests we put the nurl as an imp tracker, otherwise if the auction takes place on prebid server
324
+ // the server JS adapter puts the nurl in the adm as a tracking pixel and removes the attribute
325
+ if (bid.nurl) {
326
+ triggerPixel(replaceAuctionPrice(bid.nurl, bid.originalCpm))
334
327
  }
335
328
  }
336
- }
329
+ };
337
330
 
338
- function isVideoRequest(bid) {
339
- return bid.mediaType === 'video' || !!deepAccess(bid, 'mediaTypes.video');
340
- }
331
+ registerBidder(spec);
341
332
 
342
- function isBannerRequest(bid) {
343
- return bid.mediaType === 'banner' || !!deepAccess(bid, 'mediaTypes.banner');
344
- }
345
-
346
- function isNativeRequest(bid) {
347
- return bid.mediaType === 'native' || !!deepAccess(bid, 'mediaTypes.native');
348
- }
349
-
350
- function getFloor(bid) {
351
- if (!isFn(bid.getFloor)) {
352
- return deepAccess(bid, 'params.floor', DEFAULT_MIN_FLOOR);
353
- }
354
-
355
- try {
356
- const floor = bid.getFloor({
357
- currency: 'EUR',
358
- mediaType: '*',
359
- size: '*',
360
- bidRequest: bid
361
- });
362
- return floor.floor;
363
- } catch (e) {
364
- logWarn(BIDDER_CODE + ': call to getFloor failed:' + e.message);
365
- return DEFAULT_MIN_FLOOR;
366
- }
367
- }
368
-
369
- function parseNative(nativeResponse) {
370
- let bidNative = {};
371
- bidNative = {
372
- clickUrl: nativeResponse.link.url,
373
- impressionTrackers: nativeResponse.imptrackers,
374
- clickTrackers: nativeResponse.clktrackers,
375
- javascriptTrackers: nativeResponse.jstrackers
333
+ function parseNative(bid) {
334
+ const { assets, link, imptrackers, jstracker } = JSON.parse(bid.adm);
335
+ const result = {
336
+ clickUrl: link.url,
337
+ clickTrackers: link.clicktrackers || undefined,
338
+ impressionTrackers: imptrackers || undefined,
339
+ javascriptTrackers: jstracker ? [ jstracker ] : undefined
376
340
  };
377
-
378
- nativeResponse.assets.forEach(asset => {
379
- if (asset.title && asset.title.text) {
380
- bidNative.title = asset.title.text;
381
- }
382
-
383
- if (asset.img && asset.img.url) {
384
- bidNative.image = {
385
- url: asset.img.url,
386
- height: asset.img.h,
387
- width: asset.img.w
388
- };
389
- }
390
-
391
- if (asset.icon && asset.icon.url) {
392
- bidNative.icon = {
393
- url: asset.icon.url,
394
- height: asset.icon.h,
395
- width: asset.icon.w
396
- };
397
- }
398
-
399
- if (asset.data && asset.data.label === 'DESC' && asset.data.value) {
400
- bidNative.body = asset.data.value;
341
+ assets.forEach(asset => {
342
+ const kind = NATIVE_ASSET_IDS[asset.id];
343
+ const content = kind && asset[NATIVE_PARAMS[kind].name];
344
+ if (content) {
345
+ result[kind] = content.text || content.value || { url: content.url, width: content.w, height: content.h };
401
346
  }
347
+ });
348
+ return result;
349
+ }
402
350
 
403
- if (asset.data && asset.data.label === 'SPONSORED' && asset.data.value) {
404
- bidNative.sponsoredBy = asset.data.value;
351
+ function setOnAny(collection, key) {
352
+ for (let i = 0, result; i < collection.length; i++) {
353
+ result = deepAccess(collection[i], key);
354
+ if (result) {
355
+ return result;
405
356
  }
406
- })
407
- return bidNative;
357
+ }
408
358
  }
409
359
 
410
- registerBidder(spec)
360
+ function flatten(arr) {
361
+ return [].concat(...arr);
362
+ }