@highfivve/ad-tag 5.8.17 → 5.8.21

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 (43) hide show
  1. package/lib/ads/labelConfigService.js +14 -1
  2. package/lib/ads/modules/ad-reload/index.js +146 -142
  3. package/lib/ads/modules/adex/index.js +106 -104
  4. package/lib/ads/modules/cleanup/index.js +64 -61
  5. package/lib/ads/modules/confiant/index.js +29 -29
  6. package/lib/ads/modules/emetriq/index.js +107 -102
  7. package/lib/ads/modules/generic-skin/index.js +128 -127
  8. package/lib/ads/modules/identitylink/index.js +37 -36
  9. package/lib/ads/modules/moli-analytics/eventTracker.js +43 -0
  10. package/lib/ads/modules/moli-analytics/events/gptSlotRenderEnded.js +21 -0
  11. package/lib/ads/modules/moli-analytics/events/index.js +16 -0
  12. package/lib/ads/modules/moli-analytics/events/pageView.js +31 -0
  13. package/lib/ads/modules/moli-analytics/events/prebidAuctionEnd.js +39 -0
  14. package/lib/ads/modules/moli-analytics/events/prebidBidWon.js +23 -0
  15. package/lib/ads/modules/moli-analytics/index.js +161 -0
  16. package/lib/ads/modules/moli-analytics/session.js +60 -0
  17. package/lib/ads/modules/moli-analytics/types.js +1 -0
  18. package/lib/ads/modules/prebid-first-party-data/index.js +41 -43
  19. package/lib/ads/modules/pubstack/abTest.js +11 -0
  20. package/lib/ads/modules/pubstack/index.js +30 -28
  21. package/lib/ads/modules/sticky-footer-ad/index.js +25 -25
  22. package/lib/ads/modules/sticky-footer-ad-v2/index.js +25 -25
  23. package/lib/ads/modules/sticky-header-ad/index.js +44 -42
  24. package/lib/ads/modules/zeotap/index.js +93 -93
  25. package/lib/ads/moli.js +35 -22
  26. package/lib/bundle/adReload.js +2 -2
  27. package/lib/bundle/adex.js +2 -2
  28. package/lib/bundle/cleanup.js +2 -2
  29. package/lib/bundle/confiant.js +2 -2
  30. package/lib/bundle/emetriq.js +2 -2
  31. package/lib/bundle/identityLink.js +2 -2
  32. package/lib/bundle/moliAnalytics.js +2 -0
  33. package/lib/bundle/prebidFirstPartyData.js +2 -2
  34. package/lib/bundle/pubstack.js +2 -2
  35. package/lib/bundle/skin.js +2 -2
  36. package/lib/bundle/stickyFooterAd.js +2 -2
  37. package/lib/bundle/stickyFooterAds2.js +2 -2
  38. package/lib/bundle/stickyHeaderAd.js +2 -2
  39. package/lib/bundle/zeotap.js +2 -2
  40. package/lib/gen/packageJson.js +1 -1
  41. package/lib/types/prebidjs.js +1 -0
  42. package/lib/util/browserStorageKeys.js +1 -0
  43. package/package.json +1 -1
@@ -11,140 +11,141 @@ export const filterHighestNonSkinBid = (bidResponses, blockedAdSlotDomIds) => {
11
11
  .sort((bid1, bid2) => bid2.cpm - bid1.cpm)
12
12
  .slice(0, 1)));
13
13
  };
14
- export class Skin {
15
- constructor() {
16
- this.name = 'skin';
17
- this.description = 'Block other ad slots if a wallpaper has won the auction';
18
- this.moduleType = 'prebid';
19
- this.skinModuleConfig = null;
20
- this.bidsBackHandler = [];
21
- this.getConfigEffect = (config, bidResponses, log) => {
22
- const skinBidResponse = bidResponses[config.skinAdSlotDomId];
23
- const isSkinBid = (bid) => {
24
- const oneFilterApplied = config.formatFilter.some(filter => {
25
- switch (filter.bidder) {
26
- case '*':
27
- return true;
28
- case 'gumgum':
29
- return (bid.bidder === prebidjs.GumGum &&
30
- (filter.auid === undefined ||
31
- (typeof bid.ad !== 'string' && bid.ad.auid === filter.auid)));
32
- default:
33
- return bid.bidder === filter.bidder;
34
- }
35
- });
36
- return bid.cpm > 0 && oneFilterApplied;
37
- };
38
- const nonSkinBids = filterHighestNonSkinBid(bidResponses, config.blockedAdSlotDomIds);
39
- const combinedNonSkinCpm = nonSkinBids.reduce((prev, current) => prev + current.cpm, 0);
40
- const skinBids = skinBidResponse
14
+ export const createSkin = () => {
15
+ const name = 'skin';
16
+ let skinModuleConfig = null;
17
+ let bidsBackHandler = [];
18
+ const config__ = () => skinModuleConfig;
19
+ const getConfigEffect = (config, bidResponses, log) => {
20
+ const skinBidResponse = bidResponses[config.skinAdSlotDomId];
21
+ const isSkinBid = (bid) => {
22
+ const oneFilterApplied = config.formatFilter.some(filter => {
23
+ switch (filter.bidder) {
24
+ case '*':
25
+ return true;
26
+ case 'gumgum':
27
+ return (bid.bidder === prebidjs.GumGum &&
28
+ (filter.auid === undefined ||
29
+ (typeof bid.ad !== 'string' && bid.ad.auid === filter.auid)));
30
+ default:
31
+ return bid.bidder === filter.bidder;
32
+ }
33
+ });
34
+ return bid.cpm > 0 && oneFilterApplied;
35
+ };
36
+ const nonSkinBids = filterHighestNonSkinBid(bidResponses, config.blockedAdSlotDomIds);
37
+ const combinedNonSkinCpm = nonSkinBids.reduce((prev, current) => prev + current.cpm, 0);
38
+ const skinBids = skinBidResponse
39
+ ?
40
+ skinBidResponse.bids.filter(isSkinBid).sort((bid1, bid2) => bid2.cpm - bid1.cpm)
41
+ : [];
42
+ const skinConfigEffect = skinBids.length > 0
43
+ ? skinBids[0].cpm > combinedNonSkinCpm
41
44
  ?
42
- skinBidResponse.bids.filter(isSkinBid).sort((bid1, bid2) => bid2.cpm - bid1.cpm)
43
- : [];
44
- const skinConfigEffect = skinBids.length > 0
45
- ? skinBids[0].cpm > combinedNonSkinCpm
46
- ?
47
- "BlockOtherSlots"
48
- :
49
- "BlockSkinSlot"
45
+ "BlockOtherSlots"
50
46
  :
51
- "NoBlocking";
52
- log.debug(this.name, 'nonSkinBids', nonSkinBids);
53
- log.debug(this.name, 'skinBids', skinBids);
54
- if (config.enableCpmComparison) {
55
- return skinConfigEffect;
47
+ "BlockSkinSlot"
48
+ :
49
+ "NoBlocking";
50
+ log.debug(name, 'nonSkinBids', nonSkinBids);
51
+ log.debug(name, 'skinBids', skinBids);
52
+ if (config.enableCpmComparison) {
53
+ return skinConfigEffect;
54
+ }
55
+ return skinBids.length > 0 ? "BlockOtherSlots" : "NoBlocking";
56
+ };
57
+ const selectConfig = (skinModuleConfig, bidResponses, log) => skinModuleConfig.configs
58
+ .map(config => ({
59
+ skinConfig: config,
60
+ configEffect: getConfigEffect(config, bidResponses, log)
61
+ }))
62
+ .find(({ configEffect }) => configEffect !== "NoBlocking");
63
+ const destroyAdSlot = (slotDefinitions, gWindow) => (adSlotDomId) => {
64
+ const adSlots = slotDefinitions
65
+ .map(slot => slot.adSlot)
66
+ .filter((slot) => slot.getSlotElementId() === adSlotDomId);
67
+ gWindow.googletag.destroySlots(adSlots);
68
+ };
69
+ const hideAdSlot = (_window, log) => (domId) => {
70
+ const element = _window.document.getElementById(domId);
71
+ try {
72
+ if (element) {
73
+ log.debug('SkinModule', `Set display:none for ${domId}`);
74
+ element.style.setProperty('display', 'none');
56
75
  }
57
- return skinBids.length > 0 ? "BlockOtherSlots" : "NoBlocking";
58
- };
59
- this.selectConfig = (skinModuleConfig, bidResponses, log) => skinModuleConfig.configs
60
- .map(config => ({
61
- skinConfig: config,
62
- configEffect: this.getConfigEffect(config, bidResponses, log)
63
- }))
64
- .find(({ configEffect }) => configEffect !== "NoBlocking");
65
- this.destroyAdSlot = (slotDefinitions, gWindow) => (adSlotDomId) => {
66
- const adSlots = slotDefinitions
67
- .map(slot => slot.adSlot)
68
- .filter((slot) => slot.getSlotElementId() === adSlotDomId);
69
- gWindow.googletag.destroySlots(adSlots);
70
- };
71
- this.runSkinConfigs = (skinModuleConfig) => (ctx, bidResponses, slotDefinitions) => {
72
- const skinConfigWithEffect = this.selectConfig(skinModuleConfig, bidResponses, ctx.logger__);
73
- if (skinConfigWithEffect) {
74
- const { skinConfig, configEffect } = skinConfigWithEffect;
75
- if (configEffect === "BlockOtherSlots") {
76
- ctx.logger__.debug('SkinModule', 'Skin configuration applied', skinConfig);
77
- skinConfig.blockedAdSlotDomIds.forEach(this.destroyAdSlot(slotDefinitions, ctx.window__));
78
- if (skinConfig.hideBlockedSlots) {
79
- skinConfig.blockedAdSlotDomIds.forEach(this.hideAdSlot(ctx.window__, ctx.logger__));
80
- }
81
- if (skinConfig.hideSkinAdSlot) {
82
- this.hideAdSlot(ctx.window__, ctx.logger__)(skinConfig.skinAdSlotDomId);
83
- }
84
- if (skinConfig.hideBlockedSlotsSelector) {
85
- ctx.window__.document
86
- .querySelectorAll(skinConfig.hideBlockedSlotsSelector)
87
- .forEach(node => {
88
- ctx.logger__.debug('SkinModule', `Set display:none for container with selector ${skinConfig.hideBlockedSlotsSelector}`);
89
- node.style.setProperty('display', 'none');
90
- });
91
- }
92
- if (skinConfig.targeting) {
93
- try {
94
- ctx.window__.googletag
95
- .pubads()
96
- .setTargeting(skinConfig.targeting.key, skinConfig.targeting.value ?? '1');
97
- }
98
- catch (e) {
99
- ctx.logger__.error('SkinModule', e);
100
- }
101
- }
76
+ }
77
+ catch (e) {
78
+ log.error('SkinModule', `Couldn't set the the wallpaper div ${domId} to display:none;`, e);
79
+ }
80
+ };
81
+ const runSkinConfigs = (skinModuleConfig) => (ctx, bidResponses, slotDefinitions) => {
82
+ const skinConfigWithEffect = selectConfig(skinModuleConfig, bidResponses, ctx.logger__);
83
+ if (skinConfigWithEffect) {
84
+ const { skinConfig, configEffect } = skinConfigWithEffect;
85
+ if (configEffect === "BlockOtherSlots") {
86
+ ctx.logger__.debug('SkinModule', 'Skin configuration applied', skinConfig);
87
+ skinConfig.blockedAdSlotDomIds.forEach(destroyAdSlot(slotDefinitions, ctx.window__));
88
+ if (skinConfig.hideBlockedSlots) {
89
+ skinConfig.blockedAdSlotDomIds.forEach(hideAdSlot(ctx.window__, ctx.logger__));
102
90
  }
103
- else if (skinConfig.enableCpmComparison) {
104
- ctx.logger__.debug('SkinModule', 'Skin configuration ignored because cpm was low', skinConfig);
105
- this.destroyAdSlot(slotDefinitions, ctx.window__)(skinConfig.skinAdSlotDomId);
91
+ if (skinConfig.hideSkinAdSlot) {
92
+ hideAdSlot(ctx.window__, ctx.logger__)(skinConfig.skinAdSlotDomId);
106
93
  }
107
- }
108
- else {
109
- skinModuleConfig.configs
110
- .filter(skinConfig => skinConfig.destroySkinSlot)
111
- .map(skinConfig => skinConfig.skinAdSlotDomId)
112
- .filter(uniquePrimitiveFilter)
113
- .forEach(this.destroyAdSlot(slotDefinitions, ctx.window__));
114
- }
115
- };
116
- this.hideAdSlot = (_window, log) => (domId) => {
117
- const element = _window.document.getElementById(domId);
118
- try {
119
- if (element) {
120
- log.debug('SkinModule', `Set display:none for ${domId}`);
121
- element.style.setProperty('display', 'none');
94
+ if (skinConfig.hideBlockedSlotsSelector) {
95
+ ctx.window__.document
96
+ .querySelectorAll(skinConfig.hideBlockedSlotsSelector)
97
+ .forEach(node => {
98
+ ctx.logger__.debug('SkinModule', `Set display:none for container with selector ${skinConfig.hideBlockedSlotsSelector}`);
99
+ node.style.setProperty('display', 'none');
100
+ });
101
+ }
102
+ if (skinConfig.targeting) {
103
+ try {
104
+ ctx.window__.googletag
105
+ .pubads()
106
+ .setTargeting(skinConfig.targeting.key, skinConfig.targeting.value ?? '1');
107
+ }
108
+ catch (e) {
109
+ ctx.logger__.error('SkinModule', e);
110
+ }
122
111
  }
123
112
  }
124
- catch (e) {
125
- log.error('SkinModule', `Couldn't set the the wallpaper div ${domId} to display:none;`, e);
113
+ else if (skinConfig.enableCpmComparison) {
114
+ ctx.logger__.debug('SkinModule', 'Skin configuration ignored because cpm was low', skinConfig);
115
+ destroyAdSlot(slotDefinitions, ctx.window__)(skinConfig.skinAdSlotDomId);
126
116
  }
127
- };
128
- }
129
- config__() {
130
- return this.skinModuleConfig;
131
- }
132
- configure__(moduleConfig) {
117
+ }
118
+ else {
119
+ skinModuleConfig.configs
120
+ .filter(skinConfig => skinConfig.destroySkinSlot)
121
+ .map(skinConfig => skinConfig.skinAdSlotDomId)
122
+ .filter(uniquePrimitiveFilter)
123
+ .forEach(destroyAdSlot(slotDefinitions, ctx.window__));
124
+ }
125
+ };
126
+ const configure__ = (moduleConfig) => {
133
127
  if (moduleConfig?.skin && moduleConfig.skin.enabled) {
134
- this.skinModuleConfig = moduleConfig.skin;
135
- this.bidsBackHandler.push(this.runSkinConfigs(moduleConfig.skin));
128
+ skinModuleConfig = moduleConfig.skin;
129
+ bidsBackHandler.push(runSkinConfigs(moduleConfig.skin));
136
130
  }
137
- }
138
- initSteps__() {
139
- return [];
140
- }
141
- configureSteps__() {
142
- return [];
143
- }
144
- prepareRequestAdsSteps__() {
145
- return [];
146
- }
147
- prebidBidsBackHandler__() {
148
- return this.bidsBackHandler;
149
- }
150
- }
131
+ };
132
+ const initSteps__ = () => [];
133
+ const configureSteps__ = () => [];
134
+ const prepareRequestAdsSteps__ = () => [];
135
+ const prebidBidsBackHandler__ = () => bidsBackHandler;
136
+ return {
137
+ name,
138
+ description: 'Block other ad slots if a wallpaper has won the auction',
139
+ moduleType: 'prebid',
140
+ config__,
141
+ configure__,
142
+ initSteps__,
143
+ configureSteps__,
144
+ prepareRequestAdsSteps__,
145
+ prebidBidsBackHandler__,
146
+ getConfigEffect,
147
+ selectConfig,
148
+ destroyAdSlot,
149
+ runSkinConfigs
150
+ };
151
+ };
@@ -1,43 +1,20 @@
1
1
  import { mkInitStep } from 'ad-tag/ads/adPipeline';
2
2
  import { AssetLoadMethod } from 'ad-tag/util/assetLoaderService';
3
- export class IdentityLink {
4
- constructor() {
5
- this.name = 'identitylink';
6
- this.description = "Provides LiveRamp's ATS (authenticated traffic solution) functionality to Moli.";
7
- this.moduleType = 'identity';
8
- this.gvlid = '97';
9
- this.identityLinkConfig = null;
10
- }
11
- config__() {
12
- return this.identityLinkConfig;
13
- }
14
- configure__(moduleConfig) {
3
+ export const createIdentityLink = () => {
4
+ const name = 'identitylink';
5
+ const gvlid = '97';
6
+ let identityLinkConfig = null;
7
+ const config__ = () => identityLinkConfig;
8
+ const configure__ = (moduleConfig) => {
15
9
  if (moduleConfig?.identitylink && moduleConfig.identitylink.enabled) {
16
- this.identityLinkConfig = moduleConfig.identitylink;
10
+ identityLinkConfig = moduleConfig.identitylink;
17
11
  }
18
- }
19
- initSteps__() {
20
- const config = this.identityLinkConfig;
21
- return config
22
- ? [
23
- mkInitStep(this.name, ctx => {
24
- this.loadAts(ctx, config);
25
- return Promise.resolve();
26
- })
27
- ]
28
- : [];
29
- }
30
- configureSteps__() {
31
- return [];
32
- }
33
- prepareRequestAdsSteps__() {
34
- return [];
35
- }
36
- loadAts(context, moduleConfig) {
12
+ };
13
+ const loadAts = (context, moduleConfig) => {
37
14
  if (context.env__ === 'test') {
38
15
  return Promise.resolve();
39
16
  }
40
- if (context.tcData__.gdprApplies && !context.tcData__.vendor.consents[this.gvlid]) {
17
+ if (context.tcData__.gdprApplies && !context.tcData__.vendor.consents[gvlid]) {
41
18
  return Promise.resolve();
42
19
  }
43
20
  const window = context.window__;
@@ -62,10 +39,34 @@ export class IdentityLink {
62
39
  });
63
40
  return context.assetLoaderService__
64
41
  .loadScript({
65
- name: this.name,
42
+ name,
66
43
  loadMethod: AssetLoadMethod.TAG,
67
44
  assetUrl: `https://launchpad-wrapper.privacymanager.io/${moduleConfig.launchPadId}/launchpad-liveramp.js`
68
45
  })
69
46
  .catch(error => context.logger__.error('failed to load emetriq', error));
70
- }
71
- }
47
+ };
48
+ const initSteps__ = () => {
49
+ const config = identityLinkConfig;
50
+ return config
51
+ ? [
52
+ mkInitStep(name, ctx => {
53
+ loadAts(ctx, config);
54
+ return Promise.resolve();
55
+ })
56
+ ]
57
+ : [];
58
+ };
59
+ const configureSteps__ = () => [];
60
+ const prepareRequestAdsSteps__ = () => [];
61
+ return {
62
+ name,
63
+ description: "Provides LiveRamp's ATS (authenticated traffic solution) functionality to Moli.",
64
+ moduleType: 'identity',
65
+ config__,
66
+ configure__,
67
+ initSteps__,
68
+ configureSteps__,
69
+ prepareRequestAdsSteps__,
70
+ loadAts
71
+ };
72
+ };
@@ -0,0 +1,43 @@
1
+ export const createEventTracker = (url, batchSize, batchDelay, logger) => {
2
+ let batch = [];
3
+ let timer = null;
4
+ const processBatch = () => {
5
+ const currentBatch = batch;
6
+ batch = [];
7
+ fetch(url, {
8
+ method: 'POST',
9
+ headers: {
10
+ 'Content-Type': 'application/json'
11
+ },
12
+ body: JSON.stringify({ events: currentBatch })
13
+ })
14
+ .then(response => {
15
+ if (response.ok) {
16
+ logger?.debug(`moli-analytics: Successfully sent analytics batch of ${currentBatch.length} events`);
17
+ }
18
+ else {
19
+ logger?.error(`moli-analytics: Failed to send analytics batch: ${response.statusText}`);
20
+ }
21
+ })
22
+ .catch(error => {
23
+ logger?.error(`moli-analytics: Failed to send analytics batch: ${error}`);
24
+ });
25
+ };
26
+ const track = (event) => {
27
+ logger?.debug('moli-analytics: event', event);
28
+ batch.push(event);
29
+ if (timer != null) {
30
+ clearTimeout(timer);
31
+ timer = null;
32
+ }
33
+ if (batch.length >= batchSize) {
34
+ processBatch();
35
+ }
36
+ else {
37
+ timer = setTimeout(processBatch, batchDelay);
38
+ }
39
+ };
40
+ return {
41
+ track
42
+ };
43
+ };
@@ -0,0 +1,21 @@
1
+ export const mapGPTSlotRenderEnded = (event, context, adContext) => {
2
+ const timestamp = Date.now();
3
+ return {
4
+ v: 1,
5
+ type: 'gpt.slotRenderEnded',
6
+ publisher: context.publisher,
7
+ pageViewId: context.pageViewId,
8
+ userId: adContext.window__.pbjs.getUserIds().pubcid,
9
+ timestamp,
10
+ analyticsLabels: context.analyticsLabels,
11
+ data: {
12
+ auctionId: context.auctionId,
13
+ gpid: context.gpid,
14
+ adUnitPath: event.slot.getAdUnitPath(),
15
+ adUnitName: context.adUnitName,
16
+ adUnitCode: event.slot.getSlotElementId(),
17
+ size: Array.isArray(event.size) ? event.size.join('x') : event.size,
18
+ isEmpty: event.isEmpty
19
+ }
20
+ };
21
+ };
@@ -0,0 +1,16 @@
1
+ import { mapPrebidAuctionEnd } from 'ad-tag/ads/modules/moli-analytics/events/prebidAuctionEnd';
2
+ import { mapPrebidBidWon } from 'ad-tag/ads/modules/moli-analytics/events/prebidBidWon';
3
+ import { mapGPTSlotRenderEnded } from 'ad-tag/ads/modules/moli-analytics/events/gptSlotRenderEnded';
4
+ import { mapPageView } from 'ad-tag/ads/modules/moli-analytics/events/pageView';
5
+ export const eventMapper = {
6
+ prebid: {
7
+ auctionEnd: mapPrebidAuctionEnd,
8
+ bidWon: mapPrebidBidWon
9
+ },
10
+ gpt: {
11
+ slotRenderEnded: mapGPTSlotRenderEnded
12
+ },
13
+ page: {
14
+ view: mapPageView
15
+ }
16
+ };
@@ -0,0 +1,31 @@
1
+ const parseUTM = (search) => {
2
+ const params = new URLSearchParams(search);
3
+ const v = (k) => params.get(k) || null;
4
+ return {
5
+ source: v('utm_source'),
6
+ medium: v('utm_medium'),
7
+ campaign: v('utm_campaign'),
8
+ content: v('utm_content'),
9
+ term: v('utm_term')
10
+ };
11
+ };
12
+ export const mapPageView = (context, adContext) => {
13
+ const timestamp = Date.now();
14
+ const userIds = adContext.window__.pbjs.getUserIds ? adContext.window__.pbjs.getUserIds() : {};
15
+ return {
16
+ v: 1,
17
+ type: 'page.view',
18
+ publisher: context.publisher,
19
+ pageViewId: context.pageViewId,
20
+ userId: userIds?.pubcid,
21
+ timestamp,
22
+ analyticsLabels: context.analyticsLabels,
23
+ data: {
24
+ sessionId: context.session.getId(),
25
+ device: adContext.labelConfigService__.getDeviceLabel(),
26
+ domain: adContext.window__.moli.resolveAdUnitPath('{domain}'),
27
+ ua: adContext.window__.navigator.userAgent,
28
+ utm: parseUTM(adContext.window__.location.search)
29
+ }
30
+ };
31
+ };
@@ -0,0 +1,39 @@
1
+ export const mapPrebidAuctionEnd = (event, context, adContext) => {
2
+ const timestamp = Date.now();
3
+ return {
4
+ v: 1,
5
+ type: 'prebid.auctionEnd',
6
+ publisher: context.publisher,
7
+ pageViewId: context.pageViewId,
8
+ userId: adContext.window__.pbjs.getUserIds().pubcid,
9
+ timestamp,
10
+ analyticsLabels: context.analyticsLabels,
11
+ data: {
12
+ auctionId: event.auctionId,
13
+ adUnits: Array.from(new Map((event.adUnits || []).map(adUnit => [
14
+ adUnit.code,
15
+ {
16
+ code: adUnit.code,
17
+ adUnitName: adUnit.pubstack?.adUnitName || adUnit.code,
18
+ gpid: adUnit.ortb2Imp?.ext?.gpid
19
+ }
20
+ ])).values()),
21
+ bidderRequests: (event.bidderRequests || []).map(request => {
22
+ return {
23
+ bidderCode: request.bidderCode,
24
+ bids: (request.bids || []).map(bid => ({
25
+ adUnitCode: bid.adUnitCode
26
+ }))
27
+ };
28
+ }),
29
+ bidsReceived: (event.bidsReceived || []).map(bid => ({
30
+ bidder: bid.bidder,
31
+ adUnitCode: bid.adUnitCode,
32
+ size: bid.size,
33
+ currency: bid.currency,
34
+ cpm: bid.cpm,
35
+ timeToRespond: bid.timeToRespond
36
+ }))
37
+ }
38
+ };
39
+ };
@@ -0,0 +1,23 @@
1
+ export const mapPrebidBidWon = (event, context, adContext) => {
2
+ const timestamp = Date.now();
3
+ return {
4
+ v: 1,
5
+ type: 'prebid.bidWon',
6
+ publisher: context.publisher,
7
+ pageViewId: context.pageViewId,
8
+ userId: adContext.window__.pbjs.getUserIds().pubcid,
9
+ timestamp,
10
+ analyticsLabels: context.analyticsLabels,
11
+ data: {
12
+ auctionId: event.auctionId,
13
+ gpid: context.gpid,
14
+ bidderCode: event.bidderCode,
15
+ adUnitCode: event.adUnitCode,
16
+ size: event.size,
17
+ currency: event.currency,
18
+ cpm: event.cpm,
19
+ status: event.status,
20
+ timeToRespond: event.timeToRespond
21
+ }
22
+ };
23
+ };