soundcloud-api-ts 1.9.1 → 1.9.3

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 ADDED
@@ -0,0 +1,197 @@
1
+ # AGENTS.md — soundcloud-api-ts
2
+
3
+ Instructions for AI coding agents working with this package.
4
+
5
+ ## Setup
6
+
7
+ - **Node.js 20+** required (uses native `fetch` and Web Crypto)
8
+ - No environment variables are read by the package — all config is passed to the constructor
9
+
10
+ ```bash
11
+ npm install soundcloud-api-ts
12
+ ```
13
+
14
+ ```ts
15
+ import { SoundCloudClient } from 'soundcloud-api-ts';
16
+
17
+ const sc = new SoundCloudClient({
18
+ clientId: 'YOUR_CLIENT_ID',
19
+ clientSecret: 'YOUR_CLIENT_SECRET',
20
+ redirectUri: 'https://example.com/callback', // only needed for user auth
21
+ });
22
+ ```
23
+
24
+ ## Authentication
25
+
26
+ **Every API call requires a token.** You must call `sc.setToken()` before making requests.
27
+
28
+ ### Client Credentials (server-to-server, no user context)
29
+
30
+ ```ts
31
+ const token = await sc.auth.getClientToken();
32
+ sc.setToken(token.access_token);
33
+ // Now you can call public endpoints: tracks, users, search, playlists, resolve
34
+ ```
35
+
36
+ ### User Token (user context required)
37
+
38
+ Some endpoints require a user token (not just client credentials):
39
+ - All `sc.me.*` endpoints
40
+ - `sc.likes.*` (likeTrack, unlikeTrack, likePlaylist, unlikePlaylist)
41
+ - `sc.reposts.*` (repostTrack, unrepostTrack, repostPlaylist, unrepostPlaylist)
42
+ - `sc.tracks.createComment()`, `sc.tracks.update()`, `sc.tracks.delete()`
43
+ - `sc.playlists.create()`, `sc.playlists.update()`, `sc.playlists.delete()`
44
+ - `sc.me.follow()`, `sc.me.unfollow()`
45
+
46
+ ```ts
47
+ import { generateCodeVerifier, generateCodeChallenge } from 'soundcloud-api-ts';
48
+
49
+ const verifier = generateCodeVerifier();
50
+ const challenge = await generateCodeChallenge(verifier);
51
+ const authUrl = sc.auth.getAuthorizationUrl({ state: 'csrf-token', codeChallenge: challenge });
52
+ // User visits authUrl → redirected back with ?code=...
53
+ const token = await sc.auth.getUserToken(code, verifier);
54
+ sc.setToken(token.access_token, token.refresh_token);
55
+ ```
56
+
57
+ ## Common Operations
58
+
59
+ ### Get a track
60
+ ```ts
61
+ const track = await sc.tracks.getTrack(123456);
62
+ ```
63
+
64
+ ### Search
65
+ ```ts
66
+ const results = await sc.search.tracks('lofi hip hop');
67
+ // results.collection is SoundCloudTrack[]
68
+ ```
69
+
70
+ ### Get stream URLs
71
+ ```ts
72
+ const streams = await sc.tracks.getStreams(trackId);
73
+ // streams.hls_mp3_128_url, streams.http_mp3_128_url, etc.
74
+ ```
75
+
76
+ ### Resolve a SoundCloud URL
77
+ ```ts
78
+ const resource = await sc.resolve.resolveUrl('https://soundcloud.com/artist/track');
79
+ ```
80
+
81
+ ### Get authenticated user profile
82
+ ```ts
83
+ const me = await sc.me.getMe(); // requires user token
84
+ ```
85
+
86
+ ## Pagination
87
+
88
+ Paginated endpoints return `{ collection: T[], next_href?: string }`. Use the built-in helpers:
89
+
90
+ ```ts
91
+ // Iterate items one by one across all pages
92
+ for await (const track of sc.paginateItems(() => sc.search.tracks('lofi'))) {
93
+ console.log(track.title);
94
+ }
95
+
96
+ // Collect everything (with optional cap)
97
+ const allTracks = await sc.fetchAll(() => sc.users.getTracks(userId), { maxItems: 200 });
98
+ ```
99
+
100
+ ## Error Handling
101
+
102
+ All API errors throw `SoundCloudError`:
103
+
104
+ ```ts
105
+ import { SoundCloudError } from 'soundcloud-api-ts';
106
+
107
+ try {
108
+ await sc.tracks.getTrack(999999999);
109
+ } catch (err) {
110
+ if (err instanceof SoundCloudError) {
111
+ err.status; // HTTP status code (404, 401, 429, etc.)
112
+ err.message; // Human-readable error message
113
+ err.isNotFound; // true if 404
114
+ err.isUnauthorized; // true if 401
115
+ err.isRateLimited; // true if 429
116
+ err.isServerError; // true if 5xx
117
+ err.errorCode; // Machine-readable code like "invalid_client"
118
+ }
119
+ }
120
+ ```
121
+
122
+ ## Gotchas
123
+
124
+ 1. **Token required for ALL requests** — even public endpoints like `getTrack` need at least a client credentials token. Call `setToken()` first.
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
+ 3. **Rate limits exist** — SoundCloud returns 429 when rate limited. The client has built-in retry with exponential backoff (configurable via `maxRetries` and `retryBaseDelay`).
127
+ 4. **Auto token refresh** — pass `onTokenRefresh` in the config to automatically refresh expired tokens on 401.
128
+ 5. **No env vars** — the package reads no environment variables. Pass `clientId`, `clientSecret`, and `redirectUri` directly to the constructor.
129
+ 6. **IDs can be numbers or strings** — all ID parameters accept `string | number`.
130
+ 7. **Search pagination** — search uses zero-based `pageNumber` (10 results per page), not cursor-based pagination.
131
+
132
+ ## Project Structure (for contributors)
133
+
134
+ ```
135
+ src/
136
+ index.ts — All public exports (source of truth)
137
+ client/SoundCloudClient.ts — Main client class with all namespaced methods
138
+ client/http.ts — scFetch, scFetchUrl (HTTP layer with retry)
139
+ client/paginate.ts — paginate, paginateItems, fetchAll helpers
140
+ auth/ — Standalone auth functions + PKCE
141
+ users/ — Standalone user functions (getMe, getUser, etc.)
142
+ tracks/ — Standalone track functions
143
+ playlists/ — Standalone playlist functions
144
+ search/ — Standalone search functions
145
+ me/ — Standalone /me endpoint functions
146
+ likes/ — Standalone like/unlike functions
147
+ reposts/ — Standalone repost functions
148
+ resolve/ — Standalone resolve function
149
+ utils/ — Widget URL helper
150
+ errors.ts — SoundCloudError class
151
+ types/api.ts — All TypeScript type definitions
152
+ ```
153
+
154
+ ## Key Files
155
+
156
+ - `src/index.ts` — single source of truth for all exports
157
+ - `src/types/api.ts` — all TypeScript interfaces
158
+ - `src/client/SoundCloudClient.ts` — the main client class
159
+ - `tsup.config.ts` — build config (dual ESM/CJS)
160
+ - `vitest.config.ts` — test config
161
+ - `typedoc.json` — API docs generation config
162
+
163
+ ## Build & Test
164
+
165
+ ```bash
166
+ pnpm build # tsup → dist/ (ESM + CJS + .d.ts)
167
+ pnpm lint # ESLint
168
+ pnpm typecheck # tsc --noEmit
169
+ pnpm test # Vitest
170
+ pnpm test:watch # Vitest watch mode
171
+ pnpm docs # TypeDoc → API docs site
172
+ ```
173
+
174
+ ## How to Add a New Endpoint
175
+
176
+ 1. Create a standalone function in the appropriate `src/<category>/` directory
177
+ 2. Export it from `src/<category>/index.ts`
178
+ 3. Re-export from `src/index.ts`
179
+ 4. Add a namespaced method in `SoundCloudClient` (in `src/client/SoundCloudClient.ts`)
180
+ 5. Add tests in `src/<category>/__tests__/`
181
+ 6. Update `llms.txt` and `llms-full.txt` with the new function signature
182
+
183
+ ## Publishing
184
+
185
+ Uses **Trusted Publishing** via GitHub Releases:
186
+ 1. Bump version in `package.json`
187
+ 2. Commit and push to `main`
188
+ 3. Create a GitHub Release with the version tag (e.g. `v1.9.2`)
189
+ 4. GitHub Actions CI builds and publishes to npm automatically
190
+
191
+ ## Related Packages
192
+
193
+ - [soundcloud-api-ts-next](https://github.com/twin-paws/soundcloud-api-ts-next) — React hooks + Next.js API routes (depends on this package)
194
+
195
+ ## Full Documentation
196
+
197
+ https://twin-paws.github.io/soundcloud-api-ts/
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-≥20-339933.svg)](https://nodejs.org/)
10
+ [![Node](https://img.shields.io/badge/Node.js-≥22-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)
@@ -456,6 +456,10 @@ Full API documentation is available at **[twin-paws.github.io/soundcloud-api-ts]
456
456
 
457
457
  See [CHANGELOG.md](CHANGELOG.md) for release history.
458
458
 
459
+ ## Related Packages
460
+
461
+ - **[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.
462
+
459
463
  ## Contributing
460
464
 
461
465
  Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
@@ -1679,5 +1679,5 @@ var unrepostPlaylist = async (token, playlistId) => {
1679
1679
  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`;
1680
1680
 
1681
1681
  export { SoundCloudClient, createPlaylist, createTrackComment, deletePlaylist, deleteTrack, fetchAll, followUser, generateCodeChallenge, generateCodeVerifier, getAuthorizationUrl, getClientToken, getFollowers, getFollowings, getMe, getMeActivities, getMeActivitiesOwn, getMeActivitiesTracks, getMeFollowers, getMeFollowings, getMeFollowingsTracks, getMeLikesPlaylists, getMeLikesTracks, getMePlaylists, getMeTracks, getPlaylist, getPlaylistReposts, getPlaylistTracks, getRelatedTracks, getSoundCloudWidgetUrl, getTrack, getTrackComments, getTrackLikes, getTrackReposts, getTrackStreams, 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 };
1682
- //# sourceMappingURL=chunk-SCUOUK3L.mjs.map
1683
- //# sourceMappingURL=chunk-SCUOUK3L.mjs.map
1682
+ //# sourceMappingURL=chunk-G6S6GM75.mjs.map
1683
+ //# sourceMappingURL=chunk-G6S6GM75.mjs.map