Skip to content

Releases: juherr/kill-the-news

v0.3.1

25 May 17:02
d778849

Choose a tag to compare

Fixed

  • Feed self link (RSS/Atom/JSON) is derived from the configured domain instead
    of the request host — it no longer leaks the workers.dev host when a feed is
    reached directly, and now matches the alternate link.

v0.3.0

25 May 16:15
0f18d4c

Choose a tag to compare

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 EmailAddress value object (DDD cleanup)
  • Release version is derived from the git tag (main carries a -develop suffix; CI strips it and guards against tagging the wrong commit)

Full Changelog: v0.2.1...v0.3.0

v0.2.1

24 May 15:48
97ce9a6

Choose a tag to compare

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.txt disallows /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-srcsrc, 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 EmailAddress value object (siteBaseUrl); domain/layering cleanup.

Full changelog: v0.2.0...v0.2.1

v0.2.0

24 May 13:00
b002f8a

Choose a tag to compare

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/stats is now the canonical public stats endpoint (JSON + CORS); the deprecated /api/stats has 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.ico 404.
  • Close type-check gaps in client scripts and tooling.

📚 Documentation

  • Extracted setup/deploy/config into INSTALL.md.
  • Added SECURITY.md and CONTRIBUTING.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/ into domain/ (framework-agnostic), application/ (use-cases), infrastructure/ (KV/R2, HTTP, logging) and routes/ (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

22 May 21:51
24c7d2a

Choose a tag to compare

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 Link header; 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_DOMAIN env 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.news on every push to main, 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.js to 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