@temple-wallet/extension-ads 7.1.1 → 8.1.0-dev.1

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 (33) hide show
  1. package/dist/index.d.ts +33 -52
  2. package/dist/index.js +13 -12
  3. package/package.json +3 -6
  4. package/src/ads-actions/helpers.ts +25 -11
  5. package/src/ads-actions/index.ts +6 -3
  6. package/src/ads-actions/process-permanent-rule.ts +9 -1
  7. package/src/ads-actions/process-providers-ads.ts +39 -16
  8. package/src/ads-actions/process-rule.ts +2 -0
  9. package/src/ads-configuration.ts +8 -8
  10. package/src/constants.ts +2 -0
  11. package/src/execute-ads-actions/ads-views/index.ts +2 -2
  12. package/src/execute-ads-actions/ads-views/{make-hypelab-ad.ts → make-ads-tw-view.ts} +11 -9
  13. package/src/execute-ads-actions/ads-views/make-extension-iframe-view.ts +26 -0
  14. package/src/execute-ads-actions/ads-views/make-tkey-ad.ts +1 -1
  15. package/src/execute-ads-actions/observing.ts +13 -7
  16. package/src/execute-ads-actions/process-insert-ad-action.ts +11 -3
  17. package/src/render-ads-stack.ts +70 -14
  18. package/src/temple-wallet-api.ts +9 -2
  19. package/src/transform-raw-rules.ts +27 -11
  20. package/src/types/ad-view.ts +3 -0
  21. package/src/types/ads-actions.ts +4 -1
  22. package/src/types/ads-meta.ts +3 -18
  23. package/src/types/ads-provider.ts +1 -0
  24. package/src/types/ads-rules.ts +1 -1
  25. package/src/types/temple-wallet-api.ts +1 -0
  26. package/src/utils.ts +0 -4
  27. package/dist/referrals/index.d.ts +0 -33
  28. package/dist/referrals/index.js +0 -18
  29. package/src/execute-ads-actions/ads-views/make-persona-ad.ts +0 -15
  30. package/src/referrals/index.ts +0 -5
  31. package/src/referrals/replace.ts +0 -129
  32. package/src/referrals/takeads.ts +0 -44
  33. package/src/referrals/utils.ts +0 -14
@@ -1,12 +1,12 @@
1
1
  import { AdMetadata } from './types/ads-meta';
2
2
 
3
3
  interface IAdsConfiguration {
4
- hypelabAdsWindowUrl: string;
4
+ adsTwWindowUrl: string;
5
5
  tkeyInpageAdUrl: string;
6
6
  smallTkeyInpageAdUrl?: string;
7
7
  swapTkeyUrl: string;
8
8
  externalAdsActivityMessageType: string;
9
- getPersonaIframeURL: (id: string, slug: string) => string;
9
+ personaIframePath: string;
10
10
  getAdsStackIframeURL: (id: string, adsMetadataIds: (number | AdMetadata)[], origin: string) => string;
11
11
  buildNativeAdsMeta: (containerWidth: number, containerHeight: number) => AdMetadata[];
12
12
  bannerAdsMeta: AdMetadata[];
@@ -17,12 +17,12 @@ interface IAdsConfiguration {
17
17
 
18
18
  export class AdsConfiguration {
19
19
  static IS_MISES_BROWSER = false;
20
- static HYPELAB_ADS_WINDOW_URL = '';
20
+ static ADS_TW_WINDOW_URL = '';
21
21
  static TKEY_INPAGE_AD_URL = '';
22
22
  static SMALL_TKEY_INPAGE_AD_URL = '';
23
23
  static SWAP_TKEY_URL = '';
24
24
  static EXTERNAL_ADS_ACTIVITY_MESSAGE_TYPE = '';
25
- static getPersonaIframeURL: IAdsConfiguration['getPersonaIframeURL'] = () => '';
25
+ static personaIframePath: IAdsConfiguration['personaIframePath'] = '';
26
26
  static getAdsStackIframeURL: IAdsConfiguration['getAdsStackIframeURL'] = () => '';
27
27
  static buildNativeAdsMeta: IAdsConfiguration['buildNativeAdsMeta'] = () => [];
28
28
  static bannerAdsMeta: AdMetadata[] = [];
@@ -32,12 +32,12 @@ export class AdsConfiguration {
32
32
 
33
33
  export const configureAds = (config: IAdsConfiguration) => {
34
34
  const {
35
- hypelabAdsWindowUrl,
35
+ adsTwWindowUrl,
36
36
  tkeyInpageAdUrl,
37
37
  smallTkeyInpageAdUrl,
38
38
  swapTkeyUrl,
39
39
  externalAdsActivityMessageType,
40
- getPersonaIframeURL,
40
+ personaIframePath,
41
41
  getAdsStackIframeURL,
42
42
  buildNativeAdsMeta,
43
43
  bannerAdsMeta,
@@ -50,11 +50,11 @@ export const configureAds = (config: IAdsConfiguration) => {
50
50
  AdsConfiguration.SMALL_TKEY_INPAGE_AD_URL = smallTkeyInpageAdUrl;
51
51
  }
52
52
 
53
- AdsConfiguration.HYPELAB_ADS_WINDOW_URL = hypelabAdsWindowUrl;
53
+ AdsConfiguration.ADS_TW_WINDOW_URL = adsTwWindowUrl;
54
54
  AdsConfiguration.TKEY_INPAGE_AD_URL = tkeyInpageAdUrl;
55
55
  AdsConfiguration.SWAP_TKEY_URL = swapTkeyUrl;
56
56
  AdsConfiguration.EXTERNAL_ADS_ACTIVITY_MESSAGE_TYPE = externalAdsActivityMessageType;
57
- AdsConfiguration.getPersonaIframeURL = getPersonaIframeURL;
57
+ AdsConfiguration.personaIframePath = personaIframePath;
58
58
  AdsConfiguration.getAdsStackIframeURL = getAdsStackIframeURL;
59
59
  AdsConfiguration.buildNativeAdsMeta = buildNativeAdsMeta;
60
60
  AdsConfiguration.bannerAdsMeta = bannerAdsMeta;
package/src/constants.ts CHANGED
@@ -7,3 +7,5 @@ export const AD_RESIZE_MESSAGE_TYPE = 'resize';
7
7
  export const AD_READY_MESSAGE_TYPE = 'ready';
8
8
  export const AD_ERROR_MESSAGE_TYPE = 'error';
9
9
  export const IFRAME_ALLOWANCE = 'accelerometer; gyroscope';
10
+ export const CRYPTO_CATEGORY_NAME = 'crypto';
11
+ export const BACKGROUND_ELEMENT_ID = 'background';
@@ -1,3 +1,3 @@
1
1
  export { makeTKeyAdView } from './make-tkey-ad';
2
- export { makeHypelabAdView } from './make-hypelab-ad';
3
- export { makePersonaAdView } from './make-persona-ad';
2
+ export { makeAdsTwView } from './make-ads-tw-view';
3
+ export { makeExtensionIframeView } from './make-extension-iframe-view';
@@ -3,17 +3,17 @@ import { AES } from 'crypto-js';
3
3
  import { AdsConfiguration } from 'src/ads-configuration';
4
4
  import { IFRAME_ALLOWANCE } from 'src/constants';
5
5
  import { AdView } from 'src/types/ad-view';
6
- import { AdDimensions, HypeLabAdSource } from 'src/types/ads-meta';
6
+ import { AdDimensions, AdSource } from 'src/types/ads-meta';
7
7
 
8
- export const makeHypelabAdView = (
8
+ export const makeAdsTwView = (
9
9
  id: string,
10
- source: HypeLabAdSource,
10
+ source: AdSource,
11
11
  { width, height }: AdDimensions,
12
12
  origin: string
13
13
  ): AdView => {
14
14
  const iframe = document.createElement('iframe');
15
15
  iframe.id = id;
16
- iframe.src = getHypelabIframeUrl(source, origin, width, height, iframe.id);
16
+ iframe.src = getAdsTwUrl(source, origin, width, height, iframe.id);
17
17
  iframe.style.width = source.native ? '100%' : `${width}px`;
18
18
  iframe.style.height = `${height}px`;
19
19
  iframe.style.border = 'none';
@@ -23,21 +23,23 @@ export const makeHypelabAdView = (
23
23
  };
24
24
 
25
25
  /**
26
- * Returns URL for Hypelab ad iframe
26
+ * Returns URL for ads.templewallet.com or its preview iframe
27
27
  * @param placementType Placement type
28
28
  * @param origin Full URL of the page
29
29
  * @param width Frame width
30
30
  * @param height Frame height
31
31
  */
32
- const getHypelabIframeUrl = (source: HypeLabAdSource, origin: string, width: number, height: number, id: string) => {
33
- const url = new URL(AdsConfiguration.HYPELAB_ADS_WINDOW_URL);
34
- if (source.native) {
32
+ const getAdsTwUrl = (source: AdSource, origin: string, width: number, height: number, id: string) => {
33
+ const { providerName, slug, native } = source;
34
+ const url = new URL(AdsConfiguration.ADS_TW_WINDOW_URL);
35
+ url.searchParams.set('ap', providerName.toLowerCase());
36
+ if (native) {
35
37
  url.searchParams.set('vh', String(height));
36
38
  } else {
37
39
  url.searchParams.set('w', String(width));
38
40
  }
39
41
  url.searchParams.set('h', String(height));
40
- url.searchParams.set('p', source.slug);
42
+ url.searchParams.set('p', slug);
41
43
  url.searchParams.set('o', encryptWithAES(origin));
42
44
  if (id) {
43
45
  url.searchParams.set('id', id);
@@ -0,0 +1,26 @@
1
+ import { AdsConfiguration } from 'src/ads-configuration';
2
+ import { AdView } from 'src/types/ad-view';
3
+ import { AdDimensions, AdSource } from 'src/types/ads-meta';
4
+
5
+ export const makeExtensionIframeView = (id: string, source: AdSource, { width, height }: AdDimensions): AdView => {
6
+ const element = document.createElement('iframe');
7
+ let iframePath = '';
8
+ switch (source.providerName) {
9
+ case 'Persona':
10
+ iframePath = AdsConfiguration.personaIframePath;
11
+ break;
12
+ default:
13
+ throw new Error(`Ads from ${source.providerName} are unavailable via extension iframe`);
14
+ }
15
+ const iframeUrl = new URL(iframePath);
16
+ iframeUrl.searchParams.set('id', id);
17
+ iframeUrl.searchParams.set('slug', source.slug);
18
+ element.src = iframeUrl.toString();
19
+ element.id = id;
20
+
21
+ element.style.width = `${width}px`;
22
+ element.style.height = `${height}px`;
23
+ element.style.border = 'none';
24
+
25
+ return { element };
26
+ };
@@ -42,5 +42,5 @@ export const makeTKeyAdView = (width: number, height: number, isNative = false):
42
42
  img.style.height = '100%';
43
43
  anchor.appendChild(img);
44
44
 
45
- return { element };
45
+ return { element, creativeSet: { image: { url: img.src } } };
46
46
  };
@@ -1,5 +1,6 @@
1
1
  import browser from 'webextension-polyfill';
2
2
 
3
+ import { extendOrKeepDimension } from 'src/ads-actions/helpers';
3
4
  import { AdsConfiguration } from 'src/ads-configuration';
4
5
  import {
5
6
  AD_ERROR_MESSAGE_TYPE,
@@ -46,21 +47,26 @@ export const subscribeToAdsStackIframeLoadIfNecessary = async (element: HTMLIFra
46
47
  reject(new Error(data.reason ?? 'Unknown error'));
47
48
  break;
48
49
  case AD_RENDER_START_MESSAGE_TYPE:
49
- const { dimensions }: AdMetadata = data.adMetadata;
50
+ const { dimensions, source }: AdMetadata = data.adMetadata;
50
51
  const { width, height } = dimensions;
51
52
  if (width > 0 && height > 0) {
52
- if (!element.style.width?.endsWith('%')) {
53
- element.style.width = `${dimensions.width}px`;
53
+ if (source.native) {
54
+ element.style.height = `${height}px`;
55
+ } else {
56
+ extendOrKeepDimension(element, 'width', width);
57
+ extendOrKeepDimension(element, 'height', height);
54
58
  }
55
- element.style.height = `${dimensions.height}px`;
56
59
  }
57
60
  break;
58
61
  case AD_RESIZE_MESSAGE_TYPE:
59
62
  const { width: newWidth, height: newHeight } = data;
60
- if (!element.style.width?.endsWith('%')) {
61
- element.style.width = `${newWidth + horizontalBordersWidth}px`;
63
+
64
+ if (element.style.width?.endsWith('%')) {
65
+ element.style.height = `${newHeight + verticalBordersWidth}px`;
66
+ } else {
67
+ extendOrKeepDimension(element, 'width', newWidth + horizontalBordersWidth);
68
+ extendOrKeepDimension(element, 'height', newHeight + verticalBordersWidth);
62
69
  }
63
- element.style.height = `${newHeight + verticalBordersWidth}px`;
64
70
  }
65
71
  } catch (error) {
66
72
  console.error('Observing error:', error);
@@ -14,7 +14,7 @@ import { AdDimensions } from 'src/types/ads-meta';
14
14
  import { subscribeToAdsStackIframeLoadIfNecessary } from './observing';
15
15
  import { overrideElementStyles } from './override-element-styles';
16
16
 
17
- const adjustToAd = (wrapperElement: HTMLDivElement, adDimensions: AdDimensions) => {
17
+ const adjustToAd = (wrapperElement: HTMLDivElement, adDimensions: Pick<AdDimensions, 'width' | 'height'>) => {
18
18
  const predefinedStylesKeyToOverride = ['width', 'height'] as const;
19
19
  predefinedStylesKeyToOverride.forEach(dimensionName => {
20
20
  const predefinedStyleValue = wrapperElement.style[dimensionName] ?? '';
@@ -33,7 +33,7 @@ const processInsertAdActionOnce = async (
33
33
  insertionPoint: HTMLDivElement | HTMLTableCellElement,
34
34
  onAdsStackError: (error: Error) => void
35
35
  ) => {
36
- const { elementStyle = {}, stylesOverrides = [], adsMetadata, wrapperType } = action;
36
+ const { elementStyle = {}, stylesOverrides = [], adsMetadata, wrapperType, originalHeight, originalWidth } = action;
37
37
 
38
38
  stylesOverrides.sort((a, b) => a.parentDepth - b.parentDepth);
39
39
 
@@ -41,12 +41,17 @@ const processInsertAdActionOnce = async (
41
41
 
42
42
  const adId = nanoid();
43
43
  const adElement = document.createElement('iframe');
44
+ adElement.loading = 'lazy';
44
45
  adElement.src = AdsConfiguration.getAdsStackIframeURL(adId, adsMetadata, window.location.href);
45
46
  adElement.id = adId;
46
47
  adElement.allow = IFRAME_ALLOWANCE;
47
48
  const firstAdMetadataOrId = adsMetadata[0];
48
- const { dimensions } =
49
+ const { dimensions: minDimensions } =
49
50
  typeof firstAdMetadataOrId === 'number' ? AdsConfiguration.bannerAdsMeta[firstAdMetadataOrId] : firstAdMetadataOrId;
51
+ const dimensions = {
52
+ width: Math.max(originalWidth, minDimensions.width),
53
+ height: Math.max(originalHeight, minDimensions.height)
54
+ };
50
55
  adElement.style.width = wrapperType === 'tbody' ? '100%' : `${dimensions.width}px`;
51
56
  adElement.style.height = `${dimensions.height}px`;
52
57
  adElement.style.border = 'none';
@@ -157,6 +162,9 @@ export const processInsertAdAction = async (action: InsertAdAction) => {
157
162
  if (isNativeAd) {
158
163
  emptyAdElement.setAttribute(TEMPLE_WALLET_NATIVE_AD_ATTRIBUTE_NAME, 'true');
159
164
  }
165
+ if (action.type === AdActionType.SimpleInsertAd && action.isSiblingReplacement) {
166
+ emptyAdElement.setAttribute(SIBLING_REPLACEMENT_ATTRIBUTE_NAME, 'true');
167
+ }
160
168
  emptyAdElement.style.display = 'none';
161
169
  wrapperElement.replaceWith(emptyAdElement);
162
170
  };
@@ -1,12 +1,15 @@
1
+ import { extendOrKeepDimension } from './ads-actions/helpers';
1
2
  import { AdsConfiguration } from './ads-configuration';
2
3
  import {
3
4
  AD_ERROR_MESSAGE_TYPE,
4
5
  AD_READY_MESSAGE_TYPE,
5
6
  AD_RENDER_START_MESSAGE_TYPE,
6
- AD_RESIZE_MESSAGE_TYPE
7
+ AD_RESIZE_MESSAGE_TYPE,
8
+ BACKGROUND_ELEMENT_ID
7
9
  } from './constants';
8
- import { makeHypelabAdView, makePersonaAdView, makeTKeyAdView } from './execute-ads-actions/ads-views';
9
- import { AdView } from './types/ad-view';
10
+ import { makeAdsTwView, makeExtensionIframeView, makeTKeyAdView } from './execute-ads-actions/ads-views';
11
+ import { overrideElementStyles } from './execute-ads-actions/override-element-styles';
12
+ import { AdView, CreativeSet } from './types/ad-view';
10
13
  import { AdMetadata } from './types/ads-meta';
11
14
 
12
15
  const broadcastMessage = (content: unknown) => window.parent.postMessage(JSON.stringify(content), '*');
@@ -34,17 +37,16 @@ export const renderAdsStack = async (
34
37
 
35
38
  const { source, dimensions } = adMetadata;
36
39
  let adView: AdView;
37
- let withTempleLabel = true;
38
40
  switch (source.providerName) {
39
41
  case 'Temple':
40
42
  adView = makeTKeyAdView(dimensions.width, dimensions.height, source.native);
41
43
  break;
42
44
  case 'HypeLab':
43
- adView = makeHypelabAdView(adId, source, dimensions, origin);
44
- if (source.native) withTempleLabel = false;
45
+ case 'SmartyAds':
46
+ adView = makeAdsTwView(adId, source, dimensions, origin);
45
47
  break;
46
48
  default:
47
- adView = makePersonaAdView(adId, source, dimensions);
49
+ adView = makeExtensionIframeView(adId, source, dimensions);
48
50
  }
49
51
 
50
52
  const { element } = adView;
@@ -52,9 +54,57 @@ export const renderAdsStack = async (
52
54
  const templeLabelElement = document.getElementById('temple-label')!;
53
55
  rootElement.replaceChildren(element);
54
56
 
55
- if (withTempleLabel) templeLabelElement.setAttribute('active', '');
57
+ if (!source.native) templeLabelElement.setAttribute('active', '');
56
58
  else templeLabelElement.removeAttribute('active');
57
59
 
60
+ const updateBackground = (creativeSet: CreativeSet = {}) => {
61
+ try {
62
+ const { image, video } = creativeSet;
63
+ const prevBackgroundElement = document.getElementById(BACKGROUND_ELEMENT_ID);
64
+ let backgroundElement: HTMLImageElement | HTMLVideoElement | undefined;
65
+ if (image) {
66
+ backgroundElement = document.createElement('img');
67
+ backgroundElement.src = image.url;
68
+ backgroundElement.alt = '';
69
+ } else if (video) {
70
+ backgroundElement = document.createElement('video');
71
+ backgroundElement.src = video.url;
72
+ backgroundElement.autoplay = true;
73
+ backgroundElement.preload = 'auto';
74
+ backgroundElement.playsInline = true;
75
+ backgroundElement.muted = true;
76
+ backgroundElement.loop = true;
77
+ }
78
+
79
+ if (!backgroundElement && prevBackgroundElement) {
80
+ rootElement.removeChild(prevBackgroundElement);
81
+ }
82
+
83
+ if (!backgroundElement) return;
84
+
85
+ backgroundElement.id = BACKGROUND_ELEMENT_ID;
86
+ backgroundElement.style.zIndex = '-1';
87
+ overrideElementStyles(backgroundElement, {
88
+ position: 'absolute',
89
+ top: '0px',
90
+ left: '0px',
91
+ right: '0px',
92
+ bottom: '0px',
93
+ width: '100%',
94
+ height: '100%',
95
+ 'object-fit': 'cover',
96
+ filter: 'blur(12px)'
97
+ });
98
+ if (prevBackgroundElement) {
99
+ rootElement.replaceChild(backgroundElement, prevBackgroundElement);
100
+ } else {
101
+ rootElement.appendChild(backgroundElement);
102
+ }
103
+ } catch (e) {
104
+ console.error(e);
105
+ }
106
+ };
107
+
58
108
  if (element instanceof HTMLIFrameElement) {
59
109
  return new Promise<void>((resolve, reject) => {
60
110
  const responseTimeout = setTimeout(
@@ -82,19 +132,24 @@ export const renderAdsStack = async (
82
132
  clearTimeout(responseTimeout);
83
133
  resolve();
84
134
  }
135
+ updateBackground(data.ad?.creative_set);
85
136
  break;
86
137
  case AD_ERROR_MESSAGE_TYPE:
87
- window.removeEventListener('message', messageListener);
88
- clearTimeout(responseTimeout);
89
- reject(new Error(data.reason ?? 'Unknown error'));
138
+ if (!wasReady) {
139
+ window.removeEventListener('message', messageListener);
140
+ clearTimeout(responseTimeout);
141
+ reject(new Error(data.reason ?? 'Unknown error'));
142
+ }
90
143
  break;
91
144
  case AD_RESIZE_MESSAGE_TYPE:
92
145
  const { width, height } = data;
93
146
  if (width > 0 && height > 0) {
94
- if (!element.style.width?.endsWith('%')) {
95
- element.style.width = `${width}px`;
147
+ if (adMetadata.source.native) {
148
+ element.style.height = `${height}px`;
149
+ } else {
150
+ extendOrKeepDimension(element, 'width', width);
151
+ extendOrKeepDimension(element, 'height', height);
96
152
  }
97
- element.style.height = `${height}px`;
98
153
  broadcastMessage({ ...data, id: adId });
99
154
  }
100
155
  }
@@ -111,5 +166,6 @@ export const renderAdsStack = async (
111
166
  });
112
167
  }
113
168
 
169
+ updateBackground(adView.creativeSet);
114
170
  broadcastMessage({ id: adId, type: AD_READY_MESSAGE_TYPE, adMetadata });
115
171
  };
@@ -42,6 +42,10 @@ export class TempleWalletApi {
42
42
  this.api.get<string[]>('/slise-ad-rules/providers/all-sites')
43
43
  );
44
44
 
45
+ getProvidersCategories = withFetchDataExtraction(() =>
46
+ this.api.get<Record<string, string[]>>('/slise-ad-rules/providers/categories')
47
+ );
48
+
45
49
  getProvidersRulesForAllDomains = withFetchDataExtraction(() =>
46
50
  this.api.get<Record<string, RawAdProvidersRule[]>>('/slise-ad-rules/providers/by-sites')
47
51
  );
@@ -92,7 +96,8 @@ export class TempleWalletApi {
92
96
  permanentNativeAdPlacesRulesForAllDomains,
93
97
  adsReplaceUrlsBlacklist,
94
98
  providersNegativeSelectors,
95
- elementsToHideOrRemoveRules
99
+ elementsToHideOrRemoveRules,
100
+ providersCategories
96
101
  ] = await Promise.all([
97
102
  this.getAdPlacesRulesForAllDomains(),
98
103
  this.getProvidersRulesForAllDomains(),
@@ -102,7 +107,8 @@ export class TempleWalletApi {
102
107
  this.getPermanentNativeAdPlacesRulesForAllDomains(),
103
108
  this.getAdsReplaceUrlsBlacklist(),
104
109
  this.getNegativeSelectorsForAllProviders(),
105
- this.getElementsToHideOrRemoveRules()
110
+ this.getElementsToHideOrRemoveRules(),
111
+ this.getProvidersCategories()
106
112
  ]);
107
113
 
108
114
  return {
@@ -115,6 +121,7 @@ export class TempleWalletApi {
115
121
  adsReplaceUrlsBlacklist,
116
122
  providersNegativeSelectors,
117
123
  elementsToHideOrRemoveRules,
124
+ providersCategories,
118
125
  timestamp: Date.now()
119
126
  };
120
127
  };
@@ -3,6 +3,8 @@ import { isEqual } from 'lodash';
3
3
  import { AdPlacesRule, AdsRules } from 'src/types/ads-rules';
4
4
  import { RawAllAdsRules, RawPermanentAdPlacesRule } from 'src/types/temple-wallet-api';
5
5
 
6
+ import { CRYPTO_CATEGORY_NAME } from './constants';
7
+
6
8
  export const transformRawRules = (location: Location, rules: RawAllAdsRules): AdsRules => {
7
9
  const {
8
10
  adPlacesRulesForAllDomains,
@@ -14,6 +16,7 @@ export const transformRawRules = (location: Location, rules: RawAllAdsRules): Ad
14
16
  permanentNativeAdPlacesRulesForAllDomains = {},
15
17
  adsReplaceUrlsBlacklist = [],
16
18
  elementsToHideOrRemoveRules = {},
19
+ providersCategories = {},
17
20
  timestamp
18
21
  } = rules;
19
22
  const { hostname, href } = location;
@@ -50,14 +53,16 @@ export const transformRawRules = (location: Location, rules: RawAllAdsRules): Ad
50
53
  hrefMatchPredicate,
51
54
  providersRulesForAllDomains,
52
55
  providersSelectors,
53
- providersToReplaceAtAllSites
56
+ providersToReplaceAtAllSites,
57
+ providersCategories
54
58
  ),
55
59
  providersNegativeSelectors: buildProvidersSelectors(
56
60
  hostname,
57
61
  hrefMatchPredicate,
58
62
  providersRulesForAllDomains,
59
63
  providersNegativeSelectors,
60
- providersToReplaceAtAllSites
64
+ providersToReplaceAtAllSites,
65
+ providersCategories
61
66
  ),
62
67
  elementsToHideOrRemoveRules: buildElementsToHideOrRemoveRules(
63
68
  hostname,
@@ -163,7 +168,8 @@ const buildProvidersSelectors = (
163
168
  hrefMatchPredicate: (regex: RegExp) => boolean,
164
169
  providersRulesForAllDomains: RawAllAdsRules['providersRulesForAllDomains'],
165
170
  providersSelectors: RawAllAdsRules['providersSelectors'],
166
- providersToReplaceAtAllSites: RawAllAdsRules['providersToReplaceAtAllSites']
171
+ providersToReplaceAtAllSites: RawAllAdsRules['providersToReplaceAtAllSites'],
172
+ providersCategories: RawAllAdsRules['providersCategories']
167
173
  ): AdsRules['providersSelectors'] => {
168
174
  const providersRulesByHostname = (providersRulesForAllDomains[hostname] ?? []).map(
169
175
  ({ urlRegexes, ...restRuleProps }) => ({
@@ -176,19 +182,24 @@ const buildProvidersSelectors = (
176
182
  urlRegexes.some(hrefMatchPredicate)
177
183
  );
178
184
  const alreadyProcessedProviders = new Set<string>();
179
- const selectorsForProvidersToReplace: Record<number, Set<string>> = {};
185
+ const adsSelectors: Record<string, Record<number, Set<string>>> = {};
180
186
  const handleProvider = (provider: string) => {
181
187
  if (alreadyProcessedProviders.has(provider)) return;
182
188
 
189
+ const categoriesSlug = (providersCategories[provider] ?? [CRYPTO_CATEGORY_NAME]).join('|');
183
190
  const newSelectors = providersSelectors[provider] ?? [];
184
191
  newSelectors.forEach(selector => {
185
192
  const { selector: cssString, parentDepth } =
186
193
  typeof selector === 'string' ? { selector, parentDepth: 0 } : selector;
187
194
 
188
- if (!selectorsForProvidersToReplace[parentDepth]) {
189
- selectorsForProvidersToReplace[parentDepth] = new Set();
195
+ if (!adsSelectors[categoriesSlug]) {
196
+ adsSelectors[categoriesSlug] = {};
197
+ }
198
+ const sameCategoriesAdsSelectors = adsSelectors[categoriesSlug];
199
+ if (!sameCategoriesAdsSelectors[parentDepth]) {
200
+ sameCategoriesAdsSelectors[parentDepth] = new Set();
190
201
  }
191
- selectorsForProvidersToReplace[parentDepth].add(cssString);
202
+ sameCategoriesAdsSelectors[parentDepth].add(cssString);
192
203
  });
193
204
  alreadyProcessedProviders.add(provider);
194
205
  };
@@ -196,8 +207,13 @@ const buildProvidersSelectors = (
196
207
  providersToReplaceAtAllSites.forEach(handleProvider);
197
208
  relatedProvidersRulesByUrl.forEach(({ providers }) => providers.forEach(handleProvider));
198
209
 
199
- return Object.entries(selectorsForProvidersToReplace).map(([parentDepth, selectors]) => ({
200
- parentDepth: Number(parentDepth),
201
- selector: quickJoinSelectors(selectors)
202
- }));
210
+ return Object.entries(adsSelectors)
211
+ .map(([categoriesSlug, sameCategoriesSelectors]) =>
212
+ Object.entries(sameCategoriesSelectors).map(([parentDepth, selectors]) => ({
213
+ parentDepth: Number(parentDepth),
214
+ selector: quickJoinSelectors(selectors),
215
+ categories: categoriesSlug.split('|')
216
+ }))
217
+ )
218
+ .flat();
203
219
  };
@@ -1,3 +1,6 @@
1
+ export type CreativeSet = Partial<Record<'image' | 'video', { url: string }>>;
2
+
1
3
  export interface AdView {
2
4
  element: HTMLDivElement | HTMLIFrameElement;
5
+ creativeSet?: CreativeSet;
3
6
  }
@@ -29,6 +29,8 @@ interface InsertAdActionProps
29
29
  adsMetadata: (number | AdMetadata)[];
30
30
  elementStyle?: StringRecord<string>;
31
31
  stylesOverrides?: AdStylesOverrides[];
32
+ originalWidth: number;
33
+ originalHeight: number;
32
34
  }
33
35
 
34
36
  export interface ReplaceAllChildrenWithAdAction extends AdActionBase, InsertAdActionProps {
@@ -60,7 +62,7 @@ export interface HideElementAction extends AdActionBase {
60
62
 
61
63
  export type InsertAdAction = ReplaceAllChildrenWithAdAction | ReplaceElementWithAdAction | SimpleInsertAdAction;
62
64
 
63
- export type OmitAdInAction<T extends InsertAdActionProps> = Omit<T, 'adsMetadata'>;
65
+ export type OmitAdInAction<T extends InsertAdActionProps> = Omit<T, 'adsMetadata' | 'originalWidth' | 'originalHeight'>;
64
66
 
65
67
  export type InsertAdActionWithoutMeta =
66
68
  | OmitAdInAction<ReplaceAllChildrenWithAdAction>
@@ -73,5 +75,6 @@ export type AddActionsIfAdResolutionAvailable = (
73
75
  elementsToMeasure: Record<'width' | 'height', HTMLElement>,
74
76
  adType: AdType,
75
77
  adIsNative: boolean,
78
+ expectedCategories: string[],
76
79
  ...actionsBases: (InsertAdActionWithoutMeta | HideElementAction | RemoveElementAction)[]
77
80
  ) => boolean;
@@ -1,26 +1,11 @@
1
- interface AdSourceBase {
1
+ export interface AdSource {
2
2
  shouldNotUseStrictContainerLimits?: boolean;
3
- }
4
-
5
- /** Only covers TKEY ads for now */
6
- interface TempleAdSource extends AdSourceBase {
7
- providerName: 'Temple';
3
+ providerName: 'Temple' | 'Persona' | 'HypeLab' | 'SmartyAds';
8
4
  native?: boolean;
9
- }
10
-
11
- export interface PersonaAdSource extends AdSourceBase {
12
- providerName: 'Persona';
13
5
  slug: string;
6
+ categories?: string[];
14
7
  }
15
8
 
16
- export interface HypeLabAdSource extends AdSourceBase {
17
- providerName: 'HypeLab';
18
- native: boolean;
19
- slug: string;
20
- }
21
-
22
- type AdSource = HypeLabAdSource | TempleAdSource | PersonaAdSource;
23
-
24
9
  export interface AdDimensions {
25
10
  width: number;
26
11
  height: number;
@@ -1,5 +1,6 @@
1
1
  export enum AdsProviderTitle {
2
2
  Optimal = 'Optimal',
3
+ SmartyAds = 'SmartyAds',
3
4
  HypeLab = 'HypeLab',
4
5
  Persona = 'Persona',
5
6
  Temple = 'Temple Wallet'
@@ -17,7 +17,7 @@ export interface ElementsToHideOrRemoveRule extends Omit<RawElementsToHideOrRemo
17
17
  export interface AdsRules {
18
18
  adPlacesRules: Array<Omit<AdPlacesRule, 'urlRegexes'>>;
19
19
  permanentAdPlacesRules: PermanentAdPlacesRule[];
20
- providersSelectors: Array<{ selector: string; parentDepth: number }>;
20
+ providersSelectors: Array<{ selector: string; parentDepth: number; categories: string[] }>;
21
21
  providersNegativeSelectors: Array<{ selector: string; parentDepth: number }>;
22
22
  elementsToHideOrRemoveRules: ElementsToHideOrRemoveRule[];
23
23
  timestamp: number;
@@ -65,6 +65,7 @@ export interface RawElementsToHideOrRemoveEntry {
65
65
 
66
66
  export interface RawAllAdsRules {
67
67
  adPlacesRulesForAllDomains: Record<string, RawAdPlacesRule[]>;
68
+ providersCategories: Record<string, string[]>;
68
69
  providersRulesForAllDomains: Record<string, RawAdProvidersRule[]>;
69
70
  providersSelectors: Record<string, (string | { selector: string; parentDepth: number })[]>;
70
71
  providersNegativeSelectors: Record<string, (string | { selector: string; parentDepth: number })[]>;
package/src/utils.ts CHANGED
@@ -1,7 +1,3 @@
1
- export const IS_DEV = process && process.env && process.env.NODE_ENV === 'development';
2
-
3
- export const IS_MAC_OS = navigator.userAgent.includes('Macintosh');
4
-
5
1
  /** From lodash */
6
2
  type Truthy<T> = T extends null | undefined | void | false | '' | 0 | 0n ? never : T;
7
3
 
@@ -1,33 +0,0 @@
1
- import memoizee from 'memoizee';
2
- import * as lodash from 'lodash';
3
-
4
- declare function processAnchors(supportedDomains: Set<string>, AdsBrowserExtensionMessageType: AdsBrowserExtensionMessageTypeI): Promise<undefined>;
5
- interface AdsBrowserExtensionMessageTypeI {
6
- FetchReferrals: string;
7
- ReferralClick: string;
8
- }
9
-
10
- /**
11
- * API docs: https://docs.takeads.com
12
- */
13
- declare class TakeAdsClient {
14
- private publicKey;
15
- readonly apiUrl: string;
16
- private axios;
17
- constructor(publicKey: string, apiUrl?: string);
18
- affiliateLinks(websiteUrls: string[], subId?: string): Promise<TekeadsAffiliateResponse>;
19
- }
20
- declare const buildTakeadsClient: ((publicKey: string) => TakeAdsClient) & memoizee.Memoized<(publicKey: string) => TakeAdsClient>;
21
- interface TekeadsAffiliateResponse {
22
- data: AffiliateLink[];
23
- }
24
- interface AffiliateLink {
25
- iri: string;
26
- trackingLink: string;
27
- imageUrl: string | null;
28
- }
29
-
30
- /** Current page's domain with 'www' stripped off */
31
- declare const getCurrentPageDomain: (() => string) & lodash.MemoizedFunction;
32
-
33
- export { buildTakeadsClient, getCurrentPageDomain, processAnchors };