Documentation
¶
Overview ¶
Package state — StateReader is a read-only view of the central Store. Pane constructors accept StateReader so they cannot inadvertently call write methods (Set*, Clear*, Stamp*). The root app holds *Store directly and remains the sole writer via Update() handlers.
Package state provides the central Store — the single source of truth for all application data. Panes read from the store via accessor methods. Only the root app.Update() writes to the store via data-carrying Msg payloads, never Commands, pane Update(), or View() directly.
Index ¶
- Constants
- func IsStale(fetchedAt time.Time, ttl time.Duration) bool
- type GatewayEventLog
- type StateReader
- type Store
- func (s *Store) ActiveDevice() *domain.Device
- func (s *Store) AlbumsFetchError() error
- func (s *Store) AlbumsFetchedAt() time.Time
- func (s *Store) AlbumsFetching() bool
- func (s *Store) AlbumsLoaded() bool
- func (s *Store) AlbumsStale() bool
- func (s *Store) ClearAlbumsFetchError()
- func (s *Store) ClearDevicesError()
- func (s *Store) ClearLikedTracksFetchError()
- func (s *Store) ClearPlaylistsError()
- func (s *Store) ClearPlaylistsFetchError()
- func (s *Store) ClearQueueError()
- func (s *Store) ClearRecentPlayedFetchError()
- func (s *Store) ClearStatsError()
- func (s *Store) Devices() []domain.Device
- func (s *Store) DevicesError() error
- func (s *Store) DevicesFetchedAt() time.Time
- func (s *Store) DevicesFetching() bool
- func (s *Store) DevicesStale() bool
- func (s *Store) IsPremium() bool
- func (s *Store) IsThrottled() bool
- func (s *Store) LikedFetching() bool
- func (s *Store) LikedLoaded() bool
- func (s *Store) LikedTotal() int
- func (s *Store) LikedTracks() []domain.SavedTrack
- func (s *Store) LikedTracksFetchError() error
- func (s *Store) LikedTracksFetchedAt() time.Time
- func (s *Store) LikedTracksStale() bool
- func (s *Store) PlaybackState() *domain.PlaybackState
- func (s *Store) PlayingPlaylistID() string
- func (s *Store) PlaylistTracks(playlistID string) []domain.Track
- func (s *Store) Playlists() []domain.SimplePlaylist
- func (s *Store) PlaylistsError() error
- func (s *Store) PlaylistsFetchError() error
- func (s *Store) PlaylistsFetchedAt() time.Time
- func (s *Store) PlaylistsFetching() bool
- func (s *Store) PlaylistsStale() bool
- func (s *Store) PlaylistsTotal() int
- func (s *Store) Queue() []domain.Track
- func (s *Store) QueueError() error
- func (s *Store) ReadEventsFrom(cursor uint64) (uint64, []domain.GatewayEvent)
- func (s *Store) RecentFetching() bool
- func (s *Store) RecentPlayedFetchError() error
- func (s *Store) RecentPlayedFetchedAt() time.Time
- func (s *Store) RecentlyPlayed() []domain.PlayHistory
- func (s *Store) RecentlyPlayedStale() bool
- func (s *Store) RecordEvent(event domain.GatewayEvent)
- func (s *Store) SavedAlbums() []domain.SavedAlbum
- func (s *Store) SetActiveDevice(device *domain.Device)
- func (s *Store) SetAlbumsFetchError(err error)
- func (s *Store) SetAlbumsFetchedAt(t time.Time)
- func (s *Store) SetAlbumsFetching(f bool)
- func (s *Store) SetDevices(devices []domain.Device)
- func (s *Store) SetDevicesError(err error)
- func (s *Store) SetDevicesFetchedAt(t time.Time)
- func (s *Store) SetDevicesFetching(f bool)
- func (s *Store) SetLikedFetching(f bool)
- func (s *Store) SetLikedTotal(total int)
- func (s *Store) SetLikedTracks(tracks []domain.SavedTrack)
- func (s *Store) SetLikedTracksFetchError(err error)
- func (s *Store) SetLikedTracksFetchedAt(t time.Time)
- func (s *Store) SetPlaybackState(state *domain.PlaybackState)
- func (s *Store) SetPlayingPlaylistID(id string)
- func (s *Store) SetPlaylistTracks(playlistID string, tracks []domain.Track)
- func (s *Store) SetPlaylists(playlists []domain.SimplePlaylist)
- func (s *Store) SetPlaylistsError(err error)
- func (s *Store) SetPlaylistsFetchError(err error)
- func (s *Store) SetPlaylistsFetchedAt(t time.Time)
- func (s *Store) SetPlaylistsFetching(f bool)
- func (s *Store) SetPlaylistsTotal(total int)
- func (s *Store) SetQueue(tracks []domain.Track)
- func (s *Store) SetQueueError(err error)
- func (s *Store) SetRecentFetching(f bool)
- func (s *Store) SetRecentPlayedFetchError(err error)
- func (s *Store) SetRecentPlayedFetchedAt(t time.Time)
- func (s *Store) SetRecentlyPlayed(items []domain.PlayHistory)
- func (s *Store) SetSavedAlbums(albums []domain.SavedAlbum)
- func (s *Store) SetStatsError(err error)
- func (s *Store) SetStatsFetching(timeRange string, f bool)
- func (s *Store) SetThrottle(isThrottled bool, retryAfterSecs int, at time.Time)
- func (s *Store) SetTopArtists(timeRange string, artists []domain.FullArtist)
- func (s *Store) SetTopTracks(timeRange string, tracks []domain.Track)
- func (s *Store) SetUserProfile(p domain.UserProfile)
- func (s *Store) StampStatsFetchedAt(timeRange string)
- func (s *Store) StatsError() error
- func (s *Store) StatsFetchedAt(timeRange string) time.Time
- func (s *Store) StatsFetching(timeRange string) bool
- func (s *Store) StatsStale(timeRange string) bool
- func (s *Store) ThrottleLast429At() time.Time
- func (s *Store) ThrottleRetryAfterSecs() int
- func (s *Store) TopArtists(timeRange string) []domain.FullArtist
- func (s *Store) TopTracks(timeRange string) []domain.Track
- func (s *Store) UserID() string
- func (s *Store) UserProfile() domain.UserProfile
Constants ¶
const ( // PlaylistsTTL is the cache lifetime for the user's playlist list. PlaylistsTTL = 5 * time.Minute // AlbumsTTL is the cache lifetime for the user's saved albums. AlbumsTTL = 5 * time.Minute // LikedTracksTTL is the cache lifetime for the user's liked tracks. LikedTracksTTL = 5 * time.Minute // RecentlyPlayedTTL is the cache lifetime for recently played tracks. // Shorter than library data because it changes with every playback event. RecentlyPlayedTTL = 2 * time.Minute // StatsTTL is the cache lifetime for user stats (top tracks/artists). // Long because Spotify updates these slowly. StatsTTL = 10 * time.Minute // DevicesTTL is the cache lifetime for the available device list. // Short cooldown prevents rapid-fire API calls while ensuring fresh data on user request. DevicesTTL = 5 * time.Second )
TTL constants define how long each data domain is considered fresh. After the TTL expires, Update() should trigger a re-fetch from the Spotify API.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type GatewayEventLog ¶
type GatewayEventLog struct {
// contains filtered or unexported fields
}
GatewayEventLog is a fixed-size ring buffer of GatewayEvent values with cursor-based reads. Multiple consumers can independently track their position using monotonically increasing sequence numbers.
Thread-safe: Add() takes a write lock, ReadFrom() takes a read lock.
func NewGatewayEventLog ¶
func NewGatewayEventLog(capacity int) *GatewayEventLog
NewGatewayEventLog creates an event log with the given capacity. If capacity is <= 0 it defaults to defaultEventLogCapacity (500).
func (*GatewayEventLog) Add ¶
func (l *GatewayEventLog) Add(event domain.GatewayEvent)
Add appends an event to the ring buffer, overwriting the oldest if full.
func (*GatewayEventLog) Len ¶
func (l *GatewayEventLog) Len() int
Len returns the number of events currently stored.
func (*GatewayEventLog) ReadFrom ¶
func (l *GatewayEventLog) ReadFrom(cursor uint64) (uint64, []domain.GatewayEvent)
ReadFrom returns events added since the given cursor position. Returns the new cursor and the slice of new events. First call should use cursor=0.
If the cursor is older than the oldest retained event (due to ring buffer wraparound), all currently stored events are returned.
type StateReader ¶
type StateReader interface {
// PlaybackState returns the current playback state, or nil if nothing is playing.
PlaybackState() *domain.PlaybackState
// ActiveDevice returns the currently active Spotify device, or nil if unknown.
ActiveDevice() *domain.Device
// UserID returns the Spotify user ID of the authenticated user.
UserID() string
// UserProfile returns the full authenticated user profile.
// Returns a zero-value UserProfile before profile is loaded.
UserProfile() domain.UserProfile
// IsPremium returns true only when the authenticated user's Product is "premium".
// Returns false for free users, unknown tier, or when profile not yet loaded.
IsPremium() bool
// Queue returns the upcoming tracks in the user's play queue.
Queue() []domain.Track
// Playlists returns the user's saved playlists.
Playlists() []domain.SimplePlaylist
// PlaylistsTotal returns the total number of playlists (for pagination).
PlaylistsTotal() int
// PlaylistTracks returns cached tracks for a given playlist ID, or nil if not loaded.
PlaylistTracks(playlistID string) []domain.Track
// PlayingPlaylistID returns the Spotify playlist ID that is currently playing.
PlayingPlaylistID() string
// SavedAlbums returns the user's saved albums.
SavedAlbums() []domain.SavedAlbum
// AlbumsLoaded returns true if saved albums have been fetched at least once.
AlbumsLoaded() bool
// LikedTracks returns the user's liked tracks.
LikedTracks() []domain.SavedTrack
// LikedTotal returns the total number of liked tracks (for pagination).
LikedTotal() int
// LikedLoaded returns true if liked tracks have been fetched at least once.
LikedLoaded() bool
// RecentlyPlayed returns the recently played track history.
RecentlyPlayed() []domain.PlayHistory
// TopTracks returns cached top tracks for the given time range.
TopTracks(timeRange string) []domain.Track
// TopArtists returns cached top artists for the given time range.
TopArtists(timeRange string) []domain.FullArtist
// Devices returns the most recently fetched list of Spotify Connect devices.
Devices() []domain.Device
// StatsStale returns true if stats for the given time range should be re-fetched.
// Other staleness methods (PlaylistsStale, AlbumsStale, LikedTracksStale,
// RecentlyPlayedStale, DevicesStale) are omitted because only handlers.go
// calls them on the concrete *Store — no pane reads them via StateReader.
StatsStale(timeRange string) bool
// PlaylistsFetching returns true while a playlists fetch is in-flight.
PlaylistsFetching() bool
// AlbumsFetching returns true while a saved-albums fetch is in-flight.
AlbumsFetching() bool
// LikedFetching returns true while a liked-tracks fetch is in-flight.
LikedFetching() bool
// RecentFetching returns true while a recently-played fetch is in-flight.
RecentFetching() bool
// PlaylistsFetchedAt returns the time playlists were last successfully fetched.
PlaylistsFetchedAt() time.Time
// AlbumsFetchedAt returns the time saved albums were last successfully fetched.
AlbumsFetchedAt() time.Time
// LikedTracksFetchedAt returns the time liked tracks were last successfully fetched.
LikedTracksFetchedAt() time.Time
// RecentPlayedFetchedAt returns the time recently played was last successfully fetched.
RecentPlayedFetchedAt() time.Time
// ReadEventsFrom returns gateway events added since the given cursor.
// Pass cursor=0 on the first call.
ReadEventsFrom(cursor uint64) (uint64, []domain.GatewayEvent)
// IsThrottled returns true if the gateway is currently in a 429 backoff period.
IsThrottled() bool
// ThrottleRetryAfterSecs returns the Retry-After seconds from the last 429 response.
ThrottleRetryAfterSecs() int
}
StateReader is the read-only subset of *Store that panes are permitted to call. It contains every accessor method that pane View() and Update() bodies invoke, grouped by domain area.
Write-only methods (Set*, Clear*, Stamp*, SetDevicesFetchedAt, etc.) are intentionally omitted — only the root App.Update() may call those on the concrete *Store.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is the central application state. All panes read from here; only the root app.Update() writes to it via Msg payloads. Fields are never accessed directly — use the accessor methods to ensure safe concurrent access.
func New ¶
func New() *Store
New returns an empty Store with no playback state. statsFetchedAt is pre-allocated so callers never encounter a nil map panic when reading stats staleness before any fetch has completed.
func (*Store) ActiveDevice ¶
ActiveDevice returns the currently active Spotify device, or nil if unknown.
func (*Store) AlbumsFetchError ¶
AlbumsFetchError returns the last saved albums fetch error, or nil.
func (*Store) AlbumsFetchedAt ¶
AlbumsFetchedAt returns the time when saved albums were last successfully fetched. Returns the zero time if albums have never been fetched.
func (*Store) AlbumsFetching ¶
AlbumsFetching returns true while a saved-albums fetch is in-flight.
func (*Store) AlbumsLoaded ¶
AlbumsLoaded returns true if saved albums have been fetched at least once. Replaces the former albumsLoaded boolean sentinel — derived from albumsFetchedAt.
func (*Store) AlbumsStale ¶
AlbumsStale returns true if the saved albums are stale and should be re-fetched.
func (*Store) ClearAlbumsFetchError ¶
func (s *Store) ClearAlbumsFetchError()
ClearAlbumsFetchError clears the saved albums fetch error on successful retry.
func (*Store) ClearDevicesError ¶
func (s *Store) ClearDevicesError()
ClearDevicesError clears the devices error state on successful retry.
func (*Store) ClearLikedTracksFetchError ¶
func (s *Store) ClearLikedTracksFetchError()
ClearLikedTracksFetchError clears the liked tracks fetch error on successful retry.
func (*Store) ClearPlaylistsError ¶
func (s *Store) ClearPlaylistsError()
ClearPlaylistsError clears the playlists error state on successful retry.
func (*Store) ClearPlaylistsFetchError ¶
func (s *Store) ClearPlaylistsFetchError()
ClearPlaylistsFetchError clears the playlists list fetch error on successful retry.
func (*Store) ClearQueueError ¶
func (s *Store) ClearQueueError()
ClearQueueError clears the queue error state on successful retry.
func (*Store) ClearRecentPlayedFetchError ¶
func (s *Store) ClearRecentPlayedFetchError()
ClearRecentPlayedFetchError clears the recently played fetch error on successful retry.
func (*Store) ClearStatsError ¶
func (s *Store) ClearStatsError()
ClearStatsError clears the stats error state on successful retry.
func (*Store) Devices ¶
Devices returns the most recently fetched list of Spotify Connect devices, or nil if the list has not been fetched yet.
func (*Store) DevicesError ¶
DevicesError returns the last devices fetch error, or nil if successful.
func (*Store) DevicesFetchedAt ¶
DevicesFetchedAt returns the time when the device list was last successfully fetched. Returns the zero time if devices have never been fetched.
func (*Store) DevicesFetching ¶
DevicesFetching returns true while a devices fetch is in-flight.
func (*Store) DevicesStale ¶
DevicesStale returns true if the device list is stale and should be re-fetched.
func (*Store) IsPremium ¶
IsPremium returns true only when Product == "premium". Returns false for free users, unknown tier, or when profile not yet loaded.
func (*Store) IsThrottled ¶
IsThrottled returns true if the gateway is currently in a 429 backoff period.
func (*Store) LikedFetching ¶
LikedFetching returns true while a liked-tracks fetch is in-flight.
func (*Store) LikedLoaded ¶
LikedLoaded returns true if liked tracks have been fetched at least once. Replaces the former likedLoaded boolean sentinel — derived from likedTracksFetchedAt.
func (*Store) LikedTotal ¶
LikedTotal returns the total number of liked tracks (for pagination).
func (*Store) LikedTracks ¶
func (s *Store) LikedTracks() []domain.SavedTrack
LikedTracks returns the user's liked tracks.
func (*Store) LikedTracksFetchError ¶
LikedTracksFetchError returns the last liked tracks fetch error, or nil.
func (*Store) LikedTracksFetchedAt ¶
LikedTracksFetchedAt returns the time when liked tracks were last successfully fetched. Returns the zero time if liked tracks have never been fetched.
func (*Store) LikedTracksStale ¶
LikedTracksStale returns true if the liked tracks are stale and should be re-fetched.
func (*Store) PlaybackState ¶
func (s *Store) PlaybackState() *domain.PlaybackState
PlaybackState returns the current playback state, or nil if nothing is playing.
func (*Store) PlayingPlaylistID ¶
PlayingPlaylistID returns the Spotify playlist ID that is currently playing. Returns "" if no playlist is active or the ID is unknown.
func (*Store) PlaylistTracks ¶
PlaylistTracks returns the cached tracks for a given playlist ID, or nil if the playlist has not been loaded yet.
func (*Store) Playlists ¶
func (s *Store) Playlists() []domain.SimplePlaylist
Playlists returns the user's saved playlists.
func (*Store) PlaylistsError ¶
PlaylistsError returns the last playlists fetch error, or nil if successful.
func (*Store) PlaylistsFetchError ¶
PlaylistsFetchError returns the last playlists list fetch error, or nil.
func (*Store) PlaylistsFetchedAt ¶
PlaylistsFetchedAt returns the time when playlists were last successfully fetched. Returns the zero time if playlists have never been fetched.
func (*Store) PlaylistsFetching ¶
PlaylistsFetching returns true while a playlists fetch is in-flight.
func (*Store) PlaylistsStale ¶
PlaylistsStale returns true if the playlists list is stale and should be re-fetched.
func (*Store) PlaylistsTotal ¶
PlaylistsTotal returns the total number of playlists (for pagination).
func (*Store) QueueError ¶
QueueError returns the last queue fetch error, or nil if successful.
func (*Store) ReadEventsFrom ¶
func (s *Store) ReadEventsFrom(cursor uint64) (uint64, []domain.GatewayEvent)
ReadEventsFrom returns gateway events added since the given cursor. Returns the new cursor and the slice of new events. Pass cursor=0 on the first call.
func (*Store) RecentFetching ¶
RecentFetching returns true while a recently-played fetch is in-flight.
func (*Store) RecentPlayedFetchError ¶
RecentPlayedFetchError returns the last recently played fetch error, or nil.
func (*Store) RecentPlayedFetchedAt ¶
RecentPlayedFetchedAt returns the time when recently played was last successfully fetched. Returns the zero time if recently played has never been fetched.
func (*Store) RecentlyPlayed ¶
func (s *Store) RecentlyPlayed() []domain.PlayHistory
RecentlyPlayed returns the recently played track history.
func (*Store) RecentlyPlayedStale ¶
RecentlyPlayedStale returns true if the recently played list is stale and should be re-fetched.
func (*Store) RecordEvent ¶
func (s *Store) RecordEvent(event domain.GatewayEvent)
RecordEvent records a gateway lifecycle event. Implements domain.GatewayEventRecorder.
func (*Store) SavedAlbums ¶
func (s *Store) SavedAlbums() []domain.SavedAlbum
SavedAlbums returns the user's saved albums.
func (*Store) SetActiveDevice ¶
SetActiveDevice updates the active device independently of playback state.
func (*Store) SetAlbumsFetchError ¶
SetAlbumsFetchError records a saved albums fetch failure.
func (*Store) SetAlbumsFetchedAt ¶
SetAlbumsFetchedAt stamps the time when saved albums were last successfully loaded.
func (*Store) SetAlbumsFetching ¶
SetAlbumsFetching sets or clears the in-flight albums fetch sentinel.
func (*Store) SetDevices ¶
SetDevices replaces the cached device list. Called by app.Update() after a successful DevicesLoadedMsg.
func (*Store) SetDevicesError ¶
SetDevicesError records a devices fetch failure.
func (*Store) SetDevicesFetchedAt ¶
SetDevicesFetchedAt stamps the time when devices were last successfully loaded. Called by root app.Update() after a successful DevicesLoadedMsg.
func (*Store) SetDevicesFetching ¶
SetDevicesFetching sets or clears the in-flight devices fetch sentinel.
func (*Store) SetLikedFetching ¶
SetLikedFetching sets or clears the in-flight liked-tracks fetch sentinel.
func (*Store) SetLikedTotal ¶
SetLikedTotal updates the total liked tracks count for pagination.
func (*Store) SetLikedTracks ¶
func (s *Store) SetLikedTracks(tracks []domain.SavedTrack)
SetLikedTracks updates the liked tracks in the store. fetchedAt is only stamped when the slice is non-empty to avoid resetting the TTL on empty/error responses and blocking retries prematurely.
func (*Store) SetLikedTracksFetchError ¶
SetLikedTracksFetchError records a liked tracks fetch failure.
func (*Store) SetLikedTracksFetchedAt ¶
SetLikedTracksFetchedAt stamps the time when liked tracks were last successfully loaded.
func (*Store) SetPlaybackState ¶
func (s *Store) SetPlaybackState(state *domain.PlaybackState)
SetPlaybackState updates the playback state. Pass nil to clear (204 response). Also updates the active device from the state's Device field.
func (*Store) SetPlayingPlaylistID ¶
SetPlayingPlaylistID records the currently playing playlist ID. This is set by the root app when a PlayContextMsg plays a playlist.
func (*Store) SetPlaylistTracks ¶
SetPlaylistTracks caches the tracks for a specific playlist in the store.
func (*Store) SetPlaylists ¶
func (s *Store) SetPlaylists(playlists []domain.SimplePlaylist)
SetPlaylists updates the saved playlists in the store. fetchedAt is only stamped when the slice is non-empty, preventing an empty (nil-client or error-fallback) response from resetting the TTL and blocking retries for the full cache duration.
func (*Store) SetPlaylistsError ¶
SetPlaylistsError records a playlists fetch failure.
func (*Store) SetPlaylistsFetchError ¶
SetPlaylistsFetchError records a playlists list fetch failure.
func (*Store) SetPlaylistsFetchedAt ¶
SetPlaylistsFetchedAt stamps the time when playlists were last successfully loaded. Used by tests and import flows that need precise staleness control.
func (*Store) SetPlaylistsFetching ¶
SetPlaylistsFetching sets or clears the in-flight playlists fetch sentinel.
func (*Store) SetPlaylistsTotal ¶
SetPlaylistsTotal updates the total playlists count for pagination.
func (*Store) SetQueueError ¶
SetQueueError records a queue fetch failure.
func (*Store) SetRecentFetching ¶
SetRecentFetching sets or clears the in-flight recently-played fetch sentinel.
func (*Store) SetRecentPlayedFetchError ¶
SetRecentPlayedFetchError records a recently played fetch failure.
func (*Store) SetRecentPlayedFetchedAt ¶
SetRecentPlayedFetchedAt stamps the time when recently played was last successfully loaded.
func (*Store) SetRecentlyPlayed ¶
func (s *Store) SetRecentlyPlayed(items []domain.PlayHistory)
SetRecentlyPlayed updates the recently played history in the store. fetchedAt is only stamped when the slice is non-empty to avoid resetting the TTL on empty/error responses and blocking retries prematurely.
func (*Store) SetSavedAlbums ¶
func (s *Store) SetSavedAlbums(albums []domain.SavedAlbum)
SetSavedAlbums updates the saved albums in the store. fetchedAt is only stamped when the slice is non-empty to avoid resetting the TTL on empty/error responses and blocking retries prematurely.
func (*Store) SetStatsError ¶
SetStatsError records a stats fetch failure.
func (*Store) SetStatsFetching ¶
SetStatsFetching sets or clears the in-flight stats fetch sentinel for a time range.
func (*Store) SetThrottle ¶
SetThrottle records the current rate-limit state from the API Gateway. Called after a 429 response; cleared when the backoff period expires.
func (*Store) SetTopArtists ¶
func (s *Store) SetTopArtists(timeRange string, artists []domain.FullArtist)
SetTopArtists caches top artists for a specific time range in the store. It does NOT stamp statsFetchedAt — call StampStatsFetchedAt after both SetTopTracks and SetTopArtists succeed so the range is only marked fresh when both datasets are written (avoids partial-data false-fresh state).
func (*Store) SetTopTracks ¶
SetTopTracks caches top tracks for a specific time range in the store. It does NOT stamp statsFetchedAt — call StampStatsFetchedAt after both SetTopTracks and SetTopArtists succeed so the range is only marked fresh when both datasets are written (avoids partial-data false-fresh state).
func (*Store) SetUserProfile ¶
func (s *Store) SetUserProfile(p domain.UserProfile)
SetUserProfile stores the authenticated user's full Spotify profile. Called once at startup after GET /v1/me succeeds.
func (*Store) StampStatsFetchedAt ¶
StampStatsFetchedAt records the time when stats for a time range were fully loaded. Call this once after both SetTopTracks and SetTopArtists succeed so that StatsStale only returns false when both datasets are present.
func (*Store) StatsError ¶
StatsError returns the last stats fetch error, or nil if successful.
func (*Store) StatsFetchedAt ¶
StatsFetchedAt returns the time when stats for the given time range were last fetched. Returns the zero time if that range has never been fetched.
func (*Store) StatsFetching ¶
StatsFetching returns true while a stats fetch for the given time range is in-flight.
func (*Store) StatsStale ¶
StatsStale returns true if stats for the given time range are stale and should be re-fetched.
func (*Store) ThrottleLast429At ¶
ThrottleLast429At returns the time of the most recent 429 response.
func (*Store) ThrottleRetryAfterSecs ¶
ThrottleRetryAfterSecs returns the Retry-After seconds from the last 429 response.
func (*Store) TopArtists ¶
func (s *Store) TopArtists(timeRange string) []domain.FullArtist
TopArtists returns the cached top artists for the given time range, or nil if that range has not been fetched yet. timeRange should be "short_term", "medium_term", or "long_term".
func (*Store) TopTracks ¶
TopTracks returns the cached top tracks for the given time range, or nil if that range has not been fetched yet. timeRange should be "short_term", "medium_term", or "long_term".
func (*Store) UserID ¶
UserID returns the Spotify user ID. Returns "" before profile is loaded. Preserved for call-site compatibility — delegates to userProfile.ID.
func (*Store) UserProfile ¶
func (s *Store) UserProfile() domain.UserProfile
UserProfile returns the full authenticated user profile. Returns a zero-value UserProfile before profile is loaded.