UNPKG

spotify-api-lib

Version:

A modern, TypeScript-first wrapper for the Spotify Web API with organized endpoint categories and full type safety

855 lines (832 loc) 20.8 kB
import { AxiosInstance } from 'axios'; /** * @file httpClient.ts * @description HTTP client for making requests to Spotify API * @author Caleb Price * @version 1.0.0 * @date 2025-07-14 */ interface RequestOptions { method?: 'GET' | 'POST' | 'PUT' | 'DELETE'; data?: any; params?: Record<string, any>; headers?: Record<string, string>; retries?: number; } declare class SpotifyHttpClient { private client; private accessToken; constructor(accessToken?: string); /** * Set the access token for authentication */ setAccessToken(token: string): void; /** * Clear the access token */ clearAccessToken(): void; /** * Make an HTTP request to the Spotify API with improved error handling */ request<T = any>(endpoint: string, options?: RequestOptions): Promise<T>; /** * Check if an HTTP status code should be retried */ private isRetryableError; /** * Get retry delay from Retry-After header or default */ private getRetryAfterDelay; /** * Create a standardized error object */ private createSpotifyError; /** * Promise-based delay utility */ private delay; /** * Get the underlying axios instance for advanced usage */ getClient(): AxiosInstance; } /** * @file baseEndpoint.ts * @description Base class for API endpoint groups with convenience methods * @author Caleb Price * @version 1.1.0 * @date 2025-07-21 */ declare abstract class BaseEndpoint { protected client: SpotifyHttpClient; constructor(client: SpotifyHttpClient); protected makeRequest<T = any>(endpoint: string, options?: RequestOptions): Promise<T>; protected get<T = any>(endpoint: string, params?: Record<string, any>): Promise<T>; protected post<T = any>(endpoint: string, data?: any, params?: Record<string, any>): Promise<T>; protected put<T = any>(endpoint: string, data?: any, params?: Record<string, any>): Promise<T>; protected delete<T = any>(endpoint: string, params?: Record<string, any>): Promise<T>; protected handleError(error: any, operation: string): never; } /** * @file types.ts * @description TypeScript interfaces for Spotify API responses * @author Caleb Price * @version 1.0.0 * @date 2025-07-14 */ interface SpotifyImage { url: string; height: number | null; width: number | null; } interface SpotifyArtist { external_urls: { spotify: string; }; followers?: { href: string | null; total: number; }; genres?: string[]; href: string; id: string; images?: SpotifyImage[]; name: string; popularity?: number; type: 'artist'; uri: string; } interface SpotifyAlbum { album_type: 'album' | 'single' | 'compilation'; artists: SpotifyArtist[]; available_markets: string[]; external_urls: { spotify: string; }; href: string; id: string; images: SpotifyImage[]; name: string; release_date: string; release_date_precision: 'year' | 'month' | 'day'; total_tracks: number; type: 'album'; uri: string; popularity?: number; label?: string; } interface SpotifyTrack { album: SpotifyAlbum; artists: SpotifyArtist[]; available_markets: string[]; disc_number: number; duration_ms: number; explicit: boolean; external_ids: { isrc?: string; ean?: string; upc?: string; }; external_urls: { spotify: string; }; href: string; id: string; is_local: boolean; name: string; popularity: number; preview_url: string | null; track_number: number; type: 'track'; uri: string; } interface SpotifyPlaylist { collaborative: boolean; description: string | null; external_urls: { spotify: string; }; followers: { href: string | null; total: number; }; href: string; id: string; images: SpotifyImage[]; name: string; owner: { display_name: string | null; external_urls: { spotify: string; }; href: string; id: string; type: 'user'; uri: string; }; primary_color: string | null; public: boolean | null; snapshot_id: string; tracks: { href: string; total: number; }; type: 'playlist'; uri: string; } interface SpotifyUser { country?: string; display_name: string | null; email?: string; explicit_content?: { filter_enabled: boolean; filter_locked: boolean; }; external_urls: { spotify: string; }; followers: { href: string | null; total: number; }; href: string; id: string; images: SpotifyImage[]; product?: string; type: 'user'; uri: string; } interface SpotifySearchResponse { tracks?: { href: string; items: SpotifyTrack[]; limit: number; next: string | null; offset: number; previous: string | null; total: number; }; albums?: { href: string; items: SpotifyAlbum[]; limit: number; next: string | null; offset: number; previous: string | null; total: number; }; artists?: { href: string; items: SpotifyArtist[]; limit: number; next: string | null; offset: number; previous: string | null; total: number; }; playlists?: { href: string; items: SpotifyPlaylist[]; limit: number; next: string | null; offset: number; previous: string | null; total: number; }; } interface SpotifyPagingObject<T> { href: string; items: T[]; limit: number; next: string | null; offset: number; previous: string | null; total: number; } /** * @file playlists.ts * @description Playlist-related API endpoints * @author Caleb Price * @version 1.0.0 * @date 2025-07-14 */ declare class PlaylistEndpoints extends BaseEndpoint { /** * Get current user's playlists */ getUserPlaylists(options?: { limit?: number; offset?: number; }): Promise<SpotifyPlaylist[]>; /** * Create a new playlist */ create(name: string, options?: { description?: string; public?: boolean; collaborative?: boolean; }): Promise<SpotifyPlaylist>; /** * Add tracks to a playlist */ addTracks(playlistId: string, trackUris: string[], options?: { position?: number; }): Promise<{ snapshot_id: string; }>; /** * Get tracks from a playlist */ getTracks(playlistId: string, options?: { limit?: number; offset?: number; fields?: string; }): Promise<any>; /** * Get a playlist by ID */ getById(playlistId: string, options?: { fields?: string; market?: string; }): Promise<SpotifyPlaylist>; /** * Update playlist details */ update(playlistId: string, options: { name?: string; description?: string; public?: boolean; collaborative?: boolean; }): Promise<void>; /** * Remove tracks from a playlist */ removeTracks(playlistId: string, tracks: Array<{ uri: string; positions?: number[]; }>): Promise<{ snapshot_id: string; }>; } /** * @file tracks.ts * @description Track-related API endpoints * @author Caleb Price * @version 1.0.0 * @date 2025-07-14 */ declare class TrackEndpoints extends BaseEndpoint { /** * Get user's saved tracks (liked songs) */ getSavedTracks(options?: { limit?: number; offset?: number; market?: string; }): Promise<SpotifyPagingObject<{ added_at: string; track: SpotifyTrack; }>>; /** * Validate limit parameter */ private validateLimit; /** * Validate offset parameter */ private validateOffset; /** * Get albums from user's liked songs */ getLikedSongsAlbums(fetchLimit?: number): Promise<any[]>; /** * Get track by ID */ getById(trackId: string, options?: { market?: string; }): Promise<SpotifyTrack>; /** * Get multiple tracks by IDs */ getByIds(trackIds: string[], options?: { market?: string; }): Promise<{ tracks: SpotifyTrack[]; }>; /** * Save tracks for current user */ saveTracks(trackIds: string[]): Promise<void>; /** * Remove tracks from current user's saved tracks */ removeTracks(trackIds: string[]): Promise<void>; /** * Check if tracks are saved for current user */ checkSavedTracks(trackIds: string[]): Promise<boolean[]>; /** * Get audio features for a track */ getAudioFeatures(trackId: string): Promise<any>; /** * Get audio analysis for a track */ getAudioAnalysis(trackId: string): Promise<any>; } /** * @file albums.ts * @description Album-related API endpoints * @author Caleb Price * @version 1.0.0 * @date 2025-07-14 */ declare class AlbumEndpoints extends BaseEndpoint { /** * Get album by ID */ getById(albumId: string, options?: { market?: string; }): Promise<SpotifyAlbum>; /** * Get multiple albums by IDs */ getByIds(albumIds: string[], options?: { market?: string; }): Promise<{ albums: SpotifyAlbum[]; }>; /** * Get album tracks */ getTracks(albumId: string, options?: { limit?: number; offset?: number; market?: string; }): Promise<SpotifyPagingObject<SpotifyTrack>>; /** * Get user's saved albums */ getSavedAlbums(options?: { limit?: number; offset?: number; market?: string; }): Promise<SpotifyPagingObject<{ added_at: string; album: SpotifyAlbum; }>>; /** * Save albums for current user */ saveAlbums(albumIds: string[]): Promise<void>; /** * Remove albums from current user's saved albums */ removeAlbums(albumIds: string[]): Promise<void>; /** * Check if albums are saved for current user */ checkSavedAlbums(albumIds: string[]): Promise<boolean[]>; /** * Get new album releases */ getNewReleases(options?: { country?: string; limit?: number; offset?: number; }): Promise<SpotifyPagingObject<SpotifyAlbum>>; } /** * @file artists.ts * @description Artist-related API endpoints * @author Caleb Price * @version 1.0.0 * @date 2025-07-14 */ declare class ArtistEndpoints extends BaseEndpoint { /** * Get artist by ID */ getById(artistId: string): Promise<SpotifyArtist>; /** * Get multiple artists by IDs */ getByIds(artistIds: string[]): Promise<{ artists: SpotifyArtist[]; }>; /** * Get artist's albums */ getAlbums(artistId: string, options?: { include_groups?: string[]; market?: string; limit?: number; offset?: number; }): Promise<SpotifyPagingObject<SpotifyAlbum>>; /** * Get artist's top tracks */ getTopTracks(artistId: string, options?: { market?: string; }): Promise<{ tracks: SpotifyTrack[]; }>; /** * Get related artists */ getRelatedArtists(artistId: string): Promise<{ artists: SpotifyArtist[]; }>; /** * Follow artists */ follow(artistIds: string[]): Promise<void>; /** * Unfollow artists */ unfollow(artistIds: string[]): Promise<void>; /** * Check if user follows artists */ checkFollowing(artistIds: string[]): Promise<boolean[]>; /** * Get user's followed artists */ getFollowed(options?: { limit?: number; after?: string; }): Promise<{ artists: SpotifyPagingObject<SpotifyArtist>; }>; } /** * @file search.ts * @description Search-related API endpoints * @author Caleb Price * @version 1.0.0 * @date 2025-07-14 */ declare class SearchEndpoints extends BaseEndpoint { /** * Search for items */ search(query: string, options?: { type?: string[]; limit?: number; offset?: number; market?: string; include_external?: string; }): Promise<SpotifySearchResponse>; /** * Search for tracks */ tracks(query: string, options?: { limit?: number; offset?: number; market?: string; }): Promise<SpotifySearchResponse>; /** * Search for albums */ albums(query: string, options?: { limit?: number; offset?: number; market?: string; }): Promise<SpotifySearchResponse>; /** * Search for artists */ artists(query: string, options?: { limit?: number; offset?: number; market?: string; }): Promise<SpotifySearchResponse>; /** * Search for playlists */ playlists(query: string, options?: { limit?: number; offset?: number; market?: string; }): Promise<SpotifySearchResponse>; /** * Search for shows */ shows(query: string, options?: { limit?: number; offset?: number; market?: string; }): Promise<SpotifySearchResponse>; /** * Search for episodes */ episodes(query: string, options?: { limit?: number; offset?: number; market?: string; }): Promise<SpotifySearchResponse>; /** * Search for audiobooks */ audiobooks(query: string, options?: { limit?: number; offset?: number; market?: string; }): Promise<SpotifySearchResponse>; /** * Search everything */ all(query: string, options?: { limit?: number; offset?: number; market?: string; }): Promise<SpotifySearchResponse>; } /** * @file player.ts * @description Player-related API endpoints * @author Caleb Price * @version 1.0.0 * @date 2025-07-14 */ interface SpotifyPlaybackState { device: { id: string; is_active: boolean; is_private_session: boolean; is_restricted: boolean; name: string; type: string; volume_percent: number; }; repeat_state: 'off' | 'track' | 'context'; shuffle_state: boolean; context: { type: string; href: string; external_urls: { spotify: string; }; uri: string; } | null; timestamp: number; progress_ms: number; is_playing: boolean; item: any; currently_playing_type: 'track' | 'episode' | 'ad' | 'unknown'; actions: { interrupting_playback?: boolean; pausing?: boolean; resuming?: boolean; seeking?: boolean; skipping_next?: boolean; skipping_prev?: boolean; toggling_repeat_context?: boolean; toggling_shuffle?: boolean; toggling_repeat_track?: boolean; transferring_playback?: boolean; }; } declare class PlayerEndpoints extends BaseEndpoint { /** * Get currently playing track */ getCurrentlyPlaying(options?: { market?: string; additional_types?: string[]; }): Promise<any>; /** * Get playback state */ getPlaybackState(options?: { market?: string; additional_types?: string[]; }): Promise<SpotifyPlaybackState>; /** * Transfer playback to a device */ transferPlayback(deviceIds: string[], play?: boolean): Promise<void>; /** * Get available devices */ getDevices(): Promise<{ devices: any[]; }>; /** * Start/Resume playback */ play(options?: { device_id?: string; context_uri?: string; uris?: string[]; offset?: { position: number; } | { uri: string; }; position_ms?: number; }): Promise<void>; /** * Pause playback */ pause(device_id?: string): Promise<void>; /** * Skip to next track */ next(device_id?: string): Promise<void>; /** * Skip to previous track */ previous(device_id?: string): Promise<void>; /** * Seek to position in track */ seek(position_ms: number, device_id?: string): Promise<void>; /** * Set repeat mode */ setRepeat(state: 'track' | 'context' | 'off', device_id?: string): Promise<void>; /** * Set shuffle mode */ setShuffle(state: boolean, device_id?: string): Promise<void>; /** * Set volume */ setVolume(volume_percent: number, device_id?: string): Promise<void>; /** * Add item to playback queue */ addToQueue(uri: string, device_id?: string): Promise<void>; /** * Get the user's queue */ getQueue(): Promise<any>; /** * Get recently played tracks */ getRecentlyPlayed(options?: { limit?: number; after?: number; before?: number; }): Promise<any>; } /** * @file user.ts * @description User-related API endpoints * @author Caleb Price * @version 1.0.0 * @date 2025-07-14 */ declare class UserEndpoints extends BaseEndpoint { /** * Get current user's profile */ getCurrentUser(): Promise<SpotifyUser>; /** * Get user's profile by ID */ getById(userId: string): Promise<SpotifyUser>; /** * Get user's top items (tracks or artists) */ getTopItems(type: 'tracks' | 'artists', options?: { time_range?: 'short_term' | 'medium_term' | 'long_term'; limit?: number; offset?: number; }): Promise<any>; /** * Get user's top tracks */ getTopTracks(options?: { time_range?: 'short_term' | 'medium_term' | 'long_term'; limit?: number; offset?: number; }): Promise<any>; /** * Get user's top artists */ getTopArtists(options?: { time_range?: 'short_term' | 'medium_term' | 'long_term'; limit?: number; offset?: number; }): Promise<any>; /** * Follow a user */ followUser(userId: string): Promise<void>; /** * Unfollow a user */ unfollowUser(userId: string): Promise<void>; /** * Check if current user follows users */ checkFollowingUsers(userIds: string[]): Promise<boolean[]>; } /** * @file main.ts * @description Main Spotify API class with constructor pattern for organized API access * @author Caleb Price * @version 1.0.0 * @date 2025-07-14 * * @description * Constructor-based Spotify API wrapper that provides organized methods for * interacting with the Spotify Web API. Supports playlists, tracks, albums, artists, search, player, and user operations. * * @usage * ```javascript * const spotify = new SpotifyApi(accessToken); * const playlists = await spotify.playlists.getUserPlaylists(); * const album = await spotify.albums.getById(albumId); * const tracks = await spotify.tracks.getSavedTracks(); * ``` * * @ChangeLog * - 1.0.0: Initial implementation with all endpoint categories */ declare class SpotifyApi { private httpClient; playlists: PlaylistEndpoints; tracks: TrackEndpoints; albums: AlbumEndpoints; artists: ArtistEndpoints; search: SearchEndpoints; player: PlayerEndpoints; user: UserEndpoints; constructor(accessToken?: string); /** * Initialize all endpoint groups */ private initializeEndpoints; /** * Basic token format validation */ private isValidTokenFormat; /** * Set access token for API requests */ setAccessToken(token: string): void; /** * Clear the access token */ clearAccessToken(): void; /** * Make a raw API request */ request(endpoint: string, options?: { method?: 'GET' | 'POST' | 'PUT' | 'DELETE'; data?: any; params?: Record<string, any>; }): Promise<any>; /** * Get the HTTP client instance for advanced usage */ getHttpClient(): SpotifyHttpClient; /** * Clean up resources and clear tokens */ destroy(): void; } export { AlbumEndpoints, ArtistEndpoints, PlayerEndpoints, PlaylistEndpoints, SearchEndpoints, type SpotifyAlbum, SpotifyApi, type SpotifyArtist, SpotifyHttpClient, type SpotifyImage, type SpotifyPagingObject, type SpotifyPlaylist, type SpotifySearchResponse, type SpotifyTrack, type SpotifyUser, TrackEndpoints, UserEndpoints, SpotifyApi as default };