A play is recorded when a new track starts (pausing and resuming doesn't
count; returning after 10+ minutes does). Profiles show the last 10,
excluding the track playing now; 50 are kept per user. Recent plays are
free on every plan; the paid flag is renamed to fullHistory.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MzFywujuH9TiuXbr9vjoX8
Servers advertise many addresses (public, relay, LAN, Docker bridges).
Use the last one that worked and race the rest only if it fails. Friends'
servers that keep failing back off exponentially instead of slowing
every poll. Errors now name each server and the underlying cause, e.g.
"blackcoffee: ECONNREFUSED", instead of undici's generic "fetch failed".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MzFywujuH9TiuXbr9vjoX8
- Shared: link building, feed ordering, input schemas, API client
- API unit: track matching, private-address blocking, token crypto,
plan expiry, provider response parsing
- API integration against Postgres and Redis: auth, follows and pins,
now-playing state, webhooks, OAuth return URLs, realtime, rate limits
- Tests use a dedicated *_test database and Redis DB, and refuse to wipe
anything else; fetch is stubbed so they never hit the network
- Pin Node to 22.13+ (.nvmrc), which Vite's native bindings require
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MzFywujuH9TiuXbr9vjoX8