@temple-wallet/extension-ads 1.0.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.
package/.yarnrc.yml ADDED
@@ -0,0 +1,3 @@
1
+ nodeLinker: node-modules
2
+
3
+ yarnPath: .yarn/releases/yarn-4.1.1.cjs
package/README.md ADDED
@@ -0,0 +1 @@
1
+ # @temple-wallet/extension-ads
@@ -0,0 +1,196 @@
1
+ type StringRecord<T = string> = Record<string, T>;
2
+
3
+ interface AdSourceBase {
4
+ shouldNotUseStrictContainerLimits?: boolean;
5
+ }
6
+ interface HypeLabBannerAdSource extends AdSourceBase {
7
+ providerName: 'HypeLab';
8
+ native: false;
9
+ size: 'small' | 'high' | 'wide';
10
+ }
11
+ interface HypeLabNativeAdSource extends AdSourceBase {
12
+ providerName: 'HypeLab';
13
+ native: true;
14
+ slug: string;
15
+ }
16
+ /** Only covers TKEY ads for now */
17
+ interface TempleAdSource extends AdSourceBase {
18
+ providerName: 'Temple';
19
+ }
20
+ /** See: https://pub.persona3.io/docs
21
+ * `regular` - 321x101
22
+ * `medium` - 600x160
23
+ * `wide` - 970x90
24
+ * `squarish` - 300x250
25
+ */
26
+ type PersonaAdShape = 'regular' | 'medium' | 'wide' | 'squarish';
27
+ interface PersonaAdSource extends AdSourceBase {
28
+ providerName: 'Persona';
29
+ shape: PersonaAdShape;
30
+ }
31
+ type HypeLabAdSources = HypeLabBannerAdSource | HypeLabNativeAdSource;
32
+ type AdSource = HypeLabAdSources | TempleAdSource | PersonaAdSource;
33
+ interface AdDimensions {
34
+ width: number;
35
+ height: number;
36
+ minContainerWidth: number;
37
+ minContainerHeight: number;
38
+ maxContainerWidth: number;
39
+ maxContainerHeight: number;
40
+ }
41
+ interface AdMetadata {
42
+ source: AdSource;
43
+ dimensions: AdDimensions;
44
+ }
45
+
46
+ interface AdStylesOverrides {
47
+ parentDepth: number;
48
+ style: Record<string, string>;
49
+ }
50
+ interface RawAdPlacesRule {
51
+ urlRegexes: string[];
52
+ selector: {
53
+ isMultiple: boolean;
54
+ cssString: string;
55
+ parentDepth: number;
56
+ shouldUseDivWrapper: boolean;
57
+ divWrapperStyle?: Record<string, string>;
58
+ };
59
+ stylesOverrides?: AdStylesOverrides[];
60
+ shouldHideOriginal?: boolean;
61
+ }
62
+ interface RawPermanentAdPlacesRule {
63
+ urlRegexes: string[];
64
+ adSelector: {
65
+ isMultiple: boolean;
66
+ cssString: string;
67
+ parentDepth: number;
68
+ };
69
+ parentSelector: {
70
+ isMultiple: boolean;
71
+ cssString: string;
72
+ parentDepth: number;
73
+ };
74
+ insertionIndex?: number;
75
+ insertBeforeSelector?: string;
76
+ insertAfterSelector?: string;
77
+ insertionsCount?: number;
78
+ shouldUseDivWrapper: boolean;
79
+ divWrapperStyle?: Record<string, string>;
80
+ elementStyle?: Record<string, string>;
81
+ elementToMeasureSelector?: string;
82
+ stylesOverrides?: AdStylesOverrides[];
83
+ shouldHideOriginal?: boolean;
84
+ }
85
+ interface RawAdProvidersRule {
86
+ urlRegexes: string[];
87
+ providers: string[];
88
+ }
89
+ interface RawAllAdsRules {
90
+ adPlacesRulesForAllDomains: Record<string, RawAdPlacesRule[]>;
91
+ providersRulesForAllDomains: Record<string, RawAdProvidersRule[]>;
92
+ providersSelectors: Record<string, string[]>;
93
+ providersToReplaceAtAllSites: string[];
94
+ permanentAdPlacesRulesForAllDomains: Record<string, RawPermanentAdPlacesRule[]>;
95
+ permanentNativeAdPlacesRulesForAllDomains: Record<string, RawPermanentAdPlacesRule[]>;
96
+ timestamp: number;
97
+ }
98
+
99
+ declare enum AdActionType {
100
+ ReplaceAllChildren = "replace-all-children",
101
+ ReplaceElement = "replace-element",
102
+ SimpleInsertAd = "simple-insert-ad",
103
+ RemoveElement = "remove-element",
104
+ HideElement = "hide-element"
105
+ }
106
+ interface AdActionBase {
107
+ type: AdActionType;
108
+ }
109
+ interface InsertAdActionProps {
110
+ ad: AdMetadata;
111
+ fallbacks: AdMetadata[];
112
+ /** @deprecated // Always wrapping now
113
+ * TODO: Clean-up usage
114
+ */
115
+ shouldUseDivWrapper?: boolean;
116
+ divWrapperStyle?: StringRecord<string>;
117
+ elementStyle?: StringRecord<string>;
118
+ stylesOverrides?: AdStylesOverrides[];
119
+ }
120
+ interface ReplaceAllChildrenWithAdAction extends AdActionBase, InsertAdActionProps {
121
+ type: AdActionType.ReplaceAllChildren;
122
+ parent: HTMLElement;
123
+ }
124
+ interface ReplaceElementWithAdAction extends AdActionBase, InsertAdActionProps {
125
+ type: AdActionType.ReplaceElement;
126
+ element: HTMLElement;
127
+ }
128
+ interface SimpleInsertAdAction extends AdActionBase, InsertAdActionProps {
129
+ type: AdActionType.SimpleInsertAd;
130
+ parent: HTMLElement;
131
+ insertionIndex: number;
132
+ }
133
+ interface RemoveElementAction extends AdActionBase {
134
+ type: AdActionType.RemoveElement;
135
+ element: HTMLElement;
136
+ }
137
+ interface HideElementAction extends AdActionBase {
138
+ type: AdActionType.HideElement;
139
+ element: HTMLElement;
140
+ }
141
+ type InsertAdAction = ReplaceAllChildrenWithAdAction | ReplaceElementWithAdAction | SimpleInsertAdAction;
142
+ type AdAction = InsertAdAction | RemoveElementAction | HideElementAction;
143
+
144
+ declare enum AdsProviderTitle {
145
+ Optimal = "Optimal",
146
+ HypeLab = "HypeLab",
147
+ Persona = "Persona",
148
+ Temple = "Temple Wallet"
149
+ }
150
+ type AdsProviderName = keyof typeof AdsProviderTitle;
151
+
152
+ interface AdPlacesRule extends Omit<RawAdPlacesRule, 'urlRegexes'> {
153
+ urlRegexes: RegExp[];
154
+ }
155
+ interface PermanentAdPlacesRule extends Omit<RawPermanentAdPlacesRule, 'urlRegexes'> {
156
+ urlRegexes: RegExp[];
157
+ isNative: boolean;
158
+ }
159
+ interface AdsRules {
160
+ adPlacesRules: Array<Omit<AdPlacesRule, 'urlRegexes'>>;
161
+ permanentAdPlacesRules: PermanentAdPlacesRule[];
162
+ providersSelector: string;
163
+ timestamp: number;
164
+ }
165
+
166
+ declare const getAdsActions: ({ providersSelector, adPlacesRules, permanentAdPlacesRules }: AdsRules) => Promise<AdAction[]>;
167
+
168
+ interface IAdsConfiguration {
169
+ hypelabNativePlacementSlug: string;
170
+ hypelabSmallPlacementSlug: string;
171
+ hypelabHighPlacementSlug: string;
172
+ hypelabWidePlacementSlug: string;
173
+ hypelabAdsWindowUrl: string;
174
+ tkeyInpageAdUrl: string;
175
+ swapTkeyUrl: string;
176
+ externalAdsActivityMessageType: string;
177
+ }
178
+ declare const configureAds: (config: IAdsConfiguration) => void;
179
+
180
+ declare const executeAdsActions: (adsActions: AdAction[]) => Promise<PromiseSettledResult<void>[]>;
181
+
182
+ declare const transformRawRules: (location: Location, rules: RawAllAdsRules) => AdsRules;
183
+
184
+ declare class TempleWalletApi {
185
+ private api;
186
+ constructor(baseUrl: string);
187
+ getAdPlacesRulesForAllDomains: () => Promise<Record<string, RawAdPlacesRule[]>>;
188
+ getProvidersToReplaceAtAllSites: () => Promise<string[]>;
189
+ getProvidersRulesForAllDomains: () => Promise<Record<string, RawAdProvidersRule[]>>;
190
+ getSelectorsForAllProviders: () => Promise<Record<string, string[]>>;
191
+ getPermanentAdPlacesRulesForAllDomains: () => Promise<Record<string, RawPermanentAdPlacesRule[]>>;
192
+ getPermanentNativeAdPlacesRulesForAllDomains: () => Promise<Record<string, RawPermanentAdPlacesRule[]>>;
193
+ getAllRules: () => Promise<RawAllAdsRules>;
194
+ }
195
+
196
+ export { type AdAction, AdActionType, type AdsProviderName, AdsProviderTitle, type AdsRules, type PersonaAdShape, type RawAllAdsRules, TempleWalletApi, configureAds, executeAdsActions, getAdsActions, transformRawRules };
package/dist/index.js ADDED
@@ -0,0 +1,21 @@
1
+ 'use strict';
2
+
3
+ var nanoid = require('nanoid');
4
+ var Ce = require('webextension-polyfill');
5
+ var lodash = require('lodash');
6
+ var Ge = require('@vespaiach/axios-fetch-adapter');
7
+ var $e = require('axios');
8
+
9
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
+
11
+ var Ce__default = /*#__PURE__*/_interopDefault(Ce);
12
+ var Ge__default = /*#__PURE__*/_interopDefault(Ge);
13
+ var $e__default = /*#__PURE__*/_interopDefault($e);
14
+
15
+ var xe=Object.defineProperty,Te=Object.defineProperties;var we=Object.getOwnPropertyDescriptors;var U=Object.getOwnPropertySymbols;var se=Object.prototype.hasOwnProperty,ie=Object.prototype.propertyIsEnumerable;var re=(e,t,n)=>t in e?xe(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,y=(e,t)=>{for(var n in t||(t={}))se.call(t,n)&&re(e,n,t[n]);if(U)for(var n of U(t))ie.call(t,n)&&re(e,n,t[n]);return e},S=(e,t)=>Te(e,we(t));var g=(e,t)=>{var n={};for(var i in e)se.call(e,i)&&t.indexOf(i)<0&&(n[i]=e[i]);if(e!=null&&U)for(var i of U(e))t.indexOf(i)<0&&ie.call(e,i)&&(n[i]=e[i]);return n};var f=(e,t,n)=>new Promise((i,r)=>{var s=d=>{try{o(n.next(d));}catch(l){r(l);}},a=d=>{try{o(n.throw(d));}catch(l){r(l);}},o=d=>d.done?i(d.value):Promise.resolve(d.value).then(s,a);o((n=n.apply(e,t)).next());});var oe=e=>!!e;var I=(e=300)=>new Promise(t=>setTimeout(t,e));var h=class{};h.HYPELAB_NATIVE_PLACEMENT_SLUG="",h.HYPELAB_SMALL_PLACEMENT_SLUG="",h.HYPELAB_HIGH_PLACEMENT_SLUG="",h.HYPELAB_WIDE_PLACEMENT_SLUG="",h.HYPELAB_ADS_WINDOW_URL="",h.TKEY_INPAGE_AD_URL="",h.SWAP_TKEY_URL="",h.EXTERNAL_ADS_ACTIVITY_MESSAGE_TYPE="";var ve=e=>{let{hypelabNativePlacementSlug:t,hypelabSmallPlacementSlug:n,hypelabHighPlacementSlug:i,hypelabWidePlacementSlug:r,hypelabAdsWindowUrl:s,tkeyInpageAdUrl:a,swapTkeyUrl:o,externalAdsActivityMessageType:d}=e;h.HYPELAB_NATIVE_PLACEMENT_SLUG=t,h.HYPELAB_SMALL_PLACEMENT_SLUG=n,h.HYPELAB_HIGH_PLACEMENT_SLUG=i,h.HYPELAB_WIDE_PLACEMENT_SLUG=r,h.HYPELAB_ADS_WINDOW_URL=s,h.TKEY_INPAGE_AD_URL=a,h.SWAP_TKEY_URL=o,h.EXTERNAL_ADS_ACTIVITY_MESSAGE_TYPE=d;};var ae=[{source:{providerName:"Persona",shape:"wide"},dimensions:{width:970,height:90,minContainerWidth:600,minContainerHeight:60,maxContainerWidth:1440,maxContainerHeight:110}},{source:{providerName:"Temple"},dimensions:{width:728,height:90,minContainerWidth:600,minContainerHeight:60,maxContainerWidth:1440,maxContainerHeight:110}},{source:{providerName:"HypeLab",native:!1,size:"high"},dimensions:{width:300,height:250,minContainerWidth:210,minContainerHeight:170,maxContainerWidth:400,maxContainerHeight:300}},{source:{providerName:"Persona",shape:"squarish"},dimensions:{width:300,height:250,minContainerWidth:210,minContainerHeight:170,maxContainerWidth:400,maxContainerHeight:300}},{source:{providerName:"HypeLab",native:!1,size:"small",shouldNotUseStrictContainerLimits:!0},dimensions:{width:320,height:50,minContainerWidth:230,minContainerHeight:32,maxContainerWidth:420,maxContainerHeight:110}},{source:{providerName:"Persona",shape:"regular",shouldNotUseStrictContainerLimits:!0},dimensions:{width:321,height:101,minContainerWidth:230,minContainerHeight:32,maxContainerWidth:420,maxContainerHeight:110}}],le=(e,t)=>({source:{providerName:"HypeLab",native:!0,slug:h.HYPELAB_NATIVE_PLACEMENT_SLUG},dimensions:{width:Math.max(160,e),height:Math.max(16,t),minContainerWidth:2,minContainerHeight:2,maxContainerWidth:1/0,maxContainerHeight:1/0}});var v="twa";var M=`iframe[${v}], div[${v}]`,W=e=>{let t=e.tagName.toLowerCase();return (t==="iframe"||t==="div")&&e.hasAttribute(v)},de=e=>{let t=getComputedStyle(e),n={width:0,height:0},i=["width","height"];for(let r of i){let s=t[r],o=e.getAttribute(r)||s;if(/\d+px/.test(o))n[r]=Number(o.replace("px",""));else {let{width:d,height:l}=e.getBoundingClientRect();n[r]=r==="width"?d:l;}}return n},L=(e,t,n=document)=>e?t?[...n.querySelectorAll(e)]:[n.querySelector(e)].filter(i=>!!i):[],B=(e,t)=>{let n=e;for(let i=0;i<t;i++){let r=n.parentElement;if(!r)return null;n=r;}return n},ce=(e,t,n,i,r)=>e<2&&t<2?[]:r?[le(e,t)]:ae.filter(({source:s,dimensions:a})=>{let{minContainerWidth:o,maxContainerWidth:d,minContainerHeight:l,maxContainerHeight:u,width:m}=a,c=i?m:o;return !((n||!s.shouldNotUseStrictContainerLimits)&&(e<c||t<l&&t>=2)||n&&(e>d||t>u))});var me=(e,t,n)=>f(void 0,null,function*(){let{isMultiple:i,cssString:r,parentDepth:s}=e.parentSelector,a=L(r,i).map(o=>B(o,s)).filter(o=>!!o);return yield Promise.all(a.map(o=>f(void 0,null,function*(){yield I(0),Le(o,e,t,n);}))),a}),Le=(e,t,n,i)=>{var ee;let{shouldUseDivWrapper:r,divWrapperStyle:s,elementStyle:a,adSelector:o,insertionIndex:d,insertBeforeSelector:l,insertAfterSelector:u,insertionsCount:m=1,elementToMeasureSelector:c,stylesOverrides:A,shouldHideOriginal:E=!1,isNative:R}=t,{isMultiple:P,cssString:T,parentDepth:H}=o,J=L(M,!0,e).reduce((p,x)=>p.some(C=>C.contains(x)||x.contains(C))?p:[...p,x],[]).length,b=m-J;if(L(T,P,e).map(p=>B(p,H)).filter(p=>oe(p)&&!W(p)).forEach(p=>{var x,C;if(b<=0){let{display:N}=window.getComputedStyle(p);(!E||N!=="none")&&i.push({type:E?"hide-element":"remove-element",element:p});}else {let N=((x=p.parentElement)==null?void 0:x.children.length)===1?p.parentElement:p;c&&(N=(C=document.querySelector(c))!=null?C:N);let ye={type:"replace-element",element:p,shouldUseDivWrapper:r,divWrapperStyle:s,elementStyle:a,stylesOverrides:A},ge={type:"hide-element",element:p},Pe={type:"simple-insert-ad",shouldUseDivWrapper:r,divWrapperStyle:s,elementStyle:a,parent:p.parentElement,insertionIndex:Array.from(p.parentElement.children).indexOf(p),stylesOverrides:A},te=p.nextElementSibling,Se=te&&W(te),ne=E?Se?[]:[ge,Pe]:[ye];ne.length>0&&n(N,!1,!0,R,...ne)&&b--;}}),b<=0)return;let D=-1,Z=e,Y=e,j=l||u;if(j){let p=e.querySelector(j),x=p==null?void 0:p.parentElement;p&&x&&(Z=x,D=Array.from(e.children).indexOf(p)+(l?0:1),Y=c&&document.querySelector(c)||p);}else {let p=d!=null?d:0;D=p<0?Math.max(e.children.length+p,0):Math.min(p,e.children.length),Y=c&&document.querySelector(c)||((ee=e.children[D])!=null?ee:e);}if(D!==-1){let p={type:"simple-insert-ad",shouldUseDivWrapper:r,divWrapperStyle:s,elementStyle:a,parent:Z,insertionIndex:D,stylesOverrides:A};n(Y,!1,!0,R,...Array(b).fill(p));}};var Ae=(e,t,n)=>f(void 0,null,function*(){let{cssString:i,isMultiple:r}=e.selector,s=L(i,r);yield Promise.all(s.map(a=>f(void 0,null,function*(){yield I(0),Ie(a,e,t,n);})));}),Ie=(e,t,n,i)=>{let{selector:{shouldUseDivWrapper:r,parentDepth:s,divWrapperStyle:a},stylesOverrides:o,shouldHideOriginal:d}=t,l=B(e,s);if(!l||n.some(c=>c.contains(l))||W(l)||l.querySelector(M))return;let u={shouldUseDivWrapper:r,divWrapperStyle:a},m;if(r&&d){let c=l.parentElement,A=y({type:"simple-insert-ad",parent:c,insertionIndex:Array.from(c.children).indexOf(l),stylesOverrides:o==null?void 0:o.map(P=>{var T=P,{parentDepth:E}=T,R=g(T,["parentDepth"]);return S(y({},R),{parentDepth:E-1})})},u);m=[],window.getComputedStyle(l).display!=="none"&&m.push({type:"hide-element",element:l}),c.querySelector(M)||m.push(A);}else if(r)m=[y({type:"replace-element",element:l,stylesOverrides:o==null?void 0:o.map(R=>{var P=R,{parentDepth:A}=P,E=g(P,["parentDepth"]);return S(y({},E),{parentDepth:A-1})})},u)];else if(d){let c=y({type:"simple-insert-ad",parent:l,insertionIndex:0,stylesOverrides:o},u);m=Array.from(l.children).filter(A=>window.getComputedStyle(A).display!=="none").map(A=>({type:"hide-element",element:A})),l.querySelector(M)||m.push(c);}else m=[y({type:"replace-all-children",parent:l,stylesOverrides:o},u)];m.length>0&&i(l,!1,!1,!1,...m);};var He=i=>f(void 0,[i],function*({providersSelector:e,adPlacesRules:t,permanentAdPlacesRules:n}){var d,l,u;let r=[],s=(m,c,A,E,...R)=>{let{width:P,height:T}=de(m),H=ce(P,T,c,A,E);return H.length?(r.push(...R.map(w=>w.type==="hide-element"||w.type==="remove-element"?w:S(y({},w),{ad:H[0],fallbacks:H.slice(1)}))),!0):!1},a=[];yield Promise.all(n.map(m=>f(void 0,null,function*(){yield I(0),a=a.concat(yield me(m,s,r));}))),yield Promise.all(t.map(m=>f(void 0,null,function*(){yield I(0),yield Ae(m,a,s);})));let o=L(e,!0);for(let m of o){if(a.some(E=>E.contains(m)))continue;let c={type:"replace-element",element:m,shouldUseDivWrapper:!1},A=(u=(l=(d=m.parentElement)==null?void 0:d.closest("div, article, aside, footer, header"))!=null?l:m.parentElement)!=null?u:m;s(A,!0,!1,!1,c);}return r});var k=(e,t,n)=>{let i=document.createElement("div");i.id=nanoid.nanoid(),i.style.width=`${e}px`,i.style.height=`${t}px`;for(let o in n)i.style.setProperty(o,n[o]);let r=document.createElement("div");r.style.width=`${e}px`,r.style.height=`${t}px`,i.appendChild(r);let s=document.createElement("a");s.href=h.SWAP_TKEY_URL,s.target="_blank",s.rel="noopener noreferrer",s.style.width="100%",s.style.height="100%",r.appendChild(s);let a=document.createElement("img");return a.src=h.TKEY_INPAGE_AD_URL,a.style.width="100%",a.style.height="100%",s.appendChild(a),{element:i}};var V=(e,t,n)=>{let{width:i,height:r}=t,s=document.createElement("iframe");s.id=nanoid.nanoid(),s.src=_e(e,window.location.href,i,r,s.id),s.style.width=`${i}px`,s.style.height=`${r}px`,s.style.border="none";for(let a in n)s.style.setProperty(a,n[a]);return {element:s}},_e=(e,t,n,i,r)=>{let s,a,o;if(e.native)o=h.HYPELAB_NATIVE_PLACEMENT_SLUG,s=360,a=110;else switch(e.size){case"small":s=320,a=50,o=h.HYPELAB_SMALL_PLACEMENT_SLUG;break;case"high":s=300,a=250,o=h.HYPELAB_HIGH_PLACEMENT_SLUG;break;case"wide":s=728,a=90,o=h.HYPELAB_WIDE_PLACEMENT_SLUG;break}let d=new URL(h.HYPELAB_ADS_WINDOW_URL);return d.searchParams.set("w",String(n!=null?n:s)),d.searchParams.set("h",String(i!=null?i:a)),d.searchParams.set("p",o),d.searchParams.set("o",t),r&&d.searchParams.set("id",r),d.toString()};var G=(e,{width:t,height:n},i)=>{let r=nanoid.nanoid(),s=document.createElement("iframe");s.src=Ce__default.default.runtime.getURL(`iframes/persona-ad.html?id=${r}&shape=${e}`),s.id=r,s.style.width=`${t}px`,s.style.height=`${n}px`,s.style.border="none";for(let a in i)s.style.setProperty(a,i[a]);return {element:s}};var $=(r=>(r.Optimal="Optimal",r.HypeLab="HypeLab",r.Persona="Persona",r.Temple="Temple Wallet",r))($||{});var q=new Set,pe=new Set,ue=new Set,We=1e4,Ee=(e,t,n)=>{if(!q.has(e))return q.add(e),new Promise((i,r)=>{setTimeout(()=>{window.removeEventListener("message",s),r(new Error(`Timeout exceeded for ${e}`));},We);let s=a=>{var o;if(a.source===n.contentWindow)try{let d=typeof a.data=="string"?JSON.parse(a.data):a.data;if(d.id!==e)return;d.type==="ready"?(window.removeEventListener("message",s),i()):d.type==="error"&&(window.removeEventListener("message",s),r(new Error((o=d.reason)!=null?o:"Unknown error")));}catch(d){console.error("Observing error:",d);}};window.addEventListener("message",s);}).then(()=>{if(pe.has(e))return;pe.add(e),Be(n)?fe(e,t):K(n,t);}).finally(()=>void q.delete(e))},K=(e,t)=>{let n=new IntersectionObserver(i=>{i.some(r=>r.isIntersecting)&&(fe(e.id,t),n.disconnect());},{threshold:.5});n.observe(e);},fe=(e,t)=>{if(ue.has(e))return;ue.add(e);let n=window.parent.location.href;Ce__default.default.runtime.sendMessage({type:h.EXTERNAL_ADS_ACTIVITY_MESSAGE_TYPE,url:n,provider:$[t]}).catch(i=>void console.error(i));},Be=e=>{let t=e.getBoundingClientRect(),n=window.visualViewport;if(!n)return !1;let i=Math.min(Math.max(0,t.x),n.width),r=Math.min(Math.max(0,t.x+t.width),n.width),s=Math.min(Math.max(0,t.y),n.height),a=Math.min(Math.max(0,t.y+t.height),n.height),o=t.width*t.height;return (r-i)*(a-s)/o>=.5};var z=(e,t)=>{for(let n in t)e.style.setProperty(n,t[n]);};var Ue=(e,t,n)=>f(void 0,null,function*(){let{source:i,dimensions:r}=t,{elementStyle:s={},stylesOverrides:a=[]}=e;a.sort((c,A)=>c.parentDepth-A.parentDepth);let o,{providerName:d}=i,{element:l,postAppend:u}=d==="Temple"?k(r.width,r.height,s):d==="HypeLab"?V(i,r,s):G(i.shape,r,s);switch(l.setAttribute(v,"true"),n.appendChild(l),e.type){case"replace-all-children":o=e.parent,e.parent.innerHTML="",e.parent.appendChild(n);break;case"replace-element":o=e.element.parentElement,e.element.replaceWith(n);break;default:o=e.parent,e.parent.insertBefore(n,e.parent.children[e.insertionIndex]);break}u&&(yield u()),l instanceof HTMLIFrameElement?yield Ee(l.id,i.providerName,l):K(l,i.providerName);let m=0;a.forEach(({parentDepth:c,style:A})=>{for(;c>m&&o;)o=o.parentElement,m++;o&&z(o,A);});}),Q=(e,t)=>f(void 0,null,function*(){let{shouldUseDivWrapper:n,divWrapperStyle:i={}}=e,r=document.createElement("div");r.setAttribute(v,"true"),n?z(r,i):r.style.display="contents",yield Ue(e,t,r).catch(s=>{console.error("Inserting an ad attempt error:",s);let a=e.fallbacks.shift();if(a){let{ad:d,fallbacks:l,divWrapperStyle:u,elementStyle:m,stylesOverrides:c}=e,A={type:"replace-element",element:r,ad:d,fallbacks:l,divWrapperStyle:u,elementStyle:m,stylesOverrides:c};return Q(A,a)}let o=document.createElement("div");throw o.setAttribute(v,"true"),o.style.display="none",r.replaceWith(o),s});});var Oe=e=>Promise.allSettled(e.map(t=>f(void 0,null,function*(){t.type==="remove-element"?t.element.remove():t.type==="hide-element"?t.element.style.setProperty("display","none"):yield Q(t,t.ad);})));var Fe=(e,t)=>{let{adPlacesRulesForAllDomains:n,providersRulesForAllDomains:i,providersSelectors:r,providersToReplaceAtAllSites:s,permanentAdPlacesRulesForAllDomains:a,permanentNativeAdPlacesRulesForAllDomains:o={},timestamp:d}=t,{hostname:l,href:u}=e,m=u.replace(/#.*$/,""),c=A=>{let E=A.source.includes("#")?u:m;return A.test(E)};return {adPlacesRules:Ye(l,c,n),permanentAdPlacesRules:ke(l,c,a,o),providersSelector:Ve(l,c,i,r,s),timestamp:d}},Ye=(e,t,n)=>{var s;return ((s=n[e])!=null?s:[]).map(d=>{var l=d,{urlRegexes:a}=l,o=g(l,["urlRegexes"]);return S(y({},o),{urlRegexes:a.map(u=>new RegExp(u))})}).reduce((a,u)=>{var m=u,{urlRegexes:o,selector:d}=m,l=g(m,["urlRegexes","selector"]);if(!o.some(t))return a;let R=d,{cssString:c}=R,A=g(R,["cssString"]),E=a.findIndex(H=>{var w=H,{selector:P}=w,T=g(w,["selector"]);let F=P,b=g(F,["cssString"]);return lodash.isEqual(A,b)&&lodash.isEqual(l,T)});return E===-1?a.push(y({selector:d},l)):a[E].selector.cssString+=", ".concat(c),a},[])},ke=(e,t,n,i={})=>{var o,d;let r=(o=n[e])!=null?o:[],s=(d=i[e])!=null?d:[];return r.map(m=>{var c=m,{urlRegexes:l}=c,u=g(c,["urlRegexes"]);return S(y({},u),{urlRegexes:l.map(A=>new RegExp(A)),isNative:!1})}).concat(s.map(m=>{var c=m,{urlRegexes:l}=c,u=g(c,["urlRegexes"]);return S(y({},u),{urlRegexes:l.map(A=>new RegExp(A)),isNative:!0})})).filter(({urlRegexes:l})=>l.some(t))},Ve=(e,t,n,i,r)=>{var m;let a=((m=n[e])!=null?m:[]).map(E=>{var R=E,{urlRegexes:c}=R,A=g(R,["urlRegexes"]);return S(y({},A),{urlRegexes:c.map(P=>new RegExp(P))})}).filter(({urlRegexes:c})=>c.some(t)),o=new Set,d=new Set,l=c=>{var E;if(o.has(c))return;((E=i[c])!=null?E:[]).forEach(R=>d.add(R)),o.add(c);};r.forEach(l),a.forEach(({providers:c})=>c.forEach(l));let u="";return d.forEach(c=>{u+=c+", ";}),u&&(u=u.slice(0,-2)),u};var _=e=>(...t)=>f(void 0,null,function*(){let{data:n}=yield e(...t);return n}),X=class{constructor(t){this.getAdPlacesRulesForAllDomains=_(()=>this.api.get("/slise-ad-rules/ad-places"));this.getProvidersToReplaceAtAllSites=_(()=>this.api.get("/slise-ad-rules/providers/all-sites"));this.getProvidersRulesForAllDomains=_(()=>this.api.get("/slise-ad-rules/providers/by-sites"));this.getSelectorsForAllProviders=_(()=>this.api.get("/slise-ad-rules/providers"));this.getPermanentAdPlacesRulesForAllDomains=_(()=>this.api.get("/slise-ad-rules/ad-places/permanent"));this.getPermanentNativeAdPlacesRulesForAllDomains=_(()=>this.api.get("/slise-ad-rules/ad-places/permanent-native"));this.getAllRules=()=>f(this,null,function*(){let[t,n,i,r,s,a]=yield Promise.all([this.getAdPlacesRulesForAllDomains(),this.getProvidersRulesForAllDomains(),this.getSelectorsForAllProviders(),this.getProvidersToReplaceAtAllSites(),this.getPermanentAdPlacesRulesForAllDomains(),this.getPermanentNativeAdPlacesRulesForAllDomains()]);return {adPlacesRulesForAllDomains:t,providersRulesForAllDomains:n,providersSelectors:i,providersToReplaceAtAllSites:r,permanentAdPlacesRulesForAllDomains:s,permanentNativeAdPlacesRulesForAllDomains:a,timestamp:Date.now()}});this.api=$e__default.default.create({baseURL:new URL("/api",t).href,adapter:Ge__default.default});}};
16
+
17
+ exports.TempleWalletApi = X;
18
+ exports.configureAds = ve;
19
+ exports.executeAdsActions = Oe;
20
+ exports.getAdsActions = He;
21
+ exports.transformRawRules = Fe;
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@temple-wallet/extension-ads",
3
+ "version": "1.0.0",
4
+ "main": "dist/index.js",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/madfish-solutions/templewallet-extension-ads.git"
8
+ },
9
+ "author": "Inokentii Mazhara <keshan3262@gmail.com>",
10
+ "license": "MIT",
11
+ "scripts": {
12
+ "build:dev": "tsup src/index.ts --dts --treeshake",
13
+ "build": "tsup src/index.ts --dts --minify --treeshake",
14
+ "lint": "eslint --quiet src",
15
+ "lint:fix": "prettier \"./**/*\" --write --ignore-unknown",
16
+ "clear:lint": "rimraf node_modules/.cache/.eslintcache",
17
+ "find-deadcode": "ts-prune --error -i src/index.ts"
18
+ },
19
+ "devDependencies": {
20
+ "@types/lodash": "^4",
21
+ "@types/webextension-polyfill": "^0",
22
+ "@typescript-eslint/eslint-plugin": "^7.2.0",
23
+ "@typescript-eslint/parser": "^7.2.0",
24
+ "eslint": "^8.57.0",
25
+ "eslint-import-resolver-typescript": "^3.6.1",
26
+ "eslint-plugin-import": "^2.29.1",
27
+ "eslint-plugin-no-type-assertion": "^1.3.0",
28
+ "eslint-plugin-prettier": "^5.1.3",
29
+ "prettier": "^3.2.5",
30
+ "ts-prune": "^0.10.3",
31
+ "tsup": "^8.0.2",
32
+ "typescript": "^5.4.2"
33
+ },
34
+ "packageManager": "yarn@4.1.1",
35
+ "dependencies": {
36
+ "@vespaiach/axios-fetch-adapter": "^0.3.1",
37
+ "axios": "^1.6.8",
38
+ "lodash": "^4.17.21",
39
+ "nanoid": "^5.0.6",
40
+ "webextension-polyfill": "^0.10.0"
41
+ },
42
+ "types": "./dist/index.d.ts",
43
+ "description": "",
44
+ "bugs": {
45
+ "url": "https://github.com/madfish-solutions/templewallet-extension-ads/issues"
46
+ },
47
+ "homepage": "https://github.com/madfish-solutions/templewallet-extension-ads#readme"
48
+ }
@@ -0,0 +1,100 @@
1
+ import { BANNER_ADS_META, buildHypeLabNativeMeta } from 'src/ads-meta';
2
+ import { TEMPLE_WALLET_AD_ATTRIBUTE_NAME } from 'src/constants';
3
+ import { AdMetadata } from 'src/types/ads-meta';
4
+
5
+ export const ourAdQuerySelector = `iframe[${TEMPLE_WALLET_AD_ATTRIBUTE_NAME}], div[${TEMPLE_WALLET_AD_ATTRIBUTE_NAME}]`;
6
+
7
+ export const elementIsOurAd = (element: HTMLElement) => {
8
+ const tagName = element.tagName.toLowerCase();
9
+
10
+ return (tagName === 'iframe' || tagName === 'div') && element.hasAttribute(TEMPLE_WALLET_AD_ATTRIBUTE_NAME);
11
+ };
12
+
13
+ export const getFinalSize = (element: Element) => {
14
+ const elementStyle = getComputedStyle(element);
15
+ const size = { width: 0, height: 0 };
16
+ const dimensions = ['width', 'height'] as const;
17
+
18
+ for (const dimension of dimensions) {
19
+ const rawDimensionFromStyle = elementStyle[dimension];
20
+ const rawDimensionFromAttribute = element.getAttribute(dimension);
21
+ const rawDimension = rawDimensionFromAttribute || rawDimensionFromStyle;
22
+
23
+ if (/\d+px/.test(rawDimension)) {
24
+ size[dimension] = Number(rawDimension.replace('px', ''));
25
+ } else {
26
+ const { width, height } = element.getBoundingClientRect();
27
+ size[dimension] = dimension === 'width' ? width : height;
28
+ }
29
+ }
30
+
31
+ return size;
32
+ };
33
+
34
+ export const applyQuerySelector = <E extends Element = Element>(
35
+ querySelector: string,
36
+ isMultiple: boolean,
37
+ element: Element | Document = document
38
+ ) => {
39
+ if (!querySelector) {
40
+ return [];
41
+ }
42
+
43
+ return isMultiple
44
+ ? [...element.querySelectorAll<E>(querySelector)]
45
+ : [element.querySelector<E>(querySelector)].filter((el): el is E => Boolean(el));
46
+ };
47
+
48
+ export const getParentOfDepth = (element: HTMLElement, depth: number) => {
49
+ let parent = element;
50
+
51
+ for (let i = 0; i < depth; i++) {
52
+ const nextParent = parent.parentElement;
53
+
54
+ if (!nextParent) {
55
+ return null;
56
+ }
57
+
58
+ parent = nextParent;
59
+ }
60
+
61
+ return parent;
62
+ };
63
+
64
+ export const pickAdsToDisplay = (
65
+ containerWidth: number,
66
+ containerHeight: number,
67
+ shouldUseStrictContainerLimits: boolean,
68
+ minContainerWidthIsBannerWidth: boolean,
69
+ adIsNative: boolean
70
+ ): AdMetadata[] => {
71
+ if (containerWidth < 2 && containerHeight < 2) {
72
+ return [];
73
+ }
74
+
75
+ if (adIsNative) {
76
+ return [buildHypeLabNativeMeta(containerWidth, containerHeight)];
77
+ }
78
+
79
+ return BANNER_ADS_META.filter(({ source, dimensions }) => {
80
+ const { minContainerWidth, maxContainerWidth, minContainerHeight, maxContainerHeight, width } = dimensions;
81
+
82
+ const actualMinContainerWidth = minContainerWidthIsBannerWidth ? width : minContainerWidth;
83
+
84
+ if (
85
+ (shouldUseStrictContainerLimits || !source.shouldNotUseStrictContainerLimits) &&
86
+ (containerWidth < actualMinContainerWidth || (containerHeight < minContainerHeight && containerHeight >= 2))
87
+ ) {
88
+ return false;
89
+ }
90
+
91
+ if (
92
+ shouldUseStrictContainerLimits &&
93
+ (containerWidth > maxContainerWidth || containerHeight > maxContainerHeight)
94
+ ) {
95
+ return false;
96
+ }
97
+
98
+ return true;
99
+ });
100
+ };
@@ -0,0 +1,96 @@
1
+ import {
2
+ AddActionsIfAdResolutionAvailable,
3
+ AdAction,
4
+ AdActionType,
5
+ HideElementAction,
6
+ InsertAdActionWithoutMeta,
7
+ OmitAdInAction,
8
+ RemoveElementAction,
9
+ ReplaceElementWithAdAction
10
+ } from 'src/types/ads-actions';
11
+ import type { AdsRules } from 'src/types/ads-rules';
12
+ import { delay } from 'src/utils';
13
+
14
+ import { applyQuerySelector, getFinalSize, pickAdsToDisplay } from './helpers';
15
+ import { processPermanentAdPlacesRule } from './process-permanent-rule';
16
+ import { processAdPlacesRule } from './process-rule';
17
+
18
+ export const getAdsActions = async ({ providersSelector, adPlacesRules, permanentAdPlacesRules }: AdsRules) => {
19
+ const result: AdAction[] = [];
20
+
21
+ const addActionsIfAdResolutionAvailable: AddActionsIfAdResolutionAvailable = (
22
+ elementToMeasure: Element,
23
+ shouldUseStrictContainerLimits: boolean,
24
+ minContainerWidthIsBannerWidth: boolean,
25
+ adIsNative: boolean,
26
+ ...actionsBases: (InsertAdActionWithoutMeta | HideElementAction | RemoveElementAction)[]
27
+ ): boolean => {
28
+ const { width, height } = getFinalSize(elementToMeasure);
29
+ const stack = pickAdsToDisplay(
30
+ width,
31
+ height,
32
+ shouldUseStrictContainerLimits,
33
+ minContainerWidthIsBannerWidth,
34
+ adIsNative
35
+ );
36
+
37
+ if (!stack.length) return false;
38
+
39
+ result.push(
40
+ ...actionsBases.map<AdAction>(actionBase =>
41
+ actionBase.type === AdActionType.HideElement || actionBase.type === AdActionType.RemoveElement
42
+ ? actionBase
43
+ : { ...actionBase, ad: stack[0]!, fallbacks: stack.slice(1) }
44
+ )
45
+ );
46
+
47
+ return true;
48
+ };
49
+
50
+ let permanentAdsParents: HTMLElement[] = [];
51
+
52
+ /*
53
+ Asynchronizing processing to free-up the thread on heavyish work here.
54
+ 'Parallelizing' it (through `Promise.all`) to fill-up Event Loop right away.
55
+ Otherwise (with `for` loop), original ads start glitching through more.
56
+ */
57
+
58
+ await Promise.all(
59
+ permanentAdPlacesRules.map(async rule => {
60
+ await delay(0);
61
+
62
+ permanentAdsParents = permanentAdsParents.concat(
63
+ await processPermanentAdPlacesRule(rule, addActionsIfAdResolutionAvailable, result)
64
+ );
65
+ })
66
+ );
67
+
68
+ await Promise.all(
69
+ adPlacesRules.map(async rule => {
70
+ await delay(0);
71
+
72
+ await processAdPlacesRule(rule, permanentAdsParents, addActionsIfAdResolutionAvailable);
73
+ })
74
+ );
75
+
76
+ const bannersFromProviders = applyQuerySelector(providersSelector, true);
77
+
78
+ for (const banner of bannersFromProviders) {
79
+ if (permanentAdsParents.some(parent => parent.contains(banner))) continue;
80
+
81
+ const actionBase: OmitAdInAction<ReplaceElementWithAdAction> = {
82
+ type: AdActionType.ReplaceElement,
83
+ element: banner as HTMLElement,
84
+ shouldUseDivWrapper: false
85
+ };
86
+
87
+ const elementToMeasure =
88
+ banner.parentElement?.closest<HTMLElement>('div, article, aside, footer, header') ??
89
+ banner.parentElement ??
90
+ banner;
91
+
92
+ addActionsIfAdResolutionAvailable(elementToMeasure, true, false, false, actionBase);
93
+ }
94
+
95
+ return result;
96
+ };