- Resolve feed URLs against the request host when APP_URL is unset, so the
webcal:// / Add-to-Google links work on a default install (not just behind a
configured reverse proxy).
- Give the public link a real off switch: POST enables, PUT rotates, DELETE
clears the token (feed_token = NULL). The subscribe dialog no longer mints a
token just from being opened — the user opts in explicitly.
- Fold ICS content lines at 75 octets (UTF-8 safe) in exportICS, so download
and feed both stay RFC 5545-compliant for long/non-ASCII summaries.
- Extract VEVENTs by structural line scan instead of a lazy END:VEVENT regex
that user text could truncate.
- URL-encode the Google Calendar cid; mirror feed_token into schema.ts.
- Collapse the duplicated all-trips modal into the shared IcsSubscribeModal.
Adds TripIt-style live calendar subscriptions alongside the existing one-time
.ics download. A trip (or all of a user's trips) exposes a secret, revocable
feed URL that Google/Apple/Outlook poll to stay in sync.
- Public read endpoints GET /api/feed/trip/:token.ics and /api/feed/user/:token.ics
(no auth — the secret token is the credential), reusing the existing exportICS()
generator and adding REFRESH-INTERVAL / X-PUBLISHED-TTL hints.
- JWT-guarded token endpoints to generate (lazy, idempotent) and regenerate/revoke
per-trip and per-user feed tokens; tokens stored in nullable feed_token columns.
- All-trips feed excludes archived trips and trips ended >90 days ago.
- UI: ICS toolbar button becomes a Download/Subscribe menu; modal offers one-click
"Add to Google Calendar" (render?cid=webcal://) and a webcal:// link for
Apple/Outlook, plus copy-link fallbacks. All-trips feed reachable from dashboard.
- Feed base URL read from the existing APP_URL env var.
Purely additive: new endpoints + two nullable columns, no breaking changes.
Tests: server/tests/e2e/feeds.e2e.test.ts covers lazy token generate + idempotency,
regenerate-invalidates-old, 401/404 auth+access, public feed content-type + hint
injection, unknown-token 404, and the archived/>90-day all-trips exclusion.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>