paywall-protect-widget 1.0.0 → 1.0.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.
- package/dist/paywall-widget.esm.js +34 -32
- package/dist/paywall-widget.min.js +34 -32
- package/package.json +7 -4
|
@@ -1,32 +1,34 @@
|
|
|
1
|
-
var
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
1
|
+
var k=(s,y,a)=>new Promise((t,i)=>{var l=d=>{try{g(a.next(d))}catch(m){i(m)}},h=d=>{try{g(a.throw(d))}catch(m){i(m)}},g=d=>d.done?t(d.value):Promise.resolve(d.value).then(l,h);g((a=a.apply(s,y)).next())});(function(){"use strict";let s=document.currentScript||document.querySelector("script[data-site-id]");if(!s){console.error("[PaywallProtect] Script tag not found");return}let y=["googlebot","bingbot","slurp","duckduckbot","baiduspider","yandexbot","facebookexternalhit","twitterbot","linkedinbot","slackbot","telegrambot","whatsapp","discordbot","pinterestbot","redditbot","applebot"],a={siteId:s.dataset.siteId||s.getAttribute("data-site-id"),apiKey:s.dataset.apiKey||s.getAttribute("data-api-key"),apiUrl:s.dataset.apiUrl||s.getAttribute("data-api-url")||"",subscribeUrl:s.dataset.subscribeUrl||"/subscribe",loginUrl:s.dataset.loginUrl||"/login",mode:s.dataset.mode||"auto",seoSafe:s.dataset.seoSafe!=="false",allowBots:s.dataset.allowBots||null,protectBody:s.dataset.protectBody!=="false",debug:s.dataset.debug==="true"||s.dataset.debug==="1"},t={sessionId:"session_"+Date.now()+"_"+Math.random().toString(36).substr(2,9),logs:[],startTime:performance.now(),log(e,o,r={}){let n=new Date().toISOString(),u=Math.round(performance.now()-this.startTime),f={timestamp:n,elapsed:u,level:e,message:o,data:r,sessionId:this.sessionId};this.logs.push(f);let p="[PaywallProtect]",c=a.debug?` [+${u}ms]`:"";switch(e){case"info":console.log(`%c${p}${c} ${o}`,"color: #3b82f6",r);break;case"success":console.log(`%c${p}${c} \u2713 ${o}`,"color: #10b981; font-weight: bold",r);break;case"warn":console.warn(`${p}${c} \u26A0 ${o}`,r);break;case"error":console.error(`${p}${c} \u2717 ${o}`,r);break;case"debug":a.debug&&console.log(`%c${p}${c} [DEBUG] ${o}`,"color: #8b5cf6",r);break}this.logs.length>100&&this.logs.shift()},info(e,o){this.log("info",e,o)},success(e,o){this.log("success",e,o)},warn(e,o){this.log("warn",e,o)},error(e,o){this.log("error",e,o)},debug(e,o){this.log("debug",e,o)},getAll(){return[...this.logs]},export(){return JSON.stringify({sessionId:this.sessionId,config:{siteId:a.siteId,mode:a.mode,seoSafe:a.seoSafe,protectBody:a.protectBody,debug:a.debug},userAgent:navigator.userAgent,page:window.location.href,logs:this.logs,performance:{totalTime:Math.round(performance.now()-this.startTime),memory:performance.memory?{used:Math.round(performance.memory.usedJSHeapSize/1024/1024)+"MB",total:Math.round(performance.memory.totalJSHeapSize/1024/1024)+"MB"}:"N/A"}},null,2)},clear(){this.logs=[],console.clear(),this.info("Logs cleared")}},i=[];if(a.seoSafe&&(i=[...y]),a.allowBots){let e=a.allowBots.split(",").map(o=>o.trim().toLowerCase());i=[...i,...e],t.info("Custom allowlist added",{bots:e})}if(t.info("Initializing PaywallProtect Widget",{version:"1.2.1",siteId:a.siteId,mode:a.mode,seoSafe:a.seoSafe,protectBody:a.protectBody,debug:a.debug,allowedBotsCount:i.length}),!a.siteId||!a.apiKey){t.error("Missing required configuration",{hasSiteId:!!a.siteId,hasApiKey:!!a.apiKey});return}if(!a.apiUrl){t.error("Missing API URL",{apiUrl:a.apiUrl});return}t.success("Configuration validated"),a.seoSafe&&t.info("SEO-safe mode enabled",{allowedBots:i.length});let l={marks:{},mark(e){this.marks[e]=performance.now(),t.debug(`Performance mark: ${e}`,{time:Math.round(this.marks[e])+"ms"})},measure(e,o){let r=Math.round(performance.now()-this.marks[o]);return t.debug(`Performance: ${e}`,{duration:r+"ms"}),r}};l.mark("init_start");function h(){l.mark("allowlist_check_start");let e=navigator.userAgent.toLowerCase();t.debug("Checking user agent against allowlist",{userAgent:navigator.userAgent,allowlistSize:i.length});for(let o of i)if(e.includes(o))return l.measure("Allowlist check complete","allowlist_check_start"),t.success("Allowed bot detected",{bot:o,userAgent:navigator.userAgent}),!0;return l.measure("Allowlist check complete","allowlist_check_start"),t.debug("Not in allowlist, will check with server"),!1}function g(){l.mark("fingerprint_start"),t.debug("Generating browser fingerprint");let e={userAgent:navigator.userAgent,language:navigator.language,platform:navigator.platform,hardwareConcurrency:navigator.hardwareConcurrency||0,deviceMemory:navigator.deviceMemory||0,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,screen:{width:window.screen.width,height:window.screen.height,colorDepth:window.screen.colorDepth,pixelRatio:window.devicePixelRatio||1},timing:{pageLoadTime:Math.round(performance.now())},webdriver:navigator.webdriver||!1,canvas:d(),webgl:m(),touchSupport:"ontouchstart"in window,plugins:x()};return l.measure("Fingerprint generated","fingerprint_start"),t.debug("Fingerprint complete",{hasCanvas:!!e.canvas,hasWebGL:!!e.webgl,pluginCount:e.plugins.length,webdriver:e.webdriver}),e}function d(){try{let e=document.createElement("canvas"),o=e.getContext("2d");if(!o)return t.warn("Canvas context unavailable"),null;o.textBaseline="top",o.font="14px Arial",o.fillText("PaywallProtect",2,2);let r=e.toDataURL().substring(0,100);return t.debug("Canvas fingerprint generated",{length:r.length}),r}catch(e){return t.error("Canvas fingerprint failed",{error:e.message}),null}}function m(){try{let o=document.createElement("canvas").getContext("webgl");if(!o)return t.warn("WebGL context unavailable"),null;let r={renderer:o.getParameter(o.RENDERER),vendor:o.getParameter(o.VENDOR)};return t.debug("WebGL fingerprint generated",r),r}catch(e){return t.error("WebGL fingerprint failed",{error:e.message}),null}}function x(){try{let e=Array.from(navigator.plugins||[]).map(o=>o.name).slice(0,5);return t.debug("Plugins enumerated",{count:e.length}),e}catch(e){return t.error("Plugin enumeration failed",{error:e.message}),[]}}function P(){return k(this,null,function*(){l.mark("api_call_start"),t.info("Calling API for access check",{endpoint:a.apiUrl+"/check-access"});try{let e={siteId:a.siteId,apiKey:a.apiKey,page:window.location.pathname,userAgent:navigator.userAgent,fingerprint:g(),referrer:document.referrer,allowedBots:i};t.debug("API request payload",{siteId:e.siteId,page:e.page,hasFingerprint:!!e.fingerprint,allowedBotsCount:e.allowedBots.length});let o=yield fetch(a.apiUrl+"/check-access",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)}),r=l.measure("API call complete","api_call_start");if(!o.ok)return t.error("API returned error status",{status:o.status,statusText:o.statusText,duration:r+"ms"}),{allowed:!0,reason:"API error",showPaywall:!1};let n=yield o.json();return t.success("API response received",{allowed:n.allowed,status:n.status,showPaywall:n.showPaywall,reason:n.reason,duration:r+"ms"}),n}catch(e){let o=l.measure("API call failed","api_call_start");return t.error("Network error during API call",{error:e.message,stack:e.stack,duration:o+"ms"}),{allowed:!0,reason:"Network error",showPaywall:!1}}})}function w(e){if(document.getElementById("paywall-protect-modal")){t.warn("Paywall modal already exists, skipping creation");return}l.mark("modal_create_start"),t.info("Creating paywall modal",{type:e.type||"hard"});let o=e.type||"hard",r="";o==="hard"?r=`
|
|
2
|
+
<div class="paywall-icon">\u{1F512}</div>
|
|
3
|
+
<h2 id="paywall-title">${e.title||"Premium Content"}</h2>
|
|
4
|
+
<p>${e.message||"Subscribe to access this content."}</p>
|
|
5
|
+
<button id="paywall-subscribe" class="paywall-btn primary">Subscribe Now</button>
|
|
6
|
+
<p class="footer">Already a subscriber? <a href="${a.loginUrl}" id="paywall-login">Sign in</a></p>
|
|
7
|
+
`:o==="metered"?r=`
|
|
8
|
+
<div class="paywall-icon">\u{1F4CA}</div>
|
|
9
|
+
<h2 id="paywall-title">Free Article Limit Reached</h2>
|
|
10
|
+
<p>You've read <strong>${e.articlesRead||3} of ${e.freeLimit||3}</strong> free articles this month.</p>
|
|
11
|
+
<button id="paywall-subscribe" class="paywall-btn primary">Get Unlimited Access</button>
|
|
12
|
+
<button id="paywall-close" class="paywall-btn secondary">Maybe Later</button>
|
|
13
|
+
`:r=`
|
|
14
|
+
<div class="paywall-icon">\u{1F916}</div>
|
|
15
|
+
<h2 id="paywall-title">Access Denied</h2>
|
|
16
|
+
<p>${e.message||"Automated access is not permitted."}</p>
|
|
17
|
+
`;let n=document.createElement("div");if(n.id="paywall-protect-modal",n.innerHTML=`<div class="paywall-overlay"><div class="paywall-content">${r}</div></div>`,!document.getElementById("paywall-styles")){let c=document.createElement("style");c.id="paywall-styles",c.textContent=`
|
|
18
|
+
#paywall-protect-modal{position:fixed;top:0;left:0;width:100%;height:100%;z-index:999999;animation:fadeIn .3s}
|
|
19
|
+
.paywall-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.85);backdrop-filter:blur(8px);display:flex;align-items:center;justify-content:center;padding:20px}
|
|
20
|
+
.paywall-content{background:#fff;border-radius:16px;padding:48px 40px;max-width:500px;width:100%;text-align:center;box-shadow:0 20px 60px rgba(0,0,0,.3);animation:slideUp .3s}
|
|
21
|
+
.paywall-icon{font-size:64px;margin-bottom:24px}
|
|
22
|
+
#paywall-title{font-size:28px;font-weight:700;color:#1a1a1a;margin:0 0 16px 0}
|
|
23
|
+
.paywall-content p{font-size:16px;color:#666;line-height:1.6;margin:0 0 24px 0}
|
|
24
|
+
.paywall-btn{display:block;width:100%;padding:16px 32px;border:none;border-radius:8px;font-size:16px;font-weight:600;cursor:pointer;transition:all .2s;margin-bottom:12px}
|
|
25
|
+
.paywall-btn.primary{background:#3b82f6;color:#fff}
|
|
26
|
+
.paywall-btn.primary:hover{background:#2563eb;transform:translateY(-1px)}
|
|
27
|
+
.paywall-btn.secondary{background:transparent;color:#666;border:2px solid #e5e7eb}
|
|
28
|
+
.paywall-btn.secondary:hover{background:#f9fafb}
|
|
29
|
+
.footer{margin-top:24px;font-size:14px;color:#666}
|
|
30
|
+
.footer a{color:#3b82f6;text-decoration:none}
|
|
31
|
+
.footer a:hover{text-decoration:underline}
|
|
32
|
+
@keyframes fadeIn{from{opacity:0}to{opacity:1}}
|
|
33
|
+
@keyframes slideUp{from{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}
|
|
34
|
+
`,document.head.appendChild(c),t.debug("Paywall styles injected")}document.body.appendChild(n);let u=n.querySelector("#paywall-subscribe");u&&(u.onclick=()=>{t.info("Subscribe button clicked",{url:e.subscribeUrl||a.subscribeUrl}),window.location.href=e.subscribeUrl||a.subscribeUrl});let f=n.querySelector("#paywall-close");f&&(f.onclick=()=>{t.info("Paywall closed by user"),n.remove()});let p=n.querySelector("#paywall-login");p&&(p.onclick=c=>{c.preventDefault(),t.info("Login link clicked",{url:a.loginUrl}),window.location.href=a.loginUrl}),l.measure("Modal created","modal_create_start"),t.success("Paywall modal displayed")}function b(){l.mark("blur_start");let e=[];if(a.protectBody)e=[document.body],t.info("Protecting entire page (body element)");else{let r=["main","article",'[role="main"]',".content",".post-content",".article-content",".entry-content","#content","#main-content"];t.debug("Searching for content elements",{selectors:r});for(let n of r){let u=document.querySelector(n);if(u){e=[u],t.info("Content element found",{selector:n});break}}e.length===0&&(e=[document.body],t.warn("No content elements found, protecting body as fallback"))}let o=0;e.forEach(r=>{r.style.filter="blur(8px)",r.style.userSelect="none",r.style.pointerEvents="none",r.addEventListener("copy",n=>{n.preventDefault(),t.debug("Copy attempt blocked")}),r.addEventListener("cut",n=>{n.preventDefault(),t.debug("Cut attempt blocked")}),r.addEventListener("contextmenu",n=>{n.preventDefault(),t.debug("Context menu blocked")}),o++}),l.measure("Content blurred","blur_start"),t.success("Content protection applied",{elementsProtected:o,protectionType:a.protectBody?"body":"selective"})}function v(){return k(this,null,function*(){if(document.readyState==="loading"){t.debug("DOM not ready, waiting for DOMContentLoaded"),document.addEventListener("DOMContentLoaded",v);return}if(t.info("DOM ready, starting protection sequence"),a.mode==="never"){t.warn("Widget disabled (mode=never)");return}if(h()){t.success("Allowed bot detected, skipping all protection");return}if(a.mode==="always"){t.info("Force mode enabled (mode=always)"),b(),w({type:"hard"});return}let e=yield P();t.info("Access check decision received",{allowed:e.allowed,status:e.status,showPaywall:e.showPaywall}),!e.allowed&&e.status==="blocked"?(t.warn("Access blocked",{reason:e.reason}),b(),w({type:"bot-blocked",message:e.reason})):e.showPaywall&&e.paywallConfig?(t.info("Showing paywall to user",{type:e.paywallConfig.type}),b(),w(e.paywallConfig)):t.success("Access granted, no protection applied");let o=l.measure("Initialization complete","init_start");t.success("PaywallProtect initialization complete",{totalTime:o+"ms"})})}v(),window.PaywallProtect={version:"1.2.1",showPaywall:e=>{t.info("Manual showPaywall() called",e),b(),w(e||{type:"hard"})},hidePaywall:()=>{t.info("Manual hidePaywall() called");let e=document.getElementById("paywall-protect-modal");e?(e.remove(),t.success("Paywall hidden")):t.warn("No paywall to hide")},checkAccess:P,reload:()=>{t.info("Manual reload() called"),v()},config:a,allowedBots:i,logs:{getAll:()=>t.getAll(),export:()=>t.export(),clear:()=>t.clear(),download:()=>{let e=t.export(),o=new Blob([e],{type:"application/json"}),r=URL.createObjectURL(o),n=document.createElement("a");n.href=r,n.download=`paywall-logs-${t.sessionId}.json`,n.click(),URL.revokeObjectURL(r),t.info("Logs downloaded")}},debug:{enable:()=>{a.debug=!0,t.success("Debug mode enabled")},disable:()=>{a.debug=!1,t.info("Debug mode disabled")},status:()=>{console.table({Version:window.PaywallProtect.version,"Session ID":t.sessionId,"Site ID":a.siteId,Mode:a.mode,"SEO Safe":a.seoSafe,"Protect Body":a.protectBody,"Debug Mode":a.debug,"Allowed Bots":i.length,"Total Logs":t.logs.length,Uptime:Math.round(performance.now()-t.startTime)+"ms"})}}},t.success("Public API initialized",{methods:Object.keys(window.PaywallProtect)})})();
|
|
@@ -1,32 +1,34 @@
|
|
|
1
|
-
var PaywallProtect=(()=>{var
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
1
|
+
var PaywallProtect=(()=>{var k=(s,y,a)=>new Promise((t,i)=>{var l=d=>{try{g(a.next(d))}catch(m){i(m)}},h=d=>{try{g(a.throw(d))}catch(m){i(m)}},g=d=>d.done?t(d.value):Promise.resolve(d.value).then(l,h);g((a=a.apply(s,y)).next())});(function(){"use strict";let s=document.currentScript||document.querySelector("script[data-site-id]");if(!s){console.error("[PaywallProtect] Script tag not found");return}let y=["googlebot","bingbot","slurp","duckduckbot","baiduspider","yandexbot","facebookexternalhit","twitterbot","linkedinbot","slackbot","telegrambot","whatsapp","discordbot","pinterestbot","redditbot","applebot"],a={siteId:s.dataset.siteId||s.getAttribute("data-site-id"),apiKey:s.dataset.apiKey||s.getAttribute("data-api-key"),apiUrl:s.dataset.apiUrl||s.getAttribute("data-api-url")||"",subscribeUrl:s.dataset.subscribeUrl||"/subscribe",loginUrl:s.dataset.loginUrl||"/login",mode:s.dataset.mode||"auto",seoSafe:s.dataset.seoSafe!=="false",allowBots:s.dataset.allowBots||null,protectBody:s.dataset.protectBody!=="false",debug:s.dataset.debug==="true"||s.dataset.debug==="1"},t={sessionId:"session_"+Date.now()+"_"+Math.random().toString(36).substr(2,9),logs:[],startTime:performance.now(),log(e,o,r={}){let n=new Date().toISOString(),u=Math.round(performance.now()-this.startTime),f={timestamp:n,elapsed:u,level:e,message:o,data:r,sessionId:this.sessionId};this.logs.push(f);let p="[PaywallProtect]",c=a.debug?` [+${u}ms]`:"";switch(e){case"info":console.log(`%c${p}${c} ${o}`,"color: #3b82f6",r);break;case"success":console.log(`%c${p}${c} \u2713 ${o}`,"color: #10b981; font-weight: bold",r);break;case"warn":console.warn(`${p}${c} \u26A0 ${o}`,r);break;case"error":console.error(`${p}${c} \u2717 ${o}`,r);break;case"debug":a.debug&&console.log(`%c${p}${c} [DEBUG] ${o}`,"color: #8b5cf6",r);break}this.logs.length>100&&this.logs.shift()},info(e,o){this.log("info",e,o)},success(e,o){this.log("success",e,o)},warn(e,o){this.log("warn",e,o)},error(e,o){this.log("error",e,o)},debug(e,o){this.log("debug",e,o)},getAll(){return[...this.logs]},export(){return JSON.stringify({sessionId:this.sessionId,config:{siteId:a.siteId,mode:a.mode,seoSafe:a.seoSafe,protectBody:a.protectBody,debug:a.debug},userAgent:navigator.userAgent,page:window.location.href,logs:this.logs,performance:{totalTime:Math.round(performance.now()-this.startTime),memory:performance.memory?{used:Math.round(performance.memory.usedJSHeapSize/1024/1024)+"MB",total:Math.round(performance.memory.totalJSHeapSize/1024/1024)+"MB"}:"N/A"}},null,2)},clear(){this.logs=[],console.clear(),this.info("Logs cleared")}},i=[];if(a.seoSafe&&(i=[...y]),a.allowBots){let e=a.allowBots.split(",").map(o=>o.trim().toLowerCase());i=[...i,...e],t.info("Custom allowlist added",{bots:e})}if(t.info("Initializing PaywallProtect Widget",{version:"1.2.1",siteId:a.siteId,mode:a.mode,seoSafe:a.seoSafe,protectBody:a.protectBody,debug:a.debug,allowedBotsCount:i.length}),!a.siteId||!a.apiKey){t.error("Missing required configuration",{hasSiteId:!!a.siteId,hasApiKey:!!a.apiKey});return}if(!a.apiUrl){t.error("Missing API URL",{apiUrl:a.apiUrl});return}t.success("Configuration validated"),a.seoSafe&&t.info("SEO-safe mode enabled",{allowedBots:i.length});let l={marks:{},mark(e){this.marks[e]=performance.now(),t.debug(`Performance mark: ${e}`,{time:Math.round(this.marks[e])+"ms"})},measure(e,o){let r=Math.round(performance.now()-this.marks[o]);return t.debug(`Performance: ${e}`,{duration:r+"ms"}),r}};l.mark("init_start");function h(){l.mark("allowlist_check_start");let e=navigator.userAgent.toLowerCase();t.debug("Checking user agent against allowlist",{userAgent:navigator.userAgent,allowlistSize:i.length});for(let o of i)if(e.includes(o))return l.measure("Allowlist check complete","allowlist_check_start"),t.success("Allowed bot detected",{bot:o,userAgent:navigator.userAgent}),!0;return l.measure("Allowlist check complete","allowlist_check_start"),t.debug("Not in allowlist, will check with server"),!1}function g(){l.mark("fingerprint_start"),t.debug("Generating browser fingerprint");let e={userAgent:navigator.userAgent,language:navigator.language,platform:navigator.platform,hardwareConcurrency:navigator.hardwareConcurrency||0,deviceMemory:navigator.deviceMemory||0,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,screen:{width:window.screen.width,height:window.screen.height,colorDepth:window.screen.colorDepth,pixelRatio:window.devicePixelRatio||1},timing:{pageLoadTime:Math.round(performance.now())},webdriver:navigator.webdriver||!1,canvas:d(),webgl:m(),touchSupport:"ontouchstart"in window,plugins:x()};return l.measure("Fingerprint generated","fingerprint_start"),t.debug("Fingerprint complete",{hasCanvas:!!e.canvas,hasWebGL:!!e.webgl,pluginCount:e.plugins.length,webdriver:e.webdriver}),e}function d(){try{let e=document.createElement("canvas"),o=e.getContext("2d");if(!o)return t.warn("Canvas context unavailable"),null;o.textBaseline="top",o.font="14px Arial",o.fillText("PaywallProtect",2,2);let r=e.toDataURL().substring(0,100);return t.debug("Canvas fingerprint generated",{length:r.length}),r}catch(e){return t.error("Canvas fingerprint failed",{error:e.message}),null}}function m(){try{let o=document.createElement("canvas").getContext("webgl");if(!o)return t.warn("WebGL context unavailable"),null;let r={renderer:o.getParameter(o.RENDERER),vendor:o.getParameter(o.VENDOR)};return t.debug("WebGL fingerprint generated",r),r}catch(e){return t.error("WebGL fingerprint failed",{error:e.message}),null}}function x(){try{let e=Array.from(navigator.plugins||[]).map(o=>o.name).slice(0,5);return t.debug("Plugins enumerated",{count:e.length}),e}catch(e){return t.error("Plugin enumeration failed",{error:e.message}),[]}}function P(){return k(this,null,function*(){l.mark("api_call_start"),t.info("Calling API for access check",{endpoint:a.apiUrl+"/check-access"});try{let e={siteId:a.siteId,apiKey:a.apiKey,page:window.location.pathname,userAgent:navigator.userAgent,fingerprint:g(),referrer:document.referrer,allowedBots:i};t.debug("API request payload",{siteId:e.siteId,page:e.page,hasFingerprint:!!e.fingerprint,allowedBotsCount:e.allowedBots.length});let o=yield fetch(a.apiUrl+"/check-access",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)}),r=l.measure("API call complete","api_call_start");if(!o.ok)return t.error("API returned error status",{status:o.status,statusText:o.statusText,duration:r+"ms"}),{allowed:!0,reason:"API error",showPaywall:!1};let n=yield o.json();return t.success("API response received",{allowed:n.allowed,status:n.status,showPaywall:n.showPaywall,reason:n.reason,duration:r+"ms"}),n}catch(e){let o=l.measure("API call failed","api_call_start");return t.error("Network error during API call",{error:e.message,stack:e.stack,duration:o+"ms"}),{allowed:!0,reason:"Network error",showPaywall:!1}}})}function w(e){if(document.getElementById("paywall-protect-modal")){t.warn("Paywall modal already exists, skipping creation");return}l.mark("modal_create_start"),t.info("Creating paywall modal",{type:e.type||"hard"});let o=e.type||"hard",r="";o==="hard"?r=`
|
|
2
|
+
<div class="paywall-icon">\u{1F512}</div>
|
|
3
|
+
<h2 id="paywall-title">${e.title||"Premium Content"}</h2>
|
|
4
|
+
<p>${e.message||"Subscribe to access this content."}</p>
|
|
5
|
+
<button id="paywall-subscribe" class="paywall-btn primary">Subscribe Now</button>
|
|
6
|
+
<p class="footer">Already a subscriber? <a href="${a.loginUrl}" id="paywall-login">Sign in</a></p>
|
|
7
|
+
`:o==="metered"?r=`
|
|
8
|
+
<div class="paywall-icon">\u{1F4CA}</div>
|
|
9
|
+
<h2 id="paywall-title">Free Article Limit Reached</h2>
|
|
10
|
+
<p>You've read <strong>${e.articlesRead||3} of ${e.freeLimit||3}</strong> free articles this month.</p>
|
|
11
|
+
<button id="paywall-subscribe" class="paywall-btn primary">Get Unlimited Access</button>
|
|
12
|
+
<button id="paywall-close" class="paywall-btn secondary">Maybe Later</button>
|
|
13
|
+
`:r=`
|
|
14
|
+
<div class="paywall-icon">\u{1F916}</div>
|
|
15
|
+
<h2 id="paywall-title">Access Denied</h2>
|
|
16
|
+
<p>${e.message||"Automated access is not permitted."}</p>
|
|
17
|
+
`;let n=document.createElement("div");if(n.id="paywall-protect-modal",n.innerHTML=`<div class="paywall-overlay"><div class="paywall-content">${r}</div></div>`,!document.getElementById("paywall-styles")){let c=document.createElement("style");c.id="paywall-styles",c.textContent=`
|
|
18
|
+
#paywall-protect-modal{position:fixed;top:0;left:0;width:100%;height:100%;z-index:999999;animation:fadeIn .3s}
|
|
19
|
+
.paywall-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.85);backdrop-filter:blur(8px);display:flex;align-items:center;justify-content:center;padding:20px}
|
|
20
|
+
.paywall-content{background:#fff;border-radius:16px;padding:48px 40px;max-width:500px;width:100%;text-align:center;box-shadow:0 20px 60px rgba(0,0,0,.3);animation:slideUp .3s}
|
|
21
|
+
.paywall-icon{font-size:64px;margin-bottom:24px}
|
|
22
|
+
#paywall-title{font-size:28px;font-weight:700;color:#1a1a1a;margin:0 0 16px 0}
|
|
23
|
+
.paywall-content p{font-size:16px;color:#666;line-height:1.6;margin:0 0 24px 0}
|
|
24
|
+
.paywall-btn{display:block;width:100%;padding:16px 32px;border:none;border-radius:8px;font-size:16px;font-weight:600;cursor:pointer;transition:all .2s;margin-bottom:12px}
|
|
25
|
+
.paywall-btn.primary{background:#3b82f6;color:#fff}
|
|
26
|
+
.paywall-btn.primary:hover{background:#2563eb;transform:translateY(-1px)}
|
|
27
|
+
.paywall-btn.secondary{background:transparent;color:#666;border:2px solid #e5e7eb}
|
|
28
|
+
.paywall-btn.secondary:hover{background:#f9fafb}
|
|
29
|
+
.footer{margin-top:24px;font-size:14px;color:#666}
|
|
30
|
+
.footer a{color:#3b82f6;text-decoration:none}
|
|
31
|
+
.footer a:hover{text-decoration:underline}
|
|
32
|
+
@keyframes fadeIn{from{opacity:0}to{opacity:1}}
|
|
33
|
+
@keyframes slideUp{from{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}
|
|
34
|
+
`,document.head.appendChild(c),t.debug("Paywall styles injected")}document.body.appendChild(n);let u=n.querySelector("#paywall-subscribe");u&&(u.onclick=()=>{t.info("Subscribe button clicked",{url:e.subscribeUrl||a.subscribeUrl}),window.location.href=e.subscribeUrl||a.subscribeUrl});let f=n.querySelector("#paywall-close");f&&(f.onclick=()=>{t.info("Paywall closed by user"),n.remove()});let p=n.querySelector("#paywall-login");p&&(p.onclick=c=>{c.preventDefault(),t.info("Login link clicked",{url:a.loginUrl}),window.location.href=a.loginUrl}),l.measure("Modal created","modal_create_start"),t.success("Paywall modal displayed")}function b(){l.mark("blur_start");let e=[];if(a.protectBody)e=[document.body],t.info("Protecting entire page (body element)");else{let r=["main","article",'[role="main"]',".content",".post-content",".article-content",".entry-content","#content","#main-content"];t.debug("Searching for content elements",{selectors:r});for(let n of r){let u=document.querySelector(n);if(u){e=[u],t.info("Content element found",{selector:n});break}}e.length===0&&(e=[document.body],t.warn("No content elements found, protecting body as fallback"))}let o=0;e.forEach(r=>{r.style.filter="blur(8px)",r.style.userSelect="none",r.style.pointerEvents="none",r.addEventListener("copy",n=>{n.preventDefault(),t.debug("Copy attempt blocked")}),r.addEventListener("cut",n=>{n.preventDefault(),t.debug("Cut attempt blocked")}),r.addEventListener("contextmenu",n=>{n.preventDefault(),t.debug("Context menu blocked")}),o++}),l.measure("Content blurred","blur_start"),t.success("Content protection applied",{elementsProtected:o,protectionType:a.protectBody?"body":"selective"})}function v(){return k(this,null,function*(){if(document.readyState==="loading"){t.debug("DOM not ready, waiting for DOMContentLoaded"),document.addEventListener("DOMContentLoaded",v);return}if(t.info("DOM ready, starting protection sequence"),a.mode==="never"){t.warn("Widget disabled (mode=never)");return}if(h()){t.success("Allowed bot detected, skipping all protection");return}if(a.mode==="always"){t.info("Force mode enabled (mode=always)"),b(),w({type:"hard"});return}let e=yield P();t.info("Access check decision received",{allowed:e.allowed,status:e.status,showPaywall:e.showPaywall}),!e.allowed&&e.status==="blocked"?(t.warn("Access blocked",{reason:e.reason}),b(),w({type:"bot-blocked",message:e.reason})):e.showPaywall&&e.paywallConfig?(t.info("Showing paywall to user",{type:e.paywallConfig.type}),b(),w(e.paywallConfig)):t.success("Access granted, no protection applied");let o=l.measure("Initialization complete","init_start");t.success("PaywallProtect initialization complete",{totalTime:o+"ms"})})}v(),window.PaywallProtect={version:"1.2.1",showPaywall:e=>{t.info("Manual showPaywall() called",e),b(),w(e||{type:"hard"})},hidePaywall:()=>{t.info("Manual hidePaywall() called");let e=document.getElementById("paywall-protect-modal");e?(e.remove(),t.success("Paywall hidden")):t.warn("No paywall to hide")},checkAccess:P,reload:()=>{t.info("Manual reload() called"),v()},config:a,allowedBots:i,logs:{getAll:()=>t.getAll(),export:()=>t.export(),clear:()=>t.clear(),download:()=>{let e=t.export(),o=new Blob([e],{type:"application/json"}),r=URL.createObjectURL(o),n=document.createElement("a");n.href=r,n.download=`paywall-logs-${t.sessionId}.json`,n.click(),URL.revokeObjectURL(r),t.info("Logs downloaded")}},debug:{enable:()=>{a.debug=!0,t.success("Debug mode enabled")},disable:()=>{a.debug=!1,t.info("Debug mode disabled")},status:()=>{console.table({Version:window.PaywallProtect.version,"Session ID":t.sessionId,"Site ID":a.siteId,Mode:a.mode,"SEO Safe":a.seoSafe,"Protect Body":a.protectBody,"Debug Mode":a.debug,"Allowed Bots":i.length,"Total Logs":t.logs.length,Uptime:Math.round(performance.now()-t.startTime)+"ms"})}}},t.success("Public API initialized",{methods:Object.keys(window.PaywallProtect)})})();})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "paywall-protect-widget",
|
|
3
|
-
"version": "1.0.
|
|
2
|
+
"name": "paywall-protect-widget",
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "PaywallProtect widget for bot detection and content protection",
|
|
5
5
|
"main": "dist/paywall-widget.min.js",
|
|
6
6
|
"module": "dist/paywall-widget.esm.js",
|
|
@@ -16,10 +16,13 @@
|
|
|
16
16
|
"build:esm": "esbuild src/index.js --bundle --minify --target=es2015 --format=esm --outfile=dist/paywall-widget.esm.js",
|
|
17
17
|
"prepublishOnly": "npm run build"
|
|
18
18
|
},
|
|
19
|
-
"keywords": [
|
|
19
|
+
"keywords": [
|
|
20
|
+
"paywall",
|
|
21
|
+
"bot-detection"
|
|
22
|
+
],
|
|
20
23
|
"author": "PaywallProtect",
|
|
21
24
|
"license": "MIT",
|
|
22
25
|
"devDependencies": {
|
|
23
26
|
"esbuild": "^0.19.0"
|
|
24
27
|
}
|
|
25
|
-
}
|
|
28
|
+
}
|