Surface the xExtension-KillTheNews integration as a differentiator on
the marketing landing page.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Separate the two feed identities so the public read URL never reveals the
inbound address and vice-versa:
- FeedId becomes an opaque high-entropy token (read id + KV key); MailboxId
(noun.noun.NN) owns the inbound address and the untrusted-input boundary
via MailboxId.parse. They map only through the inbound:<mailbox> secondary
index, resolved solely at reception.
- inbound index lifecycle is owned by FeedRepository: written by save/saveConfig,
dropped by removeFromList(Bulk) — symmetric, never mirrored by hand (removes the
manual delete in feed-service + the cron loop, and a silent empty-catch).
- Feed.mailboxId exposes a MailboxId VO (symmetry with Feed.id); the
mailbox@domain shape lives on MailboxId.emailAddress(domain).
- Distinguish mailbox_unknown (no feed claims the address) from feed_not_found
(dangling index) for observability; both forwardable, both 404.
- Drop the redundant EmailParser.extractMailbox pass-through so MailboxId.parse
is the single parse boundary.
Docs (README/INSTALL/CLAUDE.md/landing) and tests updated; 439 tests green,
tsc clean, build dry-run OK.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Batch of four reader-facing improvements (TODO "Compat lecteurs + dedup"):
- JSON Feed at /json/:feedId (feed lib .json1()); all formats cross-link
- OPML export at /admin/opml (admin-protected; the registry lists every
feed URL, so it must not be public)
- Conditional GET on /rss + /atom: strong ETag + Last-Modified, 304 on
If-None-Match/If-Modified-Since, validators shared via http-cache.ts
- Duplicate-send dedup in ingestion: match by Message-ID, fall back to a
SHA-256 of normalized subject+content; a duplicate is a no-op and bumps
the new emails_deduplicated counter (status page + /api/v1/stats)
429 tests green, tsc clean, build dry-run OK. Docs (README/CLAUDE/TODO +
landing cards) updated.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Surface the feed TTL / auto-deletion capability on the landing page,
framed as a disposable temporary-mailbox use case.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Surface the new versioned REST API on the marketing landing, linking to the
live Scalar reference on the demo.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Unify the monitoring stats on the versioned API: /api/v1/stats is now public
(no auth) and CORS-enabled, mirroring the legacy /api/stats. The marketing
landing (docs/index.html) now fetches /api/v1/stats; /api/stats is kept as a
deprecated alias for existing monitors. Feed/email routes remain token-gated.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add an ATTACHMENTS_ENABLED switch (default on when R2 is bound) via a
central getAttachmentBucket helper, surface R2 + estimated KV usage
against the free tier on the status page and /api/stats (refreshed by the
hourly cron), let setup.sh create and wire the R2 bucket, and bind the
demo bucket so the deployed demo has attachments.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Capture each sender's List-Unsubscribe one-click URL during ingestion
(stored per sender in feed metadata, mirroring the iconDomain pattern) and
fire one-click POSTs via ctx.waitUntil when a feed is deleted, so newsletters
stop mailing the now-dead address. Tracked with a new unsubscribes_sent
counter surfaced on the status page and /api/stats.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Resolve each feed's most recent sender domain and serve its favicon at
GET /favicon/:feedId, falling back to the project icon. Icons are fetched
in the background on ingestion (direct /favicon.ico then a DuckDuckGo
fallback), cached base64 in KV keyed by domain with a 1-week TTL so the
fetch only fires when absent. Exposed via RSS <image> / Atom <icon>/<logo>
and rendered in the admin feed list, plus a landing-page feature card.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add a native details/summary accordion FAQ inspired by kill-the-newsletter,
rewritten for self-hosted differentiators; drop /admin from the demo URL.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Surface the live stats counter directly under the hero, ahead of the
"Try it live" banner. Demo CTAs (hero + banner) now open the demo root
instead of /admin so visitors land on the public status page first.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Fix the install step grid track (48px minmax(0,1fr)) so wide code blocks
and the WAF table no longer blow out the page width on mobile. Transpose
the WAF rate-limit table to a vertical layout (endpoints as columns,
settings as rows) and reclaim horizontal space with tighter mobile
padding.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add a "Live from the demo instance" section to the landing page that
fetches feeds_created and emails_received from the demo /api/stats and
counts them up on scroll into view. Make /api/stats publicly readable
(CORS *) and refresh the stale allowlist origins to kill-the.news.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Fix menu path: Security → Security rules (not Security → WAF)
- Add free tier limitations note: 1 rule max, 10s period/block cap
- Show recommended vs free tier limits side by side in table
- Remove HTTP method filter from conditions (not available in rate limiting rules)
- Note Terraform supports method filtering and longer periods (paid plan)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- docs/index.html: nav links (Features/How it works/Install), hero CTAs
(Try demo primary, Self-host, GitHub), demo banner with credentials,
full 7-step installation section with WAF rate limiting guide (dashboard
+ Terraform) integrated as step 7
- wrangler-example.toml: cron trigger on demo env for nightly KV reset at 03:00 UTC
- src/index.ts: scheduled handler that wipes all EMAIL_STORAGE KV keys
- TODO.md: mark WAF rate limiting as done
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Rename all references from Email-to-RSS/email-to-rss to kill-the-news
across README.md, AGENTS.md, package.json, wrangler-example.toml, setup.sh
- Add docs/index.html: dark-themed landing page for GitHub Pages
covering features, how it works, quick start, and tech stack
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>