anti-adblock-detector 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Antigravity
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,124 @@
1
+ # anti-adblock-detector
2
+
3
+ A powerful, lightweight, and professional anti-adblock detection library for React and Vanilla JavaScript. Protect your website's ad revenue with multiple detection strategies and a stunning, customizable overlay.
4
+
5
+ ## Features
6
+
7
+ - 🛡️ **Triple Detection**: Uses 3 independent strategies (Bait Element, Fake Script, Fetch Test) for maximum accuracy.
8
+ - ⚛️ **React Component**: Simple `<AntiAdBlock />` drop-in component.
9
+ - 🪝 **React Hook**: `useAdBlockDetector()` hook for custom UI implementations.
10
+ - 🍦 **Vanilla JS**: `detectAdBlocker()` function for non-React projects.
11
+ - 🎨 **Premium UI**: Glassmorphism overlay with smooth animations.
12
+ - 🔒 **Hard Block Mode**: Optionally prevent site access until ad blocker is disabled.
13
+ - ♻️ **Recheck Support**: Users can recheck after disabling their ad blocker.
14
+ - 📱 **Fully Responsive**: Looks great on desktop and mobile.
15
+ - 🪶 **Zero Dependencies**: No external runtime dependencies.
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install anti-adblock-detector
21
+ # or
22
+ yarn add anti-adblock-detector
23
+ ```
24
+
25
+ ## Quick Start (React)
26
+
27
+ ```jsx
28
+ import { AntiAdBlock } from 'anti-adblock-detector';
29
+ import 'anti-adblock-detector/styles.css';
30
+
31
+ function App() {
32
+ return (
33
+ <>
34
+ <AntiAdBlock
35
+ onDetected={(result) => console.log('Ad blocker detected!', result)}
36
+ onDismissed={() => console.log('User chose to continue')}
37
+ />
38
+ <div>Your website content here...</div>
39
+ </>
40
+ );
41
+ }
42
+ ```
43
+
44
+ ## Hard Block Mode
45
+
46
+ Force users to disable their ad blocker before accessing the site:
47
+
48
+ ```jsx
49
+ <AntiAdBlock
50
+ hardBlock={true}
51
+ title="Please Support Us"
52
+ description="This content is only available without an ad blocker."
53
+ />
54
+ ```
55
+
56
+ ## Custom Hook
57
+
58
+ Build your own UI with the `useAdBlockDetector` hook:
59
+
60
+ ```jsx
61
+ import { useAdBlockDetector } from 'anti-adblock-detector';
62
+
63
+ function CustomBanner() {
64
+ const { loading, detected, recheck } = useAdBlockDetector();
65
+
66
+ if (loading) return <p>Checking...</p>;
67
+ if (!detected) return null;
68
+
69
+ return (
70
+ <div className="my-custom-banner">
71
+ <p>We noticed you're using an ad blocker. Please support us!</p>
72
+ <button onClick={recheck}>I've disabled it</button>
73
+ </div>
74
+ );
75
+ }
76
+ ```
77
+
78
+ ## Vanilla JavaScript
79
+
80
+ ```javascript
81
+ import { detectAdBlocker } from 'anti-adblock-detector';
82
+
83
+ async function checkAds() {
84
+ const result = await detectAdBlocker();
85
+
86
+ if (result.detected) {
87
+ alert('Ad blocker detected!');
88
+ console.log('Strategies:', result.strategies);
89
+ }
90
+ }
91
+
92
+ checkAds();
93
+ ```
94
+
95
+ ## Props
96
+
97
+ | Prop | Type | Default | Description |
98
+ | :--- | :--- | :--- | :--- |
99
+ | `enabled` | `boolean` | `true` | Enable/disable detection. |
100
+ | `hardBlock` | `boolean` | `false` | If true, user cannot dismiss the overlay. |
101
+ | `title` | `string` | `"Ad Blocker Detected"` | Modal title text. |
102
+ | `description` | `string` | `"We rely on ads..."` | Modal description text. |
103
+ | `primaryButtonText` | `string` | `"I've Disabled My Ad Blocker"` | Primary button label. |
104
+ | `dismissButtonText` | `string` | `"Continue Without Disabling"` | Dismiss button label. |
105
+ | `tipText` | `string` | `"After disabling..."` | Tip text at the bottom. |
106
+ | `delay` | `number` | `500` | Delay (ms) before showing the modal. |
107
+ | `onDetected` | `(result) => void` | - | Callback when ad blocker is detected. |
108
+ | `onAllowed` | `() => void` | - | Callback when user confirms disable. |
109
+ | `onDismissed` | `() => void` | - | Callback when user dismisses overlay. |
110
+ | `children` | `ReactNode` | - | Render your own custom modal content. |
111
+
112
+ ## How Detection Works
113
+
114
+ The library uses three independent detection strategies:
115
+
116
+ 1. **Bait Element**: Creates a hidden DOM element with common ad-related class names (e.g., `ad-banner`, `adsbox`). If the element gets hidden/removed by an ad blocker, detection is positive.
117
+ 2. **Fake Script**: Attempts to load a script from Google AdSense's URL. If blocked, detection is positive.
118
+ 3. **Fetch Test**: Makes a `HEAD` request to a known ad-serving domain. If the request fails, detection is positive.
119
+
120
+ If **any** strategy returns positive, the ad blocker is considered active.
121
+
122
+ ## License
123
+
124
+ MIT © [Antigravity](https://github.com/antigravity)
package/dist/index.css ADDED
@@ -0,0 +1,2 @@
1
+ @keyframes aab-fadeIn{0%{opacity:0}to{opacity:1}}@keyframes aab-slideUp{0%{opacity:0;transform:translateY(30px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes aab-pulse{0%,to{transform:scale(1)}50%{transform:scale(1.05)}}.aab-overlay{position:fixed;inset:0;z-index:2147483647;display:flex;align-items:center;justify-content:center;padding:1.5rem;animation:aab-fadeIn .4s ease-out}.aab-backdrop{position:absolute;inset:0;background:#000000b3;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px)}.aab-modal{position:relative;width:100%;max-width:480px;background:linear-gradient(145deg,#1a1a2e,#16213e,#0f3460);border:1px solid rgba(255,255,255,.08);border-radius:24px;padding:3rem 2.5rem;text-align:center;box-shadow:0 0 0 1px #ffffff0d,0 20px 60px #00000080,0 0 80px #4f46e526;animation:aab-slideUp .5s cubic-bezier(.16,1,.3,1);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;color:#e2e8f0}.aab-icon{width:80px;height:80px;margin:0 auto 1.5rem;background:linear-gradient(135deg,#ef4444,#f97316);border-radius:50%;display:flex;align-items:center;justify-content:center;box-shadow:0 8px 32px #ef44444d;animation:aab-pulse 2s ease-in-out infinite}.aab-icon svg{width:40px;height:40px;fill:none;stroke:#fff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.aab-title{font-size:1.75rem;font-weight:700;color:#f8fafc;margin:0 0 .75rem;line-height:1.3}.aab-description{font-size:1rem;line-height:1.6;color:#94a3b8;margin:0 0 2rem}.aab-buttons{display:flex;flex-direction:column;gap:.75rem}.aab-btn-primary{width:100%;padding:1rem 2rem;font-size:1rem;font-weight:600;border:none;border-radius:14px;cursor:pointer;background:linear-gradient(135deg,#6366f1,#8b5cf6,#a855f7);color:#fff;transition:all .3s ease;box-shadow:0 4px 20px #6366f166;font-family:inherit}.aab-btn-primary:hover{transform:translateY(-2px);box-shadow:0 8px 30px #6366f180}.aab-btn-primary:active{transform:translateY(0)}.aab-btn-secondary{width:100%;padding:.875rem 2rem;font-size:.875rem;font-weight:500;background:transparent;border:1px solid rgba(255,255,255,.1);border-radius:14px;cursor:pointer;color:#64748b;transition:all .3s ease;font-family:inherit}.aab-btn-secondary:hover{background:#ffffff0d;color:#94a3b8;border-color:#ffffff26}.aab-tip{margin-top:1.5rem;font-size:.75rem;color:#475569}.aab-tip strong{color:#64748b}@media(max-width:480px){.aab-modal{padding:2rem 1.5rem;border-radius:18px}.aab-title{font-size:1.375rem}.aab-icon{width:64px;height:64px}.aab-icon svg{width:32px;height:32px}}
2
+ /*# sourceMappingURL=index.css.map */
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/styles.css"],"sourcesContent":["/* ===============================================\n Anti Ad-Block Detector - Premium Overlay Styles\n =============================================== */\n\n@keyframes aab-fadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n@keyframes aab-slideUp {\n from { opacity: 0; transform: translateY(30px) scale(0.96); }\n to { opacity: 1; transform: translateY(0) scale(1); }\n}\n\n@keyframes aab-pulse {\n 0%, 100% { transform: scale(1); }\n 50% { transform: scale(1.05); }\n}\n\n/* Overlay backdrop */\n.aab-overlay {\n position: fixed;\n inset: 0;\n z-index: 2147483647;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 1.5rem;\n animation: aab-fadeIn 0.4s ease-out;\n}\n\n/* Glassmorphism backdrop */\n.aab-backdrop {\n position: absolute;\n inset: 0;\n background: rgba(0, 0, 0, 0.7);\n backdrop-filter: blur(12px);\n -webkit-backdrop-filter: blur(12px);\n}\n\n/* Modal card */\n.aab-modal {\n position: relative;\n width: 100%;\n max-width: 480px;\n background: linear-gradient(145deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);\n border: 1px solid rgba(255, 255, 255, 0.08);\n border-radius: 24px;\n padding: 3rem 2.5rem;\n text-align: center;\n box-shadow:\n 0 0 0 1px rgba(255, 255, 255, 0.05),\n 0 20px 60px rgba(0, 0, 0, 0.5),\n 0 0 80px rgba(79, 70, 229, 0.15);\n animation: aab-slideUp 0.5s cubic-bezier(0.16, 1, 0.3, 1);\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n color: #e2e8f0;\n}\n\n/* Shield icon container */\n.aab-icon {\n width: 80px;\n height: 80px;\n margin: 0 auto 1.5rem;\n background: linear-gradient(135deg, #ef4444 0%, #f97316 100%);\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 8px 32px rgba(239, 68, 68, 0.3);\n animation: aab-pulse 2s ease-in-out infinite;\n}\n\n.aab-icon svg {\n width: 40px;\n height: 40px;\n fill: none;\n stroke: white;\n stroke-width: 2;\n stroke-linecap: round;\n stroke-linejoin: round;\n}\n\n/* Title */\n.aab-title {\n font-size: 1.75rem;\n font-weight: 700;\n color: #f8fafc;\n margin: 0 0 0.75rem;\n line-height: 1.3;\n}\n\n/* Description */\n.aab-description {\n font-size: 1rem;\n line-height: 1.6;\n color: #94a3b8;\n margin: 0 0 2rem;\n}\n\n/* Buttons container */\n.aab-buttons {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n/* Primary CTA button */\n.aab-btn-primary {\n width: 100%;\n padding: 1rem 2rem;\n font-size: 1rem;\n font-weight: 600;\n border: none;\n border-radius: 14px;\n cursor: pointer;\n background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 50%, #a855f7 100%);\n color: white;\n transition: all 0.3s ease;\n box-shadow: 0 4px 20px rgba(99, 102, 241, 0.4);\n font-family: inherit;\n}\n\n.aab-btn-primary:hover {\n transform: translateY(-2px);\n box-shadow: 0 8px 30px rgba(99, 102, 241, 0.5);\n}\n\n.aab-btn-primary:active {\n transform: translateY(0);\n}\n\n/* Secondary dismiss button */\n.aab-btn-secondary {\n width: 100%;\n padding: 0.875rem 2rem;\n font-size: 0.875rem;\n font-weight: 500;\n background: transparent;\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 14px;\n cursor: pointer;\n color: #64748b;\n transition: all 0.3s ease;\n font-family: inherit;\n}\n\n.aab-btn-secondary:hover {\n background: rgba(255, 255, 255, 0.05);\n color: #94a3b8;\n border-color: rgba(255, 255, 255, 0.15);\n}\n\n/* Tip at the bottom */\n.aab-tip {\n margin-top: 1.5rem;\n font-size: 0.75rem;\n color: #475569;\n}\n\n.aab-tip strong {\n color: #64748b;\n}\n\n/* Responsive */\n@media (max-width: 480px) {\n .aab-modal {\n padding: 2rem 1.5rem;\n border-radius: 18px;\n }\n\n .aab-title {\n font-size: 1.375rem;\n }\n\n .aab-icon {\n width: 64px;\n height: 64px;\n }\n\n .aab-icon svg {\n width: 32px;\n height: 32px;\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,48 @@
1
+ import React from 'react';
2
+
3
+ interface DetectionResult {
4
+ detected: boolean;
5
+ isBrave: boolean;
6
+ strategies: {
7
+ baitElement: boolean;
8
+ network: boolean;
9
+ brave: boolean;
10
+ };
11
+ }
12
+ /**
13
+ * Main Detection Function
14
+ */
15
+ declare function detectAdBlocker(blockBrave?: boolean): Promise<DetectionResult>;
16
+
17
+ interface AntiAdBlockProps {
18
+ enabled?: boolean;
19
+ hardBlock?: boolean;
20
+ title?: string;
21
+ description?: string;
22
+ primaryButtonText?: string;
23
+ dismissButtonText?: string;
24
+ tipText?: string;
25
+ blockBrave?: boolean;
26
+ braveTitle?: string;
27
+ braveDescription?: string;
28
+ onDetected?: (result: DetectionResult) => void;
29
+ onAllowed?: () => void;
30
+ onDismissed?: () => void;
31
+ children?: React.ReactNode;
32
+ delay?: number;
33
+ debug?: boolean;
34
+ }
35
+ declare const AntiAdBlock: React.FC<AntiAdBlockProps>;
36
+ declare function useAdBlockDetector(blockBrave?: boolean): {
37
+ loading: boolean;
38
+ detected: boolean;
39
+ isBrave: boolean;
40
+ strategies: {
41
+ baitElement: boolean;
42
+ network: boolean;
43
+ brave: boolean;
44
+ } | null;
45
+ recheck: () => Promise<DetectionResult>;
46
+ };
47
+
48
+ export { AntiAdBlock, type AntiAdBlockProps, type DetectionResult, detectAdBlocker, useAdBlockDetector };
@@ -0,0 +1,48 @@
1
+ import React from 'react';
2
+
3
+ interface DetectionResult {
4
+ detected: boolean;
5
+ isBrave: boolean;
6
+ strategies: {
7
+ baitElement: boolean;
8
+ network: boolean;
9
+ brave: boolean;
10
+ };
11
+ }
12
+ /**
13
+ * Main Detection Function
14
+ */
15
+ declare function detectAdBlocker(blockBrave?: boolean): Promise<DetectionResult>;
16
+
17
+ interface AntiAdBlockProps {
18
+ enabled?: boolean;
19
+ hardBlock?: boolean;
20
+ title?: string;
21
+ description?: string;
22
+ primaryButtonText?: string;
23
+ dismissButtonText?: string;
24
+ tipText?: string;
25
+ blockBrave?: boolean;
26
+ braveTitle?: string;
27
+ braveDescription?: string;
28
+ onDetected?: (result: DetectionResult) => void;
29
+ onAllowed?: () => void;
30
+ onDismissed?: () => void;
31
+ children?: React.ReactNode;
32
+ delay?: number;
33
+ debug?: boolean;
34
+ }
35
+ declare const AntiAdBlock: React.FC<AntiAdBlockProps>;
36
+ declare function useAdBlockDetector(blockBrave?: boolean): {
37
+ loading: boolean;
38
+ detected: boolean;
39
+ isBrave: boolean;
40
+ strategies: {
41
+ baitElement: boolean;
42
+ network: boolean;
43
+ brave: boolean;
44
+ } | null;
45
+ recheck: () => Promise<DetectionResult>;
46
+ };
47
+
48
+ export { AntiAdBlock, type AntiAdBlockProps, type DetectionResult, detectAdBlocker, useAdBlockDetector };
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ "use strict";var x=Object.defineProperty;var I=Object.getOwnPropertyDescriptor;var H=Object.getOwnPropertyNames;var L=Object.prototype.hasOwnProperty;var O=(t,e)=>{for(var o in e)x(t,o,{get:e[o],enumerable:!0})},U=(t,e,o,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of H(e))!L.call(t,r)&&r!==o&&x(t,r,{get:()=>e[r],enumerable:!(i=I(e,r))||i.enumerable});return t};var V=t=>U(x({},"__esModule",{value:!0}),t);var _={};O(_,{AntiAdBlock:()=>N,detectAdBlocker:()=>l,useAdBlockDetector:()=>P});module.exports=V(_);var n=require("react"),R=require("react-dom");function Y(){return new Promise(t=>{let e=document.createElement("div");e.innerHTML=`
2
+ <div class="adsense ad-banner adsbox pub_300x250 pub_728x90 text-ad" style="width: 1px; height: 1px;">&nbsp;</div>
3
+ <div class="ad-placement doubleclick sponsorship" style="width: 1px; height: 1px;">&nbsp;</div>
4
+ `,e.style.cssText="position:absolute; top:-9999px; left:-9999px; width: 1px; height: 1px; overflow: hidden;",document.body.appendChild(e),setTimeout(()=>{let o=!1,i=e.children;for(let r=0;r<i.length;r++){let s=i[r],c=window.getComputedStyle(s);if(c.display==="none"||c.visibility==="hidden"||s.offsetHeight===0){o=!0;break}}e.parentNode&&e.parentNode.removeChild(e),t(o)},150)})}function F(){return new Promise(t=>{let o=`https://ad.doubleclick.net/ddm/ad/N1234.12345.EXAMPLE/B1234567.123456789;sz=1x1?ord=${Math.floor(Math.random()*1e7)}`;fetch(o,{method:"HEAD",mode:"no-cors",cache:"no-store"}).then(()=>t(!1)).catch(()=>t(!0)),setTimeout(()=>t(!1),800)})}async function W(){let t=navigator;if(t.brave&&typeof t.brave.isBrave=="function")try{return await t.brave.isBrave()}catch{return!1}return!1}async function l(t=!0){let[e,o,i]=await Promise.all([Y(),F(),W()]);return{detected:e||o||t&&i,isBrave:i,strategies:{baitElement:e,network:o,brave:i}}}var a=require("react/jsx-runtime"),j=()=>(0,a.jsxs)("svg",{viewBox:"0 0 24 24",children:[(0,a.jsx)("path",{d:"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"}),(0,a.jsx)("line",{x1:"9",y1:"9",x2:"15",y2:"15"}),(0,a.jsx)("line",{x1:"15",y1:"9",x2:"9",y2:"15"})]}),N=({enabled:t=!0,hardBlock:e=!1,title:o="Ad Blocker Detected",description:i="We rely on advertising revenue to keep this website free for everyone. Please consider disabling your ad blocker to support us. We promise our ads are non-intrusive and respectful of your experience.",primaryButtonText:r="I've Disabled My Ad Blocker",dismissButtonText:s="Continue Without Disabling",tipText:c="After disabling your ad blocker, click the button above to refresh.",blockBrave:d=!0,braveTitle:C="Brave Browser Detected",braveDescription:z="Please use another browser. This website is not accessible with Brave Shields!",onDetected:y,onAllowed:v,onDismissed:k,children:w,delay:B=500,debug:b=!1})=>{let[S,u]=(0,n.useState)(!1),[M,p]=(0,n.useState)(!1),[A,m]=(0,n.useState)(!1),[f,D]=(0,n.useState)(!1);(0,n.useEffect)(()=>{if(!t)return;if(b){u(!0),p(!0);return}let h;return(async()=>{let g=await l(d);g.detected&&(u(!0),g.isBrave&&D(!0),y?.(g),h=setTimeout(()=>p(!0),B))})(),()=>clearTimeout(h)},[t,B,y,b,d]);let E=(0,n.useCallback)(async()=>{if(m(!0),b){setTimeout(()=>{m(!1)},1e3);return}(await l(d)).detected?m(!1):(u(!1),p(!1),D(!1),v?.(),window.location.reload())},[v,b,d]),T=(0,n.useCallback)(()=>{e||(p(!1),k?.())},[e,k]);return!M||!S?null:(document.body.style.overflow="hidden",(0,R.createPortal)((0,a.jsxs)("div",{className:"aab-overlay",children:[(0,a.jsx)("div",{className:"aab-backdrop",onClick:e?void 0:T}),(0,a.jsx)("div",{className:"aab-modal",children:w||(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("div",{className:"aab-icon",children:(0,a.jsx)(j,{})}),(0,a.jsx)("h2",{className:"aab-title",children:f?C:o}),(0,a.jsx)("p",{className:"aab-description",children:f?z:i}),(0,a.jsxs)("div",{className:"aab-buttons",children:[(0,a.jsx)("button",{className:"aab-btn-primary",onClick:E,disabled:A,children:A?"Checking...":r}),!e&&(0,a.jsx)("button",{className:"aab-btn-secondary",onClick:T,children:s})]}),!f&&(0,a.jsxs)("p",{className:"aab-tip",children:[(0,a.jsx)("strong",{children:"Tip:"})," ",c]})]})})]}),document.body))};function P(t=!0){let[e,o]=(0,n.useState)(null),[i,r]=(0,n.useState)(!0);return(0,n.useEffect)(()=>{l(t).then(s=>{o(s),r(!1)})},[t]),{loading:i,detected:e?.detected??!1,isBrave:e?.isBrave??!1,strategies:e?.strategies??null,recheck:async()=>{r(!0);let s=await l(t);return o(s),r(!1),s}}}0&&(module.exports={AntiAdBlock,detectAdBlocker,useAdBlockDetector});
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/AntiAdBlock.tsx","../src/detector.ts"],"sourcesContent":["export { AntiAdBlock, useAdBlockDetector } from './AntiAdBlock';\nexport type { AntiAdBlockProps } from './AntiAdBlock';\nexport { detectAdBlocker } from './detector';\nexport type { DetectionResult } from './detector';\nimport './styles.css';\n","import React, { useState, useEffect, useCallback } from 'react';\nimport { createPortal } from 'react-dom';\nimport { detectAdBlocker, type DetectionResult } from './detector';\nimport './styles.css';\n\nexport interface AntiAdBlockProps {\n enabled?: boolean;\n hardBlock?: boolean;\n title?: string;\n description?: string;\n primaryButtonText?: string;\n dismissButtonText?: string;\n tipText?: string;\n\n // New brave-specific props\n blockBrave?: boolean;\n braveTitle?: string;\n braveDescription?: string;\n\n onDetected?: (result: DetectionResult) => void;\n onAllowed?: () => void;\n onDismissed?: () => void;\n children?: React.ReactNode;\n delay?: number;\n debug?: boolean;\n}\n\nconst ShieldIcon: React.FC = () => (\n <svg viewBox=\"0 0 24 24\">\n <path d=\"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z\" />\n <line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\" />\n <line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\" />\n </svg>\n);\n\nexport const AntiAdBlock: React.FC<AntiAdBlockProps> = ({\n enabled = true,\n hardBlock = false,\n title = 'Ad Blocker Detected',\n description = \"We rely on advertising revenue to keep this website free for everyone. Please consider disabling your ad blocker to support us. We promise our ads are non-intrusive and respectful of your experience.\",\n primaryButtonText = \"I've Disabled My Ad Blocker\",\n dismissButtonText = 'Continue Without Disabling',\n tipText = 'After disabling your ad blocker, click the button above to refresh.',\n blockBrave = true,\n braveTitle = 'Brave Browser Detected',\n braveDescription = 'Please use another browser. This website is not accessible with Brave Shields!',\n onDetected,\n onAllowed,\n onDismissed,\n children,\n delay = 500,\n debug = false,\n}) => {\n const [isBlocked, setIsBlocked] = useState(false);\n const [showOverlay, setShowOverlay] = useState(false);\n const [isRechecking, setIsRechecking] = useState(false);\n const [isBrave, setIsBrave] = useState(false);\n\n useEffect(() => {\n if (!enabled) return;\n\n if (debug) {\n setIsBlocked(true);\n setShowOverlay(true);\n return;\n }\n\n let timeout: ReturnType<typeof setTimeout>;\n\n const runDetection = async () => {\n const result = await detectAdBlocker(blockBrave);\n if (result.detected) {\n setIsBlocked(true);\n if (result.isBrave) setIsBrave(true);\n onDetected?.(result);\n timeout = setTimeout(() => setShowOverlay(true), delay);\n }\n };\n\n runDetection();\n\n return () => clearTimeout(timeout);\n }, [enabled, delay, onDetected, debug, blockBrave]);\n\n const handleRecheck = useCallback(async () => {\n setIsRechecking(true);\n\n if (debug) {\n setTimeout(() => {\n setIsRechecking(false);\n }, 1000);\n return;\n }\n\n const result = await detectAdBlocker(blockBrave);\n\n if (!result.detected) {\n setIsBlocked(false);\n setShowOverlay(false);\n setIsBrave(false);\n onAllowed?.();\n window.location.reload();\n } else {\n setIsRechecking(false);\n }\n }, [onAllowed, debug, blockBrave]);\n\n const handleDismiss = useCallback(() => {\n if (hardBlock) return;\n setShowOverlay(false);\n onDismissed?.();\n }, [hardBlock, onDismissed]);\n\n if (!showOverlay || !isBlocked) return null;\n\n document.body.style.overflow = 'hidden';\n\n const overlay = (\n <div className=\"aab-overlay\">\n <div className=\"aab-backdrop\" onClick={hardBlock ? undefined : handleDismiss} />\n <div className=\"aab-modal\">\n {children ? (\n children\n ) : (\n <>\n <div className=\"aab-icon\">\n <ShieldIcon />\n </div>\n <h2 className=\"aab-title\">{isBrave ? braveTitle : title}</h2>\n <p className=\"aab-description\">{isBrave ? braveDescription : description}</p>\n <div className=\"aab-buttons\">\n <button\n className=\"aab-btn-primary\"\n onClick={handleRecheck}\n disabled={isRechecking}\n >\n {isRechecking ? 'Checking...' : primaryButtonText}\n </button>\n {!hardBlock && (\n <button\n className=\"aab-btn-secondary\"\n onClick={handleDismiss}\n >\n {dismissButtonText}\n </button>\n )}\n </div>\n {!isBrave && (\n <p className=\"aab-tip\">\n <strong>Tip:</strong> {tipText}\n </p>\n )}\n </>\n )}\n </div>\n </div>\n );\n\n return createPortal(overlay, document.body);\n};\n\nexport function useAdBlockDetector(blockBrave: boolean = true) {\n const [result, setResult] = useState<DetectionResult | null>(null);\n const [loading, setLoading] = useState(true);\n\n useEffect(() => {\n detectAdBlocker(blockBrave).then((r) => {\n setResult(r);\n setLoading(false);\n });\n }, [blockBrave]);\n\n return {\n loading,\n detected: result?.detected ?? false,\n isBrave: result?.isBrave ?? false,\n strategies: result?.strategies ?? null,\n recheck: async () => {\n setLoading(true);\n const r = await detectAdBlocker(blockBrave);\n setResult(r);\n setLoading(false);\n return r;\n },\n };\n}\n","export interface DetectionResult {\n detected: boolean;\n isBrave: boolean;\n strategies: {\n baitElement: boolean;\n network: boolean;\n brave: boolean;\n };\n}\n\n/**\n * Strategy 1: The fastest and most reliable way - DOM Cosmetic Filtering\n */\nfunction detectViaDom(): Promise<boolean> {\n return new Promise((resolve) => {\n const container = document.createElement('div');\n container.innerHTML = `\n <div class=\"adsense ad-banner adsbox pub_300x250 pub_728x90 text-ad\" style=\"width: 1px; height: 1px;\">&nbsp;</div>\n <div class=\"ad-placement doubleclick sponsorship\" style=\"width: 1px; height: 1px;\">&nbsp;</div>\n `;\n \n container.style.cssText = 'position:absolute; top:-9999px; left:-9999px; width: 1px; height: 1px; overflow: hidden;';\n document.body.appendChild(container);\n\n setTimeout(() => {\n let blocked = false;\n const elements = container.children;\n \n for (let i = 0; i < elements.length; i++) {\n const el = elements[i] as HTMLElement;\n const styles = window.getComputedStyle(el);\n \n if (\n styles.display === 'none' ||\n styles.visibility === 'hidden' ||\n el.offsetHeight === 0\n ) {\n blocked = true;\n break;\n }\n }\n\n if (container.parentNode) {\n container.parentNode.removeChild(container);\n }\n \n resolve(blocked);\n }, 150);\n });\n}\n\n/**\n * Strategy 2: Fast Network Block Detection\n */\nfunction detectViaNetwork(): Promise<boolean> {\n return new Promise((resolve) => {\n // Note: uBlock Origin completely ignores blocking on 'localhost' by default in many configs\n const randomNum = Math.floor(Math.random() * 10000000);\n const testUrl = `https://ad.doubleclick.net/ddm/ad/N1234.12345.EXAMPLE/B1234567.123456789;sz=1x1?ord=${randomNum}`;\n\n fetch(testUrl, {\n method: 'HEAD',\n mode: 'no-cors',\n cache: 'no-store'\n })\n .then(() => resolve(false))\n .catch(() => resolve(true));\n\n setTimeout(() => resolve(false), 800);\n });\n}\n\n/**\n * Strategy 3: Dedicated Brave Browser Detection\n * Brave inherently blocks ads natively at the browser core level.\n */\nasync function detectViaBrave(): Promise<boolean> {\n const nav = navigator as any;\n if (nav.brave && typeof nav.brave.isBrave === 'function') {\n try {\n return await nav.brave.isBrave();\n } catch {\n return false;\n }\n }\n return false;\n}\n\n/**\n * Main Detection Function\n */\nexport async function detectAdBlocker(blockBrave: boolean = true): Promise<DetectionResult> {\n const [domBlocked, networkBlocked, isBrave] = await Promise.all([\n detectViaDom(),\n detectViaNetwork(),\n detectViaBrave()\n ]);\n\n const isDetected = domBlocked || networkBlocked || (blockBrave && isBrave);\n\n return {\n detected: isDetected,\n isBrave,\n strategies: {\n baitElement: domBlocked,\n network: networkBlocked,\n brave: isBrave\n }\n };\n}\n\n"],"mappings":"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","names":["index_exports","__export","AntiAdBlock","detectAdBlocker","useAdBlockDetector","__toCommonJS","import_react","import_react_dom","detectViaDom","resolve","container","blocked","elements","i","el","styles","detectViaNetwork","testUrl","detectViaBrave","nav","detectAdBlocker","blockBrave","domBlocked","networkBlocked","isBrave","import_jsx_runtime","ShieldIcon","AntiAdBlock","enabled","hardBlock","title","description","primaryButtonText","dismissButtonText","tipText","blockBrave","braveTitle","braveDescription","onDetected","onAllowed","onDismissed","children","delay","debug","isBlocked","setIsBlocked","showOverlay","setShowOverlay","isRechecking","setIsRechecking","isBrave","setIsBrave","timeout","result","detectAdBlocker","handleRecheck","handleDismiss","useAdBlockDetector","setResult","loading","setLoading","r"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,5 @@
1
+ import{useState as l,useEffect as N,useCallback as R}from"react";import{createPortal as L}from"react-dom";function E(){return new Promise(t=>{let e=document.createElement("div");e.innerHTML=`
2
+ <div class="adsense ad-banner adsbox pub_300x250 pub_728x90 text-ad" style="width: 1px; height: 1px;">&nbsp;</div>
3
+ <div class="ad-placement doubleclick sponsorship" style="width: 1px; height: 1px;">&nbsp;</div>
4
+ `,e.style.cssText="position:absolute; top:-9999px; left:-9999px; width: 1px; height: 1px; overflow: hidden;",document.body.appendChild(e),setTimeout(()=>{let a=!1,r=e.children;for(let i=0;i<r.length;i++){let n=r[i],d=window.getComputedStyle(n);if(d.display==="none"||d.visibility==="hidden"||n.offsetHeight===0){a=!0;break}}e.parentNode&&e.parentNode.removeChild(e),t(a)},150)})}function I(){return new Promise(t=>{let a=`https://ad.doubleclick.net/ddm/ad/N1234.12345.EXAMPLE/B1234567.123456789;sz=1x1?ord=${Math.floor(Math.random()*1e7)}`;fetch(a,{method:"HEAD",mode:"no-cors",cache:"no-store"}).then(()=>t(!1)).catch(()=>t(!0)),setTimeout(()=>t(!1),800)})}async function H(){let t=navigator;if(t.brave&&typeof t.brave.isBrave=="function")try{return await t.brave.isBrave()}catch{return!1}return!1}async function s(t=!0){let[e,a,r]=await Promise.all([E(),I(),H()]);return{detected:e||a||t&&r,isBrave:r,strategies:{baitElement:e,network:a,brave:r}}}import{Fragment as Y,jsx as o,jsxs as c}from"react/jsx-runtime";var O=()=>c("svg",{viewBox:"0 0 24 24",children:[o("path",{d:"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"}),o("line",{x1:"9",y1:"9",x2:"15",y2:"15"}),o("line",{x1:"15",y1:"9",x2:"9",y2:"15"})]}),U=({enabled:t=!0,hardBlock:e=!1,title:a="Ad Blocker Detected",description:r="We rely on advertising revenue to keep this website free for everyone. Please consider disabling your ad blocker to support us. We promise our ads are non-intrusive and respectful of your experience.",primaryButtonText:i="I've Disabled My Ad Blocker",dismissButtonText:n="Continue Without Disabling",tipText:d="After disabling your ad blocker, click the button above to refresh.",blockBrave:b=!0,braveTitle:P="Brave Browser Detected",braveDescription:C="Please use another browser. This website is not accessible with Brave Shields!",onDetected:y,onAllowed:v,onDismissed:k,children:w,delay:B=500,debug:p=!1})=>{let[z,m]=l(!1),[S,u]=l(!1),[A,f]=l(!1),[h,D]=l(!1);N(()=>{if(!t)return;if(p){m(!0),u(!0);return}let g;return(async()=>{let x=await s(b);x.detected&&(m(!0),x.isBrave&&D(!0),y?.(x),g=setTimeout(()=>u(!0),B))})(),()=>clearTimeout(g)},[t,B,y,p,b]);let M=R(async()=>{if(f(!0),p){setTimeout(()=>{f(!1)},1e3);return}(await s(b)).detected?f(!1):(m(!1),u(!1),D(!1),v?.(),window.location.reload())},[v,p,b]),T=R(()=>{e||(u(!1),k?.())},[e,k]);return!S||!z?null:(document.body.style.overflow="hidden",L(c("div",{className:"aab-overlay",children:[o("div",{className:"aab-backdrop",onClick:e?void 0:T}),o("div",{className:"aab-modal",children:w||c(Y,{children:[o("div",{className:"aab-icon",children:o(O,{})}),o("h2",{className:"aab-title",children:h?P:a}),o("p",{className:"aab-description",children:h?C:r}),c("div",{className:"aab-buttons",children:[o("button",{className:"aab-btn-primary",onClick:M,disabled:A,children:A?"Checking...":i}),!e&&o("button",{className:"aab-btn-secondary",onClick:T,children:n})]}),!h&&c("p",{className:"aab-tip",children:[o("strong",{children:"Tip:"})," ",d]})]})})]}),document.body))};function V(t=!0){let[e,a]=l(null),[r,i]=l(!0);return N(()=>{s(t).then(n=>{a(n),i(!1)})},[t]),{loading:r,detected:e?.detected??!1,isBrave:e?.isBrave??!1,strategies:e?.strategies??null,recheck:async()=>{i(!0);let n=await s(t);return a(n),i(!1),n}}}export{U as AntiAdBlock,s as detectAdBlocker,V as useAdBlockDetector};
5
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/AntiAdBlock.tsx","../src/detector.ts"],"sourcesContent":["import React, { useState, useEffect, useCallback } from 'react';\nimport { createPortal } from 'react-dom';\nimport { detectAdBlocker, type DetectionResult } from './detector';\nimport './styles.css';\n\nexport interface AntiAdBlockProps {\n enabled?: boolean;\n hardBlock?: boolean;\n title?: string;\n description?: string;\n primaryButtonText?: string;\n dismissButtonText?: string;\n tipText?: string;\n\n // New brave-specific props\n blockBrave?: boolean;\n braveTitle?: string;\n braveDescription?: string;\n\n onDetected?: (result: DetectionResult) => void;\n onAllowed?: () => void;\n onDismissed?: () => void;\n children?: React.ReactNode;\n delay?: number;\n debug?: boolean;\n}\n\nconst ShieldIcon: React.FC = () => (\n <svg viewBox=\"0 0 24 24\">\n <path d=\"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z\" />\n <line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\" />\n <line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\" />\n </svg>\n);\n\nexport const AntiAdBlock: React.FC<AntiAdBlockProps> = ({\n enabled = true,\n hardBlock = false,\n title = 'Ad Blocker Detected',\n description = \"We rely on advertising revenue to keep this website free for everyone. Please consider disabling your ad blocker to support us. We promise our ads are non-intrusive and respectful of your experience.\",\n primaryButtonText = \"I've Disabled My Ad Blocker\",\n dismissButtonText = 'Continue Without Disabling',\n tipText = 'After disabling your ad blocker, click the button above to refresh.',\n blockBrave = true,\n braveTitle = 'Brave Browser Detected',\n braveDescription = 'Please use another browser. This website is not accessible with Brave Shields!',\n onDetected,\n onAllowed,\n onDismissed,\n children,\n delay = 500,\n debug = false,\n}) => {\n const [isBlocked, setIsBlocked] = useState(false);\n const [showOverlay, setShowOverlay] = useState(false);\n const [isRechecking, setIsRechecking] = useState(false);\n const [isBrave, setIsBrave] = useState(false);\n\n useEffect(() => {\n if (!enabled) return;\n\n if (debug) {\n setIsBlocked(true);\n setShowOverlay(true);\n return;\n }\n\n let timeout: ReturnType<typeof setTimeout>;\n\n const runDetection = async () => {\n const result = await detectAdBlocker(blockBrave);\n if (result.detected) {\n setIsBlocked(true);\n if (result.isBrave) setIsBrave(true);\n onDetected?.(result);\n timeout = setTimeout(() => setShowOverlay(true), delay);\n }\n };\n\n runDetection();\n\n return () => clearTimeout(timeout);\n }, [enabled, delay, onDetected, debug, blockBrave]);\n\n const handleRecheck = useCallback(async () => {\n setIsRechecking(true);\n\n if (debug) {\n setTimeout(() => {\n setIsRechecking(false);\n }, 1000);\n return;\n }\n\n const result = await detectAdBlocker(blockBrave);\n\n if (!result.detected) {\n setIsBlocked(false);\n setShowOverlay(false);\n setIsBrave(false);\n onAllowed?.();\n window.location.reload();\n } else {\n setIsRechecking(false);\n }\n }, [onAllowed, debug, blockBrave]);\n\n const handleDismiss = useCallback(() => {\n if (hardBlock) return;\n setShowOverlay(false);\n onDismissed?.();\n }, [hardBlock, onDismissed]);\n\n if (!showOverlay || !isBlocked) return null;\n\n document.body.style.overflow = 'hidden';\n\n const overlay = (\n <div className=\"aab-overlay\">\n <div className=\"aab-backdrop\" onClick={hardBlock ? undefined : handleDismiss} />\n <div className=\"aab-modal\">\n {children ? (\n children\n ) : (\n <>\n <div className=\"aab-icon\">\n <ShieldIcon />\n </div>\n <h2 className=\"aab-title\">{isBrave ? braveTitle : title}</h2>\n <p className=\"aab-description\">{isBrave ? braveDescription : description}</p>\n <div className=\"aab-buttons\">\n <button\n className=\"aab-btn-primary\"\n onClick={handleRecheck}\n disabled={isRechecking}\n >\n {isRechecking ? 'Checking...' : primaryButtonText}\n </button>\n {!hardBlock && (\n <button\n className=\"aab-btn-secondary\"\n onClick={handleDismiss}\n >\n {dismissButtonText}\n </button>\n )}\n </div>\n {!isBrave && (\n <p className=\"aab-tip\">\n <strong>Tip:</strong> {tipText}\n </p>\n )}\n </>\n )}\n </div>\n </div>\n );\n\n return createPortal(overlay, document.body);\n};\n\nexport function useAdBlockDetector(blockBrave: boolean = true) {\n const [result, setResult] = useState<DetectionResult | null>(null);\n const [loading, setLoading] = useState(true);\n\n useEffect(() => {\n detectAdBlocker(blockBrave).then((r) => {\n setResult(r);\n setLoading(false);\n });\n }, [blockBrave]);\n\n return {\n loading,\n detected: result?.detected ?? false,\n isBrave: result?.isBrave ?? false,\n strategies: result?.strategies ?? null,\n recheck: async () => {\n setLoading(true);\n const r = await detectAdBlocker(blockBrave);\n setResult(r);\n setLoading(false);\n return r;\n },\n };\n}\n","export interface DetectionResult {\n detected: boolean;\n isBrave: boolean;\n strategies: {\n baitElement: boolean;\n network: boolean;\n brave: boolean;\n };\n}\n\n/**\n * Strategy 1: The fastest and most reliable way - DOM Cosmetic Filtering\n */\nfunction detectViaDom(): Promise<boolean> {\n return new Promise((resolve) => {\n const container = document.createElement('div');\n container.innerHTML = `\n <div class=\"adsense ad-banner adsbox pub_300x250 pub_728x90 text-ad\" style=\"width: 1px; height: 1px;\">&nbsp;</div>\n <div class=\"ad-placement doubleclick sponsorship\" style=\"width: 1px; height: 1px;\">&nbsp;</div>\n `;\n \n container.style.cssText = 'position:absolute; top:-9999px; left:-9999px; width: 1px; height: 1px; overflow: hidden;';\n document.body.appendChild(container);\n\n setTimeout(() => {\n let blocked = false;\n const elements = container.children;\n \n for (let i = 0; i < elements.length; i++) {\n const el = elements[i] as HTMLElement;\n const styles = window.getComputedStyle(el);\n \n if (\n styles.display === 'none' ||\n styles.visibility === 'hidden' ||\n el.offsetHeight === 0\n ) {\n blocked = true;\n break;\n }\n }\n\n if (container.parentNode) {\n container.parentNode.removeChild(container);\n }\n \n resolve(blocked);\n }, 150);\n });\n}\n\n/**\n * Strategy 2: Fast Network Block Detection\n */\nfunction detectViaNetwork(): Promise<boolean> {\n return new Promise((resolve) => {\n // Note: uBlock Origin completely ignores blocking on 'localhost' by default in many configs\n const randomNum = Math.floor(Math.random() * 10000000);\n const testUrl = `https://ad.doubleclick.net/ddm/ad/N1234.12345.EXAMPLE/B1234567.123456789;sz=1x1?ord=${randomNum}`;\n\n fetch(testUrl, {\n method: 'HEAD',\n mode: 'no-cors',\n cache: 'no-store'\n })\n .then(() => resolve(false))\n .catch(() => resolve(true));\n\n setTimeout(() => resolve(false), 800);\n });\n}\n\n/**\n * Strategy 3: Dedicated Brave Browser Detection\n * Brave inherently blocks ads natively at the browser core level.\n */\nasync function detectViaBrave(): Promise<boolean> {\n const nav = navigator as any;\n if (nav.brave && typeof nav.brave.isBrave === 'function') {\n try {\n return await nav.brave.isBrave();\n } catch {\n return false;\n }\n }\n return false;\n}\n\n/**\n * Main Detection Function\n */\nexport async function detectAdBlocker(blockBrave: boolean = true): Promise<DetectionResult> {\n const [domBlocked, networkBlocked, isBrave] = await Promise.all([\n detectViaDom(),\n detectViaNetwork(),\n detectViaBrave()\n ]);\n\n const isDetected = domBlocked || networkBlocked || (blockBrave && isBrave);\n\n return {\n detected: isDetected,\n isBrave,\n strategies: {\n baitElement: domBlocked,\n network: networkBlocked,\n brave: isBrave\n }\n };\n}\n\n"],"mappings":"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","names":["useState","useEffect","useCallback","createPortal","detectViaDom","resolve","container","blocked","elements","el","styles","detectViaNetwork","testUrl","detectViaBrave","nav","detectAdBlocker","blockBrave","domBlocked","networkBlocked","isBrave","Fragment","jsx","jsxs","ShieldIcon","AntiAdBlock","enabled","hardBlock","title","description","primaryButtonText","dismissButtonText","tipText","blockBrave","braveTitle","braveDescription","onDetected","onAllowed","onDismissed","children","delay","debug","isBlocked","setIsBlocked","useState","showOverlay","setShowOverlay","isRechecking","setIsRechecking","isBrave","setIsBrave","useEffect","timeout","result","detectAdBlocker","handleRecheck","useCallback","handleDismiss","createPortal","useAdBlockDetector","setResult","loading","setLoading","r"]}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "anti-adblock-detector",
3
+ "version": "1.0.0",
4
+ "description": "A powerful, lightweight anti-adblock detection library for React and Vanilla JS. Detects ad blockers with multiple strategies and shows a professional, customizable overlay.",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "exports": {
12
+ ".": {
13
+ "import": "./dist/index.mjs",
14
+ "require": "./dist/index.js",
15
+ "types": "./dist/index.d.ts"
16
+ },
17
+ "./styles.css": "./dist/index.css"
18
+ },
19
+ "scripts": {
20
+ "build": "tsup src/index.ts --format cjs,esm --dts --minify --sourcemap --clean",
21
+ "dev": "tsup src/index.ts --format cjs,esm --watch --dts",
22
+ "lint": "tsc"
23
+ },
24
+ "keywords": [
25
+ "adblock",
26
+ "anti-adblock",
27
+ "adblock-detector",
28
+ "ad-blocker",
29
+ "monetization",
30
+ "react",
31
+ "typescript"
32
+ ],
33
+ "author": "Antigravity",
34
+ "license": "MIT",
35
+ "peerDependencies": {
36
+ "react": ">=16.8.0",
37
+ "react-dom": ">=16.8.0"
38
+ },
39
+ "devDependencies": {
40
+ "@types/react": "^18.3.28",
41
+ "@types/react-dom": "^18.3.7",
42
+ "tsup": "^8.5.1",
43
+ "typescript": "^5.9.3"
44
+ }
45
+ }