{"_id":"@d-i-t-a/web-content-protection","_rev":"4-dbe4e92e568e5c546c3fed48e78111e4","name":"@d-i-t-a/web-content-protection","dist-tags":{"latest":"1.1.1"},"versions":{"1.0.0":{"name":"@d-i-t-a/web-content-protection","version":"1.0.0","keywords":["drm","content-protection","ebook","reader","copy-protection","print-protection","obfuscation","web-reader"],"author":{"url":"DITA","name":"AM Consulting LLC"},"license":"Apache-2.0","_id":"@d-i-t-a/web-content-protection@1.0.0","maintainers":[{"name":"aferditamuriqi","email":"aferdita.muriqi@gmail.com"}],"homepage":"https://github.com/d-i-t-a/web-content-protection#readme","bugs":{"url":"https://github.com/d-i-t-a/web-content-protection/issues"},"dist":{"shasum":"a7b1174e688d9107fd6016494ff9eda0cd591731","tarball":"https://registry.npmjs.org/@d-i-t-a/web-content-protection/-/web-content-protection-1.0.0.tgz","fileCount":9,"integrity":"sha512-GSmjEyOm6FhgbW5tWtbCxD0Q2u2ygpHCm51ebUrZ6A3cDMwaBVX423nAGxS/EgzYL5JFX9xxsSAKlGO2db5Yzw==","signatures":[{"sig":"MEYCIQC7Og6tJDajplav4nqj2+yJ2Ic5npbgtVjyw2VRhDd1HAIhAP3vwnf6q86u+Yq/zSPPXhMPtHsYJauG/2LVBe/18RTi","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":576201},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"gitHead":"a112549307a5acdc89243670af42e0c53768d2c3","scripts":{"dev":"tsup --watch","demo":"npm run build && npx serve . -l 3456 --no-clipboard","build":"tsup","prepublishOnly":"npm run build"},"_npmUser":{"name":"aferditamuriqi","email":"aferdita.muriqi@gmail.com"},"repository":{"url":"git+https://github.com/d-i-t-a/web-content-protection.git","type":"git"},"_npmVersion":"10.9.4","description":"Client-side content protection for web-based ebook readers. Drag prevention, copy protection, print blocking, text obfuscation, DevTools detection, and more.","directories":{},"_nodeVersion":"22.21.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","typescript":"^5.5.0"},"optionalDependencies":{"devtools-detector":"^2.0.14","browserslist-useragent-regexp":"^4.1.3"},"_npmOperationalInternal":{"tmp":"tmp/web-content-protection_1.0.0_1774011690329_0.43831545893315527","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@d-i-t-a/web-content-protection","version":"1.0.1","keywords":["drm","content-protection","ebook","reader","copy-protection","print-protection","obfuscation","web-reader"],"author":{"url":"DITA","name":"AM Consulting LLC"},"license":"Apache-2.0","_id":"@d-i-t-a/web-content-protection@1.0.1","maintainers":[{"name":"aferditamuriqi","email":"aferdita.muriqi@gmail.com"}],"homepage":"https://github.com/d-i-t-a/web-content-protection#readme","bugs":{"url":"https://github.com/d-i-t-a/web-content-protection/issues"},"dist":{"shasum":"2836ae75df669f6f7530f22e725903e12072e337","tarball":"https://registry.npmjs.org/@d-i-t-a/web-content-protection/-/web-content-protection-1.0.1.tgz","fileCount":9,"integrity":"sha512-1UIBY/X++E7a7aLKmurrYQCd9+gXdFXNVKZxZ+5ZstKHB/t2UwYt1Lhk3rLxfHYwHenCdyKvdj986/epfUCSHg==","signatures":[{"sig":"MEUCIAkaoahd70KJL4Uv2S166ZeMTSKk/suOz5HoxLkssrIgAiEAgjs9NFEhaCm6yajcV7goX1Sfc54ODSoT2USPAh4akCg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":579312},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"gitHead":"2b3882442e0d3f09f03de9cf468a17a0670a2e3d","scripts":{"dev":"tsup --watch","demo":"npm run build && npx serve . -l 3456 --no-clipboard","lint":"eslint src/","build":"tsup","format":"prettier --write 'src/**/*.ts'","lint:fix":"eslint src/ --fix","format:check":"prettier --check 'src/**/*.ts'","prepublishOnly":"npm run lint && npm run build"},"_npmUser":{"name":"aferditamuriqi","email":"aferdita.muriqi@gmail.com"},"repository":{"url":"git+https://github.com/d-i-t-a/web-content-protection.git","type":"git"},"_npmVersion":"10.9.4","description":"Client-side content protection for web-based ebook readers. Drag prevention, copy protection, print blocking, text obfuscation, DevTools detection, and more.","directories":{},"_nodeVersion":"22.21.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","eslint":"^10.1.0","prettier":"^3.8.1","typescript":"^5.5.0","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.5","@typescript-eslint/parser":"^8.57.1","@typescript-eslint/eslint-plugin":"^8.57.1"},"optionalDependencies":{"devtools-detector":"^2.0.14","browserslist-useragent-regexp":"^4.1.3"},"_npmOperationalInternal":{"tmp":"tmp/web-content-protection_1.0.1_1774108675140_0.017394732884097097","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@d-i-t-a/web-content-protection","version":"1.1.0","keywords":["drm","content-protection","ebook","reader","copy-protection","print-protection","obfuscation","web-reader"],"author":{"url":"DITA","name":"AM Consulting LLC"},"license":"Apache-2.0","_id":"@d-i-t-a/web-content-protection@1.1.0","maintainers":[{"name":"aferditamuriqi","email":"aferdita.muriqi@gmail.com"}],"homepage":"https://github.com/d-i-t-a/web-content-protection#readme","bugs":{"url":"https://github.com/d-i-t-a/web-content-protection/issues"},"dist":{"shasum":"8facee23c3eb13226ecb1c472472090f87bced8f","tarball":"https://registry.npmjs.org/@d-i-t-a/web-content-protection/-/web-content-protection-1.1.0.tgz","fileCount":9,"integrity":"sha512-vKX0FIfgxuOlFnanczk+qNhxw8x1QuSmKQ/x8gEJBO73y2jbCMgjtPpCWn4FeGachRMPA41GLrMPGnfBE+a8FA==","signatures":[{"sig":"MEYCIQC06GsaHFeDAukn5Frd6zIieyNvcS5R68tFScjnK/xP/wIhAJyrC4+ruM/B3T5hAOhsL+qEb1lV6ktGjeVpcHA3eLSP","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@d-i-t-a%2fweb-content-protection@1.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":605283},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"gitHead":"5ae5163380cc1bf462ba1525119e1696e97fd02e","scripts":{"dev":"tsup --watch","demo":"npm run build && npx serve . -l 3456 --no-clipboard","lint":"eslint src/","build":"tsup","format":"prettier --write 'src/**/*.ts'","lint:fix":"eslint src/ --fix","format:check":"prettier --check 'src/**/*.ts'","prepublishOnly":"npm run lint && npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:655c1941-f7ec-409a-9c73-e60e80722b94"}},"repository":{"url":"git+https://github.com/d-i-t-a/web-content-protection.git","type":"git"},"_npmVersion":"11.11.0","description":"Client-side content protection for web-based ebook readers. Drag prevention, copy protection, print blocking, text obfuscation, DevTools detection, and more.","directories":{},"_nodeVersion":"24.14.1","publishConfig":{"registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","eslint":"^10.1.0","prettier":"^3.8.1","typescript":"^5.5.0","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.5","@typescript-eslint/parser":"^8.57.1","@typescript-eslint/eslint-plugin":"^8.57.1"},"optionalDependencies":{"devtools-detector":"^2.0.14","browserslist-useragent-regexp":"^4.1.3"},"_npmOperationalInternal":{"tmp":"tmp/web-content-protection_1.1.0_1776275368673_0.18007532261260262","host":"s3://npm-registry-packages-npm-production"}},"1.1.1":{"name":"@d-i-t-a/web-content-protection","version":"1.1.1","description":"Client-side content protection for web-based ebook readers. Drag prevention, copy protection, print blocking, text obfuscation, DevTools detection, and more.","author":{"name":"AM Consulting LLC","url":"DITA"},"license":"Apache-2.0","type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"scripts":{"build":"tsup","dev":"tsup --watch","demo":"npm run build && npx serve . -l 3456 --no-clipboard","lint":"eslint src/","lint:fix":"eslint src/ --fix","format":"prettier --write 'src/**/*.ts'","format:check":"prettier --check 'src/**/*.ts'","prepublishOnly":"npm run lint && npm run build"},"devDependencies":{"@typescript-eslint/eslint-plugin":"^8.57.1","@typescript-eslint/parser":"^8.57.1","eslint":"^10.1.0","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.5","prettier":"^3.8.1","tsup":"^8.0.0","typescript":"^5.5.0"},"optionalDependencies":{"browserslist-useragent-regexp":"^4.1.3","devtools-detector":"^2.0.14"},"keywords":["drm","content-protection","ebook","reader","copy-protection","print-protection","obfuscation","web-reader"],"repository":{"type":"git","url":"git+https://github.com/d-i-t-a/web-content-protection.git"},"publishConfig":{"registry":"https://registry.npmjs.org/"},"gitHead":"1b3bbb82c42f4d77167de832ac9bc26a7d6d4944","_id":"@d-i-t-a/web-content-protection@1.1.1","bugs":{"url":"https://github.com/d-i-t-a/web-content-protection/issues"},"homepage":"https://github.com/d-i-t-a/web-content-protection#readme","_nodeVersion":"24.14.1","_npmVersion":"11.11.0","dist":{"integrity":"sha512-Dlod39CD+jAF7cJzWg7HZwURkmZorMn1cegnQ6ElKz8uSTU09bTuybDheDvmig6XN+3lxxMoC28ElxvMlUcoBw==","shasum":"a972731970d79020542a482ffa007f71dadc8fc6","tarball":"https://registry.npmjs.org/@d-i-t-a/web-content-protection/-/web-content-protection-1.1.1.tgz","fileCount":9,"unpackedSize":607699,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@d-i-t-a%2fweb-content-protection@1.1.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCID2PiSA5EX1I2sl2OcNlYod2Wp6YALtsx0U6XHDx1KMpAiAtYxHQY94z5VnnPCsWs/iZpErnSiO8aa946VkGu2hU6g=="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:655c1941-f7ec-409a-9c73-e60e80722b94"}},"directories":{},"maintainers":[{"name":"aferditamuriqi","email":"aferdita.muriqi@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/web-content-protection_1.1.1_1776351109378_0.2861110370016491"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-20T13:01:30.183Z","modified":"2026-04-16T14:51:49.876Z","1.0.0":"2026-03-20T13:01:30.501Z","1.0.1":"2026-03-21T15:57:55.288Z","1.1.0":"2026-04-15T17:49:28.828Z","1.1.1":"2026-04-16T14:51:49.529Z"},"bugs":{"url":"https://github.com/d-i-t-a/web-content-protection/issues"},"author":{"name":"AM Consulting LLC","url":"DITA"},"license":"Apache-2.0","homepage":"https://github.com/d-i-t-a/web-content-protection#readme","keywords":["drm","content-protection","ebook","reader","copy-protection","print-protection","obfuscation","web-reader"],"repository":{"type":"git","url":"git+https://github.com/d-i-t-a/web-content-protection.git"},"description":"Client-side content protection for web-based ebook readers. Drag prevention, copy protection, print blocking, text obfuscation, DevTools detection, and more.","maintainers":[{"name":"aferditamuriqi","email":"aferdita.muriqi@gmail.com"}],"readme":"# @d-i-t-a/web-content-protection\n\nClient-side content protection for web-based ebook readers. Framework-agnostic, zero required dependencies, tree-shakable.\n\n## Table of Contents\n\n- [Install](#install)\n- [Demo](#demo)\n- [Quick Start](#quick-start)\n- [Modules](#modules)\n- [Standalone Module Usage](#standalone-module-usage)\n- [Copy Protection Modes](#copy-protection-modes)\n- [Text Obfuscation](#text-obfuscation)\n- [Watermarking](#watermarking)\n- [Image Protection](#image-protection)\n- [Anti-Automation Detection](#anti-automation-detection)\n- [Speech Synthesis Blocking](#speech-synthesis-blocking)\n- [Content Expiration](#content-expiration)\n- [Clipboard Attribution](#clipboard-attribution)\n- [Media Protection](#media-protection)\n- [Media Stream Protection](#media-stream-protection)\n- [Tamper Detection](#tamper-detection)\n- [Screenshot Detection](#screenshot-detection)\n- [Page Navigation](#page-navigation)\n- [Event Logging](#event-logging)\n- [Integration Notes](#integration-notes)\n- [License](#license)\n\n## Install\n\n```bash\nnpm install @d-i-t-a/web-content-protection\n```\n\nOptional dependencies for enhanced features:\n\n```bash\nnpm install devtools-detector              # Better DevTools detection\nnpm install browserslist-useragent-regexp   # Accurate browser enforcement\n```\n\n## Demo\n\nAn interactive demo is included that lets you toggle each module on/off and test protections in real time.\n\n```bash\ngit clone https://github.com/d-i-t-a/web-content-protection.git\ncd web-content-protection\nnpm install\nnpm run demo\n```\n\nThen open [http://localhost:3456/demo/](http://localhost:3456/demo/) in your browser.\n\nThe demo simulates a book reader with:\n- **Left sidebar** — toggle each of the 19 modules on/off\n- **Center** — sample book content with active protections\n- **Right panel** — highlights & notes panel (also protected)\n- **Bottom** — live event log showing every blocked action\n- **Toolbar** — test buttons for copy, print, select-all, and innerText dump\n\nTry right-clicking, Ctrl+C, Ctrl+P, dragging text, or opening DevTools to see the protections in action.\n\n## Quick Start\n\nUse the `ContentProtection` orchestrator to enable multiple protections at once:\n\n```typescript\nimport { ContentProtection } from \"@d-i-t-a/web-content-protection\";\n\nconst contentEl = document.getElementById(\"reader-content\")!;\nconst iframes = Array.from(document.querySelectorAll(\"iframe\")) as HTMLIFrameElement[];\n\nconst protection = new ContentProtection({\n  onEvent: (e) => console.log(`[Protection] ${e.type}`, e.detail),\n\n  dragPrevention: { contentElement: contentEl, contentIframes: iframes },\n  printProtection: { contentElement: contentEl, contentIframes: iframes },\n  copyProtection: { contentElement: contentEl, contentIframes: iframes, mode: \"block\" },\n  contextMenuProtection: { contentElement: contentEl, contentIframes: iframes },\n  keyboardProtection: { contentElement: contentEl, contentIframes: iframes },\n  devToolsDetection: { action: \"redirect\" },\n  textObfuscation: {\n    scrollContainer: contentEl,\n    contentRoot: contentEl,\n    contentIframes: iframes,\n  },\n});\n\nawait protection.activate();\n```\n\n## Modules\n\nEach module can be used standalone or through the orchestrator.\n\n| Module | What it does |\n|--------|-------------|\n| **DragPrevention** | Blocks text/image drag-and-drop to external apps |\n| **PrintProtection** | Hides content on print (CSS + event-based + keyboard) |\n| **CopyProtection** | Blocks or restricts clipboard operations (block / character-limited modes) |\n| **ContextMenuProtection** | Disables right-click context menu |\n| **KeyboardProtection** | Blocks Save, View Source, DevTools, F12, and custom key combos |\n| **DevToolsDetection** | Detects open DevTools; can redirect, clear storage, or fire callback |\n| **TextObfuscation** | Scrambles text outside viewport in main document and iframes; supports scrolling and paginated layouts; DOM dumps return gibberish |\n| **LinkUrlHiding** | Hides link target URLs from status bar |\n| **BrowserEnforcement** | Restricts to whitelisted browsers |\n| **ScreenshotDetection** | Blanks content on tab blur / visibility change / PrintScreen |\n| **Watermarking** | Invisible visual + zero-width-character watermarks for leak tracing |\n| **SelectionLimiting** | Caps how much text can be selected at once |\n| **ImageProtection** | Blocks right-click save, drag, open-in-new-tab on images; optional canvas rendering |\n| **AntiAutomation** | Detects Puppeteer, Playwright, Selenium, headless browsers |\n| **SpeechSynthesisBlocking** | Blocks or restricts `speechSynthesis.speak()` to prevent TTS extraction |\n| **ContentExpiration** | Time-limited viewing sessions with optional extension |\n| **MediaProtection** | Protects `<audio>` and `<video>` elements — hides download button, blob URLs, blocks right-click, disables PiP |\n| **MediaStreamProtection** | Blocks MediaRecorder, AudioContext capture, and `captureStream()` on protected elements |\n| **TamperDetection** | Detects screen grabber CSS injection + DOM tampering via hidden sentinels; blanks content on detection |\n\n## Standalone Module Usage\n\n```typescript\nimport { CopyProtection } from \"@d-i-t-a/web-content-protection\";\n\nconst copy = new CopyProtection({\n  contentElement: document.getElementById(\"reader\")!,\n  mode: \"restrict\",\n  maxCharacters: 200,\n  onEvent: (e) => console.log(e),\n});\n\ncopy.activate();\n```\n\n## Copy Protection Modes\n\n### Block all copying\n```typescript\ncopyProtection: { contentElement: el, mode: \"block\" }\n```\n\n### Allow limited copying (citations)\n```typescript\ncopyProtection: { contentElement: el, mode: \"restrict\", maxCharacters: 200 }\n```\n\n### Citation bypass\n```typescript\n// Temporarily allow full copy for citation workflow\nprotection.copyProtection!.citationMode = true;\n// ... user copies citation ...\nprotection.copyProtection!.citationMode = false;\n```\n\n## Text Obfuscation\n\nThe most effective client-side protection. All text outside the visible viewport is scrambled. A `document.body.innerText` dump returns gibberish. Supports both scrolling and paginated (CSS columns + translateX) layouts.\n\n```typescript\ntextObfuscation: {\n  scrollContainer: readerFrame,\n  contentRoot: readerFrame,\n  contentIframes: [iframe],       // obfuscates text inside iframes\n  excludeNodes: [\"script\", \"style\", \"code\"],\n  viewportPadding: 50,\n}\n```\n\nCall `reinitialize()` on page/chapter changes:\n```typescript\nprotection.textObfuscation!.reinitialize();\n```\n\nCall `recalculate()` after page turns in paginated layouts:\n```typescript\nprotection.textObfuscation!.recalculate();\n```\n\nCall `scrambleAll()` to permanently scramble all text (requires page refresh to undo):\n```typescript\nprotection.textObfuscation!.scrambleAll();\n```\n\nWhen `devToolsDetection` is enabled, `scrambleAll()` is called automatically when DevTools is detected.\n\n## Watermarking\n\nTwo-layer watermarking for leak tracing:\n\n1. **Visual**: Near-invisible overlay with user ID + timestamp. Survives screenshots.\n2. **Text fingerprint**: Zero-width Unicode characters injected into text. Survives copy-paste.\n\n```typescript\nwatermarking: {\n  contentRoot: bodyEl,\n  userId: \"user-12345\",\n  sessionId: \"session-abc\",\n  enableTextFingerprint: true,\n}\n```\n\nDecode a fingerprint from leaked text:\n```typescript\nimport { Watermarking } from \"@d-i-t-a/web-content-protection\";\n\nconst userId = Watermarking.decodeFingerprint(leakedText);\nconsole.log(`Leaked by: ${userId}`);\n```\n\n## Image Protection\n\nPrevents image extraction via right-click, drag, and open-in-new-tab.\n\n```typescript\nimageProtection: {\n  contentRoot: bodyEl,\n  disablePointerEvents: true,  // blocks right-click \"Save image as...\"\n  overlayMode: true,           // transparent overlay above images\n  blockDrag: true,             // prevents drag to desktop/other apps\n  canvasMode: false,           // replace <img> with <canvas> (strongest)\n  blobUrls: false,             // convert src to blob URLs (hides original URL)\n}\n```\n\n## Anti-Automation Detection\n\nDetects headless browsers and automation frameworks (Selenium, Puppeteer, Playwright).\n\n```typescript\nantiAutomation: {\n  action: \"block\",             // \"block\" | \"warn\" | \"callback\"\n  detectWebDriver: true,       // navigator.webdriver flag\n  detectHeadless: true,        // HeadlessChrome, missing plugins, etc.\n  detectAutomationProps: true,  // framework-specific globals\n  recheckInterval: 5000,       // re-check every 5s (automation can be injected late)\n}\n```\n\n## Speech Synthesis Blocking\n\nPrevents text extraction via the Web Speech API (`speechSynthesis.speak()`).\n\n```typescript\nspeechSynthesisBlocking: {\n  mode: \"block\",               // \"block\" all or \"restrict\" to maxCharacters\n  maxCharacters: 500,          // only used in \"restrict\" mode\n}\n```\n\n## Content Expiration\n\nTime-limited viewing sessions. Content blanks or redirects when the session expires.\n\n```typescript\ncontentExpiration: {\n  protectedElements: [contentEl],\n  sessionDuration: 3600000,    // 1 hour\n  warningBefore: 300000,       // warn 5 min before\n  action: \"blank\",             // \"blank\" | \"redirect\" | \"callback\"\n  allowExtension: true,        // user can extend session\n  maxExtensions: 3,\n  extensionDuration: 1800000,  // 30 min per extension\n  onWarning: (ms) => showToast(`Session expires in ${ms/1000}s`),\n  onExpired: () => showModal(\"Session expired\"),\n}\n```\n\nExtend programmatically:\n```typescript\nprotection.contentExpiration!.extend(); // returns false if max extensions reached\n```\n\n## Clipboard Attribution\n\nAppends source attribution to any copied text (in \"restrict\" mode):\n\n```typescript\ncopyProtection: {\n  contentElement: el,\n  mode: \"restrict\",\n  maxCharacters: 200,\n  attribution: \"Copied from 'Book Title' — © Publisher Name\",\n  attributionSeparator: \"\\n\\n—\\n\",\n}\n```\n\n## Media Protection\n\nProtects `<audio>` and `<video>` elements embedded in EPUB3 or any HTML content. Especially relevant for enriched ebooks, educational content, and audiobook previews.\n\n```typescript\nmediaProtection: {\n  contentRoot: bodyEl,\n  hideDownloadButton: true,     // CSS-hides the native download button\n  blobUrls: true,               // converts src to blob: URLs (hides original URL)\n  blockContextMenu: true,       // blocks right-click \"Save audio/video as...\"\n  enforceNoDownload: true,      // sets controlslist=\"nodownload\"\n  disablePictureInPicture: true, // prevents PiP on video elements\n  protectSourceUrls: true,      // intercepts currentSrc getter\n  detectRecording: false,       // detect virtual audio devices (heuristic)\n}\n```\n\n## Media Stream Protection\n\nBlocks JavaScript-based stream capture — MediaRecorder, AudioContext routing, and `captureStream()`.\n\n```typescript\nmediaStreamProtection: {\n  contentRoot: bodyEl,\n  blockMediaRecorder: true,     // blocks new MediaRecorder() on protected streams\n  blockAudioCapture: true,      // blocks createMediaElementSource() routing\n  blockCaptureStream: true,     // blocks captureStream() on media + canvas\n}\n```\n\nThese two modules are designed for EPUB3 media content rendered inside a web reader. The audio/video files end up as `<audio>`/`<video>` elements in the DOM — same context as the text, same protection surface.\n\n## Tamper Detection\n\nDetects screen grabber extensions (GoFullPage, Nimbus, Awesome Screenshot, etc.) that inject CSS styles onto DOM elements to time their captures. Places invisible sentinel elements throughout the content and watches for style injection via mutation observers and periodic computed-style checks.\n\n```typescript\ntamperDetection: {\n  protectedElements: [contentEl, annotationsPanel],\n  contentRoot: bodyEl,\n  sentinelCount: 3,              // distribute 3 sentinels in content\n  action: \"blank\",               // \"blank\" | \"scramble\" | \"callback\"\n  autoRestore: true,             // restore when tampering stops\n  restoreDelay: 2000,            // wait 2s before restoring\n}\n```\n\nDetects:\n- Inline style injection on sentinel elements (animation, transition, transform, filter, etc.)\n- Computed style anomalies from CSS rule injection (class/id-based)\n- Sentinel removal from DOM\n\n## Screenshot Detection\n\nBlanks content when the tab loses focus or visibility changes (common when using screenshot tools).\n\n```typescript\nscreenshotDetection: {\n  protectedElements: [contentEl, annotationsPanel],\n  blankOnBlur: true,\n  blankOnHidden: true,\n  detectPrintScreen: true,\n  restoreDelay: 500,\n}\n```\n\n## Page Navigation\n\nWhen the reader navigates to a new page or chapter, reinitialize content-dependent modules:\n\n```typescript\nreader.on(\"pageChange\", () => {\n  protection.textObfuscation?.reinitialize();\n  protection.watermarking?.reinitialize();\n});\n```\n\n## Event Logging\n\nAll protection events are logged:\n\n```typescript\nconst events = protection.getEventLog();\n// Send to analytics\nanalytics.track(\"content_protection_events\", events);\n```\n\n## Integration Notes\n\n### Finding the right elements\n\n| Reader Architecture | Content Target | Scroll Target |\n|---------------------|---------------|---------------|\n| iframe-based | `iframe.contentDocument.body` | `iframe.contentDocument.documentElement` |\n| Shadow DOM | `shadowRoot.querySelector('.content')` | Shadow host or inner scroller |\n| Direct injection | `.reader-content` | Same element or parent |\n\n### Adding iframes dynamically\n\nIf iframes are loaded after page init, deactivate and re-activate with new references:\n\n```typescript\nprotection.deactivate();\n// Update config with new iframes\nconst newProtection = new ContentProtection({ ...config, contentIframes: newIframes });\nawait newProtection.activate();\n```\n\n## License\n\nApache-2.0 — Copyright 2018-2026 DITA (AM Consulting LLC)\n","readmeFilename":"README.md"}