- TypeScript 91%
- JavaScript 8.6%
- CSS 0.3%
What - The release feed used <kbd> tags for keyboard shortcuts (e.g. "press <kbd>j</kbd>"), but the DOMPurify allowlist did not include <kbd>. The tag was being stripped from rendered articles, showing plain text "j" instead of a styled key cap. Why - ALLOWED_TAGS was missing <kbd>. <kbd> is a standard HTML5 element with no script-execution risk; the omission was an oversight. Fix - Add "kbd" to ALLOWED_TAGS in sanitizer.ts. - Refresh tests/fixtures/release-feed.xml to the latest landing-side output (which now correctly preserves <code> and <kbd> tags after the build-releases.mjs whitelist fix on the landing repo). Prevention - Add a sanitizer unit test that asserts <kbd> survives sanitization. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|---|---|---|
| .claude/skills/new-release | ||
| .husky | ||
| api | ||
| docs | ||
| public | ||
| scripts | ||
| src | ||
| tests | ||
| .gitignore | ||
| .mcp.json | ||
| CLAUDE.md | ||
| components.json | ||
| CONTRIBUTING.md | ||
| feedzero-screenshot.png | ||
| index.html | ||
| package-lock.json | ||
| package.json | ||
| playwright.config.js | ||
| README.md | ||
| SECURITY.md | ||
| server.ts | ||
| tsconfig.json | ||
| vercel.json | ||
| vite.config.js | ||
| vitest.config.js | ||
FeedZero
A privacy-first RSS reader that runs entirely in your browser. No accounts, no tracking, no analytics. Your reading habits stay yours.
What It Does
- Subscribes to RSS, Atom, and JSON Feed sources
- Stores all data encrypted in your browser (AES-GCM-256)
- Optionally syncs across devices with end-to-end encryption
- Extracts full article text when feeds provide only summaries
- Works offline after first load
Privacy Model
FeedZero minimizes server-side data exposure:
| Component | What the server sees |
|---|---|
| Feed fetching | Feed URLs (required for CORS proxy) |
| Cloud sync | Encrypted blob + vault ID (cannot decrypt without your passphrase) |
| Everything else | Nothing — parsing, storage, and rendering happen in-browser |
No telemetry. No analytics. No crash reporting. No third-party tracking.
For the full threat model, cryptographic details, and honest limitations, see docs/architecture.md.
Trust Considerations
The CORS proxy is a trust point. It must see feed URLs to fetch them. If you don't trust the hosted version, you can self-host the entire stack.
Quick Start
npm install
npm run dev
Open http://localhost:3000. Add a feed URL. That's it.
Usage
Adding Feeds
Paste any URL into the "Add feed" input:
- Direct feed URL:
https://example.com/feed.xml - Website URL: FeedZero will discover the feed automatically
Keyboard Navigation
| Key | Action |
|---|---|
j / k |
Next / previous item |
Enter |
Open selected item |
Escape |
Go back |
Cloud Sync (Optional)
- Open Settings → Data & Storage
- Enable cloud sync
- Save your 4-word passphrase — it's the only way to access your data
Your passphrase never leaves your browser. The server stores only encrypted blobs.
OPML Import/Export
- Import: Settings → Import OPML → select file
- Export: Settings → Export OPML → downloads your feed list
Development
npm test # Unit/integration tests (Vitest)
npm run test:watch # Watch mode
npm run test:coverage # Coverage report (90% threshold)
npm run test:e2e # E2E tests (Playwright)
npx tsc --noEmit # Type check
Project Structure
src/
├── core/ # Framework-agnostic business logic
│ ├── feeds/ # Feed fetching, parsing, refresh
│ ├── parser/ # RSS/Atom/JSON Feed parsing
│ ├── storage/ # IndexedDB + encryption
│ ├── sync/ # E2E encrypted cloud sync
│ └── extractor/ # Full-text extraction
├── stores/ # Zustand state management
├── components/ # React UI components
└── pages/ # Route components
See docs/architecture.md for detailed architecture documentation.
Self-Hosting
FeedZero can run entirely on your own infrastructure:
npm run build:all
npm run serve
This starts a standalone Hono server with all API endpoints. Point your reverse proxy at it.
For Vercel deployment, git push to a connected repository. The api/ directory contains serverless function wrappers.
Tech Stack
- UI: React 19, TypeScript, Tailwind CSS v4
- State: Zustand
- Storage: Dexie.js (IndexedDB), Web Crypto API
- Parsing: Custom RSS/Atom/JSON Feed parser
- Sanitization: DOMPurify
- Extraction: Defuddle
- Testing: Vitest, Playwright, React Testing Library
Security
Found a vulnerability? See SECURITY.md for reporting guidelines.
Contributing
See CONTRIBUTING.md for development workflow and guidelines.
License
MIT