soundcloud-api-ts 1.13.0 → 1.13.2

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
@@ -131,6 +131,11 @@ try {
131
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
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.
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).
135
+ 12. **`sc.me.getConnections()`** — list linked social accounts. Requires user token. May require elevated API access.
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
+ 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
+ 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.
134
139
  6. **No env vars** — the package reads no environment variables. Pass `clientId`, `clientSecret`, and `redirectUri` directly to the constructor.
135
140
  7. **IDs can be numbers or strings** — all ID parameters accept `string | number`.
136
141
  8. **Search pagination** — search uses zero-based `pageNumber` (10 results per page), not cursor-based pagination.
@@ -141,9 +146,14 @@ try {
141
146
  src/
142
147
  index.ts — All public exports (source of truth)
143
148
  client/SoundCloudClient.ts — Main client class with all namespaced methods
144
- client/http.ts — scFetch, scFetchUrl (HTTP layer with retry)
149
+ client/http.ts — scFetch, scFetchUrl (HTTP layer with retry + RetryInfo hook)
145
150
  client/paginate.ts — paginate, paginateItems, fetchAll helpers
151
+ client/raw.ts — RawClient (sc.raw escape hatch)
152
+ client/dedupe.ts — InFlightDeduper (GET coalescing)
153
+ client/cache.ts — SoundCloudCache interface
154
+ client/registry.ts — IMPLEMENTED_OPERATIONS (OpenAPI coverage tracking)
146
155
  auth/ — Standalone auth functions + PKCE
156
+ auth/token-provider.ts — TokenProvider + TokenStore interfaces
147
157
  users/ — Standalone user functions (getMe, getUser, etc.)
148
158
  tracks/ — Standalone track functions
149
159
  playlists/ — Standalone playlist functions
package/README.md CHANGED
@@ -11,7 +11,7 @@
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)
14
- [![OpenAPI Coverage](https://img.shields.io/badge/OpenAPI%20coverage-tracked-blue)](tools/coverage-baseline.json)
14
+ [![Endpoints](https://img.shields.io/badge/endpoints-51%20wrapped-blue)](https://github.com/twin-paws/soundcloud-api-ts/blob/main/src/client/registry.ts)
15
15
 
16
16
  The TypeScript SoundCloud API client built on the official API. Zero runtime dependencies, native `fetch`, OAuth 2.1 + PKCE, production-grade retry and deduplication, pluggable cache, raw escape hatch, and an interactive CLI.
17
17
 
@@ -589,6 +589,7 @@ See [CHANGELOG.md](CHANGELOG.md) for release history.
589
589
  ## Related Packages
590
590
 
591
591
  - **[soundcloud-api-ts-next](https://github.com/twin-paws/soundcloud-api-ts-next)** — React hooks + Next.js API route handlers built on this package. Use it when building Next.js apps that need SoundCloud data with secrets kept server-side.
592
+ - **[soundcloud-widget-react](https://github.com/twin-paws/soundcloud-widget-react)** — React component for the SoundCloud HTML5 Widget API. Embed SoundCloud players and control playback programmatically. Complements this package for full SoundCloud integration.
592
593
 
593
594
  ## Contributing
594
595
 
@@ -559,17 +559,13 @@ var SoundCloudClient = class _SoundCloudClient {
559
559
  * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/oauth2/post_oauth2_token
560
560
  */
561
561
  async getClientToken() {
562
- const basicAuth = Buffer.from(
563
- `${this.config.clientId}:${this.config.clientSecret}`
564
- ).toString("base64");
565
562
  return this.fetch({
566
563
  path: "/oauth/token",
567
564
  method: "POST",
568
- headers: {
569
- Authorization: `Basic ${basicAuth}`
570
- },
571
565
  body: new URLSearchParams({
572
- grant_type: "client_credentials"
566
+ grant_type: "client_credentials",
567
+ client_id: this.config.clientId,
568
+ client_secret: this.config.clientSecret
573
569
  })
574
570
  });
575
571
  }
@@ -1071,6 +1067,11 @@ var SoundCloudClient = class _SoundCloudClient {
1071
1067
  * @param options - Optional token override
1072
1068
  * @returns Array of track objects (may be shorter than `ids` if some tracks are unavailable)
1073
1069
  * @throws {SoundCloudError} When the API returns an error
1070
+ * @throws {Error} When more than 200 IDs are provided
1071
+ *
1072
+ * @remarks
1073
+ * SoundCloud's API likely caps at ~200 IDs per request. Passing more than 200 IDs
1074
+ * will throw immediately without making a network request.
1074
1075
  *
1075
1076
  * @example
1076
1077
  * ```ts
@@ -1081,6 +1082,9 @@ var SoundCloudClient = class _SoundCloudClient {
1081
1082
  * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/tracks/get_tracks
1082
1083
  */
1083
1084
  async getTracks(ids, options) {
1085
+ if (ids.length > 200) {
1086
+ throw new Error("getTracks: SoundCloud API supports a maximum of 200 IDs per request");
1087
+ }
1084
1088
  const t = resolveToken(this.getToken, options?.token);
1085
1089
  return this.fetch({ path: `/tracks?ids=${ids.join(",")}`, method: "GET", token: t });
1086
1090
  }
@@ -1725,15 +1729,13 @@ var IMPLEMENTED_OPERATIONS = [
1725
1729
 
1726
1730
  // src/auth/getClientToken.ts
1727
1731
  var getClientToken = (clientId, clientSecret) => {
1728
- const basicAuth = Buffer.from(`${clientId}:${clientSecret}`).toString("base64");
1729
1732
  return scFetch({
1730
1733
  path: "/oauth/token",
1731
1734
  method: "POST",
1732
- headers: {
1733
- Authorization: `Basic ${basicAuth}`
1734
- },
1735
1735
  body: new URLSearchParams({
1736
- grant_type: "client_credentials"
1736
+ grant_type: "client_credentials",
1737
+ client_id: clientId,
1738
+ client_secret: clientSecret
1737
1739
  })
1738
1740
  });
1739
1741
  };
@@ -1843,11 +1845,16 @@ var getUserWebProfiles = (token, userId) => scFetch({ path: `/users/${userId}/we
1843
1845
  var getTrack = (token, trackId) => scFetch({ path: `/tracks/${trackId}`, method: "GET", token });
1844
1846
 
1845
1847
  // src/tracks/getTracks.ts
1846
- var getTracks = (token, ids) => scFetch({
1847
- path: `/tracks?ids=${ids.join(",")}`,
1848
- method: "GET",
1849
- token
1850
- });
1848
+ var getTracks = (token, ids) => {
1849
+ if (ids.length > 200) {
1850
+ throw new Error("getTracks: SoundCloud API supports a maximum of 200 IDs per request");
1851
+ }
1852
+ return scFetch({
1853
+ path: `/tracks?ids=${ids.join(",")}`,
1854
+ method: "GET",
1855
+ token
1856
+ });
1857
+ };
1851
1858
 
1852
1859
  // src/tracks/getComments.ts
1853
1860
  var getTrackComments = (token, trackId, limit) => scFetch({ path: `/tracks/${trackId}/comments?threaded=1&filter_replies=0${limit ? `&limit=${limit}` : ""}&linked_partitioning=true`, method: "GET", token });
@@ -2026,5 +2033,5 @@ var unrepostPlaylist = async (token, playlistId) => {
2026
2033
  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`;
2027
2034
 
2028
2035
  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 };
2029
- //# sourceMappingURL=chunk-JH7TLL2C.mjs.map
2030
- //# sourceMappingURL=chunk-JH7TLL2C.mjs.map
2036
+ //# sourceMappingURL=chunk-DCZIPG5T.mjs.map
2037
+ //# sourceMappingURL=chunk-DCZIPG5T.mjs.map