A local-first PWA that proxies web novel chapters through a headless Chromium browser, strips ads and Cloudflare bot protection, and serves clean distraction-free content on mobile.
- Cloudflare bypass — Playwright headless Chromium with anti-detection flags and stealth user agent
- Surgical DOM extraction — Cheerio pruning targeting
.epcontent,.entry-content,.reading-content - Auto-pagination — "Next Chapter" button reads the site's next-chapter link before pruning
- SQLite cache — instant re-reads; chapters persist across restarts
- Manual URL input — paste any chapter URL directly in the home page
- PWA Share Target — share URLs from your mobile browser's share sheet directly to ProseProxy
- Three reading themes — Light (warm cream), Sepia (amber), Dark (ink black); persisted across sessions
- Lora serif typography — comfortable long-form reading experience
- GoatCounter analytics — optional, production-only, anonymous event tracking
git clone <repo>
cd ProseProxy
npm install
npx playwright install chromium # one-time browser download
npm run dev # http://localhost:3000Open http://localhost:3000, paste a chapter URL, and read.
Mobile Share / URL input
│
▼
GET /api/share (App Router) ← extracts URL, redirects to /read
│
▼
/read?url=… (App Router page) ← client component, POSTs to API
│
▼
POST /api/fetch-chapter (Pages Router API)
├─ cache hit → return from novels.db instantly
└─ cache miss → Playwright → Cheerio → INSERT → return JSON
Dual router: src/app/ is App Router (UI + /api/share). pages/api/ is Pages Router (/api/fetch-chapter) — required because Playwright and SQLite are incompatible with serverless/Edge runtimes.
npm run dev # dev server with hot reload
npm run build # production build (type-checks)
npm start # serve production build
npm run lint # ESLint
npm test # Jest unit + API integration tests
npm run test:e2e # Playwright E2E tests (requires running server)
npm run test:e2e:ui # Playwright interactive test UIHosted locally, exposed via Cloudflare Tunnel — no Vercel/PaaS (Playwright and SQLite need a persistent runtime). See deploy/README.md for tunnel setup and systemd services.
For a quick temporary public URL (no account needed):
npm run build && npm start &
cloudflared tunnel --url http://localhost:3000Add to .env.local to enable GoatCounter in production:
NEXT_PUBLIC_GOATCOUNTER_URL=https://your-site.goatcounter.com/count
Events tracked: chapter fetches, errors, next-chapter taps, theme changes. No personal data.
docs/developer-guide.md— architecture, extraction pipeline, testing, DB schemadocs/user-manual.md— installation, reading, themes, troubleshootingdocs/configure_prose-ithinkandicode-space.md— Cloudflare Tunnel + Porkbun DNS setupdocs/adr/— Architecture Decision Records