soundcloud-api-ts 1.10.2 → 1.11.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 +4 -3
- package/README.md +29 -0
- package/dist/{chunk-ACK4KMGD.mjs → chunk-5FCXAR2S.mjs} +75 -17
- package/dist/chunk-5FCXAR2S.mjs.map +1 -0
- package/dist/{chunk-J2PMIV3Z.js → chunk-7IRQD552.js} +75 -17
- package/dist/chunk-7IRQD552.js.map +1 -0
- package/dist/cli.js +6 -6
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +24 -3
- package/dist/index.d.ts +24 -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) => {
|
|
@@ -1746,5 +1804,5 @@ exports.unrepostPlaylist = unrepostPlaylist;
|
|
|
1746
1804
|
exports.unrepostTrack = unrepostTrack;
|
|
1747
1805
|
exports.updatePlaylist = updatePlaylist;
|
|
1748
1806
|
exports.updateTrack = updateTrack;
|
|
1749
|
-
//# sourceMappingURL=chunk-
|
|
1750
|
-
//# sourceMappingURL=chunk-
|
|
1807
|
+
//# sourceMappingURL=chunk-7IRQD552.js.map
|
|
1808
|
+
//# sourceMappingURL=chunk-7IRQD552.js.map
|