diff --git a/src/SpotifyApi.ts b/src/SpotifyApi.ts index f75aa89..a600904 100644 --- a/src/SpotifyApi.ts +++ b/src/SpotifyApi.ts @@ -85,7 +85,7 @@ export class SpotifyApi { method: "GET" | "POST" | "PUT" | "DELETE", url: string, body: any = undefined, - contentType: string | undefined = undefined, + contentType: string | undefined = undefined ): Promise { try { const accessToken = @@ -187,12 +187,12 @@ export class SpotifyApi { clientId: string, redirectUri: string, scopes: string[] = [], - config?: SdkOptions, + config?: SdkOptions ): SpotifyApi { const strategy = new AuthorizationCodeWithPKCEStrategy( clientId, redirectUri, - scopes, + scopes ); return new SpotifyApi(strategy, config); } @@ -200,14 +200,9 @@ export class SpotifyApi { public static withClientCredentials( clientId: string, clientSecret: string, - scopes: string[] = [], - config?: SdkOptions, + config?: SdkOptions ): SpotifyApi { - const strategy = new ClientCredentialsStrategy( - clientId, - clientSecret, - scopes, - ); + const strategy = new ClientCredentialsStrategy(clientId, clientSecret); return new SpotifyApi(strategy, config); } @@ -215,7 +210,7 @@ export class SpotifyApi { clientId: string, redirectUri: string, scopes: string[] = [], - config?: SdkOptions, + config?: SdkOptions ): SpotifyApi { const strategy = new ImplicitGrantStrategy(clientId, redirectUri, scopes); return new SpotifyApi(strategy, config); @@ -228,7 +223,7 @@ export class SpotifyApi { public static withAccessToken( clientId: string, token: AccessToken, - config?: SdkOptions, + config?: SdkOptions ): SpotifyApi { const strategy = new ProvidedAccessTokenStrategy(clientId, token); return new SpotifyApi(strategy, config); @@ -247,7 +242,7 @@ export class SpotifyApi { redirectUri: string, scopes: string[], postbackUrl: string, - config?: SdkOptions, + config?: SdkOptions ): Promise; /** @@ -264,7 +259,7 @@ export class SpotifyApi { redirectUri: string, scopes: string[], onAuthorization: (token: AccessToken) => Promise, - config?: SdkOptions, + config?: SdkOptions ): Promise; public static async performUserAuthorization( @@ -272,12 +267,12 @@ export class SpotifyApi { redirectUri: string, scopes: string[], onAuthorizationOrUrl: ((token: AccessToken) => Promise) | string, - config?: SdkOptions, + config?: SdkOptions ): Promise { const strategy = new AuthorizationCodeWithPKCEStrategy( clientId, redirectUri, - scopes, + scopes ); const client = new SpotifyApi(strategy, config); const accessToken = @@ -298,164 +293,10 @@ export class SpotifyApi { } } - public async makeRequest(method: "GET" | "POST" | "PUT" | "DELETE", url: string, body: any = undefined, contentType: string | undefined = undefined): Promise { - try { - const accessToken = await this.authenticationStrategy.getOrCreateAccessToken(); - if (isEmptyAccessToken(accessToken)) { - console.warn("No access token found, authenticating now."); - return null as TReturnType; - } - - const token = accessToken?.access_token; - - const fullUrl = SpotifyApi.rootUrl + url; - const opts: RequestInit = { - method: method, - headers: { - Authorization: `Bearer ${token}`, - "Content-Type": contentType ?? "application/json" - }, - body: body ? typeof body === "string" ? body : JSON.stringify(body) : undefined - }; - - this.sdkConfig.beforeRequest(fullUrl, opts); - const result = await this.sdkConfig.fetch(fullUrl, opts); - this.sdkConfig.afterRequest(fullUrl, opts, result); - - if (result.status === 204) { - return null as TReturnType; - } - - await this.sdkConfig.responseValidator.validateResponse(result); - return this.sdkConfig.deserializer.deserialize(result); - } catch (error) { - const handled = await this.sdkConfig.errorHandler.handleErrors(error); - if (!handled) { - throw error; - } - return null as TReturnType; - } - } - - private initializeSdk(config: SdkOptions | undefined): SdkConfiguration { - const isBrowser = typeof window !== 'undefined'; - - const defaultConfig: SdkConfiguration = { - fetch: (req: RequestInfo | URL, init: RequestInit | undefined) => fetch(req, init), - beforeRequest: (_: string, __: RequestInit) => { }, - afterRequest: (_: string, __: RequestInit, ___: Response) => { }, - deserializer: new DefaultResponseDeserializer(), - responseValidator: new DefaultResponseValidator(), - errorHandler: new NoOpErrorHandler(), - redirectionStrategy: new DocumentLocationRedirectionStrategy(), - cachingStrategy: isBrowser - ? new LocalStorageCachingStrategy() - : new InMemoryCachingStrategy() - }; - - return { ...defaultConfig, ...config }; - } - - public switchAuthenticationStrategy(authentication: IAuthStrategy) { - this.authenticationStrategy = authentication; - this.authenticationStrategy.setConfiguration(this.sdkConfig); - this.authenticationStrategy.getOrCreateAccessToken(); // trigger any redirects - } - - /** - * Use this when you're running in a browser and you want to control when first authentication+redirect happens. - */ - public async authenticate(): Promise { - const response = await this.authenticationStrategy.getOrCreateAccessToken(); // trigger any redirects - - return { - authenticated: response.expires! > Date.now() && !isEmptyAccessToken(response), - accessToken: response - }; - } - - /** - * @returns the current access token. null implies the SpotifyApi is not yet authenticated. - */ - public async getAccessToken(): Promise { - return this.authenticationStrategy.getAccessToken(); - } - - /** - * Removes the access token if it exists. - */ - public logOut(): void { - this.authenticationStrategy.removeAccessToken(); - } - - public static withUserAuthorization(clientId: string, redirectUri: string, scopes: string[] = [], config?: SdkOptions): SpotifyApi { - const strategy = new AuthorizationCodeWithPKCEStrategy(clientId, redirectUri, scopes); - return new SpotifyApi(strategy, config); - } - - public static withClientCredentials(clientId: string, clientSecret: string, config?: SdkOptions): SpotifyApi {//change - const strategy = new ClientCredentialsStrategy(clientId, clientSecret); - return new SpotifyApi(strategy, config); - } - - public static withImplicitGrant(clientId: string, redirectUri: string, scopes: string[] = [], config?: SdkOptions): SpotifyApi { - const strategy = new ImplicitGrantStrategy(clientId, redirectUri, scopes); - return new SpotifyApi(strategy, config); - } - - /** - * Use this when you're running in a Node environment, and accepting the access token from a client-side `performUserAuthorization` call. - * You can also use this method if you already have an access token and don't want to use the built-in authentication strategies. - */ - public static withAccessToken(clientId: string, token: AccessToken, config?: SdkOptions): SpotifyApi { - const strategy = new ProvidedAccessTokenStrategy(clientId, token); - return new SpotifyApi(strategy, config); - } - - /** - * Use this when you're running in the browser, and want to perform the user authorization flow to post back to your server with the access token. - * @param clientId Your Spotify client ID - * @param redirectUri The URI to redirect to after the user has authorized your app - * @param scopes The scopes to request - * @param postbackUrl The URL to post the access token to - * @param config Optional configuration - */ - public static async performUserAuthorization(clientId: string, redirectUri: string, scopes: string[], postbackUrl: string, config?: SdkOptions): Promise; - - /** - * Use this when you're running in the browser, and want to perform the user authorization flow to post back to your server with the access token. - * This overload is provided for you to perform the postback yourself, if you want to do something other than a simple HTTP POST to a URL - for example, if you want to use a WebSocket, or provide custom authentication. - * @param clientId Your Spotify client ID - * @param redirectUri The URI to redirect to after the user has authorized your app - * @param scopes The scopes to request - * @param onAuthorization A function to call with the access token where YOU perform the server-side postback - * @param config Optional configuration - */ - public static async performUserAuthorization(clientId: string, redirectUri: string, scopes: string[], onAuthorization: (token: AccessToken) => Promise, config?: SdkOptions): Promise; - - public static async performUserAuthorization(clientId: string, redirectUri: string, scopes: string[], onAuthorizationOrUrl: ((token: AccessToken) => Promise) | string, config?: SdkOptions): Promise { - const strategy = new AuthorizationCodeWithPKCEStrategy(clientId, redirectUri, scopes); - const client = new SpotifyApi(strategy, config); - const accessToken = await client.authenticationStrategy.getOrCreateAccessToken(); - - if (!isEmptyAccessToken(accessToken)) { - if (typeof onAuthorizationOrUrl === "string") { - console.log("Posting access token to postback URL."); - await fetch(onAuthorizationOrUrl, { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify(accessToken) - }); - } else { - await onAuthorizationOrUrl(accessToken); - } - } - - return { - authenticated: accessToken.expires! > Date.now() && !isEmptyAccessToken(accessToken), - accessToken - }; - } + return { + authenticated: + accessToken.expires! > Date.now() && !isEmptyAccessToken(accessToken), + accessToken, + }; + } }