Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@soundify/api

Package Overview
Dependencies
Maintainers
1
Versions
16
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@soundify/api - npm Package Compare versions

Comparing version 0.0.35 to 0.0.36

README.md

85

esm/client.js

@@ -14,41 +14,26 @@ import { objectToSearchParams, } from "@soundify/shared";

/**
* Returns promise that will be resolved after specified delay
* @param delay milliseconds
*/
export const wait = (delay) => {
return new Promise((res) => {
setTimeout(res, delay);
});
};
/**
* A client for making requests to the Spotify API.
*/
export class SpotifyClient {
/**
* Access token or object that implements `IAccessProvider`
*/
#accessProvider;
#retry5xx = {
times: 0,
delay: 0,
};
#retry429 = {
times: 0,
delay: 0,
};
authProvider;
opts;
constructor(
/**
* It is recommended to pass a class that implements `Accessor`
* It is recommended to pass a class that implements `IAuthProvider`
* to automatically update tokens. If you do not need this behavior,
* you can simply pass an access token.
*/
accessProvider, opts = {}) {
this.#accessProvider = accessProvider;
if (opts.retry5xx)
this.#retry5xx = opts.retry5xx;
if (opts.retry429)
this.#retry429 = opts.retry429;
authProvider, opts = {
retryOnRateLimit: false,
retryDelayOn5xx: 0,
retryTimesOn5xx: 0,
}) {
this.authProvider = authProvider;
this.opts = opts;
}
setAccessProvider(accessor) {
this.#accessProvider = accessor;
/**
* Method that changes the existing authProvider to the specified one
*/
setAuthProvider(authProvider) {
this.authProvider = authProvider;
}

@@ -61,8 +46,7 @@ async fetch(baseURL, responseType, { body, query, method } = {}) {

const serializedBody = body ? JSON.stringify(body) : undefined;
let isTriedRefresh = false;
let retry5xx = this.#retry5xx.times;
let retry429 = this.#retry429.times;
let accessToken = typeof this.#accessProvider === "string"
? this.#accessProvider
: await this.#accessProvider.getAccessToken();
let isTriedRefreshToken = false;
let retryTimesOn5xx = this.opts.retryTimesOn5xx;
let accessToken = typeof this.authProvider === "string"
? this.authProvider
: await this.authProvider.getAccessToken();
const call = async () => {

@@ -80,7 +64,7 @@ const res = await fetch(url, {

return res;
if (res.status === 401 && typeof this.#accessProvider !== "string" &&
!isTriedRefresh) {
if (res.status === 401 && typeof this.authProvider !== "string" &&
!isTriedRefreshToken) {
try {
accessToken = await this.#accessProvider.getAccessToken(true);
isTriedRefresh = true;
accessToken = await this.authProvider.getAccessToken(true);
isTriedRefreshToken = true;
return call();

@@ -92,12 +76,15 @@ }

}
if (res.status === 429 && retry429) {
if (this.#retry429.delay)
await wait(this.#retry429.delay);
retry429--;
return call();
if (res.status === 429 && this.opts.retryOnRateLimit) {
// time in seconds
const retryAfter = Number(res.headers.get("Retry-After"));
if (retryAfter) {
await new Promise((r) => setTimeout(r, retryAfter * 1000));
return call();
}
}
if (res.status.toString().startsWith("5") && retry5xx) {
if (this.#retry5xx.delay)
await wait(this.#retry5xx.delay);
retry5xx--;
if (res.status.toString().startsWith("5") && retryTimesOn5xx) {
if (this.opts.retryDelayOn5xx) {
await new Promise((r) => setTimeout(r, this.opts.retryDelayOn5xx));
}
retryTimesOn5xx--;
return call();

@@ -104,0 +91,0 @@ }

@@ -5,4 +5,4 @@ {

"name": "@soundify/api",
"version": "0.0.35",
"description": "Modern Spotify api wrapper for Node, Deno, and browser 🎧",
"version": "0.0.36",
"description": "🎧 Modern Spotify api wrapper for Node, Deno, and browser",
"license": "MIT",

@@ -13,5 +13,5 @@ "devDependencies": {

"dependencies": {
"@soundify/shared": "0.0.35"
"@soundify/shared": "0.0.36"
},
"packageManager": "pnpm@7.29.1",
"packageManager": "pnpm@7.29.3",
"repository": {

@@ -18,0 +18,0 @@ "type": "git",

@@ -1,3 +0,10 @@

import { FetchOpts, HTTPClient, IAccessProvider, JSONValue } from "@soundify/shared";
type Retry = {
import { FetchOpts, HTTPClient, IAuthProvider, JSONValue } from "@soundify/shared";
/**
* The Spotify client will throw this error if the api response is not "ok" (status >= 400)
*/
export declare class SpotifyError extends Error {
readonly status: number;
constructor(message: string, status: number, options?: ErrorOptions);
}
export interface SpotifyClientOpts {
/**

@@ -8,3 +15,3 @@ * How many times do you want to try again until you throw the error

*/
times: number;
retryTimesOn5xx?: number;
/**

@@ -15,25 +22,10 @@ * How long in miliseconds do you want to wait until the next retry

*/
delay: number;
};
/**
* The Spotify client will throw this error if the api response is not "ok" (status >= 400)
*/
export declare class SpotifyError extends Error {
readonly status: number;
constructor(message: string, status: number, options?: ErrorOptions);
}
/**
* Returns promise that will be resolved after specified delay
* @param delay milliseconds
*/
export declare const wait: (delay: number) => Promise<void>;
export interface SpotifyClientOpts {
retryDelayOn5xx?: number;
/**
* Retry options for errors with status code >= 500
* If it is set to true, it would refetch the same request after a paticular time interval sent by the spotify api in the headers `Retry-After` so you cannot face any obstacles.
* Otherwise, it will throw an error.
*
* @default false
*/
retry5xx?: Retry;
/**
* Retry options for rate limit errors
*/
retry429?: Retry;
retryOnRateLimit?: boolean;
}

@@ -44,14 +36,22 @@ /**

export declare class SpotifyClient implements HTTPClient {
#private;
/**
* It is recommended to pass a class that implements `IAuthProvider`
* to automatically update tokens. If you do not need this behavior,
* you can simply pass an access token.
*/
private authProvider;
private readonly opts;
constructor(
/**
* It is recommended to pass a class that implements `Accessor`
* It is recommended to pass a class that implements `IAuthProvider`
* to automatically update tokens. If you do not need this behavior,
* you can simply pass an access token.
*/
accessProvider: IAccessProvider | string, opts?: SpotifyClientOpts);
setAccessProvider(accessor: IAccessProvider | string): void;
authProvider: IAuthProvider | string, opts?: SpotifyClientOpts);
/**
* Method that changes the existing authProvider to the specified one
*/
setAuthProvider(authProvider: IAuthProvider | string): void;
fetch(baseURL: string, responseType: "void", opts?: FetchOpts): Promise<void>;
fetch<R extends JSONValue = JSONValue>(baseURL: string, responseType: "json", opts?: FetchOpts): Promise<R>;
}
export {};
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc