soundcloud-api-ts 1.10.2 → 1.11.1
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 +4 -3
- package/README.md +29 -0
- package/dist/{chunk-ACK4KMGD.mjs → chunk-DGZEPXIQ.mjs} +81 -20
- package/dist/chunk-DGZEPXIQ.mjs.map +1 -0
- package/dist/{chunk-J2PMIV3Z.js → chunk-GTSVJU3P.js} +81 -20
- package/dist/chunk-GTSVJU3P.js.map +1 -0
- package/dist/cli.js +6 -6
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +25 -3
- package/dist/index.d.ts +25 -3
- package/dist/index.js +63 -63
- package/dist/index.mjs +1 -1
- package/llms.txt +11 -1
- package/package.json +1 -1
- package/dist/chunk-ACK4KMGD.mjs.map +0 -1
- package/dist/chunk-J2PMIV3Z.js.map +0 -1
|
@@ -30,8 +30,23 @@ async function parseErrorBody(response) {
|
|
|
30
30
|
return void 0;
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
|
-
async function scFetch(options, refreshCtx) {
|
|
33
|
+
async function scFetch(options, refreshCtx, onRequest) {
|
|
34
34
|
const retryConfig = refreshCtx?.retry ?? DEFAULT_RETRY;
|
|
35
|
+
const telemetryCallback = onRequest ?? refreshCtx?.onRequest;
|
|
36
|
+
const startTime = Date.now();
|
|
37
|
+
let retryCount = 0;
|
|
38
|
+
let finalStatus = 0;
|
|
39
|
+
const emitTelemetry = (error) => {
|
|
40
|
+
if (!telemetryCallback) return;
|
|
41
|
+
telemetryCallback({
|
|
42
|
+
method: options.method,
|
|
43
|
+
path: options.path,
|
|
44
|
+
durationMs: Date.now() - startTime,
|
|
45
|
+
status: finalStatus,
|
|
46
|
+
retryCount,
|
|
47
|
+
...error ? { error } : {}
|
|
48
|
+
});
|
|
49
|
+
};
|
|
35
50
|
const execute = async (tokenOverride) => {
|
|
36
51
|
const isAuthPath = options.path.startsWith("/oauth");
|
|
37
52
|
const url = `${isAuthPath ? AUTH_BASE_URL : BASE_URL}${options.path}`;
|
|
@@ -65,22 +80,32 @@ async function scFetch(options, refreshCtx) {
|
|
|
65
80
|
body: fetchBody,
|
|
66
81
|
redirect: "manual"
|
|
67
82
|
});
|
|
83
|
+
finalStatus = response.status;
|
|
68
84
|
if (response.status === 302) {
|
|
69
85
|
const location = response.headers.get("location");
|
|
70
|
-
if (location)
|
|
86
|
+
if (location) {
|
|
87
|
+
emitTelemetry();
|
|
88
|
+
return location;
|
|
89
|
+
}
|
|
71
90
|
}
|
|
72
91
|
if (response.status === 204 || response.headers.get("content-length") === "0") {
|
|
92
|
+
emitTelemetry();
|
|
73
93
|
return void 0;
|
|
74
94
|
}
|
|
75
95
|
if (response.ok) {
|
|
76
|
-
|
|
96
|
+
const result = response.json();
|
|
97
|
+
emitTelemetry();
|
|
98
|
+
return result;
|
|
77
99
|
}
|
|
78
100
|
if (!isRetryable(response.status)) {
|
|
79
101
|
const body2 = await parseErrorBody(response);
|
|
80
|
-
|
|
102
|
+
const err2 = new chunkMLVA534Z_js.SoundCloudError(response.status, response.statusText, body2);
|
|
103
|
+
emitTelemetry(err2.message);
|
|
104
|
+
throw err2;
|
|
81
105
|
}
|
|
82
106
|
lastResponse = response;
|
|
83
107
|
if (attempt < retryConfig.maxRetries) {
|
|
108
|
+
retryCount = attempt + 1;
|
|
84
109
|
const delayMs = getRetryDelay(response, attempt, retryConfig);
|
|
85
110
|
retryConfig.onDebug?.(
|
|
86
111
|
`Retry ${attempt + 1}/${retryConfig.maxRetries} after ${Math.round(delayMs)}ms (status ${response.status})`
|
|
@@ -89,7 +114,9 @@ async function scFetch(options, refreshCtx) {
|
|
|
89
114
|
}
|
|
90
115
|
}
|
|
91
116
|
const body = await parseErrorBody(lastResponse);
|
|
92
|
-
|
|
117
|
+
const err = new chunkMLVA534Z_js.SoundCloudError(lastResponse.status, lastResponse.statusText, body);
|
|
118
|
+
emitTelemetry(err.message);
|
|
119
|
+
throw err;
|
|
93
120
|
};
|
|
94
121
|
try {
|
|
95
122
|
return await execute();
|
|
@@ -102,29 +129,53 @@ async function scFetch(options, refreshCtx) {
|
|
|
102
129
|
throw err;
|
|
103
130
|
}
|
|
104
131
|
}
|
|
105
|
-
async function scFetchUrl(url, token, retryConfig) {
|
|
132
|
+
async function scFetchUrl(url, token, retryConfig, onRequest) {
|
|
106
133
|
const config = retryConfig ?? DEFAULT_RETRY;
|
|
107
134
|
const headers = { Accept: "application/json" };
|
|
108
135
|
if (token) headers["Authorization"] = `OAuth ${token}`;
|
|
136
|
+
const startTime = Date.now();
|
|
137
|
+
let retryCount = 0;
|
|
138
|
+
let finalStatus = 0;
|
|
139
|
+
const emitTelemetry = (error) => {
|
|
140
|
+
if (!onRequest) return;
|
|
141
|
+
onRequest({
|
|
142
|
+
method: "GET",
|
|
143
|
+
path: url,
|
|
144
|
+
durationMs: Date.now() - startTime,
|
|
145
|
+
status: finalStatus,
|
|
146
|
+
retryCount,
|
|
147
|
+
...error ? { error } : {}
|
|
148
|
+
});
|
|
149
|
+
};
|
|
109
150
|
let lastResponse;
|
|
110
151
|
for (let attempt = 0; attempt <= config.maxRetries; attempt++) {
|
|
111
152
|
const response = await fetch(url, { method: "GET", headers, redirect: "manual" });
|
|
153
|
+
finalStatus = response.status;
|
|
112
154
|
if (response.status === 302) {
|
|
113
155
|
const location = response.headers.get("location");
|
|
114
|
-
if (location)
|
|
156
|
+
if (location) {
|
|
157
|
+
emitTelemetry();
|
|
158
|
+
return location;
|
|
159
|
+
}
|
|
115
160
|
}
|
|
116
161
|
if (response.status === 204 || response.headers.get("content-length") === "0") {
|
|
162
|
+
emitTelemetry();
|
|
117
163
|
return void 0;
|
|
118
164
|
}
|
|
119
165
|
if (response.ok) {
|
|
120
|
-
|
|
166
|
+
const result = response.json();
|
|
167
|
+
emitTelemetry();
|
|
168
|
+
return result;
|
|
121
169
|
}
|
|
122
170
|
if (!isRetryable(response.status)) {
|
|
123
171
|
const body2 = await parseErrorBody(response);
|
|
124
|
-
|
|
172
|
+
const err2 = new chunkMLVA534Z_js.SoundCloudError(response.status, response.statusText, body2);
|
|
173
|
+
emitTelemetry(err2.message);
|
|
174
|
+
throw err2;
|
|
125
175
|
}
|
|
126
176
|
lastResponse = response;
|
|
127
177
|
if (attempt < config.maxRetries) {
|
|
178
|
+
retryCount = attempt + 1;
|
|
128
179
|
const delayMs = getRetryDelay(response, attempt, config);
|
|
129
180
|
config.onDebug?.(
|
|
130
181
|
`Retry ${attempt + 1}/${config.maxRetries} after ${Math.round(delayMs)}ms (status ${response.status})`
|
|
@@ -133,7 +184,9 @@ async function scFetchUrl(url, token, retryConfig) {
|
|
|
133
184
|
}
|
|
134
185
|
}
|
|
135
186
|
const body = await parseErrorBody(lastResponse);
|
|
136
|
-
|
|
187
|
+
const err = new chunkMLVA534Z_js.SoundCloudError(lastResponse.status, lastResponse.statusText, body);
|
|
188
|
+
emitTelemetry(err.message);
|
|
189
|
+
throw err;
|
|
137
190
|
}
|
|
138
191
|
|
|
139
192
|
// src/client/paginate.ts
|
|
@@ -212,14 +265,16 @@ exports.SoundCloudClient = class _SoundCloudClient {
|
|
|
212
265
|
return result;
|
|
213
266
|
},
|
|
214
267
|
setToken: (a, r) => this.setToken(a, r),
|
|
215
|
-
retry: retryConfig
|
|
268
|
+
retry: retryConfig,
|
|
269
|
+
onRequest: config.onRequest
|
|
216
270
|
} : {
|
|
217
271
|
getToken,
|
|
218
272
|
setToken: (
|
|
219
273
|
/* v8 ignore next */
|
|
220
274
|
(a, r) => this.setToken(a, r)
|
|
221
275
|
),
|
|
222
|
-
retry: retryConfig
|
|
276
|
+
retry: retryConfig,
|
|
277
|
+
onRequest: config.onRequest
|
|
223
278
|
};
|
|
224
279
|
this.auth = new _SoundCloudClient.Auth(this.config);
|
|
225
280
|
this.me = new _SoundCloudClient.Me(getToken, refreshCtx);
|
|
@@ -269,7 +324,8 @@ exports.SoundCloudClient = class _SoundCloudClient {
|
|
|
269
324
|
*/
|
|
270
325
|
paginate(firstPage) {
|
|
271
326
|
const token = this._accessToken;
|
|
272
|
-
|
|
327
|
+
const onReq = this.config.onRequest;
|
|
328
|
+
return paginate(firstPage, (url) => scFetchUrl(url, token, void 0, onReq));
|
|
273
329
|
}
|
|
274
330
|
/**
|
|
275
331
|
* Async generator that yields individual items across all pages.
|
|
@@ -286,7 +342,8 @@ exports.SoundCloudClient = class _SoundCloudClient {
|
|
|
286
342
|
*/
|
|
287
343
|
paginateItems(firstPage) {
|
|
288
344
|
const token = this._accessToken;
|
|
289
|
-
|
|
345
|
+
const onReq = this.config.onRequest;
|
|
346
|
+
return paginateItems(firstPage, (url) => scFetchUrl(url, token, void 0, onReq));
|
|
290
347
|
}
|
|
291
348
|
/**
|
|
292
349
|
* Collects all pages into a single flat array.
|
|
@@ -304,7 +361,8 @@ exports.SoundCloudClient = class _SoundCloudClient {
|
|
|
304
361
|
*/
|
|
305
362
|
fetchAll(firstPage, options) {
|
|
306
363
|
const token = this._accessToken;
|
|
307
|
-
|
|
364
|
+
const onReq = this.config.onRequest;
|
|
365
|
+
return fetchAll(firstPage, (url) => scFetchUrl(url, token, void 0, onReq), options);
|
|
308
366
|
}
|
|
309
367
|
};
|
|
310
368
|
((SoundCloudClient2) => {
|
|
@@ -312,6 +370,9 @@ exports.SoundCloudClient = class _SoundCloudClient {
|
|
|
312
370
|
constructor(config) {
|
|
313
371
|
this.config = config;
|
|
314
372
|
}
|
|
373
|
+
fetch(opts) {
|
|
374
|
+
return scFetch(opts, void 0, this.config.onRequest);
|
|
375
|
+
}
|
|
315
376
|
/**
|
|
316
377
|
* Build the authorization URL to redirect users to SoundCloud's OAuth login page.
|
|
317
378
|
*
|
|
@@ -358,7 +419,7 @@ exports.SoundCloudClient = class _SoundCloudClient {
|
|
|
358
419
|
* @see https://developers.soundcloud.com/docs/api/explorer/open-api#/oauth2/post_oauth2_token
|
|
359
420
|
*/
|
|
360
421
|
async getClientToken() {
|
|
361
|
-
return
|
|
422
|
+
return this.fetch({
|
|
362
423
|
path: "/oauth/token",
|
|
363
424
|
method: "POST",
|
|
364
425
|
body: new URLSearchParams({
|
|
@@ -393,7 +454,7 @@ exports.SoundCloudClient = class _SoundCloudClient {
|
|
|
393
454
|
code
|
|
394
455
|
};
|
|
395
456
|
if (codeVerifier) params.code_verifier = codeVerifier;
|
|
396
|
-
return
|
|
457
|
+
return this.fetch({
|
|
397
458
|
path: "/oauth/token",
|
|
398
459
|
method: "POST",
|
|
399
460
|
body: new URLSearchParams(params)
|
|
@@ -415,7 +476,7 @@ exports.SoundCloudClient = class _SoundCloudClient {
|
|
|
415
476
|
* @see https://developers.soundcloud.com/docs/api/explorer/open-api#/oauth2/post_oauth2_token
|
|
416
477
|
*/
|
|
417
478
|
async refreshUserToken(refreshToken) {
|
|
418
|
-
return
|
|
479
|
+
return this.fetch({
|
|
419
480
|
path: "/oauth/token",
|
|
420
481
|
method: "POST",
|
|
421
482
|
body: new URLSearchParams({
|
|
@@ -1746,5 +1807,5 @@ exports.unrepostPlaylist = unrepostPlaylist;
|
|
|
1746
1807
|
exports.unrepostTrack = unrepostTrack;
|
|
1747
1808
|
exports.updatePlaylist = updatePlaylist;
|
|
1748
1809
|
exports.updateTrack = updateTrack;
|
|
1749
|
-
//# sourceMappingURL=chunk-
|
|
1750
|
-
//# sourceMappingURL=chunk-
|
|
1810
|
+
//# sourceMappingURL=chunk-GTSVJU3P.js.map
|
|
1811
|
+
//# sourceMappingURL=chunk-GTSVJU3P.js.map
|