soundcloud-api-ts 1.13.3 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md CHANGED
@@ -125,20 +125,20 @@ try {
125
125
  2. **User token vs client token** — write operations (like, repost, comment, follow, create/update/delete) require a user token obtained via the authorization code flow. A client credentials token won't work.
126
126
  3. **Rate limits exist** — SoundCloud returns 429 when rate limited. The client has built-in retry with exponential backoff (configurable via `maxRetries` and `retryBaseDelay`). `Retry-After` header is honored (capped 60s).
127
127
  4. **Auto token refresh** — pass `onTokenRefresh` in the config to automatically refresh expired tokens on 401.
128
- 5. **Request telemetry** — pass `onRequest` in the config to receive `SCRequestTelemetry` after every request (method, path, duration, status, retries, error). Fires on all paths including pagination and retries.
128
+ 5. **Request telemetry** — pass `onRequest` in the config to receive `SCRequestTelemetry` after every client-namespace request (method, path, duration, status, retries, error), including pagination and retries. NOT emitted for `sc.raw.*` or `auth.signOut`.
129
129
  6. **sc.raw** — `sc.raw.get('/tracks/{id}', { id: 123456 })` calls any endpoint without a typed wrapper. Returns `RawResponse<T>` with `{ data, status, headers }`. Does NOT throw on non-2xx — check `res.status` yourself. Good for endpoints not yet wrapped.
130
- 7. **Fetch injection** — pass `fetch` and `AbortController` in the constructor for Bun/Deno/Cloudflare Workers portability. No Node-only APIs used at runtime.
131
- 8. **Deduplication** — concurrent identical GETs share a single in-flight promise (`dedupe: true` by default). Prevents redundant fetches in SSR or concurrent component trees.
132
- 9. **Cache** — pass a `SoundCloudCache` implementation in the constructor to cache GET responses. Base package defines the interface only; bring your own backend. `cacheTtlMs` defaults to 60000ms.
130
+ 7. **Fetch injection** — pass `fetch` in the constructor for Bun/Deno/Cloudflare Workers portability. No Node-only APIs used at runtime. There is no `AbortController` option — bake cancellation/timeouts into the `fetch` you inject.
131
+ 8. **Deduplication** — concurrent identical GETs through the client namespaces share a single in-flight promise (`dedupe: true` by default; wired up in v1.14.0 earlier versions accepted but ignored the option). `sc.raw.*` and pagination `next_href` fetches are not deduped.
132
+ 9. **Cache** — pass a `SoundCloudCache` implementation in the constructor to cache namespace GET responses (also wired up in v1.14.0). Base package defines the interface only; bring your own backend. `cacheTtlMs` defaults to 60000ms.
133
133
  10. **Retry hook** — pass `onRetry` to receive `RetryInfo` on each retry: `{ attempt, delayMs, reason, status?, url }`.
134
- 11. **`sc.tracks.getTracks(ids[])`** — batch fetch multiple tracks by ID array in a single request. Returns `SoundCloudTrack[]` (may be shorter than input if some tracks are unavailable).
134
+ 11. **`sc.tracks.getTracks(ids[])`** — batch fetch multiple tracks by ID array in a single request. Max 200 IDs — throws immediately above that, before any network call. Returns `SoundCloudTrack[]` (may be shorter than input if some tracks are unavailable).
135
135
  12. **`sc.me.getConnections()`** — list linked social accounts. Requires user token. May require elevated API access.
136
136
  13. **TokenProvider / TokenStore interfaces** — in `src/auth/token-provider.ts`. Implement to integrate with NextAuth, Clerk, Redis, or any session framework. See `docs/auth-guide.md`.
137
137
  14. **Auth guide** — `docs/auth-guide.md` covers: client creds vs user tokens, full PKCE flow, auto-refresh, NextAuth/Clerk bridge patterns, 401 troubleshooting table (invalid_client / insufficient_scope / invalid_token / unauthorized_client).
138
138
  15. **OpenAPI tooling** — `pnpm openapi:sync` fetches the spec (if available), `pnpm openapi:coverage` reports implemented vs total. `src/client/registry.ts` is the source of truth — update it when adding new endpoints.
139
- 6. **No env vars** — the package reads no environment variables. Pass `clientId`, `clientSecret`, and `redirectUri` directly to the constructor.
140
- 7. **IDs can be numbers or strings** — all ID parameters accept `string | number`.
141
- 8. **Search pagination** — search uses zero-based `pageNumber` (10 results per page), not cursor-based pagination.
139
+ 16. **No env vars** — the package reads no environment variables. Pass `clientId`, `clientSecret`, and `redirectUri` directly to the constructor.
140
+ 17. **IDs can be numbers or strings** — all ID parameters accept `string | number`.
141
+ 18. **Search pagination** — search uses zero-based `pageNumber` (10 results per page), not cursor-based pagination.
142
142
 
143
143
  ## Project Structure (for contributors)
144
144
 
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  [![bundle size](https://img.shields.io/bundlephobia/minzip/soundcloud-api-ts)](https://bundlephobia.com/package/soundcloud-api-ts)
8
8
  [![install size](https://packagephobia.com/badge?p=soundcloud-api-ts)](https://packagephobia.com/result?p=soundcloud-api-ts)
9
9
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.9+-blue.svg)](https://www.typescriptlang.org/)
10
- [![Node](https://img.shields.io/badge/Node.js-≥22-339933.svg)](https://nodejs.org/)
10
+ [![Node](https://img.shields.io/badge/Node.js-≥20-339933.svg)](https://nodejs.org/)
11
11
  [![coverage](https://img.shields.io/badge/coverage-100%25-brightgreen.svg)]()
12
12
  [![docs](https://img.shields.io/badge/docs-TypeDoc-blue.svg)](https://twin-paws.github.io/soundcloud-api-ts/)
13
13
  [![GitHub stars](https://img.shields.io/github/stars/twin-paws/soundcloud-api-ts)](https://github.com/twin-paws/soundcloud-api-ts)
@@ -25,11 +25,11 @@ It is built on SoundCloud's **official documented API** with registered app cred
25
25
  - **TypeScript-first** — full types ship in the package. No `@types/*` installs, no casting to `any`.
26
26
  - **Zero dependencies** — native `fetch`, nothing in `node_modules` at runtime. 4.5 KB min+gz.
27
27
  - **Production HTTP layer** — exponential backoff on 429/5xx, `Retry-After` header respected, in-flight GET deduplication, pluggable cache interface, `onRetry` hook.
28
- - **Runtime portable** — inject your own `fetch` and `AbortController` for Cloudflare Workers, Bun, Deno, and Edge runtimes.
28
+ - **Runtime portable** — inject your own `fetch` for Cloudflare Workers, Bun, Deno, and Edge runtimes.
29
29
  - **Raw escape hatch** — `sc.raw.get('/any/endpoint/{id}', { id })` calls anything in the spec, not just wrapped endpoints. Never blocked by a missing wrapper.
30
30
  - **Full auth support** — client credentials flow for server-to-server, authorization code + PKCE for user-context operations, auto token refresh on 401.
31
31
  - **Pagination built-in** — async iterators and `fetchAll` helpers across all paginated endpoints.
32
- - **Interactive CLI** — `sc-cli tracks <id>`, `sc-cli search <query>`, `sc-cli me` from your terminal.
32
+ - **Interactive CLI** — `sc-cli track <id>`, `sc-cli search <query>`, `sc-cli me` from your terminal.
33
33
  - **LLM-friendly** — ships `llms.txt`, `llms-full.txt`, and `AGENTS.md` for AI coding agents.
34
34
 
35
35
  ## Comparison
@@ -131,9 +131,11 @@ sc.setToken(token.access_token);
131
131
 
132
132
  // Now all calls use the stored token automatically
133
133
  const results = await sc.search.tracks("electronic");
134
- const me = await sc.me.getMe();
135
134
  const track = await sc.tracks.getTrack(123456);
136
135
  const streams = await sc.tracks.getStreams(123456);
136
+
137
+ // /me endpoints need a user token (authorization code flow), not a client token:
138
+ // const me = await sc.me.getMe();
137
139
  ```
138
140
 
139
141
  ## OAuth 2.1 Flow
@@ -240,7 +242,7 @@ sc.users.getWebProfiles(userId, options?)
240
242
 
241
243
  // Tracks
242
244
  sc.tracks.getTrack(trackId, options?)
243
- sc.tracks.getTracks(ids[], options?) // batch fetch by IDs
245
+ sc.tracks.getTracks(ids[], options?) // batch fetch by IDs (max 200, throws above)
244
246
  sc.tracks.getStreams(trackId, options?)
245
247
  sc.tracks.getComments(trackId, limit?, options?)
246
248
  sc.tracks.createComment(trackId, body, timestamp?, options?)
@@ -277,12 +279,12 @@ sc.search.playlists(query, pageNumber?, options?)
277
279
 
278
280
  // Resolve
279
281
  sc.resolve.resolveUrl(url, options?)
280
- ```
281
282
 
282
283
  // Raw escape hatch — call any endpoint
283
284
  sc.raw.get('/tracks/{id}', { id: 123456 })
284
285
  sc.raw.post('/tracks/{id}/comments', { body: { body: 'great track' } })
285
286
  sc.raw.request({ method: 'GET', path: '/me', query: {} })
287
+ ```
286
288
 
287
289
  Where `options` is `{ token?: string }` — only needed to override the stored token.
288
290
 
@@ -461,6 +463,10 @@ const sc = new SoundCloudClient({
461
463
  });
462
464
  ```
463
465
 
466
+ Dedupe and cache apply to GETs made through the client namespaces (`sc.tracks.*`, `sc.users.*`, …). `sc.raw.*` and pagination `next_href` continuation fetches are not deduped or cached.
467
+
468
+ > **Note:** the `dedupe`, `cache`, and `cacheTtlMs` options were accepted but not actually wired up in v1.12.0–v1.13.4 — they take effect from v1.14.0.
469
+
464
470
  ### Pluggable Cache
465
471
 
466
472
  Bring your own cache backend — in-memory, Redis, Cloudflare KV, whatever. The base package defines the interface only (no implementation, no deps):
@@ -490,12 +496,11 @@ Pass a custom `fetch` implementation to work in any runtime — Cloudflare Worke
490
496
  ```ts
491
497
  const sc = new SoundCloudClient({
492
498
  clientId, clientSecret,
493
- fetch: myCustomFetch, // optional: custom fetch
494
- AbortController: myAbortCtrl, // optional: custom AbortController
499
+ fetch: myCustomFetch, // optional: custom fetch (defaults to globalThis.fetch)
495
500
  });
496
501
  ```
497
502
 
498
- No Node-only APIs are used at runtime. The client works anywhere `fetch` is available.
503
+ No Node-only APIs are used at runtime. The client works anywhere `fetch` is available. There is no `AbortController` option — if you need cancellation or timeouts, wrap them into the `fetch` you inject.
499
504
 
500
505
  ---
501
506
 
@@ -551,7 +556,7 @@ The `SCRequestTelemetry` object includes:
551
556
  | `retryCount` | `number` | Number of retries (0 = first attempt succeeded) |
552
557
  | `error` | `string?` | Error message if the request failed |
553
558
 
554
- Telemetry fires on every code path: direct calls, pagination, retries, and 401 token refresh. It's fully optional — zero overhead when `onRequest` is not set.
559
+ Telemetry fires for all client-namespace requests: direct calls, pagination, retries, and 401 token refresh. It is **not** emitted for `sc.raw.*` or `auth.signOut`. Fully optional — zero overhead when `onRequest` is not set.
555
560
 
556
561
  ## API Terms Compliance
557
562
 
@@ -3,6 +3,7 @@ import { SoundCloudError } from './chunk-QYYEWUIJ.mjs';
3
3
  // src/client/http.ts
4
4
  var BASE_URL = "https://api.soundcloud.com";
5
5
  var AUTH_BASE_URL = "https://secure.soundcloud.com";
6
+ var DEFAULT_CACHE_TTL_MS = 6e4;
6
7
  var DEFAULT_RETRY = { maxRetries: 3, retryBaseDelay: 1e3 };
7
8
  function delay(ms) {
8
9
  return new Promise((resolve) => setTimeout(resolve, ms));
@@ -29,6 +30,26 @@ async function parseErrorBody(response) {
29
30
  }
30
31
  }
31
32
  async function scFetch(options, refreshCtx, onRequest) {
33
+ const deduper = refreshCtx?.deduper;
34
+ const cache = refreshCtx?.cache;
35
+ if (options.method !== "GET" || !deduper && !cache) {
36
+ return scFetchCore(options, refreshCtx, onRequest);
37
+ }
38
+ const key = `GET ${options.path} ${options.token ?? ""}`;
39
+ const run = async () => {
40
+ if (cache) {
41
+ const hit = await cache.get(key);
42
+ if (hit !== void 0) return hit;
43
+ }
44
+ const result = await scFetchCore(options, refreshCtx, onRequest);
45
+ if (cache && result !== void 0) {
46
+ await cache.set(key, result, { ttlMs: refreshCtx?.cacheTtlMs ?? DEFAULT_CACHE_TTL_MS });
47
+ }
48
+ return result;
49
+ };
50
+ return deduper ? deduper.add(key, run) : run();
51
+ }
52
+ async function scFetchCore(options, refreshCtx, onRequest) {
32
53
  const retryConfig = refreshCtx?.retry ?? DEFAULT_RETRY;
33
54
  const telemetryCallback = onRequest ?? refreshCtx?.onRequest;
34
55
  const startTime = Date.now();
@@ -71,8 +92,9 @@ async function scFetch(options, refreshCtx, onRequest) {
71
92
  headers["Content-Type"] = options.contentType;
72
93
  }
73
94
  let lastResponse;
95
+ const fetchFn = refreshCtx?.fetchImpl ?? fetch;
74
96
  for (let attempt = 0; attempt <= retryConfig.maxRetries; attempt++) {
75
- const response = await fetch(url, {
97
+ const response = await fetchFn(url, {
76
98
  method: options.method,
77
99
  headers,
78
100
  body: fetchBody,
@@ -151,7 +173,7 @@ async function scFetch(options, refreshCtx, onRequest) {
151
173
  throw err;
152
174
  }
153
175
  }
154
- async function scFetchUrl(url, token, retryConfig, onRequest) {
176
+ async function scFetchUrl(url, token, retryConfig, onRequest, fetchImpl) {
155
177
  const config = retryConfig ?? DEFAULT_RETRY;
156
178
  const headers = { Accept: "application/json" };
157
179
  if (token) headers["Authorization"] = `OAuth ${token}`;
@@ -170,8 +192,9 @@ async function scFetchUrl(url, token, retryConfig, onRequest) {
170
192
  });
171
193
  };
172
194
  let lastResponse;
195
+ const fetchFn = fetchImpl ?? fetch;
173
196
  for (let attempt = 0; attempt <= config.maxRetries; attempt++) {
174
- const response = await fetch(url, { method: "GET", headers, redirect: "manual" });
197
+ const response = await fetchFn(url, { method: "GET", headers, redirect: "manual" });
175
198
  finalStatus = response.status;
176
199
  if (response.status === 302) {
177
200
  const location = response.headers.get("location");
@@ -235,6 +258,14 @@ async function scFetchUrl(url, token, retryConfig, onRequest) {
235
258
  throw err;
236
259
  }
237
260
 
261
+ // src/utils/base64.ts
262
+ var toBase64 = (value) => {
263
+ if (typeof Buffer !== "undefined") {
264
+ return Buffer.from(value).toString("base64");
265
+ }
266
+ return btoa(value);
267
+ };
268
+
238
269
  // src/client/paginate.ts
239
270
  async function* paginate(firstPage, fetchNext) {
240
271
  let page = await firstPage();
@@ -353,6 +384,28 @@ var RawClient = class {
353
384
  }
354
385
  };
355
386
 
387
+ // src/client/dedupe.ts
388
+ var InFlightDeduper = class {
389
+ inFlight = /* @__PURE__ */ new Map();
390
+ /**
391
+ * Return an existing in-flight promise for `key`, or start a new one via `factory`.
392
+ * The entry is removed from the map once the promise settles (resolve or reject).
393
+ */
394
+ add(key, factory) {
395
+ const existing = this.inFlight.get(key);
396
+ if (existing) return existing;
397
+ const promise = factory().finally(() => {
398
+ this.inFlight.delete(key);
399
+ });
400
+ this.inFlight.set(key, promise);
401
+ return promise;
402
+ }
403
+ /** Number of currently in-flight requests */
404
+ get size() {
405
+ return this.inFlight.size;
406
+ }
407
+ };
408
+
356
409
  // src/client/SoundCloudClient.ts
357
410
  function resolveToken(tokenGetter, explicit) {
358
411
  const t = explicit ?? tokenGetter();
@@ -397,6 +450,14 @@ var SoundCloudClient = class _SoundCloudClient {
397
450
  onDebug: config.onDebug,
398
451
  onRetry: config.onRetry
399
452
  };
453
+ const sharedCtx = {
454
+ retry: retryConfig,
455
+ onRequest: config.onRequest,
456
+ fetchImpl: config.fetch,
457
+ deduper: config.dedupe ?? true ? new InFlightDeduper() : void 0,
458
+ cache: config.cache,
459
+ cacheTtlMs: config.cacheTtlMs
460
+ };
400
461
  const refreshCtx = config.onTokenRefresh ? {
401
462
  getToken,
402
463
  onTokenRefresh: async () => {
@@ -404,16 +465,14 @@ var SoundCloudClient = class _SoundCloudClient {
404
465
  return result;
405
466
  },
406
467
  setToken: (a, r) => this.setToken(a, r),
407
- retry: retryConfig,
408
- onRequest: config.onRequest
468
+ ...sharedCtx
409
469
  } : {
410
470
  getToken,
411
471
  setToken: (
412
472
  /* v8 ignore next */
413
473
  (a, r) => this.setToken(a, r)
414
474
  ),
415
- retry: retryConfig,
416
- onRequest: config.onRequest
475
+ ...sharedCtx
417
476
  };
418
477
  this.auth = new _SoundCloudClient.Auth(this.config);
419
478
  this.me = new _SoundCloudClient.Me(getToken, refreshCtx);
@@ -465,7 +524,7 @@ var SoundCloudClient = class _SoundCloudClient {
465
524
  paginate(firstPage) {
466
525
  const token = this._accessToken;
467
526
  const onReq = this.config.onRequest;
468
- return paginate(firstPage, (url) => scFetchUrl(url, token, void 0, onReq));
527
+ return paginate(firstPage, (url) => scFetchUrl(url, token, void 0, onReq, this.config.fetch));
469
528
  }
470
529
  /**
471
530
  * Async generator that yields individual items across all pages.
@@ -483,7 +542,7 @@ var SoundCloudClient = class _SoundCloudClient {
483
542
  paginateItems(firstPage) {
484
543
  const token = this._accessToken;
485
544
  const onReq = this.config.onRequest;
486
- return paginateItems(firstPage, (url) => scFetchUrl(url, token, void 0, onReq));
545
+ return paginateItems(firstPage, (url) => scFetchUrl(url, token, void 0, onReq, this.config.fetch));
487
546
  }
488
547
  /**
489
548
  * Collects all pages into a single flat array.
@@ -502,7 +561,7 @@ var SoundCloudClient = class _SoundCloudClient {
502
561
  fetchAll(firstPage, options) {
503
562
  const token = this._accessToken;
504
563
  const onReq = this.config.onRequest;
505
- return fetchAll(firstPage, (url) => scFetchUrl(url, token, void 0, onReq), options);
564
+ return fetchAll(firstPage, (url) => scFetchUrl(url, token, void 0, onReq, this.config.fetch), options);
506
565
  }
507
566
  };
508
567
  ((SoundCloudClient2) => {
@@ -511,7 +570,25 @@ var SoundCloudClient = class _SoundCloudClient {
511
570
  this.config = config;
512
571
  }
513
572
  fetch(opts) {
514
- return scFetch(opts, void 0, this.config.onRequest);
573
+ const ctx = {
574
+ getToken: (
575
+ /* v8 ignore next */
576
+ () => void 0
577
+ ),
578
+ setToken: (
579
+ /* v8 ignore next */
580
+ () => {
581
+ }
582
+ ),
583
+ retry: {
584
+ maxRetries: this.config.maxRetries ?? 3,
585
+ retryBaseDelay: this.config.retryBaseDelay ?? 1e3,
586
+ onDebug: this.config.onDebug,
587
+ onRetry: this.config.onRetry
588
+ },
589
+ fetchImpl: this.config.fetch
590
+ };
591
+ return scFetch(opts, ctx, this.config.onRequest);
515
592
  }
516
593
  /**
517
594
  * Build the authorization URL to redirect users to SoundCloud's OAuth login page.
@@ -559,7 +636,7 @@ var SoundCloudClient = class _SoundCloudClient {
559
636
  * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/oauth2/post_oauth2_token
560
637
  */
561
638
  async getClientToken() {
562
- const credentials = Buffer.from(`${this.config.clientId}:${this.config.clientSecret}`).toString("base64");
639
+ const credentials = toBase64(`${this.config.clientId}:${this.config.clientSecret}`);
563
640
  return this.fetch({
564
641
  path: "/oauth/token",
565
642
  method: "POST",
@@ -586,6 +663,7 @@ var SoundCloudClient = class _SoundCloudClient {
586
663
  * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/oauth2/post_oauth2_token
587
664
  */
588
665
  async getUserToken(code, codeVerifier) {
666
+ if (!this.config.redirectUri) throw new Error("redirectUri is required for getUserToken");
589
667
  const params = {
590
668
  grant_type: "authorization_code",
591
669
  client_id: this.config.clientId,
@@ -616,6 +694,7 @@ var SoundCloudClient = class _SoundCloudClient {
616
694
  * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/oauth2/post_oauth2_token
617
695
  */
618
696
  async refreshUserToken(refreshToken) {
697
+ if (!this.config.redirectUri) throw new Error("redirectUri is required for refreshUserToken");
619
698
  return this.fetch({
620
699
  path: "/oauth/token",
621
700
  method: "POST",
@@ -644,7 +723,8 @@ var SoundCloudClient = class _SoundCloudClient {
644
723
  * ```
645
724
  */
646
725
  async signOut(accessToken) {
647
- const res = await fetch("https://secure.soundcloud.com/sign-out", {
726
+ const fetchFn = this.config.fetch ?? fetch;
727
+ const res = await fetchFn("https://secure.soundcloud.com/sign-out", {
648
728
  method: "POST",
649
729
  headers: { "Content-Type": "application/json" },
650
730
  body: JSON.stringify({ access_token: accessToken })
@@ -1643,28 +1723,6 @@ var SoundCloudClient = class _SoundCloudClient {
1643
1723
  SoundCloudClient2.Reposts = Reposts;
1644
1724
  })(SoundCloudClient || (SoundCloudClient = {}));
1645
1725
 
1646
- // src/client/dedupe.ts
1647
- var InFlightDeduper = class {
1648
- inFlight = /* @__PURE__ */ new Map();
1649
- /**
1650
- * Return an existing in-flight promise for `key`, or start a new one via `factory`.
1651
- * The entry is removed from the map once the promise settles (resolve or reject).
1652
- */
1653
- add(key, factory) {
1654
- const existing = this.inFlight.get(key);
1655
- if (existing) return existing;
1656
- const promise = factory().finally(() => {
1657
- this.inFlight.delete(key);
1658
- });
1659
- this.inFlight.set(key, promise);
1660
- return promise;
1661
- }
1662
- /** Number of currently in-flight requests */
1663
- get size() {
1664
- return this.inFlight.size;
1665
- }
1666
- };
1667
-
1668
1726
  // src/client/registry.ts
1669
1727
  var IMPLEMENTED_OPERATIONS = [
1670
1728
  // Auth
@@ -1729,13 +1787,13 @@ var IMPLEMENTED_OPERATIONS = [
1729
1787
 
1730
1788
  // src/auth/getClientToken.ts
1731
1789
  var getClientToken = (clientId, clientSecret) => {
1790
+ const credentials = toBase64(`${clientId}:${clientSecret}`);
1732
1791
  return scFetch({
1733
1792
  path: "/oauth/token",
1734
1793
  method: "POST",
1794
+ headers: { Authorization: `Basic ${credentials}` },
1735
1795
  body: new URLSearchParams({
1736
- grant_type: "client_credentials",
1737
- client_id: clientId,
1738
- client_secret: clientSecret
1796
+ grant_type: "client_credentials"
1739
1797
  })
1740
1798
  });
1741
1799
  };
@@ -2033,5 +2091,5 @@ var unrepostPlaylist = async (token, playlistId) => {
2033
2091
  var getSoundCloudWidgetUrl = (trackId) => `https%3A//api.soundcloud.com/tracks/${trackId}&show_teaser=false&color=%2300a99d&inverse=false&show_user=false&sharing=false&buying=false&liking=false&show_artwork=false&show_name=false`;
2034
2092
 
2035
2093
  export { IMPLEMENTED_OPERATIONS, InFlightDeduper, RawClient, SoundCloudClient, createPlaylist, createTrackComment, deletePlaylist, deleteTrack, fetchAll, followUser, generateCodeChallenge, generateCodeVerifier, getAuthorizationUrl, getClientToken, getFollowers, getFollowings, getMe, getMeActivities, getMeActivitiesOwn, getMeActivitiesTracks, getMeConnections, getMeFollowers, getMeFollowings, getMeFollowingsTracks, getMeLikesPlaylists, getMeLikesTracks, getMePlaylists, getMeTracks, getPlaylist, getPlaylistReposts, getPlaylistTracks, getRelatedTracks, getSoundCloudWidgetUrl, getTrack, getTrackComments, getTrackLikes, getTrackReposts, getTrackStreams, getTracks, getUser, getUserLikesPlaylists, getUserLikesTracks, getUserPlaylists, getUserToken, getUserTracks, getUserWebProfiles, likePlaylist, likeTrack, paginate, paginateItems, refreshUserToken, repostPlaylist, repostTrack, resolveUrl, scFetch, scFetchUrl, searchPlaylists, searchTracks, searchUsers, signOut, unfollowUser, unlikePlaylist, unlikeTrack, unrepostPlaylist, unrepostTrack, updatePlaylist, updateTrack };
2036
- //# sourceMappingURL=chunk-QNL6UJL5.mjs.map
2037
- //# sourceMappingURL=chunk-QNL6UJL5.mjs.map
2094
+ //# sourceMappingURL=chunk-4FNI5QIN.mjs.map
2095
+ //# sourceMappingURL=chunk-4FNI5QIN.mjs.map