Expand description
FeatherReader — a minimalist, atproto-native RSS/Atom feed reader.
Your feed subscriptions live in your own atproto PDS
(via the open community.lexicon.rss.* community lexicon), so your reading
list follows you across any compatible reader — you own your data, not the
app. Minimalist by design.
This crate ships as a single server binary (featherreader) plus this small
library, which declares the module tree and the shared types the binary and
its subsystems build on. The heavy lifting lives in sibling modules:
config— env-driven runtime configuration (FEATHERREADER_*).lexicon— thecommunity.lexicon.rss.*record schemas (subscription, folder, saved, readState) as serde types.store— the per-DID SQLite cache + read-state working copy (sqlx, runtime queries).feed— polite fetching (conditional GET, backoff), feed-rs parsing, and ammonia sanitization.atproto— the atproto identity + PDS record layer (subscriptions, folders, saved, batched read-state sync), including the Node sidecar’s client (atproto::SidecarClient).oauth— the Rust-native atproto OAuth client (therustrepo backend, which production runs).repo— the one dispatcher everycom.atproto.repo.*call goes through, choosing the sidecar or the Rust client byFEATHERREADER_REPO_BACKEND.standard_site— reading standard.site publications from their authors’ repos.network— read-only queries against the public atproto network (the relay adoption probe). A projection, never a source of truth, and never on a reader path.web— the axum router + askama server-rendered views.sanitized_html— the reader’s article body, re-sanitized at render so the template never emits a stored string unescaped.
Status: experimental / pre-1.0. See https://feather-reader.com.
Modules§
- atproto
- The atproto identity + PDS record layer.
- config
- Runtime configuration for the FeatherReader server.
- feed
- Feed fetch → parse → sanitize → store pipeline.
- lexicon
- Serde types for the
community.lexicon.rss.*atproto record schemas. - metrics
- Side-by-side latency for the two repo backends.
- net
- Hardened outbound HTTP for untrusted, user-supplied feed URLs.
- network
- Read-only queries against the public atproto network.
- oauth
- Rust-native atproto OAuth — the replacement for the Node sidecar.
- readstate
- Read-state flushing — turning dirty local cursors into
readStaterecords in the user’s own PDS. - repo
- The one place the two repo backends are chosen between, and timed.
- runtime_
health - What the background loops are actually doing, readable from a request.
- safe_
link - The
hreftype. - sanitized_
html - The reader view’s article body.
- standard_
site - Reading
standard.sitepublications as feeds. - store
- SQLite persistence layer (via
sqlx, runtime queries). - vetted
- Record types that cannot exist unvetted.
- web
- The axum web layer — server-rendered HTML + a dash of htmx, no SPA.
Structs§
- AppState
- Shared application state handed to every axum handler.
- Session
- One logged-in identity, resolved from the OAuth sidecar and keyed by DID.
- Session
Registry - In-memory session registry: opaque random session-id →
Session.
Constants§
- USER_
AGENT - The
User-AgentFeatherReader identifies itself with when fetching feeds. - VERSION
- The crate version — surfaced for the server’s
--version/ health output.
Functions§
- block_
on_ then_ shutdown - Run
futureon a new multi-thread runtime — what#[tokio::main]builds — then shut that runtime down waiting at mostshutdownfor work still on its blocking pool, where dropping it would wait without limit. The server’smainruns on this; see itsRUNTIME_SHUTDOWN_TIMEOUTfor why (#226: an abandoned ingest sanitize cannot be cancelled). - build_
http_ client - The shared HTTP client
AppStatecarries, also used by the binary’s maintenance commands (--revoke-all-sessions) so they reach the network exactly as the serving app does.