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.
94bf2f59c10017a0b3145
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.
fb56e46fc7ec70 - 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.
fd46011e0637b826f038693ee1751609e3ea01f7e7c512b4d0bdd9471063319954e75608999f3722a0c6bd5dc9b738d47e5d3969e86270d51d33f598fa4616e92027ca1a9aecc16b78e159d717b01f43818598f2c59d51a0557eb16a8b80a7841b1bfa87fd0 - 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.
6b3d860aef0c7e0497775
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.
0fbd7328491a08e5de885c913c8644d0b49f85aea7
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.
2a740064448dc0 - 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.
cfbac1640c5bd15d8a77a - 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.
b1b5f1bce761b260ca29162025a6a24d2659efb4f7e86a1c8 - 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.
32fb937a7f9366eab62ea241305d - 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