Releases: juherr/kill-the-news
v0.3.1
v0.3.0
Highlights
Native feed detection
Kill-the-news now inspects incoming newsletters for a self-advertised Atom/RSS/JSON feed (rel=alternate links in the email HTML) and stores the discovered feeds per sender on the Feed aggregate. If a newsletter already publishes a real feed, you can subscribe to it directly — surfaced as chips on the feed detail page, a dashboard pill, and (read-only) on the REST Feed schema, with a dismissable notice.
Subscription confirmation surfacing
Confirmation emails ("click to confirm your subscription") are detected at ingestion and flagged on the feed. The admin UI surfaces the confirmation link, a badge, a dashboard pill, and an inline banner so a pending double-opt-in never gets silently stuck — all dismissable. Tightened to cut false positives via a weak-signal heuristic.
Read/write identity decoupling (privacy)
The public read id (FeedId, used in /rss/:feedId) is now fully decoupled from the inbound email address (MailboxId, noun.noun.NN). A feed's read URL never reveals its inbound alias and vice-versa — reading /rss/<noun.noun.NN> 404s.
Reader compatibility
- JSON Feed 1.1 output (
/json/:feedId) - OPML export of all feeds (
/admin/opml) - Conditional GET (ETag / Last-Modified / 304) on the feed routes
Admin & API
- Per-feed Subscribe chips for RSS/Atom/JSON with copy / open / validate actions, reused across dashboard and feed detail page
- Email detail page links to its public entry page
- Land on the feed's emails page right after creation
- Optional per-feed "sender in title" toggle
- Running version shown in the admin/status footer,
/health, and/api/v1/stats
Internal & release
- Sender display name, site URL and parsing now owned by the
EmailAddressvalue object (DDD cleanup) - Release version is derived from the git tag (
maincarries a-developsuffix; CI strips it and guards against tagging the wrong commit)
Full Changelog: v0.2.1...v0.3.0
v0.2.1
Reader-rendering correctness, privacy hardening, and a catch-all fallback for self-hosters.
Privacy
- Feed, entry, and attachment responses now send
X-Robots-Tag: noindex, and a new/robots.txtdisallows/rss,/atom,/entries,/files, and/admin— private feeds and emails stay out of search engines.
Feed rendering (works reliably in strict readers)
- Relative links/images in email bodies are absolutized against the sender's site.
- Lazy-loaded images are promoted (
data-src→src,loading="lazy"stripped) so they don't render blank. - Feed
<title>is plain text (HTML stripped, entities decoded). - XML-illegal control characters are stripped from generated feeds (emoji and other valid astral characters preserved).
Self-hosting
- Optional
FALLBACK_FORWARD_ADDRESS: forward non-feed mail to a verified address so you can point a domain's catch-all at kill-the-news without swallowing personal mail. Forwarded mail is counted in the stats dashboard.
Internal
- Sender-site derivation moved onto the
EmailAddressvalue object (siteBaseUrl); domain/layering cleanup.
Full changelog: v0.2.0...v0.2.1
v0.2.0
This release adds a versioned REST API, full attachment support (R2), per-feed favicons, one-click unsubscribe, and a redesigned landing/status page — on top of a large internal refactor toward a clean domain-driven architecture.
✨ Features
REST API & OpenAPI
- New versioned REST API (
/api/v1/feeds*) with an OpenAPI 3.1 spec (/api/openapi.json) and rendered reference docs via Scalar (/api/docs). /api/v1/statsis now the canonical public stats endpoint (JSON + CORS); the deprecated/api/statshas been removed.
Attachments (Cloudflare R2)
- Optional R2 attachment storage with a config toggle, storage metrics on the status page, and a demo configuration.
- Attachments are listed with download links on the email view and the admin email detail page; a paperclip indicator flags emails that carry attachments.
- Inline
cid:images are now rendered in place inside the email/feed body instead of being shown as separate attachments.
Favicons
- Project favicon served from the envelope logo (
/favicon.svg,/favicon.ico). - Per-feed favicon derived from the last sender's domain (
/favicon/:feedId), falling back to the project icon.
Feeds
- RFC 8058 one-click unsubscribe dispatched when a feed is deleted.
Landing & status page
- Redesigned status page: hero, themed sections, responsive layout, FAQ.
- Live counter moved above the demo banner; CTAs point to the demo; feature cards for the REST API and auto-expiring feeds.
Admin UX
- Status-page link added to the dashboard header.
- Create-feed form collapsed into an accordion to declutter the dashboard.
🐛 Fixes
- Render inline
cid:images correctly in emails and feeds. - Purge R2 attachments when bulk-deleting emails via the no-JS path.
- Add a landing-page favicon to fix the
/favicon.ico404. - Close type-check gaps in client scripts and tooling.
📚 Documentation
- Extracted setup/deploy/config into
INSTALL.md. - Added
SECURITY.mdandCONTRIBUTING.md. - README: continuous-deployment section (CI secrets) and a note on the R2 permission needed for scoped deploy tokens.
- License: added Julien Herr copyright alongside the original author.
🏗️ Internal / Architecture
A substantial refactor toward domain-driven design (no behavior change for users):
- Split
src/intodomain/(framework-agnostic),application/(use-cases),infrastructure/(KV/R2, HTTP, logging) androutes/(HTTP edge). - Introduced the Feed aggregate as the single write path for feed config + the email index, with domain events (
FeedCreated,EmailIngested) driving side effects (counters, WebSub, favicon). - Consolidated all KV access behind repository adapters (
FeedRepository,IconRepository,WebSubSubscriptionRepository,CountersRepository) and a single key schema. - Added value objects (
FeedId,EmailAddress,Domain,SenderPolicy,Lifetime) and a domain/persistence translation seam (feed-mapper).
Full changelog: v0.1.0...v0.2.0
v0.1.0
What's new
Features vs kill-the-newsletter upstream
- Atom feed format — feeds are now available at `atom/:feedId
(application/atom+xml) in addition to RSS 2.0, with correct,, and HTML` elements. - WebSub push notifications — Atom and RSS feeds advertise a WebSub hub via
Linkheader; subscribers receive real-time push notifications on new emails instead of polling. - HTML email processing — email bodies are sanitized via
linkedom+escape-html(XSS prevention, MSO style stripping, plain-text fallback). - Email attachments as RSS enclosures — attachments are stored in Cloudflare R2 and served at
/files/:attachmentId/:filename, exposed as<enclosure>in RSS and<link rel="enclosure">in Atom. - Sender blocklist — block/allow senders by exact address or domain, with 4-level priority matching. Quick-add dropdown directly from the emails list.
EMAIL_DOMAINenv var — separate web domain and email domain.- Authelia / reverse-proxy auth — trusted header support (
Remote-User,X-Forwarded-User) for delegating admin auth to an external identity provider. - Demo environment — auto-deployed to
demo.kill-the.newson every push tomain, with a nightly KV reset.
Admin UI
- Full redesign: Inter font, orange theme, site header/footer, Atom feed links, unified container width.
- Scripts extracted to
src/scripts/client/and compiled via esbuild. - Templates migrated to
hono/jsx.
Infrastructure & CI
- Release action builds and attaches
dist/index.jsto each GitHub release. - Cloudflare WAF rate limiting documented (no code changes required).
- Dependabot updates: Hono 4.12, Zod 4.4, actions/checkout v6, actions/setup-node v6.
Known limitation
- Race condition on concurrent emails — two emails arriving simultaneously for the same feed can overwrite each other in KV. Fix planned via Durable Objects (see TODO).
Full Changelog: upstream...v0.1.0