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>
146 lines
6.4 KiB
Markdown
146 lines
6.4 KiB
Markdown
# Changelog
|
|
|
|
All notable changes to this project are documented in this file.
|
|
|
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
|
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.dev` host 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=alternate` links 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 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 (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 `EmailAddress`
|
|
value 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.txt` disallows `/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 `EmailAddress` value 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/stats` as 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/stats` endpoint (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 `Link` header 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_DOMAIN`** env 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.news` with a nightly KV
|
|
reset.
|
|
- Admin UI redesign (Inter font, orange theme), client scripts compiled via
|
|
esbuild, templates on `hono/jsx`.
|
|
|
|
[Unreleased]: https://github.com/juherr/kill-the-news/compare/v0.3.1...HEAD
|
|
[0.3.1]: https://github.com/juherr/kill-the-news/compare/v0.3.0...v0.3.1
|
|
[0.3.0]: https://github.com/juherr/kill-the-news/compare/v0.2.1...v0.3.0
|
|
[0.2.1]: https://github.com/juherr/kill-the-news/compare/v0.2.0...v0.2.1
|
|
[0.2.0]: https://github.com/juherr/kill-the-news/compare/v0.1.0...v0.2.0
|
|
[0.1.0]: https://github.com/juherr/kill-the-news/releases/tag/v0.1.0
|