@highfivve/ad-tag 5.5.4

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 (132) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +149 -0
  3. package/lib/ads/a9.js +190 -0
  4. package/lib/ads/adPipeline.js +159 -0
  5. package/lib/ads/adService.js +251 -0
  6. package/lib/ads/adUnitPath.js +37 -0
  7. package/lib/ads/auctions/adRequestThrottling.js +22 -0
  8. package/lib/ads/auctions/biddersDisabling.js +90 -0
  9. package/lib/ads/auctions/frequencyCapping.js +189 -0
  10. package/lib/ads/auctions/interstitialContext.js +92 -0
  11. package/lib/ads/auctions/previousBidCpms.js +33 -0
  12. package/lib/ads/auctions/resume.js +3 -0
  13. package/lib/ads/bridge/bridge.js +62 -0
  14. package/lib/ads/consent.js +63 -0
  15. package/lib/ads/eventService.js +44 -0
  16. package/lib/ads/globalAuctionContext.js +98 -0
  17. package/lib/ads/googleAdManager.js +380 -0
  18. package/lib/ads/keyValues.js +1 -0
  19. package/lib/ads/labelConfigService.js +42 -0
  20. package/lib/ads/modules/ad-reload/adVisibilityService.js +158 -0
  21. package/lib/ads/modules/ad-reload/index.js +163 -0
  22. package/lib/ads/modules/ad-reload/userActivityService.js +70 -0
  23. package/lib/ads/modules/adex/adex-mapping.js +77 -0
  24. package/lib/ads/modules/adex/adexUtiq.js +15 -0
  25. package/lib/ads/modules/adex/index.js +142 -0
  26. package/lib/ads/modules/adex/sendAdvertisingId.js +20 -0
  27. package/lib/ads/modules/blocklist-url/index.js +118 -0
  28. package/lib/ads/modules/cleanup/index.js +93 -0
  29. package/lib/ads/modules/confiant/index.js +47 -0
  30. package/lib/ads/modules/emetriq/index.js +154 -0
  31. package/lib/ads/modules/emetriq/trackInApp.js +34 -0
  32. package/lib/ads/modules/emetriq/trackLoginEvent.js +59 -0
  33. package/lib/ads/modules/generic-skin/index.js +150 -0
  34. package/lib/ads/modules/identitylink/index.js +58 -0
  35. package/lib/ads/modules/interstitial/index.js +38 -0
  36. package/lib/ads/modules/interstitial/interstitialAd.js +111 -0
  37. package/lib/ads/modules/lazy-load/index.js +191 -0
  38. package/lib/ads/modules/lazy-load/selectInfiniteSlot.js +11 -0
  39. package/lib/ads/modules/prebid-first-party-data/index.js +115 -0
  40. package/lib/ads/modules/pubstack/index.js +59 -0
  41. package/lib/ads/modules/sticky-footer-ad/desktopFloorAd.js +63 -0
  42. package/lib/ads/modules/sticky-footer-ad/index.js +43 -0
  43. package/lib/ads/modules/sticky-footer-ad/mobileSticky.js +93 -0
  44. package/lib/ads/modules/sticky-footer-ad-v2/footerStickyAd.js +118 -0
  45. package/lib/ads/modules/sticky-footer-ad-v2/index.js +43 -0
  46. package/lib/ads/modules/sticky-header-ad/fadeOutCallback.js +25 -0
  47. package/lib/ads/modules/sticky-header-ad/index.js +103 -0
  48. package/lib/ads/modules/sticky-header-ad/renderResult.js +24 -0
  49. package/lib/ads/modules/utiq/index.js +79 -0
  50. package/lib/ads/modules/yield-optimization/dynamicFloorPrice.js +86 -0
  51. package/lib/ads/modules/yield-optimization/index.js +57 -0
  52. package/lib/ads/modules/yield-optimization/isYieldOptimizationConfigDynamic.js +6 -0
  53. package/lib/ads/modules/yield-optimization/yieldOptimizationService.js +169 -0
  54. package/lib/ads/modules/zeotap/index.js +111 -0
  55. package/lib/ads/moli.js +645 -0
  56. package/lib/ads/moliGlobal.js +11 -0
  57. package/lib/ads/prebid-outstream.js +13 -0
  58. package/lib/ads/prebid.js +406 -0
  59. package/lib/ads/sizeConfigService.js +49 -0
  60. package/lib/ads/spa.js +32 -0
  61. package/lib/bundle/adReload.js +2 -0
  62. package/lib/bundle/adex.js +2 -0
  63. package/lib/bundle/blocklistUrls.js +2 -0
  64. package/lib/bundle/cleanup.js +2 -0
  65. package/lib/bundle/confiant.js +2 -0
  66. package/lib/bundle/configureFromEndpoint.js +40 -0
  67. package/lib/bundle/emetriq.js +2 -0
  68. package/lib/bundle/identityLink.js +2 -0
  69. package/lib/bundle/init.js +2 -0
  70. package/lib/bundle/interstitialModule.js +2 -0
  71. package/lib/bundle/lazyLoad.js +2 -0
  72. package/lib/bundle/prebidFirstPartyData.js +2 -0
  73. package/lib/bundle/pubstack.js +2 -0
  74. package/lib/bundle/skin.js +2 -0
  75. package/lib/bundle/stickyFooterAd.js +2 -0
  76. package/lib/bundle/stickyFooterAds2.js +2 -0
  77. package/lib/bundle/stickyHeaderAd.js +2 -0
  78. package/lib/bundle/utiq.js +2 -0
  79. package/lib/bundle/yieldOptimization.js +2 -0
  80. package/lib/bundle/zeotap.js +2 -0
  81. package/lib/console/components/adSlotConfig.js +225 -0
  82. package/lib/console/components/consentConfig.js +138 -0
  83. package/lib/console/components/globalConfig.js +634 -0
  84. package/lib/console/components/labelConfigDebug.js +19 -0
  85. package/lib/console/components/sizeConfigDebug.js +34 -0
  86. package/lib/console/components/tag.js +4 -0
  87. package/lib/console/debug.js +38 -0
  88. package/lib/console/util/array.js +1 -0
  89. package/lib/console/util/calculateAdDensity.js +36 -0
  90. package/lib/console/util/debounce.js +12 -0
  91. package/lib/console/util/debugLogger.js +6 -0
  92. package/lib/console/util/extractPositionFromPath.js +8 -0
  93. package/lib/console/util/prebid.js +3 -0
  94. package/lib/console/util/stringUtils.js +23 -0
  95. package/lib/console/util/themingService.js +31 -0
  96. package/lib/console/util/windowResizeService.js +22 -0
  97. package/lib/console/validations/adReloadValidations.js +47 -0
  98. package/lib/console/validations/bucketValidations.js +78 -0
  99. package/lib/console/validations/sizesConfigValidations.js +97 -0
  100. package/lib/gen/packageJson.js +3 -0
  101. package/lib/index.js +3 -0
  102. package/lib/types/apstag.js +1 -0
  103. package/lib/types/dom.js +1 -0
  104. package/lib/types/emetriq.js +1 -0
  105. package/lib/types/googletag.js +1 -0
  106. package/lib/types/identitylink.js +1 -0
  107. package/lib/types/module.js +1 -0
  108. package/lib/types/moliConfig.js +1 -0
  109. package/lib/types/moliRuntime.js +1 -0
  110. package/lib/types/prebidjs.js +45 -0
  111. package/lib/types/supplyChainObject.js +1 -0
  112. package/lib/types/tcfapi.js +48 -0
  113. package/lib/util/addNewInfiniteSlotToConfig.js +11 -0
  114. package/lib/util/arrayUtils.js +9 -0
  115. package/lib/util/assetLoaderService.js +91 -0
  116. package/lib/util/browserStorageKeys.js +7 -0
  117. package/lib/util/debugDelay.js +12 -0
  118. package/lib/util/domready.js +15 -0
  119. package/lib/util/environmentOverride.js +16 -0
  120. package/lib/util/extractAdTagVersion.js +16 -0
  121. package/lib/util/extractTopPrivateDomainFromHostname.js +17 -0
  122. package/lib/util/localStorage.js +26 -0
  123. package/lib/util/logging.js +106 -0
  124. package/lib/util/objectUtils.js +29 -0
  125. package/lib/util/query.js +40 -0
  126. package/lib/util/queryParameters.js +5 -0
  127. package/lib/util/resolveOverrides.js +21 -0
  128. package/lib/util/resolveStoredRequestIdInOrtb2Object.js +12 -0
  129. package/lib/util/sizes.js +3 -0
  130. package/lib/util/test-slots.js +150 -0
  131. package/lib/util/uuid.js +10 -0
  132. package/package.json +127 -0
@@ -0,0 +1,169 @@
1
+ import { resolveAdUnitPath } from 'ad-tag/ads/adUnitPath';
2
+ import { isYieldConfigDynamic } from 'ad-tag/ads/modules/yield-optimization/isYieldOptimizationConfigDynamic';
3
+ import { calculateDynamicPriceRule } from 'ad-tag/ads/modules/yield-optimization/dynamicFloorPrice';
4
+ export const createYieldOptimizationService = (yieldConfig) => {
5
+ const emptyAdUnitPriceRulesResponse = {
6
+ rules: {},
7
+ browser: 'None'
8
+ };
9
+ let adUnitPricingRuleResponse = Promise.resolve(emptyAdUnitPriceRulesResponse);
10
+ let isEnabled = false;
11
+ let device = 'mobile';
12
+ let adUnitPathVariables = {};
13
+ const init = (deviceLabel, adUnitPathVars, adUnitPaths, fetch, logger) => {
14
+ device = deviceLabel;
15
+ adUnitPathVariables = adUnitPathVars;
16
+ switch (yieldConfig.provider) {
17
+ case 'none':
18
+ logger.warn('YieldOptimizationService', 'Yield optimization is disabled!');
19
+ isEnabled = false;
20
+ adUnitPricingRuleResponse = Promise.resolve(emptyAdUnitPriceRulesResponse);
21
+ break;
22
+ case 'static':
23
+ logger.warn('YieldOptimizationService', 'Yield optimization is static!');
24
+ isEnabled = true;
25
+ adUnitPricingRuleResponse = Promise.resolve({
26
+ rules: yieldConfig.config
27
+ .rules,
28
+ browser: 'None'
29
+ });
30
+ break;
31
+ case 'dynamic':
32
+ isEnabled = true;
33
+ const excludedAdUnitPaths = yieldConfig.excludedAdUnitPaths;
34
+ const filteredAdUnitPaths = adUnitPaths.filter(adUnitPath => excludedAdUnitPaths.indexOf(adUnitPath) < 0);
35
+ const resolvedAdUnits = filteredAdUnitPaths.map(adUnitPath => resolveAdUnitPath(adUnitPath, adUnitPathVariables));
36
+ adUnitPricingRuleResponse = loadConfigWithRetry(yieldConfig.configEndpoint, 3, resolvedAdUnits, fetch)
37
+ .then(config => {
38
+ logger.info('YieldOptimizationService', `loaded pricing rules for device ${device}`, config);
39
+ return config;
40
+ })
41
+ .catch(error => {
42
+ logger.error('YieldOptimizationService', 'failed to initialize service', error);
43
+ return emptyAdUnitPriceRulesResponse;
44
+ });
45
+ break;
46
+ default:
47
+ isEnabled = false;
48
+ adUnitPricingRuleResponse = Promise.reject('Unknown config provider');
49
+ }
50
+ return Promise.resolve();
51
+ };
52
+ const getPriceRule = (adUnitPath) => {
53
+ return adUnitPricingRuleResponse.then(response => response.rules[resolveAdUnitPath(adUnitPath, adUnitPathVariables)]);
54
+ };
55
+ const getBrowser = () => {
56
+ return adUnitPricingRuleResponse.then(response => response.browser || 'None');
57
+ };
58
+ const setTargeting = (adSlot, adServer, logger, yieldOptimizationConfig, auctionContext) => {
59
+ const adUnitPath = resolveAdUnitPath(adSlot.getAdUnitPath(), adUnitPathVariables);
60
+ return adUnitPricingRuleResponse.then(config => {
61
+ const rule = config.rules[adUnitPath];
62
+ if (adServer === 'gam') {
63
+ if (rule) {
64
+ adSlot.setTargeting('upr_model', rule.model || 'static');
65
+ if (rule.main) {
66
+ adSlot.setTargeting('upr_main', 'true');
67
+ const lastBidCpmsOnPosition = auctionContext?.getLastBidCpmsOfAdUnit(adSlot.getSlotElementId());
68
+ if (lastBidCpmsOnPosition &&
69
+ lastBidCpmsOnPosition?.length > 0 &&
70
+ isYieldConfigDynamic(yieldOptimizationConfig) &&
71
+ yieldOptimizationConfig.dynamicFloorPrices) {
72
+ const { strategy, roundingStepsInCents, maxPriceRuleInCents, minPriceRuleInCents } = yieldOptimizationConfig.dynamicFloorPrices;
73
+ const newRule = calculateDynamicPriceRule({
74
+ strategy,
75
+ previousCpms: lastBidCpmsOnPosition,
76
+ standardRule: rule,
77
+ roundingStepsInCents,
78
+ maxPriceRuleInCents,
79
+ minPriceRuleInCents
80
+ });
81
+ logger.debug('YieldOptimizationService', `set dynamic price rule id ${newRule.priceRuleId} for ${adUnitPath} based on previous bid cpms on same position. Stategy is '${strategy}'. Main traffic share ${rule.main}. Cpm is ${newRule.floorprice}.`);
82
+ adSlot.setTargeting('upr_id', newRule.priceRuleId.toFixed(0));
83
+ return newRule;
84
+ }
85
+ else {
86
+ adSlot.setTargeting('upr_id', rule.priceRuleId.toFixed(0));
87
+ }
88
+ }
89
+ else {
90
+ logger.debug('YieldOptimizationService', `set price rule id ${rule.priceRuleId} for ${adUnitPath}. Main traffic share ${rule.main}. cpm is ${rule.floorprice}`);
91
+ adSlot.setTargeting('upr_id', rule.priceRuleId.toFixed(0));
92
+ }
93
+ }
94
+ else if (isEnabled) {
95
+ logger.warn('YieldOptimizationService', `No price rule found for ${adUnitPath}`);
96
+ }
97
+ }
98
+ return rule;
99
+ });
100
+ };
101
+ const loadConfigWithRetry = (configEndpoint, retriesLeft, adUnitPaths, fetch, lastError = null) => {
102
+ if (retriesLeft <= 0) {
103
+ return Promise.reject(lastError);
104
+ }
105
+ return fetch(configEndpoint, {
106
+ method: 'POST',
107
+ mode: 'cors',
108
+ headers: {
109
+ 'Content-Type': 'application/json',
110
+ Accept: 'application/json'
111
+ },
112
+ body: JSON.stringify({
113
+ device: device,
114
+ key: 'adUnitPath',
115
+ adUnitPaths: adUnitPaths
116
+ })
117
+ })
118
+ .then(response => {
119
+ return response.ok
120
+ ? response.json()
121
+ : response
122
+ .text()
123
+ .then(errorMessage => Promise.reject(`${response.statusText}: ${errorMessage}`));
124
+ })
125
+ .then((response) => {
126
+ if (typeof response !== 'object' || response === null) {
127
+ return Promise.reject('Invalid response');
128
+ }
129
+ if (!isAdunitPricesRulesResponse(response)) {
130
+ return Promise.reject('response is missing rules property');
131
+ }
132
+ if (validateRules(response.rules)) {
133
+ return response;
134
+ }
135
+ else {
136
+ return Promise.reject('At least one rule object was not valid');
137
+ }
138
+ })
139
+ .catch(error => {
140
+ const exponentialBackoff = new Promise(resolve => setTimeout(resolve, 100 / retriesLeft));
141
+ return exponentialBackoff.then(() => loadConfigWithRetry(configEndpoint, retriesLeft - 1, adUnitPaths, fetch, error));
142
+ });
143
+ };
144
+ const isAdunitPricesRulesResponse = (obj) => {
145
+ return obj.hasOwnProperty('rules');
146
+ };
147
+ const isPriceRules = (obj) => {
148
+ return typeof obj === 'object' && obj !== null;
149
+ };
150
+ const validateRules = (rules) => {
151
+ if (!isPriceRules(rules)) {
152
+ return false;
153
+ }
154
+ return Object.keys(rules).every(adUnit => {
155
+ const rule = rules[adUnit];
156
+ return (typeof rule === 'object' &&
157
+ rule !== null &&
158
+ typeof rule.main === 'boolean' &&
159
+ typeof rule.floorprice === 'number' &&
160
+ typeof rule.priceRuleId === 'number');
161
+ });
162
+ };
163
+ return {
164
+ init,
165
+ getPriceRule,
166
+ getBrowser,
167
+ setTargeting
168
+ };
169
+ };
@@ -0,0 +1,111 @@
1
+ import { mkConfigureStepOncePerRequestAdsCycle, mkInitStep } from 'ad-tag/ads/adPipeline';
2
+ import { AssetLoadMethod } from 'ad-tag/util/assetLoaderService';
3
+ import { tcfapi } from 'ad-tag/types/tcfapi';
4
+ export class Zeotap {
5
+ constructor() {
6
+ this.name = 'zeotap';
7
+ this.description = 'Provides Zeotap functionality (data collection and identity plus) to Moli.';
8
+ this.moduleType = 'identity';
9
+ this.gvlid = 301;
10
+ this.loadScriptCount = 0;
11
+ this.zeotapConfig = null;
12
+ this.hasConsent = (tcData) => {
13
+ if (tcData.gdprApplies) {
14
+ return (tcData.vendor.consents[this.gvlid] &&
15
+ tcData.purpose.consents[tcfapi.responses.TCPurpose.STORE_INFORMATION_ON_DEVICE] &&
16
+ tcData.purpose.consents[tcfapi.responses.TCPurpose.CREATE_PERSONALISED_ADS_PROFILE] &&
17
+ tcData.purpose.consents[tcfapi.responses.TCPurpose.SELECT_PERSONALISED_ADS] &&
18
+ tcData.purpose.consents[tcfapi.responses.TCPurpose.CREATE_PERSONALISED_CONTENT_PROFILE] &&
19
+ tcData.purpose.consents[tcfapi.responses.TCPurpose.SELECT_PERSONALISED_CONTENT] &&
20
+ tcData.purpose.consents[tcfapi.responses.TCPurpose.MEASURE_AD_PERFORMANCE] &&
21
+ tcData.purpose.consents[tcfapi.responses.TCPurpose.APPLY_MARKET_RESEARCH] &&
22
+ tcData.purpose.consents[tcfapi.responses.TCPurpose.DEVELOP_IMPROVE_PRODUCTS]);
23
+ }
24
+ return true;
25
+ };
26
+ this.loadScript = (config, assetLoaderService, moduleConfig) => {
27
+ const { mode, dataKeyValues, exclusionKeyValues, assetUrl, hashedEmailAddress, countryCode } = moduleConfig;
28
+ if (!assetLoaderService) {
29
+ return Promise.reject('Zeotap module :: no asset loader found, module not initialized yet?');
30
+ }
31
+ if (mode === 'default' && this.loadScriptCount > 0) {
32
+ return Promise.reject("Zeotap module :: can't reload script in default mode.");
33
+ }
34
+ const keyValuesMap = this.makeKeyValuesMap(config.targeting?.keyValues);
35
+ if (exclusionKeyValues.some(kv => this.isExclusionKeyValueSet(kv, keyValuesMap))) {
36
+ return Promise.reject('Zeotap module :: targeting exclusions prevented loading the script.');
37
+ }
38
+ const customData = dataKeyValues
39
+ .map(kv => this.parameterFromKeyValue(kv, keyValuesMap))
40
+ .join('&');
41
+ const loadIdPlus = !!moduleConfig.hashedEmailAddress && this.loadScriptCount === 0;
42
+ const url = assetUrl +
43
+ `&idp=${loadIdPlus ? 1 : 0}` +
44
+ (customData.length > 0 ? `&${customData}` : '') +
45
+ (countryCode ? `&ctry=${countryCode}` : '') +
46
+ (hashedEmailAddress ? `&z_e_sha2_l=${hashedEmailAddress}` : '');
47
+ this.loadScriptCount++;
48
+ return assetLoaderService.loadScript({
49
+ name: this.name,
50
+ loadMethod: AssetLoadMethod.TAG,
51
+ assetUrl: url
52
+ });
53
+ };
54
+ this.parameterFromKeyValue = (kv, keyValuesMap) => {
55
+ const value = keyValuesMap.get(kv.keyValueKey);
56
+ if (Array.isArray(value)) {
57
+ return `${kv.parameterKey}=${encodeURIComponent(value.join(','))}`;
58
+ }
59
+ return `${kv.parameterKey}=${encodeURIComponent(value || '')}`;
60
+ };
61
+ this.isExclusionKeyValueSet = (kv, keyValuesMap) => {
62
+ const value = keyValuesMap.get(kv.keyValueKey);
63
+ if (Array.isArray(value)) {
64
+ return value.indexOf(kv.disableOnValue) > -1;
65
+ }
66
+ return value === kv.disableOnValue;
67
+ };
68
+ this.makeKeyValuesMap = (keyValues) => {
69
+ return keyValues
70
+ ? new Map(Object.keys(keyValues)
71
+ .map(key => [key, keyValues[key]])
72
+ .filter(([, value]) => !!value))
73
+ : new Map();
74
+ };
75
+ }
76
+ config__() {
77
+ return this.zeotapConfig;
78
+ }
79
+ configure__(moduleConfig) {
80
+ if (moduleConfig?.zeotap && moduleConfig.zeotap.enabled) {
81
+ this.zeotapConfig = moduleConfig.zeotap;
82
+ }
83
+ }
84
+ initSteps__() {
85
+ const config = this.zeotapConfig;
86
+ return config && config.mode === 'default'
87
+ ? [
88
+ mkInitStep(this.name, context => {
89
+ if (this.hasConsent(context.tcData__)) {
90
+ this.loadScript(context.config__, context.assetLoaderService__, config).catch(error => context.logger__.error(this.name, error));
91
+ }
92
+ return Promise.resolve();
93
+ })
94
+ ]
95
+ : [];
96
+ }
97
+ configureSteps__() {
98
+ const config = this.zeotapConfig;
99
+ return config && config.mode === 'spa'
100
+ ? [
101
+ mkConfigureStepOncePerRequestAdsCycle(this.name, context => {
102
+ this.loadScript(context.config__, context.assetLoaderService__, config).catch(error => context.logger__.error(this.name, error));
103
+ return Promise.resolve();
104
+ })
105
+ ]
106
+ : [];
107
+ }
108
+ prepareRequestAdsSteps__() {
109
+ return [];
110
+ }
111
+ }