prebid.js 6.7.0 → 6.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/integrationExamples/gpt/x-domain/creative.html +53 -26
  2. package/modules/adagioBidAdapter.js +0 -8
  3. package/modules/adagioBidAdapter.md +1 -1
  4. package/modules/appnexusBidAdapter.js +11 -0
  5. package/modules/brandmetricsRtdProvider.js +168 -0
  6. package/modules/brandmetricsRtdProvider.md +40 -0
  7. package/modules/criteoBidAdapter.js +9 -0
  8. package/modules/currency.js +26 -1
  9. package/modules/displayioBidAdapter.js +157 -0
  10. package/modules/displayioBidAdapter.md +148 -0
  11. package/modules/e_volutionBidAdapter.js +158 -0
  12. package/modules/gumgumBidAdapter.js +52 -38
  13. package/modules/interactiveOffersBidAdapter.js +9 -6
  14. package/modules/sovrnBidAdapter.js +93 -18
  15. package/modules/sovrnBidAdapter.md +80 -2
  16. package/modules/undertoneBidAdapter.js +17 -1
  17. package/modules/yahoosspBidAdapter.js +2 -0
  18. package/package.json +1 -1
  19. package/src/adRendering.js +38 -0
  20. package/src/auction.js +44 -9
  21. package/src/prebid.js +3 -19
  22. package/src/secureCreatives.js +111 -42
  23. package/src/utils.js +13 -3
  24. package/test/helpers/syncPromise.js +71 -0
  25. package/test/spec/auctionmanager_spec.js +148 -16
  26. package/test/spec/modules/adagioBidAdapter_spec.js +0 -10
  27. package/test/spec/modules/appnexusBidAdapter_spec.js +27 -0
  28. package/test/spec/modules/brandmetricsRtdProvider_spec.js +191 -0
  29. package/test/spec/modules/criteoBidAdapter_spec.js +21 -0
  30. package/test/spec/modules/currency_spec.js +21 -6
  31. package/test/spec/modules/displayioBidAdapter_spec.js +239 -0
  32. package/test/spec/modules/e_volutionBidAdapter_spec.js +242 -0
  33. package/test/spec/modules/gumgumBidAdapter_spec.js +46 -0
  34. package/test/spec/modules/sovrnBidAdapter_spec.js +413 -333
  35. package/test/spec/modules/undertoneBidAdapter_spec.js +55 -2
  36. package/test/spec/modules/yahoosspBidAdapter_spec.js +10 -0
  37. package/test/spec/unit/pbjs_api_spec.js +17 -1
  38. package/test/spec/unit/secureCreatives_spec.js +85 -0
@@ -10,9 +10,9 @@ Maintainer: jrosendahl@sovrn.com
10
10
 
11
11
  Sovrn's adapter integration to the Prebid library. Posts plain-text JSON to the /rtb/bid endpoint.
12
12
 
13
- # Test Parameters
13
+ # Banner Test Parameters
14
14
 
15
- ```
15
+ ```js
16
16
  var adUnits = [
17
17
  {
18
18
  code: 'test-leaderboard',
@@ -45,3 +45,81 @@ var adUnits = [
45
45
  }
46
46
  ]
47
47
  ```
48
+
49
+ # Video Test Parameters
50
+ ### Instream
51
+ ```js
52
+ var videoAdUnit = {
53
+ code: 'video1',
54
+ sizes: [640, 480],
55
+ mediaTypes: {
56
+ video: {
57
+ context: 'instream',
58
+ playerSize: [640, 480],
59
+ mimes: ['video/mp4'],
60
+ protocols: [1, 2, 3, 4, 5, 6, 7, 8],
61
+ playbackmethod: [2],
62
+ skip: 1,
63
+ },
64
+ },
65
+ bids: [
66
+ {
67
+ bidder: 'sovrn',
68
+ // Prebid Server Bidder Params https://docs.prebid.org/dev-docs/pbs-bidders.html#sovrn
69
+ params: {
70
+ tagid: '315045',
71
+ bidfloor: '0.04',
72
+ },
73
+ },
74
+ ],
75
+ }
76
+ ```
77
+ ### Outstream
78
+ ```js
79
+ var adUnits = [
80
+ {
81
+ code: videoId,
82
+ mediaTypes: {
83
+ video: {
84
+ context: 'outstream',
85
+ playerSize: [640, 360],
86
+ mimes: ['video/mp4'],
87
+ protocols: [1, 2, 3, 4, 5, 6, 7, 8],
88
+ playbackmethod: [2],
89
+ skip: 1,
90
+ },
91
+ },
92
+ bids: [
93
+ {
94
+ bidder: 'sovrn',
95
+ // Prebid Server Bidder Params https://docs.prebid.org/dev-docs/pbs-bidders.html#sovrn
96
+ params: {
97
+ tagid: '315045',
98
+ bidfloor: '0.04',
99
+ },
100
+ },
101
+ ],
102
+ renderer: {
103
+ url: 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js',
104
+ render: function (bid) {
105
+ adResponse = {
106
+ ad: {
107
+ video: {
108
+ content: bid.vastXml,
109
+ player_height: bid.height,
110
+ player_width: bid.width,
111
+ },
112
+ },
113
+ }
114
+ // push to render queue because ANOutstreamVideo may not be loaded yet.
115
+ bid.renderer.push(() => {
116
+ ANOutstreamVideo.renderAd({
117
+ targetId: bid.adUnitCode,
118
+ adResponse: adResponse,
119
+ })
120
+ })
121
+ },
122
+ },
123
+ },
124
+ ]
125
+ ```
@@ -12,6 +12,20 @@ const FRAME_USER_SYNC = 'https://cdn.undertone.com/js/usersync.html';
12
12
  const PIXEL_USER_SYNC_1 = 'https://usr.undertone.com/userPixel/syncOne?id=1&of=2';
13
13
  const PIXEL_USER_SYNC_2 = 'https://usr.undertone.com/userPixel/syncOne?id=2&of=2';
14
14
 
15
+ function getBidFloor(bidRequest, mediaType) {
16
+ if (typeof bidRequest.getFloor !== 'function') {
17
+ return 0;
18
+ }
19
+
20
+ const floor = bidRequest.getFloor({
21
+ currency: 'USD',
22
+ mediaType: mediaType,
23
+ size: '*'
24
+ });
25
+
26
+ return (floor && floor.currency === 'USD' && floor.floor) || 0;
27
+ }
28
+
15
29
  function getCanonicalUrl() {
16
30
  try {
17
31
  let doc = window.top.document;
@@ -134,6 +148,9 @@ export const spec = {
134
148
  params: bidReq.params
135
149
  };
136
150
  const videoMediaType = deepAccess(bidReq, 'mediaTypes.video');
151
+ const mediaType = videoMediaType ? VIDEO : BANNER;
152
+ bid.mediaType = mediaType;
153
+ bid.bidfloor = getBidFloor(bidReq, mediaType);
137
154
  if (videoMediaType) {
138
155
  bid.video = {
139
156
  playerSize: deepAccess(bidReq, 'mediaTypes.video.playerSize') || null,
@@ -142,7 +159,6 @@ export const spec = {
142
159
  maxDuration: deepAccess(bidReq, 'params.video.maxDuration') || null,
143
160
  skippable: deepAccess(bidReq, 'params.video.skippable') || null
144
161
  };
145
- bid.mediaType = 'video';
146
162
  }
147
163
  payload['x-ut-hb-params'].push(bid);
148
164
  });
@@ -6,6 +6,7 @@ import { Renderer } from '../src/Renderer.js';
6
6
 
7
7
  const INTEGRATION_METHOD = 'prebid.js';
8
8
  const BIDDER_CODE = 'yahoossp';
9
+ const GVLID = 25;
9
10
  const ADAPTER_VERSION = '1.0.2';
10
11
  const PREBID_VERSION = '$prebid.version$';
11
12
  const DEFAULT_BID_TTL = 300;
@@ -515,6 +516,7 @@ function createRenderer(bidderRequest, bidResponse) {
515
516
 
516
517
  export const spec = {
517
518
  code: BIDDER_CODE,
519
+ gvlid: GVLID,
518
520
  aliases: [],
519
521
  supportedMediaTypes: [BANNER, VIDEO],
520
522
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prebid.js",
3
- "version": "6.7.0",
3
+ "version": "6.8.0",
4
4
  "description": "Header Bidding Management Library",
5
5
  "main": "src/prebid.js",
6
6
  "scripts": {
@@ -0,0 +1,38 @@
1
+ import {logError} from './utils.js';
2
+ import events from './events.js';
3
+ import CONSTANTS from './constants.json';
4
+
5
+ const {AD_RENDER_FAILED, AD_RENDER_SUCCEEDED} = CONSTANTS.EVENTS;
6
+
7
+ /**
8
+ * Emit the AD_RENDER_FAILED event.
9
+ *
10
+ * @param reason one of the values in CONSTANTS.AD_RENDER_FAILED_REASON
11
+ * @param message failure description
12
+ * @param bid? bid response object that failed to render
13
+ * @param id? adId that failed to render
14
+ */
15
+ export function emitAdRenderFail({ reason, message, bid, id }) {
16
+ const data = { reason, message };
17
+ if (bid) data.bid = bid;
18
+ if (id) data.adId = id;
19
+
20
+ logError(message);
21
+ events.emit(AD_RENDER_FAILED, data);
22
+ }
23
+
24
+ /**
25
+ * Emit the AD_RENDER_SUCCEEDED event.
26
+ *
27
+ * @param doc document object that was used to `.write` the ad. Should be `null` if unavailable (e.g. for documents in
28
+ * a cross-origin frame).
29
+ * @param bid bid response object for the ad that was rendered
30
+ * @param id adId that was rendered.
31
+ */
32
+ export function emitAdRenderSucceeded({ doc, bid, id }) {
33
+ const data = { doc };
34
+ if (bid) data.bid = bid;
35
+ if (id) data.adId = id;
36
+
37
+ events.emit(AD_RENDER_SUCCEEDED, data);
38
+ }
package/src/auction.js CHANGED
@@ -250,10 +250,7 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels, a
250
250
 
251
251
  let callbacks = auctionCallbacks(auctionDone, this);
252
252
  adapterManager.callBids(_adUnits, bidRequests, function(...args) {
253
- addBidResponse.apply({
254
- dispatch: callbacks.addBidResponse,
255
- bidderRequest: this
256
- }, args)
253
+ callbacks.addBidResponse.apply(this, args);
257
254
  }, callbacks.adapterDone, {
258
255
  request(source, origin) {
259
256
  increment(outstandingRequests, origin);
@@ -344,6 +341,7 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels, a
344
341
  addWinningBid,
345
342
  setBidTargeting,
346
343
  getWinningBids: () => _winningBids,
344
+ getAuctionStart: () => _auctionStart,
347
345
  getTimeout: () => _timeout,
348
346
  getAuctionId: () => _auctionId,
349
347
  getAuctionStatus: () => _auctionStatus,
@@ -355,8 +353,12 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels, a
355
353
  }
356
354
  }
357
355
 
358
- export const addBidResponse = hook('async', function(adUnitCode, bid) {
359
- this.dispatch.call(this.bidderRequest, adUnitCode, bid);
356
+ /**
357
+ * addBidResponse may return a Promise; if it does, the auction will attempt to
358
+ * wait for it to complete (successfully or not) before closing.
359
+ */
360
+ export const addBidResponse = hook('sync', function(adUnitCode, bid) {
361
+ return this.dispatch.call(this.bidderRequest, adUnitCode, bid);
360
362
  }, 'addBidResponse');
361
363
 
362
364
  export const addBidderRequests = hook('sync', function(bidderRequests) {
@@ -374,6 +376,32 @@ export function auctionCallbacks(auctionDone, auctionInstance) {
374
376
  let allAdapterCalledDone = false;
375
377
  let bidderRequestsDone = new Set();
376
378
  let bidResponseMap = {};
379
+ const ready = {};
380
+
381
+ function waitFor(bidderRequest, result) {
382
+ const id = bidderRequest.bidderRequestId;
383
+ if (ready[id] == null) {
384
+ ready[id] = Promise.resolve();
385
+ }
386
+ ready[id] = ready[id].then(() => Promise.resolve(result).catch(() => {}))
387
+ }
388
+
389
+ function guard(bidderRequest, fn) {
390
+ let timeout = bidderRequest.timeout;
391
+ if (timeout == null || timeout > auctionInstance.getTimeout()) {
392
+ timeout = auctionInstance.getTimeout();
393
+ }
394
+ const timeRemaining = auctionInstance.getAuctionStart() + timeout - Date.now();
395
+ const wait = ready[bidderRequest.bidderRequestId];
396
+ if (wait != null && timeRemaining > 0) {
397
+ Promise.race([
398
+ new Promise((resolve) => setTimeout(resolve, timeRemaining)),
399
+ wait
400
+ ]).then(fn);
401
+ } else {
402
+ fn();
403
+ }
404
+ }
377
405
 
378
406
  function afterBidAdded() {
379
407
  outstandingBidsAdded--;
@@ -382,7 +410,7 @@ export function auctionCallbacks(auctionDone, auctionInstance) {
382
410
  }
383
411
  }
384
412
 
385
- function addBidResponse(adUnitCode, bid) {
413
+ function handleBidResponse(adUnitCode, bid) {
386
414
  let bidderRequest = this;
387
415
 
388
416
  bidResponseMap[bid.requestId] = true;
@@ -429,8 +457,15 @@ export function auctionCallbacks(auctionDone, auctionInstance) {
429
457
  }
430
458
 
431
459
  return {
432
- addBidResponse,
433
- adapterDone
460
+ addBidResponse: function (...args) {
461
+ waitFor(this, addBidResponse.apply({
462
+ dispatch: handleBidResponse,
463
+ bidderRequest: this
464
+ }, args));
465
+ },
466
+ adapterDone: function () {
467
+ guard(this, adapterDone.bind(this))
468
+ }
434
469
  }
435
470
  }
436
471
 
package/src/prebid.js CHANGED
@@ -19,6 +19,7 @@ import { adunitCounter } from './adUnits.js';
19
19
  import { executeRenderer, isRendererRequired } from './Renderer.js';
20
20
  import { createBid } from './bidfactory.js';
21
21
  import { storageCallbacks } from './storageManager.js';
22
+ import { emitAdRenderSucceeded, emitAdRenderFail } from './adRendering.js';
22
23
 
23
24
  const $$PREBID_GLOBAL$$ = getGlobal();
24
25
  const CONSTANTS = require('./constants.json');
@@ -27,7 +28,7 @@ const events = require('./events.js');
27
28
  const { triggerUserSyncs } = userSync;
28
29
 
29
30
  /* private variables */
30
- const { ADD_AD_UNITS, BID_WON, REQUEST_BIDS, SET_TARGETING, AD_RENDER_FAILED, AD_RENDER_SUCCEEDED, STALE_RENDER } = CONSTANTS.EVENTS;
31
+ const { ADD_AD_UNITS, BID_WON, REQUEST_BIDS, SET_TARGETING, STALE_RENDER } = CONSTANTS.EVENTS;
31
32
  const { PREVENT_WRITING_ON_MAIN_DOCUMENT, NO_AD, EXCEPTION, CANNOT_FIND_AD, MISSING_DOC_OR_ADID } = CONSTANTS.AD_RENDER_FAILED_REASON;
32
33
 
33
34
  const eventValidators = {
@@ -146,7 +147,7 @@ function validateNativeMediaType(adUnit) {
146
147
  function validateAdUnitPos(adUnit, mediaType) {
147
148
  let pos = deepAccess(adUnit, `mediaTypes.${mediaType}.pos`);
148
149
 
149
- if (!pos || !isNumber(pos) || !isFinite(pos)) {
150
+ if (!isNumber(pos) || isNaN(pos) || !isFinite(pos)) {
150
151
  let warning = `Value of property 'pos' on ad unit ${adUnit.code} should be of type: Number`;
151
152
 
152
153
  logWarn(warning);
@@ -385,23 +386,6 @@ $$PREBID_GLOBAL$$.setTargetingForAst = function (adUnitCodes) {
385
386
  events.emit(SET_TARGETING, targeting.getAllTargeting());
386
387
  };
387
388
 
388
- function emitAdRenderFail({ reason, message, bid, id }) {
389
- const data = { reason, message };
390
- if (bid) data.bid = bid;
391
- if (id) data.adId = id;
392
-
393
- logError(message);
394
- events.emit(AD_RENDER_FAILED, data);
395
- }
396
-
397
- function emitAdRenderSucceeded({ doc, bid, id }) {
398
- const data = { doc };
399
- if (bid) data.bid = bid;
400
- if (id) data.adId = id;
401
-
402
- events.emit(AD_RENDER_SUCCEEDED, data);
403
- }
404
-
405
389
  /**
406
390
  * This function will check for presence of given node in given parent. If not present - will inject it.
407
391
  * @param {Node} node node, whose existance is in question
@@ -4,18 +4,25 @@
4
4
  */
5
5
 
6
6
  import events from './events.js';
7
- import { fireNativeTrackers, getAssetMessage, getAllAssetsMessage } from './native.js';
7
+ import {fireNativeTrackers, getAllAssetsMessage, getAssetMessage} from './native.js';
8
8
  import constants from './constants.json';
9
- import { logWarn, replaceAuctionPrice, deepAccess, isGptPubadsDefined, isApnGetTagDefined } from './utils.js';
10
- import { auctionManager } from './auctionManager.js';
9
+ import {deepAccess, isApnGetTagDefined, isGptPubadsDefined, logError, logWarn, replaceAuctionPrice} from './utils.js';
10
+ import {auctionManager} from './auctionManager.js';
11
11
  import find from 'core-js-pure/features/array/find.js';
12
- import { isRendererRequired, executeRenderer } from './Renderer.js';
12
+ import {executeRenderer, isRendererRequired} from './Renderer.js';
13
13
  import includes from 'core-js-pure/features/array/includes.js';
14
- import { config } from './config.js';
14
+ import {config} from './config.js';
15
+ import {emitAdRenderFail, emitAdRenderSucceeded} from './adRendering.js';
15
16
 
16
17
  const BID_WON = constants.EVENTS.BID_WON;
17
18
  const STALE_RENDER = constants.EVENTS.STALE_RENDER;
18
19
 
20
+ const HANDLER_MAP = {
21
+ 'Prebid Request': handleRenderRequest,
22
+ 'Prebid Native': handleNativeRequest,
23
+ 'Prebid Event': handleEventRequest,
24
+ }
25
+
19
26
  export function listenMessagesFromCreative() {
20
27
  window.addEventListener('message', receiveMessage, false);
21
28
  }
@@ -29,52 +36,114 @@ export function receiveMessage(ev) {
29
36
  return;
30
37
  }
31
38
 
32
- if (data && data.adId) {
39
+ if (data && data.adId && data.message) {
33
40
  const adObject = find(auctionManager.getBidsReceived(), function (bid) {
34
41
  return bid.adId === data.adId;
35
42
  });
43
+ if (HANDLER_MAP.hasOwnProperty(data.message)) {
44
+ HANDLER_MAP[data.message](ev, data, adObject);
45
+ }
46
+ }
47
+ }
36
48
 
37
- if (adObject && data.message === 'Prebid Request') {
38
- if (adObject.status === constants.BID_STATUS.RENDERED) {
39
- logWarn(`Ad id ${adObject.adId} has been rendered before`);
40
- events.emit(STALE_RENDER, adObject);
41
- if (deepAccess(config.getConfig('auctionOptions'), 'suppressStaleRender')) {
42
- return;
43
- }
44
- }
49
+ function handleRenderRequest(ev, data, adObject) {
50
+ if (adObject == null) {
51
+ emitAdRenderFail({
52
+ reason: constants.AD_RENDER_FAILED_REASON.CANNOT_FIND_AD,
53
+ message: `Cannot find ad '${data.adId}' for cross-origin render request`,
54
+ id: data.adId
55
+ });
56
+ return;
57
+ }
58
+ if (adObject.status === constants.BID_STATUS.RENDERED) {
59
+ logWarn(`Ad id ${adObject.adId} has been rendered before`);
60
+ events.emit(STALE_RENDER, adObject);
61
+ if (deepAccess(config.getConfig('auctionOptions'), 'suppressStaleRender')) {
62
+ return;
63
+ }
64
+ }
45
65
 
46
- _sendAdToCreative(adObject, ev);
66
+ try {
67
+ _sendAdToCreative(adObject, ev);
68
+ } catch (e) {
69
+ emitAdRenderFail({
70
+ reason: constants.AD_RENDER_FAILED_REASON.EXCEPTION,
71
+ message: e.message,
72
+ id: data.adId,
73
+ bid: adObject
74
+ });
75
+ return;
76
+ }
47
77
 
48
- // save winning bids
49
- auctionManager.addWinningBid(adObject);
78
+ // save winning bids
79
+ auctionManager.addWinningBid(adObject);
50
80
 
51
- events.emit(BID_WON, adObject);
52
- }
81
+ events.emit(BID_WON, adObject);
82
+ }
53
83
 
54
- // handle this script from native template in an ad server
55
- // window.parent.postMessage(JSON.stringify({
56
- // message: 'Prebid Native',
57
- // adId: '%%PATTERN:hb_adid%%'
58
- // }), '*');
59
- if (adObject && data.message === 'Prebid Native') {
60
- if (data.action === 'assetRequest') {
61
- const message = getAssetMessage(data, adObject);
62
- ev.source.postMessage(JSON.stringify(message), ev.origin);
63
- } else if (data.action === 'allAssetRequest') {
64
- const message = getAllAssetsMessage(data, adObject);
65
- ev.source.postMessage(JSON.stringify(message), ev.origin);
66
- } else if (data.action === 'resizeNativeHeight') {
67
- adObject.height = data.height;
68
- adObject.width = data.width;
69
- resizeRemoteCreative(adObject);
70
- } else {
71
- const trackerType = fireNativeTrackers(data, adObject);
72
- if (trackerType === 'click') { return; }
73
-
74
- auctionManager.addWinningBid(adObject);
75
- events.emit(BID_WON, adObject);
84
+ function handleNativeRequest(ev, data, adObject) {
85
+ // handle this script from native template in an ad server
86
+ // window.parent.postMessage(JSON.stringify({
87
+ // message: 'Prebid Native',
88
+ // adId: '%%PATTERN:hb_adid%%'
89
+ // }), '*');
90
+ if (adObject == null) {
91
+ logError(`Cannot find ad '${data.adId}' for x-origin event request`);
92
+ return;
93
+ }
94
+ switch (data.action) {
95
+ case 'assetRequest':
96
+ reply(getAssetMessage(data, adObject));
97
+ break;
98
+ case 'allAssetRequest':
99
+ reply(getAllAssetsMessage(data, adObject));
100
+ break;
101
+ case 'resizeNativeHeight':
102
+ adObject.height = data.height;
103
+ adObject.width = data.width;
104
+ resizeRemoteCreative(adObject);
105
+ break;
106
+ default:
107
+ const trackerType = fireNativeTrackers(data, adObject);
108
+ if (trackerType === 'click') {
109
+ return;
76
110
  }
77
- }
111
+ auctionManager.addWinningBid(adObject);
112
+ events.emit(BID_WON, adObject);
113
+ }
114
+
115
+ function reply(message) {
116
+ ev.source.postMessage(JSON.stringify(message), ev.origin);
117
+ }
118
+ }
119
+
120
+ function handleEventRequest(ev, data, adObject) {
121
+ if (adObject == null) {
122
+ logError(`Cannot find ad '${data.adId}' for x-origin event request`);
123
+ return;
124
+ }
125
+ if (adObject.status !== constants.BID_STATUS.RENDERED) {
126
+ logWarn(`Received x-origin event request without corresponding render request for ad '${data.adId}'`);
127
+ return;
128
+ }
129
+ switch (data.event) {
130
+ case constants.EVENTS.AD_RENDER_FAILED:
131
+ emitAdRenderFail({
132
+ bid: adObject,
133
+ id: data.adId,
134
+ reason: data.info.reason,
135
+ message: data.info.message
136
+ });
137
+ break;
138
+ case constants.EVENTS.AD_RENDER_SUCCEEDED:
139
+ emitAdRenderSucceeded({
140
+ doc: null,
141
+ bid: adObject,
142
+ id: data.adId
143
+ });
144
+ break;
145
+ default:
146
+ logError(`Received x-origin event request for unsupported event: '${data.event}' (adId: '${data.adId}')`)
78
147
  }
79
148
  }
80
149
 
package/src/utils.js CHANGED
@@ -22,7 +22,17 @@ let consoleLogExists = Boolean(consoleExists && window.console.log);
22
22
  let consoleInfoExists = Boolean(consoleExists && window.console.info);
23
23
  let consoleWarnExists = Boolean(consoleExists && window.console.warn);
24
24
  let consoleErrorExists = Boolean(consoleExists && window.console.error);
25
- var events = require('./events.js');
25
+
26
+ const emitEvent = (function () {
27
+ // lazy load events to avoid circular import
28
+ let ev;
29
+ return function() {
30
+ if (ev == null) {
31
+ ev = require('./events.js');
32
+ }
33
+ return ev.emit.apply(ev, arguments);
34
+ }
35
+ })();
26
36
 
27
37
  // this allows stubbing of utility functions that are used internally by other utility functions
28
38
  export const internal = {
@@ -265,14 +275,14 @@ export function logWarn() {
265
275
  if (debugTurnedOn() && consoleWarnExists) {
266
276
  console.warn.apply(console, decorateLog(arguments, 'WARNING:'));
267
277
  }
268
- events.emit(CONSTANTS.EVENTS.AUCTION_DEBUG, {type: 'WARNING', arguments: arguments});
278
+ emitEvent(CONSTANTS.EVENTS.AUCTION_DEBUG, {type: 'WARNING', arguments: arguments});
269
279
  }
270
280
 
271
281
  export function logError() {
272
282
  if (debugTurnedOn() && consoleErrorExists) {
273
283
  console.error.apply(console, decorateLog(arguments, 'ERROR:'));
274
284
  }
275
- events.emit(CONSTANTS.EVENTS.AUCTION_DEBUG, {type: 'ERROR', arguments: arguments});
285
+ emitEvent(CONSTANTS.EVENTS.AUCTION_DEBUG, {type: 'ERROR', arguments: arguments});
276
286
  }
277
287
 
278
288
  function decorateLog(args, prefix) {
@@ -0,0 +1,71 @@
1
+ const orig = {};
2
+ ['resolve', 'reject', 'all', 'race', 'allSettled'].forEach((k) => orig[k] = Promise[k].bind(Promise))
3
+
4
+ // Callbacks attached through Promise.resolve(value).then(...) will usually
5
+ // not execute immediately even if `value` is immediately available. This
6
+ // breaks tests that were written before promises even though they are semantically still valid.
7
+ // They can be made to work by making promises quasi-synchronous.
8
+
9
+ export function SyncPromise(value, fail = false) {
10
+ if (value instanceof SyncPromise) {
11
+ return value;
12
+ } else if (typeof value === 'object' && typeof value.then === 'function') {
13
+ return orig.resolve(value);
14
+ } else {
15
+ Object.assign(this, {
16
+ then: function (cb, err) {
17
+ const handler = fail ? err : cb;
18
+ if (handler != null) {
19
+ return new SyncPromise(handler(value));
20
+ } else {
21
+ return this;
22
+ }
23
+ },
24
+ catch: function (cb) {
25
+ if (fail) {
26
+ return new SyncPromise(cb(value))
27
+ } else {
28
+ return this;
29
+ }
30
+ },
31
+ finally: function (cb) {
32
+ cb();
33
+ return this;
34
+ },
35
+ __value: fail ? {status: 'rejected', reason: value} : {status: 'fulfilled', value}
36
+ })
37
+ }
38
+ }
39
+
40
+ Object.assign(SyncPromise, {
41
+ resolve: (val) => new SyncPromise(val),
42
+ reject: (val) => new SyncPromise(val, true),
43
+ race: (promises) => promises.find((p) => p instanceof SyncPromise) || orig.race(promises),
44
+ allSettled: (promises) => {
45
+ if (promises.every((p) => p instanceof SyncPromise)) {
46
+ return new SyncPromise(promises.map((p) => p.__value))
47
+ } else {
48
+ return orig.allSettled(promises);
49
+ }
50
+ },
51
+ all: (promises) => {
52
+ if (promises.every((p) => p instanceof SyncPromise)) {
53
+ return SyncPromise.allSettled(promises).then((result) => {
54
+ const err = result.find((r) => r.status === 'rejected');
55
+ if (err != null) {
56
+ return new SyncPromise(err.reason, true);
57
+ } else {
58
+ return new SyncPromise(result.map((r) => r.value))
59
+ }
60
+ })
61
+ } else {
62
+ return orig.all(promises);
63
+ }
64
+ }
65
+ })
66
+
67
+ export function synchronizePromise(sandbox) {
68
+ Object.keys(orig).forEach((k) => {
69
+ sandbox.stub(window.Promise, k).callsFake(SyncPromise[k]);
70
+ })
71
+ }