diff --git a/README.md b/README.md
index 692bede..ea39a43 100644
--- a/README.md
+++ b/README.md
@@ -23,15 +23,17 @@ The full API of this library can be found in [api.md](api.md).
```js
-import Spotify from '@stainless-commons/spotify';
+import { SpotifyClient } from '@stainless-commons/spotify';
-const client = new Spotify();
+const client = new SpotifyClient();
const album = await client.albums.retrieve('4aawyAB9vmqN3uQ7FjRGTy');
console.log(album.id);
```
+If no `auth` option is provided, the client reads the `SPOTIFY_ACCESS_TOKEN` environment variable automatically.
+
## Authentication
The SDK supports multiple authentication modes via the `SpotifyClient` class. Choose the mode that fits your use case.
@@ -42,7 +44,7 @@ Use this when your app needs to access Spotify catalog data without a user conte
```ts
-import { SpotifyClient } from '@stainless-commons/spotify/lib/auth';
+import { SpotifyClient } from '@stainless-commons/spotify';
const client = new SpotifyClient({
auth: {
@@ -64,11 +66,13 @@ Use this when a user has authorized your app via OAuth and you have an access to
```ts
-import { SpotifyClient } from '@stainless-commons/spotify/lib/auth';
+import { SpotifyClient } from '@stainless-commons/spotify';
-const client = new SpotifyClient({
- auth: process.env['SPOTIFY_ACCESS_TOKEN']!,
-});
+// Reads SPOTIFY_ACCESS_TOKEN from the environment automatically:
+const client = new SpotifyClient();
+
+// Or pass the token explicitly:
+// const client = new SpotifyClient({ auth: 'my-access-token' });
const me = await client.me.retrieve();
console.log(me.display_name);
@@ -83,9 +87,10 @@ This library includes TypeScript definitions for all request params and response
```ts
+import { SpotifyClient } from '@stainless-commons/spotify';
import Spotify from '@stainless-commons/spotify';
-const client = new Spotify();
+const client = new SpotifyClient();
const album: Spotify.AlbumRetrieveResponse = await client.albums.retrieve('4aawyAB9vmqN3uQ7FjRGTy');
```
@@ -135,10 +140,9 @@ You can use the `maxRetries` option to configure or disable this:
```js
// Configure the default for all requests:
-const client = new Spotify({
+const client = new SpotifyClient({
maxRetries: 0, // default is 2
});
-
// Or, configure per-request:
await client.albums.retrieve('4aawyAB9vmqN3uQ7FjRGTy', {
maxRetries: 5,
@@ -152,7 +156,7 @@ Requests time out after 1 minute by default. You can configure this with a `time
```ts
// Configure the default for all requests:
-const client = new Spotify({
+const client = new SpotifyClient({
timeout: 20 * 1000, // 20 seconds (default is 1 minute)
});
@@ -212,7 +216,7 @@ Unlike `.asResponse()` this method consumes the body, returning once it is parse
```ts
-const client = new Spotify();
+const client = new SpotifyClient({ auth });
const response = await client.albums.retrieve('4aawyAB9vmqN3uQ7FjRGTy').asResponse();
console.log(response.headers.get('X-My-Header'));
@@ -239,9 +243,8 @@ The log level can be configured in two ways:
2. Using the `logLevel` client option (overrides the environment variable if set)
```ts
-import Spotify from '@stainless-commons/spotify';
-
-const client = new Spotify({
+const client = new SpotifyClient({
+ auth: process.env['SPOTIFY_AUTH_CLIENT'],
logLevel: 'debug', // Show all log messages
});
```
@@ -272,7 +275,7 @@ import pino from 'pino';
const logger = pino();
-const client = new Spotify({
+const client = new SpotifyClient({
logger: logger.child({ name: 'Spotify' }),
logLevel: 'debug', // Send all messages to pino, allowing it to filter
});
@@ -339,7 +342,7 @@ Or pass it to the client:
import Spotify from '@stainless-commons/spotify';
import fetch from 'my-fetch';
-const client = new Spotify({ fetch });
+const client = new SpotifyClient({ fetch });
```
### Fetch options
@@ -349,7 +352,7 @@ If you want to set custom `fetch` options without overriding the `fetch` functio
```ts
import Spotify from '@stainless-commons/spotify';
-const client = new Spotify({
+const client = new SpotifyClient({
fetchOptions: {
// `RequestInit` options
},
@@ -364,11 +367,11 @@ options to requests:
**Node** [[docs](https://github.com/nodejs/undici/blob/main/docs/docs/api/ProxyAgent.md#example---proxyagent-with-fetch)]
```ts
-import Spotify from '@stainless-commons/spotify';
+import { SpotifyClient } from '@stainless-commons/spotify';
import * as undici from 'undici';
const proxyAgent = new undici.ProxyAgent('http://localhost:8888');
-const client = new Spotify({
+const client = new SpotifyClient({
fetchOptions: {
dispatcher: proxyAgent,
},
@@ -378,9 +381,9 @@ const client = new Spotify({
**Bun** [[docs](https://bun.sh/guides/http/proxy)]
```ts
-import Spotify from '@stainless-commons/spotify';
+import { SpotifyClient } from '@stainless-commons/spotify';
-const client = new Spotify({
+const client = new SpotifyClient({
fetchOptions: {
proxy: 'http://localhost:8888',
},
@@ -390,10 +393,10 @@ const client = new Spotify({
**Deno** [[docs](https://docs.deno.com/api/deno/~/Deno.createHttpClient)]
```ts
-import Spotify from 'npm:@stainless-commons/spotify';
+import { SpotifyClient } from 'npm:@stainless-commons/spotify';
const httpClient = Deno.createHttpClient({ proxy: { url: 'http://localhost:8888' } });
-const client = new Spotify({
+const client = new SpotifyClient({
fetchOptions: {
client: httpClient,
},
diff --git a/examples/auth-token.ts b/examples/auth-token.ts
index 7941692..9417f8c 100644
--- a/examples/auth-token.ts
+++ b/examples/auth-token.ts
@@ -1,15 +1,16 @@
-import { SpotifyClient } from '@stainless-commons/spotify/lib/auth';
+import { SpotifyClient } from '@stainless-commons/spotify';
/**
* Access Token flow: user-level auth with a pre-obtained token.
* Required for user-specific endpoints (/me, saved tracks, user playlists).
*
- * Required env vars:
- * SPOTIFY_ACCESS_TOKEN (user-scoped OAuth token)
+ * If SPOTIFY_ACCESS_TOKEN is set in the environment, you can omit the auth option:
+ * const client = new SpotifyClient();
+ *
+ * Or pass it explicitly:
+ * const client = new SpotifyClient({ auth: process.env['SPOTIFY_ACCESS_TOKEN']! });
*/
-const client = new SpotifyClient({
- auth: process.env['SPOTIFY_ACCESS_TOKEN']!,
-});
+const client = new SpotifyClient();
async function main() {
const me = await client.me.retrieve();
diff --git a/examples/oauth-client-creds.ts b/examples/oauth-client-creds.ts
index 8d29854..0c279f5 100644
--- a/examples/oauth-client-creds.ts
+++ b/examples/oauth-client-creds.ts
@@ -1,4 +1,4 @@
-import { SpotifyClient } from '@stainless-commons/spotify/lib/auth';
+import { SpotifyClient } from '@stainless-commons/spotify';
/**
* Client Credentials flow: app-level auth, no user context.
diff --git a/src/index.ts b/src/index.ts
index f4d6e00..6a1188d 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -6,6 +6,7 @@ export { type Uploadable, toFile } from './core/uploads';
export { APIPromise } from './core/api-promise';
export { Spotify, type ClientOptions } from './client';
export { PagePromise } from './core/pagination';
+export { SpotifyClient, type SpotifyClientOptions } from './lib/spotify-client';
export {
SpotifyError,
APIError,
diff --git a/src/lib/spotify-client.ts b/src/lib/spotify-client.ts
index 93faabe..3706216 100644
--- a/src/lib/spotify-client.ts
+++ b/src/lib/spotify-client.ts
@@ -6,20 +6,25 @@ import { TokenManager } from './auth/token-manager';
import type { AuthConfig } from './auth/types';
export interface SpotifyClientOptions extends Omit {
- auth: AuthConfig | string;
+ auth?: AuthConfig | string | undefined;
}
export class SpotifyClient extends Spotify {
private tokenManager: TokenManager;
private authConfig: AuthConfig;
- constructor(options: SpotifyClientOptions) {
- if (!options.auth) {
- throw new Error('The `auth` option is required. Pass an access token string or an AuthConfig object.');
+ constructor(options: SpotifyClientOptions = {}) {
+ const resolvedAuth = options.auth ?? process.env['SPOTIFY_ACCESS_TOKEN'];
+
+ if (!resolvedAuth) {
+ throw new Error(
+ 'No authentication provided. Pass an `auth` option (access token string or AuthConfig object) ' +
+ 'or set the SPOTIFY_ACCESS_TOKEN environment variable.',
+ );
}
const authConfig: AuthConfig =
- typeof options.auth === 'string' ? { type: 'access_token', accessToken: options.auth } : options.auth;
+ typeof resolvedAuth === 'string' ? { type: 'access_token', accessToken: resolvedAuth } : resolvedAuth;
const { auth: _auth, ...baseOptions } = options;
super(baseOptions);