mirror of
https://github.com/juherr/kill-the-news.git
synced 2026-06-20 22:03:48 +00:00
7297e06b94
linkedom escapes & in text nodes but not in attribute values, so URLs with query strings (?a=1&b=2) serialized with bare ampersands. Valid XML inside the feed CDATA, but the W3C validator parses the embedded HTML and warns "Named entity expected. Got none." on <description>/<content:encoded> (RSS) and <summary>/<content> (Atom). Escape every & not already starting a valid entity; covers all three formats via processEmailContent. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
6.4 KiB
6.4 KiB
Changelog
All notable changes to this project are documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Keep the ## [Unreleased] section up to date as part of every change (the
same rule as the rest of the docs). At release time npm run release X.Y.Z
promotes this section to ## [X.Y.Z] and the Release workflow publishes it
verbatim as the GitHub Release notes — so what you write here is what ships.
Unreleased
Fixed
- Subscription-confirmation detection now recognises a confirm email whose CTA button carries the subscribe/subscription hint only in its visible text (e.g. "Yes, subscribe me to this mailing list.") over an opaque tracking-redirect href — previously the link scored zero and the email was missed.
- Sender favicons now recover from a transient miss: a failed favicon lookup is cached negatively for 6 hours instead of a full week, so a domain whose icon was momentarily unavailable (e.g. not yet indexed upstream) is retried on the next email instead of staying blank for days.
- Feed entry HTML now escapes bare ampersands in attribute URLs (e.g. query
strings like
?a=1&b=2), clearing the W3C feed validator's "Named entity expected. Got none." warning and improving interoperability with stricter feed readers.
0.3.1 - 2026-05-25
Fixed
- Feed self link (RSS/Atom/JSON) is derived from the configured domain instead
of the request host — it no longer leaks the
workers.devhost when a feed is reached directly, and now matches the alternate link.
0.3.0 - 2026-05-25
Added
- Native feed detection — incoming newsletters are inspected for a
self-advertised Atom/RSS/JSON feed (
rel=alternatelinks in the email HTML); discovered feeds are stored per sender on the Feed aggregate and surfaced as chips on the feed detail page, a dashboard pill, and (read-only) on the RESTFeedschema, 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 (all dismissable), tightened against false positives via a weak-signal heuristic.
- JSON Feed 1.1 output (
/json/:feedId). - OPML export of all feeds (
/admin/opml). - Conditional GET (ETag / Last-Modified / 304) on the feed routes.
- 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.
Changed
- Read/write identity decoupling (privacy) — the public read id (
FeedId, used in/rss/:feedId) is 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). - Sender display name, site URL and parsing now owned by the
EmailAddressvalue object (DDD cleanup). - Release version is derived from the git tag; CI guards against tagging the wrong commit.
0.2.1 - 2026-05-24
Added
- Optional
FALLBACK_FORWARD_ADDRESS: forward non-feed mail to a verified address so a domain catch-all can point at kill-the-news without swallowing personal mail (forwarded mail is counted in the stats dashboard).
Changed
- Feed, entry, and attachment responses send
X-Robots-Tag: noindex; a new/robots.txtdisallows/rss,/atom,/entries,/files, and/admin— private feeds and emails stay out of search engines. - Relative links/images in email bodies are absolutized against the sender's site; lazy-loaded images are promoted so they don't render blank.
- Feed
<title>is plain text (HTML stripped, entities decoded). - Sender-site derivation moved onto the
EmailAddressvalue object (siteBaseUrl).
Fixed
- XML-illegal control characters are stripped from generated feeds (valid astral characters such as emoji preserved).
0.2.0 - 2026-05-24
Added
- 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/statsas the canonical public stats endpoint (JSON + CORS).- Optional R2 attachment storage with a config toggle, storage metrics, download
links on the email/admin views, and inline
cid:image rendering. - Project favicon (
/favicon.svg,/favicon.ico) and per-feed favicon derived from the last sender's domain (/favicon/:feedId). - RFC 8058 one-click unsubscribe dispatched when a feed is deleted.
Changed
- Large internal refactor toward a clean domain-driven architecture; redesigned landing/status page.
Removed
- The deprecated
/api/statsendpoint (use/api/v1/stats).
0.1.0 - 2026-05-22
Added
- Atom feed format (
/atom/:feedId) alongside RSS 2.0. - WebSub push notifications advertised via
Linkheader for real-time delivery instead of polling. - HTML email processing — bodies sanitized via
linkedom+escape-html(XSS prevention, MSO style stripping, plain-text fallback). - Email attachments as RSS enclosures, stored in R2 and served at
/files/:attachmentId/:filename. - Sender blocklist with 4-level priority matching and a quick-add dropdown.
EMAIL_DOMAINenv var to separate web domain and email domain.- Authelia / reverse-proxy auth via trusted headers (
Remote-User,X-Forwarded-User). - Demo environment auto-deployed to
demo.kill-the.newswith a nightly KV reset. - Admin UI redesign (Inter font, orange theme), client scripts compiled via
esbuild, templates on
hono/jsx.