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.
@@ -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) return 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
- return response.json();
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
- throw new chunkMLVA534Z_js.SoundCloudError(response.status, response.statusText, body2);
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
- throw new chunkMLVA534Z_js.SoundCloudError(lastResponse.status, lastResponse.statusText, body);
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) return 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
- return response.json();
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
- throw new chunkMLVA534Z_js.SoundCloudError(response.status, response.statusText, body2);
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
- throw new chunkMLVA534Z_js.SoundCloudError(lastResponse.status, lastResponse.statusText, body);
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
- return paginate(firstPage, (url) => scFetchUrl(url, token));
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
- return paginateItems(firstPage, (url) => scFetchUrl(url, token));
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
- return fetchAll(firstPage, (url) => scFetchUrl(url, token), options);
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-J2PMIV3Z.js.map
1750
- //# sourceMappingURL=chunk-J2PMIV3Z.js.map
1807
+ //# sourceMappingURL=chunk-7IRQD552.js.map
1808
+ //# sourceMappingURL=chunk-7IRQD552.js.map