ReviewOS

chris/very-good-adblock

Build STX-powered Chrome MV3 Adblock extension

#1
Closed chris opened this 8 days ago ·
8 days ago

Summary

Build a polished Chrome Manifest V3 ad blocker named Adblock using Bun + STX, with a premium extension UI, balanced blocking behavior, local/sync stats, and first-class YouTube and X/Twitter cleanup.

Principles

  • Use STX for extension UI pages; no React.
  • Keep all extension-page behavior in external bundled TypeScript modules for MV3 CSP compatibility.
  • Use bundled static DNR rules plus dynamic local user/site rules; no remote updater in v1.
  • Keep blocking balanced and maintainable: DNR, cosmetic cleanup, YouTube/X content scripts, skip-button automation where available, and no brittle video media hacks.
  • Store no telemetry and make estimated data/time savings clear.
  • Push small conventional commits as chrisbbreuer with no Co-authored-by trailers.

Foundation

  • Scaffold Bun TypeScript project.
  • Install @stacksjs/stx and bun-plugin-stx as proper package dependencies.
  • Add src/, pages/, components/, rules/, scripts/, public/, and generated dist/ structure.
  • Generate Chrome MV3 manifest.json into dist/.
  • Build popup/options STX pages into extension-safe HTML.
  • Bundle background service worker, content scripts, popup script, and options script.
  • Add package script and docs for creating an extension zip.

Blocking Engine

  • Generate and validate static declarativeNetRequest rules.
  • Add curated pinned filter attribution in NOTICE.md.
  • Add dynamic DNR rules for per-site allowlist/blocklist and user overrides.
  • Implement site protection state with default-on protection.
  • Handle YouTube ad containers, overlays, companion ad slots, Shorts fixtures, and skip buttons.
  • Handle X/Twitter promoted posts and noisy ad containers across home/search/profile fixtures.
  • Add generic cosmetic filtering with mutation-observer performance guardrails.

Metrics And Storage

  • Store compact settings and lifetime totals in chrome.storage.sync.
  • Store hourly/daily rings and per-site rollups in chrome.storage.local.
  • Track content-script block events.
  • Reconcile recent and active-tab DNR matched-rule telemetry where Chrome exposes it.
  • Estimate data saved by resource category.
  • Estimate video minutes saved from detected/skipped video-ad durations.
  • Add reset and export flows.

Popup UI

  • Premium glass visual system with restrained depth and responsive popup sizing.
  • Protection toggle and current-site state.
  • Today and lifetime blocked counts.
  • Estimated data saved and estimated video minutes saved.
  • Top categories and mini timeline chart.
  • Quick allowlist/site controls.
  • Loading, empty, error, disabled, and no-active-tab states.

Options Dashboard

  • Dashboard overview with history charts.
  • Filter/ruleset status and diagnostics.
  • Site rules management for allowlisted and manually blocked sites.
  • Privacy/settings controls.
  • Export/reset controls.
  • Build/version information.

QA

  • bun test passes.
  • bun run typecheck passes.
  • bun run build passes.
  • bun run package creates a zip artifact.
  • Generated DNR JSON validates.
  • MV3 artifact validation passes with referenced files, PNG icons, and CSP-safe extension HTML.
  • Chrome unpacked extension loads without manifest/CSP errors in Playwright Chromium.
  • Smoke test: ad-heavy page, YouTube watch page, YouTube Shorts, X/Twitter home/search/profile fixtures.
  • Smoke test: per-site pause/resume, reset/export, popup/options responsiveness and overflow checks.

Implemented Commit Chunks

  1. Project scaffold, STX/Bun build pipeline, manifest generation, popup/options, zip script.
  2. Static and dynamic DNR rules pipeline, allowlist model, rule validation tests.
  3. Background service worker, storage schema, sync/local metrics service, badge/current-tab accounting.
  4. Content scripts for cosmetic filtering, YouTube, X/Twitter, video-ad detection, and performance throttling.
  5. Polished STX popup UI with live stats, controls, charts, and states.
  6. Options/dashboard UI, settings, history, diagnostics, export/reset.
  7. QA pass, docs, packaged extension artifact, final push.
  8. Pinned EasyList/AdGuard host-rule generation, DNR telemetry, richer site-rule controls, and expanded Chromium smoke coverage.

Verification Evidence

  • Latest verified commit: 738ad88 (fix: install stx package dependency).
  • CI run: https://github.com/chrisbbreuer/adblock/actions/runs/28330429892
  • CI passed: lint, test, typecheck, build, static DNR validation, MV3 artifact validation, package, and Chromium smoke.
  • Local smoke passed with: generic=3, youtube=3, shorts=3, x=6, allowed=0, resumed=3, popup>=15, dashboard>=15.
8 days ago

Implemented initial STX-powered Chrome MV3 extension scaffold.

Completed locally:

  • Bun + TypeScript project using ts-starter-style tooling and CI shape.
  • STX popup and options/dashboard pages with MV3-safe external scripts.
  • Generated MV3 manifest and static DNR ruleset.
  • Dynamic allowlist/blocklist rule model.
  • Background service worker for settings, sync/local stats, badge state, reset/export, and runtime messages.
  • Content script cleanup for generic ad containers, YouTube, X/Twitter, and video skip events.
  • Premium popup/dashboard UI with charts, site controls, settings, diagnostics, export, and reset.
  • NOTICE/README and unit tests for rules, metrics, and domain helpers.

Validation run:

  • bun run typecheck
  • bun test
  • bun run lint
  • bun run build
  • bun run validate:rules
  • bun run package

Remaining follow-up for a future pass:

  • Manual Chrome unpacked-extension smoke test.
  • Broader pinned upstream filter ingestion with exact source/version attribution.
  • Store-grade PNG icon generation if preparing Chrome Web Store submission.
8 days ago

E2E verification update for b04ed54 (test: expand extension smoke coverage).

Local verification passed:

  • bun run typecheck
  • bun test
  • bun run lint
  • bun run build
  • bun run validate:rules
  • bun run validate:extension
  • bun run package
  • bun run smoke:chrome

Local browser smoke loaded the unpacked extension in Playwright Chromium and verified:

  • generic cosmetic filtering hid 3 fixture ad elements
  • YouTube-specific cleanup hid 3 fixture ad elements and clicked the skip-ad button
  • X/Twitter-specific cleanup hid 2 promoted/tracking fixture elements
  • popup stats showed 9 blocked items
  • options dashboard stats showed 9 blocked items

Remote GitHub Actions run also passed all jobs: lint, test, typecheck, build, static DNR validation, MV3 artifact validation, package, and Chromium smoke.

CI run: https://github.com/chrisbbreuer/adblock/actions/runs/28330000221

8 days ago

Corrected STX setup per latest feedback: removed the hardcoded /Users/chris/Code/Tools/stx/... plugin path and installed @stacksjs/stx as a proper package dependency alongside bun-plugin-stx.

Verification for latest commit 738ad88 passed locally and remotely. GitHub Actions is green for lint, test, typecheck, build, rules validation, MV3 artifact validation, package, and Chromium smoke.

CI: https://github.com/chrisbbreuer/adblock/actions/runs/28330429892

8 days ago

Dependency and smoke-harness correction

Implemented the follow-up cleanup requested after the full build:

  • Removed the direct @stacksjs/stx dependency from adblock; bun-plugin-stx is now the only STX runtime dependency in the extension project, with @stacksjs/stx coming transitively.
  • Updated /Users/chris/Code/Tools/stx/packages/bun-plugin/package.json so bun-plugin-stx declares @stacksjs/stx and stx-router as normal semver dependencies instead of workspace-only dependencies. Pushed to stacksjs/stx as 3d7bdcac24.
  • Removed Playwright from adblock dependencies and CI.
  • Replaced the old Playwright smoke test with a Bun WebView harness that exercises:
    • built popup/options pages through the real bundles with an MV3-safe Chrome API shim,
    • generic cosmetic filtering,
    • YouTube watch and Shorts cleanup plus skip automation,
    • X/Twitter promoted-content cleanup,
    • popup toggles, allowlist interaction, chart/data rendering,
    • options dashboard add/remove, export, reset, desktop/mobile overflow checks,
    • screenshot generation via Bun.WebView.screenshot().

Local verification after the change:

bun run typecheck
bun test
bun run validate:rules
bun run validate:extension
bun run package
bun run lint
bun run smoke:chrome

Smoke result:

Bun WebView smoke tested Adblock: generic=3 youtube=3 shorts=3 x=6 popup=21 dashboard=1287 screenshots=/Users/chris/Code/adblock/temp/smoke-screenshots

Adblock commit: c3fb087 test: replace playwright smoke with bun webview.

Note: bun-plugin-stx build passes after the metadata change. Its existing typecheck target currently fails on unrelated monorepo rootDir include errors, and its test target points at a missing ../../test-utils/happy-dom.ts preload from the plugin package path.

8 days ago

CI passed for commit c3fb087: run 28330851678 completed successfully across lint, typecheck, tests, build, rule validation, extension validation, package, and Bun WebView smoke.

8 days ago

Cached YouTube skip regression

Added a deterministic YouTube-like watch-page regression backed by /Users/chris/Code/Libraries/ts-web-scraper:

  • Improved ts-web-scraper so its cache can be constructed with defaults and its parser can see custom elements/hyphenated attributes like ytd-display-ad-renderer, ytd-watch-flexy, video-id, and data-ad-slot.
  • Added scripts/cache-youtube-fixture.ts, which uses the local scraper cache to validate/cache a YouTube-shaped fixture and writes test/fixtures/youtube-watch.cached.html for deterministic offline/CI tests.
  • Added a Bun WebView test that serves the cached fixture as https://www.youtube.com/..., injects the real built content script, and asserts a skip button nested inside .video-ads is clicked before containers are hidden.
  • Improved the YouTube content cleanup order so skip-button automation runs before hiding YouTube ad containers.
  • Scoped bun run test to the project tests to avoid unrelated vendored pantry/ package tests.

Local verification:

bun run test
bun run typecheck
bun run build
bun run smoke:chrome
bun run validate:rules
bun run validate:extension
bun run package
bun run lint

Scraper verification:

bun test test/cache.test.ts test/index.test.ts
bun run typecheck
bun run build

Commits:

  • stacksjs/ts-web-scraper@7a30638 fix: support custom element scraping
  • chrisbbreuer/adblock@734898c test: cache youtube skip regression
8 days ago

CI passed for cached YouTube regression commit 734898c: run 28336568609 completed successfully across lint, typecheck, scoped Bun tests including the cached YouTube skip regression, build, validation, package, and Bun WebView smoke.

8 days ago

Cloud stats sync for fresh installs

Added compact Chrome cloud sync for stats so a new Chrome install can hydrate the dashboard after the user signs into Chrome sync.

Implemented:

  • New cloudStats payload in chrome.storage.sync containing:
    • lifetime blocked/data/video-time totals,
    • last 60 daily buckets,
    • top 20 site rollups,
    • schema version and sync timestamp.
  • Local hydration on startup/install from the cloud snapshot into chrome.storage.local.
  • Sync-change hydration when Chrome delivers cloudStats after the background worker is already running.
  • Merge-by-max behavior for lifetime totals, daily buckets, and site rollups to avoid double-counting replayed cloud snapshots.
  • Dashboard diagnostics for cloud sync status, daily history count, and site rollup count.
  • Tests verifying bounded snapshot size under Chrome sync item limits, fresh-install hydration, and no double-counting.

Local verification:

bun run test
bun run typecheck
bun run build
bun run smoke:chrome
bun run validate:rules
bun run validate:extension
bun run package
bun run lint

Commit: 98bdac0 feat: sync compact stats through chrome cloud.

8 days ago

CI passed for cloud stats sync commit 98bdac0: run 28337186477 completed successfully across lint, typecheck, scoped Bun tests, build, rule validation, extension validation, package, and Bun WebView smoke.

Sign in to comment on this issue.