feat(search): replace PostgreSQL FTS with Typesense for user library search
Typesense is now the search engine for all user-uploaded track queries,
scoped strictly per-user (filter_by=user_id:=...) so no user can see
another user's tracks in results.
TypeScript (apps/api):
- src/typesense/client.ts: Typesense client (TYPESENSE_HOST/PORT/PROTOCOL/API_KEY env vars)
- src/typesense/schema.ts: library_tracks collection schema + ensureCollection()
- src/typesense/library.ts: indexLibraryTrack, removeLibraryTrack, searchLibraryTracks
- src/lib/env.ts: TYPESENSE_HOST, TYPESENSE_PORT, TYPESENSE_PROTOCOL, TYPESENSE_API_KEY vars
- src/uploads/app.ts: index on upload, Typesense search when ?q= is set, remove on delete
- src/scripts/typesense-import.ts: bulk-import all existing uploads (run once to backfill)
Rust (navidrome):
- src/typesense.rs: TypesenseClient with search_track_ids / search_album_names /
search_artist_names; falls back to PostgreSQL LIKE if TYPESENSE_API_KEY is unset
- repo/track.rs: get_tracks_by_ids (ANY batch fetch, preserves Typesense order)
- repo/album.rs: get_albums_by_names (batch lookup matching Typesense album hits)
- repo/artist.rs: get_artists_by_names (batch lookup matching Typesense artist hits)
- handlers/search.rs: search3/search2 use Typesense then DB batch fetch pipeline
- handlers/mod.rs + lib.rs: TypesenseClient in app state, threaded to search handler
feat(navidrome): add Subsonic REST API v1.16.1 compatible crate
Implements a new `rocksky-navidrome` crate providing a Navidrome/Subsonic
compatible API so any Subsonic client can browse and stream user-uploaded
audio. Auth uses the Bluesky handle as username and an existing API key
as password (plain, hex-encoded, or token/salt MD5).
Endpoints: ping, getMusicFolders, getArtists/getIndexes, getArtist,
getAlbum, getSong, stream (presigned S3 redirect), getCoverArt,
search3/search2, scrobble, updateNowPlaying, getAlbumList2/getAlbumList,
getRandomSongs, star, unstar. Both JSON and XML response formats are
supported. Start with `rockskyd navidrome` (default port 4533).