soundcloud-api-ts 1.11.3 → 1.12.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 +6 -1
- package/README.md +90 -1
- package/dist/{chunk-2747SK6H.js → chunk-D7AF372V.js} +236 -8
- package/dist/chunk-D7AF372V.js.map +1 -0
- package/dist/{chunk-HCEUCJMA.mjs → chunk-JLRQJWU5.mjs} +234 -9
- package/dist/chunk-JLRQJWU5.mjs.map +1 -0
- package/dist/cli.js +6 -6
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +163 -1
- package/dist/index.d.ts +163 -1
- package/dist/index.js +75 -63
- package/dist/index.mjs +1 -1
- package/llms.txt +45 -0
- package/package.json +4 -2
- package/dist/chunk-2747SK6H.js.map +0 -1
- package/dist/chunk-HCEUCJMA.mjs.map +0 -1
package/AGENTS.md
CHANGED
|
@@ -123,9 +123,14 @@ try {
|
|
|
123
123
|
|
|
124
124
|
1. **Token required for ALL requests** — even public endpoints like `getTrack` need at least a client credentials token. Call `setToken()` first.
|
|
125
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`).
|
|
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`). `Retry-After` header is honored (capped 60s).
|
|
127
127
|
4. **Auto token refresh** — pass `onTokenRefresh` in the config to automatically refresh expired tokens on 401.
|
|
128
128
|
5. **Request telemetry** — pass `onRequest` in the config to receive `SCRequestTelemetry` after every request (method, path, duration, status, retries, error). Fires on all paths including pagination and retries.
|
|
129
|
+
6. **sc.raw** — `sc.raw.get('/tracks/{id}', { id: 123456 })` calls any endpoint without a typed wrapper. Returns `RawResponse<T>` with `{ data, status, headers }`. Does NOT throw on non-2xx — check `res.status` yourself. Good for endpoints not yet wrapped.
|
|
130
|
+
7. **Fetch injection** — pass `fetch` and `AbortController` in the constructor for Bun/Deno/Cloudflare Workers portability. No Node-only APIs used at runtime.
|
|
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
|
+
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
|
+
10. **Retry hook** — pass `onRetry` to receive `RetryInfo` on each retry: `{ attempt, delayMs, reason, status?, url }`.
|
|
129
134
|
6. **No env vars** — the package reads no environment variables. Pass `clientId`, `clientSecret`, and `redirectUri` directly to the constructor.
|
|
130
135
|
7. **IDs can be numbers or strings** — all ID parameters accept `string | number`.
|
|
131
136
|
8. **Search pagination** — search uses zero-based `pageNumber` (10 results per page), not cursor-based pagination.
|
package/README.md
CHANGED
|
@@ -267,6 +267,11 @@ sc.search.playlists(query, pageNumber?, options?)
|
|
|
267
267
|
sc.resolve.resolveUrl(url, options?)
|
|
268
268
|
```
|
|
269
269
|
|
|
270
|
+
// Raw escape hatch — call any endpoint
|
|
271
|
+
sc.raw.get('/tracks/{id}', { id: 123456 })
|
|
272
|
+
sc.raw.post('/tracks/{id}/comments', { body: { body: 'great track' } })
|
|
273
|
+
sc.raw.request({ method: 'GET', path: '/me', query: {} })
|
|
274
|
+
|
|
270
275
|
Where `options` is `{ token?: string }` — only needed to override the stored token.
|
|
271
276
|
|
|
272
277
|
## Standalone Functions
|
|
@@ -403,21 +408,105 @@ try {
|
|
|
403
408
|
|
|
404
409
|
Error messages are parsed directly from SoundCloud's API response format, giving you the most useful message available.
|
|
405
410
|
|
|
411
|
+
## Raw API — Call Any Endpoint
|
|
412
|
+
|
|
413
|
+
`sc.raw` is a low-level escape hatch that lets you call any SoundCloud API endpoint — including ones not yet wrapped — while still using your configured auth and fetch.
|
|
414
|
+
|
|
415
|
+
```ts
|
|
416
|
+
import { SoundCloudClient, type RawResponse } from 'soundcloud-api-ts';
|
|
417
|
+
|
|
418
|
+
const sc = new SoundCloudClient({ clientId, clientSecret });
|
|
419
|
+
const token = await sc.auth.getClientToken();
|
|
420
|
+
sc.setToken(token.access_token);
|
|
421
|
+
|
|
422
|
+
// Path templating: {id} is replaced from the params object
|
|
423
|
+
const res: RawResponse = await sc.raw.get('/tracks/{id}', { id: 123456 });
|
|
424
|
+
console.log(res.data); // parsed JSON body
|
|
425
|
+
console.log(res.status); // 200
|
|
426
|
+
console.log(res.headers); // response headers
|
|
427
|
+
|
|
428
|
+
// POST with body
|
|
429
|
+
await sc.raw.post('/tracks/{id}/comments', { id: 123456, body: { body: 'great track', timestamp: 30000 } });
|
|
430
|
+
|
|
431
|
+
// Fully generic
|
|
432
|
+
await sc.raw.request({ method: 'DELETE', path: '/tracks/{id}', query: { id: 123456 } });
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
`sc.raw` returns `RawResponse<T = unknown>` — `{ data: T, status: number, headers: Record<string, string> }`. It does **not** throw on non-2xx status codes; check `res.status` yourself.
|
|
436
|
+
|
|
437
|
+
---
|
|
438
|
+
|
|
439
|
+
## In-Flight Deduplication & Caching
|
|
440
|
+
|
|
441
|
+
### GET Coalescing (default on)
|
|
442
|
+
|
|
443
|
+
When multiple callers fire the same GET request simultaneously (SSR, React StrictMode, concurrent components), only one fetch is made. All callers share the same promise.
|
|
444
|
+
|
|
445
|
+
```ts
|
|
446
|
+
const sc = new SoundCloudClient({
|
|
447
|
+
clientId, clientSecret,
|
|
448
|
+
dedupe: true, // default — set false to disable
|
|
449
|
+
});
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
### Pluggable Cache
|
|
453
|
+
|
|
454
|
+
Bring your own cache backend — in-memory, Redis, Cloudflare KV, whatever. The base package defines the interface only (no implementation, no deps):
|
|
455
|
+
|
|
456
|
+
```ts
|
|
457
|
+
import { SoundCloudClient, type SoundCloudCache } from 'soundcloud-api-ts';
|
|
458
|
+
|
|
459
|
+
const myCache: SoundCloudCache = {
|
|
460
|
+
get: (key) => store.get(key),
|
|
461
|
+
set: (key, value, { ttlMs }) => store.set(key, value, ttlMs),
|
|
462
|
+
delete: (key) => store.delete(key),
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
const sc = new SoundCloudClient({
|
|
466
|
+
clientId, clientSecret,
|
|
467
|
+
cache: myCache,
|
|
468
|
+
cacheTtlMs: 30_000, // 30s default per GET response
|
|
469
|
+
});
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
---
|
|
473
|
+
|
|
474
|
+
## Runtime Portability
|
|
475
|
+
|
|
476
|
+
Pass a custom `fetch` implementation to work in any runtime — Cloudflare Workers, Deno, Bun, or environments without a global `fetch`:
|
|
477
|
+
|
|
478
|
+
```ts
|
|
479
|
+
const sc = new SoundCloudClient({
|
|
480
|
+
clientId, clientSecret,
|
|
481
|
+
fetch: myCustomFetch, // optional: custom fetch
|
|
482
|
+
AbortController: myAbortCtrl, // optional: custom AbortController
|
|
483
|
+
});
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
No Node-only APIs are used at runtime. The client works anywhere `fetch` is available.
|
|
487
|
+
|
|
488
|
+
---
|
|
489
|
+
|
|
406
490
|
## Rate Limiting & Retries
|
|
407
491
|
|
|
408
492
|
The client automatically retries on **429 Too Many Requests** and **5xx Server Errors** with exponential backoff:
|
|
409
493
|
|
|
410
494
|
```ts
|
|
495
|
+
import { SoundCloudClient, type RetryInfo } from 'soundcloud-api-ts';
|
|
496
|
+
|
|
411
497
|
const sc = new SoundCloudClient({
|
|
412
498
|
clientId: "...",
|
|
413
499
|
clientSecret: "...",
|
|
414
500
|
maxRetries: 3, // default: 3
|
|
415
501
|
retryBaseDelay: 1000, // default: 1000ms
|
|
416
502
|
onDebug: (msg) => console.log(msg), // optional retry logging
|
|
503
|
+
onRetry: (info: RetryInfo) => {
|
|
504
|
+
console.warn(`[SC] retry #${info.attempt} — ${info.reason} (${info.status}) delay=${info.delayMs}ms url=${info.url}`);
|
|
505
|
+
},
|
|
417
506
|
});
|
|
418
507
|
```
|
|
419
508
|
|
|
420
|
-
- **429 responses**
|
|
509
|
+
- **429 responses** use the `Retry-After` header value as the delay (capped at 60s)
|
|
421
510
|
- **5xx responses** (500, 502, 503, 504) are retried with exponential backoff
|
|
422
511
|
- **4xx errors** (except 429) are NOT retried — they throw immediately
|
|
423
512
|
- **401 errors** trigger `onTokenRefresh` (if configured) instead of retry
|
|
@@ -17,7 +17,7 @@ function getRetryDelay(response, attempt, config) {
|
|
|
17
17
|
const retryAfter = response.headers.get("retry-after");
|
|
18
18
|
if (retryAfter) {
|
|
19
19
|
const seconds = Number(retryAfter);
|
|
20
|
-
if (!Number.isNaN(seconds)) return seconds * 1e3;
|
|
20
|
+
if (!Number.isNaN(seconds)) return Math.min(seconds * 1e3, 6e4);
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
const base = config.retryBaseDelay * Math.pow(2, attempt);
|
|
@@ -93,9 +93,26 @@ async function scFetch(options, refreshCtx, onRequest) {
|
|
|
93
93
|
return void 0;
|
|
94
94
|
}
|
|
95
95
|
if (response.ok) {
|
|
96
|
-
const
|
|
96
|
+
const data = await response.json();
|
|
97
|
+
if (typeof data === "object" && data !== null) {
|
|
98
|
+
const metaHeaders = {};
|
|
99
|
+
if (typeof response.headers.forEach === "function") {
|
|
100
|
+
response.headers.forEach((value, key) => {
|
|
101
|
+
metaHeaders[key] = value;
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
try {
|
|
105
|
+
Object.defineProperty(data, "_meta", {
|
|
106
|
+
value: { status: response.status, headers: metaHeaders },
|
|
107
|
+
enumerable: false,
|
|
108
|
+
configurable: true,
|
|
109
|
+
writable: true
|
|
110
|
+
});
|
|
111
|
+
} catch {
|
|
112
|
+
}
|
|
113
|
+
}
|
|
97
114
|
emitTelemetry();
|
|
98
|
-
return
|
|
115
|
+
return data;
|
|
99
116
|
}
|
|
100
117
|
if (!isRetryable(response.status)) {
|
|
101
118
|
const body2 = await parseErrorBody(response);
|
|
@@ -110,6 +127,13 @@ async function scFetch(options, refreshCtx, onRequest) {
|
|
|
110
127
|
retryConfig.onDebug?.(
|
|
111
128
|
`Retry ${attempt + 1}/${retryConfig.maxRetries} after ${Math.round(delayMs)}ms (status ${response.status})`
|
|
112
129
|
);
|
|
130
|
+
retryConfig.onRetry?.({
|
|
131
|
+
attempt: retryCount,
|
|
132
|
+
delayMs,
|
|
133
|
+
reason: `${response.status} ${response.statusText}`,
|
|
134
|
+
status: response.status,
|
|
135
|
+
url
|
|
136
|
+
});
|
|
113
137
|
await delay(delayMs);
|
|
114
138
|
}
|
|
115
139
|
}
|
|
@@ -163,9 +187,26 @@ async function scFetchUrl(url, token, retryConfig, onRequest) {
|
|
|
163
187
|
return void 0;
|
|
164
188
|
}
|
|
165
189
|
if (response.ok) {
|
|
166
|
-
const
|
|
190
|
+
const data = await response.json();
|
|
191
|
+
if (typeof data === "object" && data !== null) {
|
|
192
|
+
const metaHeaders = {};
|
|
193
|
+
if (typeof response.headers.forEach === "function") {
|
|
194
|
+
response.headers.forEach((value, key) => {
|
|
195
|
+
metaHeaders[key] = value;
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
try {
|
|
199
|
+
Object.defineProperty(data, "_meta", {
|
|
200
|
+
value: { status: response.status, headers: metaHeaders },
|
|
201
|
+
enumerable: false,
|
|
202
|
+
configurable: true,
|
|
203
|
+
writable: true
|
|
204
|
+
});
|
|
205
|
+
} catch {
|
|
206
|
+
}
|
|
207
|
+
}
|
|
167
208
|
emitTelemetry();
|
|
168
|
-
return
|
|
209
|
+
return data;
|
|
169
210
|
}
|
|
170
211
|
if (!isRetryable(response.status)) {
|
|
171
212
|
const body2 = await parseErrorBody(response);
|
|
@@ -180,6 +221,13 @@ async function scFetchUrl(url, token, retryConfig, onRequest) {
|
|
|
180
221
|
config.onDebug?.(
|
|
181
222
|
`Retry ${attempt + 1}/${config.maxRetries} after ${Math.round(delayMs)}ms (status ${response.status})`
|
|
182
223
|
);
|
|
224
|
+
config.onRetry?.({
|
|
225
|
+
attempt: retryCount,
|
|
226
|
+
delayMs,
|
|
227
|
+
reason: `${response.status} ${response.statusText}`,
|
|
228
|
+
status: response.status,
|
|
229
|
+
url
|
|
230
|
+
});
|
|
183
231
|
await delay(delayMs);
|
|
184
232
|
}
|
|
185
233
|
}
|
|
@@ -217,6 +265,96 @@ async function fetchAll(firstPage, fetchNext, options) {
|
|
|
217
265
|
return result;
|
|
218
266
|
}
|
|
219
267
|
|
|
268
|
+
// src/client/raw.ts
|
|
269
|
+
var RawClient = class {
|
|
270
|
+
constructor(baseUrl, getToken, fetchFn) {
|
|
271
|
+
this.baseUrl = baseUrl;
|
|
272
|
+
this.getToken = getToken;
|
|
273
|
+
this.fetchFn = fetchFn;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Make a raw HTTP request. Path template placeholders like `{id}` are substituted
|
|
277
|
+
* from matching keys in `query` before the remaining query params are appended to
|
|
278
|
+
* the URL as search parameters.
|
|
279
|
+
*/
|
|
280
|
+
async request({
|
|
281
|
+
method,
|
|
282
|
+
path,
|
|
283
|
+
query,
|
|
284
|
+
body,
|
|
285
|
+
token
|
|
286
|
+
}) {
|
|
287
|
+
let resolvedPath = path;
|
|
288
|
+
const remainingQuery = {};
|
|
289
|
+
if (query) {
|
|
290
|
+
for (const [key, value] of Object.entries(query)) {
|
|
291
|
+
if (value === void 0) continue;
|
|
292
|
+
const placeholder = `{${key}}`;
|
|
293
|
+
if (resolvedPath.includes(placeholder)) {
|
|
294
|
+
resolvedPath = resolvedPath.replace(new RegExp(`\\{${key}\\}`, "g"), String(value));
|
|
295
|
+
} else {
|
|
296
|
+
remainingQuery[key] = String(value);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
const fullUrl = resolvedPath.startsWith("http") ? new URL(resolvedPath) : new URL(resolvedPath, this.baseUrl);
|
|
301
|
+
for (const [key, value] of Object.entries(remainingQuery)) {
|
|
302
|
+
fullUrl.searchParams.set(key, value);
|
|
303
|
+
}
|
|
304
|
+
const headers = {
|
|
305
|
+
Accept: "application/json"
|
|
306
|
+
};
|
|
307
|
+
const authToken = token ?? this.getToken();
|
|
308
|
+
if (authToken) {
|
|
309
|
+
headers["Authorization"] = `OAuth ${authToken}`;
|
|
310
|
+
}
|
|
311
|
+
let fetchBody;
|
|
312
|
+
if (body !== void 0) {
|
|
313
|
+
headers["Content-Type"] = "application/json";
|
|
314
|
+
fetchBody = JSON.stringify(body);
|
|
315
|
+
}
|
|
316
|
+
const response = await this.fetchFn(fullUrl.toString(), {
|
|
317
|
+
method,
|
|
318
|
+
headers,
|
|
319
|
+
body: fetchBody
|
|
320
|
+
});
|
|
321
|
+
const responseHeaders = {};
|
|
322
|
+
if (typeof response.headers.forEach === "function") {
|
|
323
|
+
response.headers.forEach((value, key) => {
|
|
324
|
+
responseHeaders[key] = value;
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
let data;
|
|
328
|
+
const contentLength = response.headers.get("content-length");
|
|
329
|
+
if (response.status === 204 || contentLength === "0") {
|
|
330
|
+
data = void 0;
|
|
331
|
+
} else {
|
|
332
|
+
try {
|
|
333
|
+
data = await response.json();
|
|
334
|
+
} catch {
|
|
335
|
+
data = void 0;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return { data, status: response.status, headers: responseHeaders };
|
|
339
|
+
}
|
|
340
|
+
/** GET shorthand */
|
|
341
|
+
get(path, params) {
|
|
342
|
+
return this.request({ method: "GET", path, query: params });
|
|
343
|
+
}
|
|
344
|
+
/** POST shorthand */
|
|
345
|
+
post(path, body) {
|
|
346
|
+
return this.request({ method: "POST", path, body });
|
|
347
|
+
}
|
|
348
|
+
/** PUT shorthand */
|
|
349
|
+
put(path, body) {
|
|
350
|
+
return this.request({ method: "PUT", path, body });
|
|
351
|
+
}
|
|
352
|
+
/** DELETE shorthand */
|
|
353
|
+
delete(path) {
|
|
354
|
+
return this.request({ method: "DELETE", path });
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
|
|
220
358
|
// src/client/SoundCloudClient.ts
|
|
221
359
|
function resolveToken(tokenGetter, explicit) {
|
|
222
360
|
const t = explicit ?? tokenGetter();
|
|
@@ -245,6 +383,8 @@ exports.SoundCloudClient = class _SoundCloudClient {
|
|
|
245
383
|
likes;
|
|
246
384
|
/** Repost/unrepost actions (/reposts) */
|
|
247
385
|
reposts;
|
|
386
|
+
/** Low-level raw HTTP client — returns status/headers without throwing on non-2xx */
|
|
387
|
+
raw;
|
|
248
388
|
/**
|
|
249
389
|
* Creates a new SoundCloudClient instance.
|
|
250
390
|
*
|
|
@@ -256,7 +396,8 @@ exports.SoundCloudClient = class _SoundCloudClient {
|
|
|
256
396
|
const retryConfig = {
|
|
257
397
|
maxRetries: config.maxRetries ?? 3,
|
|
258
398
|
retryBaseDelay: config.retryBaseDelay ?? 1e3,
|
|
259
|
-
onDebug: config.onDebug
|
|
399
|
+
onDebug: config.onDebug,
|
|
400
|
+
onRetry: config.onRetry
|
|
260
401
|
};
|
|
261
402
|
const refreshCtx = config.onTokenRefresh ? {
|
|
262
403
|
getToken,
|
|
@@ -285,6 +426,7 @@ exports.SoundCloudClient = class _SoundCloudClient {
|
|
|
285
426
|
this.resolve = new _SoundCloudClient.Resolve(getToken, refreshCtx);
|
|
286
427
|
this.likes = new _SoundCloudClient.Likes(getToken, refreshCtx);
|
|
287
428
|
this.reposts = new _SoundCloudClient.Reposts(getToken, refreshCtx);
|
|
429
|
+
this.raw = new RawClient("https://api.soundcloud.com", getToken, config.fetch ?? globalThis.fetch);
|
|
288
430
|
}
|
|
289
431
|
/**
|
|
290
432
|
* Store an access token (and optionally refresh token) on this client instance.
|
|
@@ -1458,6 +1600,89 @@ exports.SoundCloudClient = class _SoundCloudClient {
|
|
|
1458
1600
|
SoundCloudClient2.Reposts = Reposts;
|
|
1459
1601
|
})(exports.SoundCloudClient || (exports.SoundCloudClient = {}));
|
|
1460
1602
|
|
|
1603
|
+
// src/client/dedupe.ts
|
|
1604
|
+
var InFlightDeduper = class {
|
|
1605
|
+
inFlight = /* @__PURE__ */ new Map();
|
|
1606
|
+
/**
|
|
1607
|
+
* Return an existing in-flight promise for `key`, or start a new one via `factory`.
|
|
1608
|
+
* The entry is removed from the map once the promise settles (resolve or reject).
|
|
1609
|
+
*/
|
|
1610
|
+
add(key, factory) {
|
|
1611
|
+
const existing = this.inFlight.get(key);
|
|
1612
|
+
if (existing) return existing;
|
|
1613
|
+
const promise = factory().finally(() => {
|
|
1614
|
+
this.inFlight.delete(key);
|
|
1615
|
+
});
|
|
1616
|
+
this.inFlight.set(key, promise);
|
|
1617
|
+
return promise;
|
|
1618
|
+
}
|
|
1619
|
+
/** Number of currently in-flight requests */
|
|
1620
|
+
get size() {
|
|
1621
|
+
return this.inFlight.size;
|
|
1622
|
+
}
|
|
1623
|
+
};
|
|
1624
|
+
|
|
1625
|
+
// src/client/registry.ts
|
|
1626
|
+
var IMPLEMENTED_OPERATIONS = [
|
|
1627
|
+
// Auth
|
|
1628
|
+
"post_oauth2_token",
|
|
1629
|
+
"delete_oauth2_token",
|
|
1630
|
+
// Me
|
|
1631
|
+
"get_me",
|
|
1632
|
+
"get_me_activities",
|
|
1633
|
+
"get_me_activities_own",
|
|
1634
|
+
"get_me_activities_tracks",
|
|
1635
|
+
"get_me_likes_tracks",
|
|
1636
|
+
"get_me_likes_playlists",
|
|
1637
|
+
"get_me_followings",
|
|
1638
|
+
"get_me_followings_tracks",
|
|
1639
|
+
"post_me_followings_user_id",
|
|
1640
|
+
"delete_me_followings_user_id",
|
|
1641
|
+
"get_me_followers",
|
|
1642
|
+
"get_me_playlists",
|
|
1643
|
+
"get_me_tracks",
|
|
1644
|
+
// Users
|
|
1645
|
+
"get_users_user_id",
|
|
1646
|
+
"get_users_user_id_followers",
|
|
1647
|
+
"get_users_user_id_followings",
|
|
1648
|
+
"get_users_user_id_tracks",
|
|
1649
|
+
"get_users_user_id_playlists",
|
|
1650
|
+
"get_users_user_id_likes_tracks",
|
|
1651
|
+
"get_users_user_id_likes_playlists",
|
|
1652
|
+
"get_users_user_id_web_profiles",
|
|
1653
|
+
// Tracks
|
|
1654
|
+
"get_tracks_track_id",
|
|
1655
|
+
"put_tracks_track_id",
|
|
1656
|
+
"delete_tracks_track_id",
|
|
1657
|
+
"get_tracks_track_id_comments",
|
|
1658
|
+
"post_tracks_track_id_comments",
|
|
1659
|
+
"get_tracks_track_id_likes",
|
|
1660
|
+
"get_tracks_track_id_reposts",
|
|
1661
|
+
"get_tracks_track_id_related",
|
|
1662
|
+
"get_tracks_track_id_streams",
|
|
1663
|
+
"post_likes_tracks_track_id",
|
|
1664
|
+
"delete_likes_tracks_track_id",
|
|
1665
|
+
"post_reposts_tracks_track_id",
|
|
1666
|
+
"delete_reposts_tracks_track_id",
|
|
1667
|
+
// Playlists
|
|
1668
|
+
"get_playlists_playlist_id",
|
|
1669
|
+
"post_playlists",
|
|
1670
|
+
"put_playlists_playlist_id",
|
|
1671
|
+
"delete_playlists_playlist_id",
|
|
1672
|
+
"get_playlists_playlist_id_tracks",
|
|
1673
|
+
"get_playlists_playlist_id_reposts",
|
|
1674
|
+
"post_likes_playlists_playlist_id",
|
|
1675
|
+
"delete_likes_playlists_playlist_id",
|
|
1676
|
+
"post_reposts_playlists_playlist_id",
|
|
1677
|
+
"delete_reposts_playlists_playlist_id",
|
|
1678
|
+
// Search
|
|
1679
|
+
"get_tracks",
|
|
1680
|
+
"get_users",
|
|
1681
|
+
"get_playlists",
|
|
1682
|
+
// Resolve
|
|
1683
|
+
"get_resolve"
|
|
1684
|
+
];
|
|
1685
|
+
|
|
1461
1686
|
// src/auth/getClientToken.ts
|
|
1462
1687
|
var getClientToken = (clientId, clientSecret) => {
|
|
1463
1688
|
const basicAuth = Buffer.from(`${clientId}:${clientSecret}`).toString("base64");
|
|
@@ -1750,6 +1975,9 @@ var unrepostPlaylist = async (token, playlistId) => {
|
|
|
1750
1975
|
// src/utils/widget.ts
|
|
1751
1976
|
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`;
|
|
1752
1977
|
|
|
1978
|
+
exports.IMPLEMENTED_OPERATIONS = IMPLEMENTED_OPERATIONS;
|
|
1979
|
+
exports.InFlightDeduper = InFlightDeduper;
|
|
1980
|
+
exports.RawClient = RawClient;
|
|
1753
1981
|
exports.createPlaylist = createPlaylist;
|
|
1754
1982
|
exports.createTrackComment = createTrackComment;
|
|
1755
1983
|
exports.deletePlaylist = deletePlaylist;
|
|
@@ -1811,5 +2039,5 @@ exports.unrepostPlaylist = unrepostPlaylist;
|
|
|
1811
2039
|
exports.unrepostTrack = unrepostTrack;
|
|
1812
2040
|
exports.updatePlaylist = updatePlaylist;
|
|
1813
2041
|
exports.updateTrack = updateTrack;
|
|
1814
|
-
//# sourceMappingURL=chunk-
|
|
1815
|
-
//# sourceMappingURL=chunk-
|
|
2042
|
+
//# sourceMappingURL=chunk-D7AF372V.js.map
|
|
2043
|
+
//# sourceMappingURL=chunk-D7AF372V.js.map
|