No description
  • TypeScript 91%
  • JavaScript 8.6%
  • CSS 0.3%
Find a file
github.sudoku 261f659f5c fix(sanitizer): allow <kbd> elements; refresh release-feed fixture
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>
2026-05-09 12:21:26 +02:00
.claude/skills/new-release docs: update /new-release skill with screenshot step + bento style guide 2026-04-19 13:09:42 +02:00
.husky test: add pre-commit hook + folder test coverage 2026-04-06 20:09:26 +02:00
api refactor: move release notes feed to feedzero.app 2026-04-11 23:02:40 +02:00
docs fix: restore E2E test suite — 75/76 desktop, 0 failures 2026-03-29 21:27:27 +02:00
public feat: prepare for public alpha launch 2026-03-22 16:30:42 +01:00
scripts feat: v0.2.0 — Explore tab, feed catalog, and UX overhaul 2026-03-25 10:44:58 +01:00
src fix(sanitizer): allow <kbd> elements; refresh release-feed fixture 2026-05-09 12:21:26 +02:00
tests fix(sanitizer): allow <kbd> elements; refresh release-feed fixture 2026-05-09 12:21:26 +02:00
.gitignore fix: replace api/*.ts content in-place with esbuild bundles for Vercel 2026-02-04 13:06:55 +01:00
.mcp.json fix: sidebar UI polish — fixed-width buttons, smaller font, kbd hints 2026-02-04 20:12:42 +01:00
CLAUDE.md docs: fix stale paths and drifting test counts in CLAUDE.md 2026-04-19 17:46:09 +02:00
components.json feat: feed switching validation, keyboard nav, and UI enhancements 2026-02-04 19:59:28 +01:00
CONTRIBUTING.md docs: add privacy architecture, security policy, and contributing guide 2026-02-07 12:19:48 +01:00
feedzero-screenshot.png chore: add screenshot script and landing page screenshot 2026-03-22 16:54:50 +01:00
index.html fix: add safe-area insets for iPhone Dynamic Island / notch 2026-04-17 20:08:42 +02:00
package-lock.json feat: replace mobile sidebar with persistent swipeable bottom drawer 2026-05-02 07:28:30 +02:00
package.json release: bump version to 0.8.0, update release feed fixture 2026-05-09 12:12:43 +02:00
playwright.config.js test: comprehensive structural assertion and E2E test suite 2026-02-04 15:53:32 +01:00
README.md docs: add privacy architecture, security policy, and contributing guide 2026-02-07 12:19:48 +01:00
SECURITY.md fix: allow external HTTPS images in Content-Security-Policy 2026-03-28 19:54:57 +01:00
server.ts refactor: move release notes feed to feedzero.app 2026-04-11 23:02:40 +02:00
tsconfig.json feat: migrate UI to React + TypeScript + Zustand + React Router 2026-02-01 09:57:33 +01:00
vercel.json fix: allow external HTTPS images in Content-Security-Policy 2026-03-28 19:54:57 +01:00
vite.config.js refactor: move release notes feed to feedzero.app 2026-04-11 23:02:40 +02:00
vitest.config.js test: comprehensive structural assertion and E2E test suite 2026-02-04 15:53:32 +01:00

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)

  1. Open Settings → Data & Storage
  2. Enable cloud sync
  3. 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