RDLTR

Notes from every release

This release overhauls the save pipeline with a durable save-first architecture, adds RSS feeds (per-user and global), ships a fully automated iOS Shortcut with per-user signing, improves metadata extraction for NYT, Bloomberg, Reddit, and Reuters, decouples and hardens favicon fetching, migrates authentication to Neo Login, moves profiles to @username URLs, removes the click-redirect layer, adds an "open in archive" browser extension action, and migrates infrastructure from a Raspberry Pi to a Hetzner VPS.

Breaking changes

  • Authentication replaced with Neo Login — passkeys removedUser identity now flows through the Neo Login service. The passkey-era schema columns are dropped and replaced with email and external_id. The iOS Shortcut and API token path use a new long-lived Bearer token revocable via users.tokens_invalid_before. The browser extension reads the nl_session cookie instead of parsing its own cookie or sending X-Username. a0254ad
  • Profile URLs move to @username — old bare /username paths no longer workUser profiles are now at /@username (e.g. /@alice). Page routes drop the /~/ prefix: /join, /welcome, /help, /privacy, /stats, and related pages are now at their bare names. Existing bookmarks or links to the old URL shapes will 404. f3d1196
  • Click-redirect layer removed — links now point directly to their destinationsThe /api/r/:id/:domain/:slug redirect endpoint has been removed. All outbound hrefs now point directly to the canonical destination URL. Old /api/r/... URLs from the brief window they were live will return 404. Domain grouping in the list view was updated to parse hostnames from destination URLs directly. 94bf2f5 9c10017 a0b3145

New

  • RSS feeds for public profiles and the global timelineEach public user profile now exposes a GET /:username/rss feed (RSS 2.0, capped at 50 recent unread links) with an autodiscovery tag so feed readers pick it up automatically. A global /rss feed mirrors the home timeline with the same autodiscovery tag on the root page. Private profiles return 404 and omit the tag. fb56e46 fc7ec70
  • iOS Shortcut now installs with credentials pre-baked — no manual paste requiredLogged-in users can download a personalized .shortcut binary from /RDLTR.shortcut that has their token and username already embedded as static text. The shortcut is signed via HubSign and delivered with the correct iOS permission scope so the share-sheet "Always Allow" prompt persists across runs. The build pipeline compiles from a Jelly source file and patches the plist to match the legacy shortcut's structure exactly. fd46011 e0637b8 26f0386 93ee175 1609e3e a01f7e7 c512b4d 0bdd947 1063319 954e756 08999f3 722a0c6 bd5dc9b 738d47e 5d3969e 86270d5 1d33f59 8fa4616 e92027c a1a9aec c16b78e 159d717 b01f438 18598f2 c59d51a 0557eb1 6a8b80a 7841b1b fa87fd0
  • Browser extension: open current page or link in archive.phA new "Open in archive" action is available via right-click context menu and the Shift+AA keyboard chord. Medium URLs are routed to freedium.cfd; all others go to archive.ph. The archive URL strips query parameters to match existing snapshots. Extension manifests bumped to 1.5.0. 6b3d860 aef0c7e 0497775

Improved

  • Saves are now durable even under load — accepted saves never disappearPOST /api/link and /api/link/seen now write the row to the database synchronously and return 202 immediately. Metadata extraction happens asynchronously in a background worker and updates the row when ready. If the worker is overloaded or the process restarts, a sweep picks up pending rows within 60 seconds. A save that returns 2xx is guaranteed to land in the database. 0fbd732 8491a08 e5de885 c913c86 44d0b49 f85aea7

Fixed

  • NYT articles now extract correctly despite DataDome bot blockingWorker requests to nytimes.com were returning a 403 challenge page whose title was being stored as the article title. The extractor now uses NYT's first-party oEmbed API, which is not gated by DataDome and covers all article types including older pieces, interactives, and Wirecutter — verified against 534 production URLs. 2a74006 4448dc0
  • Bloomberg, Reddit, and Reuters articles now extract real titlesBloomberg saves were silently disappearing due to Cloudflare bot-wall blocks; the extractor now uses Bloomberg's public mobile API. Reddit was returning a generic site title; the extractor now uses Reddit's oEmbed endpoint and strips share_id from canonical URLs for cleaner deduplication. A publisher registry in src/publishers.ts makes adding new extractors a single-line change. cfbac16 40c5bd1 5d8a77a
  • Favicons now resolve correctly for redirected and cross-host URLsFavicons are fetched through a dedicated pipeline (OVERRIDES → root HTML scrape → article URL scrape → Google s2 fallback) keyed on the canonical host after metadata rewrites the stored URL. Links stay hidden until both metadata and favicon have settled, so the placeholder icon never appears mid-enrichment. Favicon paths are fingerprinted with BUILD_ID on each deploy to flush stale browser caches. b1b5f1b ce761b2 60ca291 62025a6 a24d265 9efb4f7 e86a1c8
  • Saved URLs are now stored under their canonical form — duplicate saves collapse correctlyThe stored URL is updated to the publisher's declared rel=canonical (falling back to og:url, then response.url) after enrichment. Tracker-laden query parameters (utm_*, fbclid, gclid, etc.) are stripped on save. When the same article is saved twice via different shorteners or tracking URLs, the duplicate is merged into the existing row and a live SSE removal fires so open tabs update immediately. 32fb937 a7f9366 eab62ea 241305d
  • SSE live updates now stay scoped to the correct user — cross-user leakage fixedSSE broadcasts were previously sent to every connected client regardless of which profile page they were viewing, so one user's saves could appear in another user's tab until reload. Broadcasts are now filtered to the saving user's subscribers. The /api/events endpoint also now requires authentication when the requested profile is private. 7952cff