@omelhorsite/sdk 0.4.0 → 0.4.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/README.md +4 -4
- package/dist/index.js +4 -4
- package/dist/types/auth/device.d.ts +1 -1
- package/dist/types/auth/index.d.ts +2 -2
- package/dist/types/auth/tokens.d.ts +15 -15
- package/dist/types/client.d.ts +10 -10
- package/dist/types/errors.d.ts +12 -15
- package/dist/types/http.d.ts +74 -118
- package/dist/types/index.d.ts +1 -2
- package/dist/types/local/qr.d.ts +1 -1
- package/dist/types/local/wordlist.d.ts +2 -3
- package/dist/types/resources/account.d.ts +14 -17
- package/dist/types/resources/auth/index.d.ts +1 -1
- package/dist/types/resources/auth/passkeys.d.ts +127 -163
- package/dist/types/resources/auth/sessions.d.ts +110 -152
- package/dist/types/resources/chests.d.ts +27 -31
- package/dist/types/resources/dynamicQrs.d.ts +29 -45
- package/dist/types/resources/forms.d.ts +37 -58
- package/dist/types/resources/jobs.d.ts +28 -40
- package/dist/types/resources/media.d.ts +48 -61
- package/dist/types/resources/music/artists.d.ts +179 -245
- package/dist/types/resources/music/imports.d.ts +181 -210
- package/dist/types/resources/music/index.d.ts +8 -7
- package/dist/types/resources/music/playlists.d.ts +77 -110
- package/dist/types/resources/music/social.d.ts +153 -228
- package/dist/types/resources/music/songs.d.ts +160 -206
- package/dist/types/resources/realtime.d.ts +75 -88
- package/dist/types/resources/shortLinks.d.ts +33 -45
- package/dist/types/resources/storage/upload.d.ts +42 -56
- package/dist/types/resources/storage.d.ts +71 -104
- package/dist/types/resources/tools/backgroundRemoval.d.ts +11 -13
- package/dist/types/resources/tools/captions.d.ts +107 -135
- package/dist/types/resources/tools/upscale.d.ts +12 -16
- package/dist/types/types.d.ts +29 -38
- package/package.json +1 -1
|
@@ -2,41 +2,24 @@
|
|
|
2
2
|
* The `music.social` namespace: jams, the music half of a public profile, the
|
|
3
3
|
* music storage meter, the chat assistant and the DJ.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* `modifiers[page]`). What a route sends is exactly what its `ok!({ ... })`
|
|
11
|
-
* literal says, which is why every interface below is documented against the
|
|
12
|
-
* controller rather than against a blueprint view. There is no paging anywhere
|
|
13
|
-
* in this file either: every listing is a whole bare array with a server-side
|
|
14
|
-
* cap, so no method returns a `Paginated`.
|
|
5
|
+
* None of these is a CRUD resource. The payloads are bespoke, none carries the
|
|
6
|
+
* `id`/`created_at`/`updated_at` base fields as a matter of course, none
|
|
7
|
+
* accepts the list DSL (`search[...]`, `exact_search[...]`, `modifiers[page]`),
|
|
8
|
+
* and there is no paging: every listing is a whole bare array with a
|
|
9
|
+
* server-side cap, so no method returns a `Paginated`.
|
|
15
10
|
*
|
|
16
|
-
* ##
|
|
17
|
-
*
|
|
18
|
-
* `/jams*` and `/users/:id/music_profile` are used by both clients and are the
|
|
19
|
-
* best-tested surface here. **`/music/storage`, `/music_assistant*` and
|
|
20
|
-
* `/music_dj*` are called only by the native app** - the web frontend has no
|
|
21
|
-
* service for any of them. They are in the SDK because the app is one of the
|
|
22
|
-
* three clients it serves, and because the assistant and the DJ are perfectly
|
|
23
|
-
* usable from the CLI and the MCP server. Nothing about them needs a phone; the
|
|
24
|
-
* note is about where the field experience comes from, so treat their shapes as
|
|
25
|
-
* less battle-hardened than the jam ones.
|
|
26
|
-
*
|
|
27
|
-
* ## A jam is half HTTP and half cable, and this file is the HTTP half
|
|
11
|
+
* ## A jam is half HTTP and half realtime, and this file is the HTTP half
|
|
28
12
|
*
|
|
29
13
|
* Every method below performs an ACTION and returns what that action produced.
|
|
30
14
|
* None of them tells you what the jam is doing right now. The host's current
|
|
31
15
|
* song and position, the queue members are watching, the running skip tally,
|
|
32
|
-
* "somebody joined", "the jam ended" - all of that arrives over
|
|
33
|
-
* two streams this SDK does not open and has no code for:
|
|
16
|
+
* "somebody joined", "the jam ended" - all of that arrives over the realtime
|
|
17
|
+
* WebSocket, on two streams this SDK does not open and has no code for:
|
|
34
18
|
*
|
|
35
19
|
* - `jam:<jam_id>` (see {@link jamStreamName}), carrying `snapshot`,
|
|
36
20
|
* `state_changed`, `position_tick`, `members_changed`, `jam_updated`,
|
|
37
21
|
* `song_proposed`, `skip_votes`, `skipped` and `ended`. It is RECEIVE-ONLY:
|
|
38
|
-
*
|
|
39
|
-
* in a jam is one of the HTTP calls below.
|
|
22
|
+
* every mutation in a jam is one of the HTTP calls below.
|
|
40
23
|
* - `playback:user:<host_id>`, the host's own playback stream, where
|
|
41
24
|
* {@link MusicJamsNamespace.propose} and a passing
|
|
42
25
|
* {@link MusicJamsNamespace.skipVote} deposit a `command` for the host's
|
|
@@ -44,11 +27,10 @@
|
|
|
44
27
|
*
|
|
45
28
|
* Two consequences to design around:
|
|
46
29
|
*
|
|
47
|
-
* 1. **Join over HTTP first, subscribe second.**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* not retry-loop.
|
|
30
|
+
* 1. **Join over HTTP first, subscribe second.** The jam stream admits members
|
|
31
|
+
* only, so a subscription opened before `POST /jams/:id/join` has returned
|
|
32
|
+
* is rejected. A rejection later in the session means the jam ended or you
|
|
33
|
+
* were dropped - clear local state, do not retry-loop.
|
|
52
34
|
* 2. **A `200` from `propose` means "the message was sent", not "the song is
|
|
53
35
|
* queued".** The song enters the jam when the HOST's client acts on the
|
|
54
36
|
* `jam_add_song` command; a host whose app is backgrounded and disconnected
|
|
@@ -57,23 +39,18 @@
|
|
|
57
39
|
*
|
|
58
40
|
* ## Rate limits
|
|
59
41
|
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
* refusal, which is why {@link MusicDjNamespace} turns retrying off by default -
|
|
67
|
-
* see {@link MUSIC_DJ_HOURLY_CAP}.
|
|
42
|
+
* Every path here sits under the general authenticated ceiling of **600
|
|
43
|
+
* requests a minute**, keyed by the `Authorization` header. The single extra
|
|
44
|
+
* ceiling is forty DJ generations per user per hour, shared between
|
|
45
|
+
* `/music_dj` and `/music_dj/batch` and counted per REQUEST, refused ones
|
|
46
|
+
* included, which is why {@link MusicDjNamespace} turns retrying off by
|
|
47
|
+
* default - see {@link MUSIC_DJ_HOURLY_CAP}.
|
|
68
48
|
*
|
|
69
49
|
* ## An OAuth access token cannot reach any of this
|
|
70
50
|
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* OAuth token gets `403 {"error":"insufficient_scope"}` on every route in this
|
|
75
|
-
* file, whatever scopes it was granted. Use a session token (`POST /sessions`)
|
|
76
|
-
* or, in the browser, the session cookie.
|
|
51
|
+
* Every route in this file answers `403 {"error":"insufficient_scope"}` to an
|
|
52
|
+
* OAuth access token, whatever scopes it was granted. Use a session token
|
|
53
|
+
* (`POST /sessions`) or, in the browser, the session cookie.
|
|
77
54
|
*
|
|
78
55
|
* ## Errors are bare JSON strings
|
|
79
56
|
*
|
|
@@ -81,8 +58,7 @@
|
|
|
81
58
|
* found"`. There is no `{ error: ... }` object and no envelope; the SDK's
|
|
82
59
|
* `OmsError` carries the string in `message`. One status is worth calling out
|
|
83
60
|
* before it costs somebody a session: **a refused join or a refused host action
|
|
84
|
-
* is `401`, not `403
|
|
85
|
-
* authorization failures. A host-wide "on 401, log the user out" interceptor
|
|
61
|
+
* is `401`, not `403`**. A host-wide "on 401, log the user out" interceptor
|
|
86
62
|
* will sign somebody out for tapping Join on the wrong jam. Test the message,
|
|
87
63
|
* or scope the interceptor to the auth routes.
|
|
88
64
|
*/
|
|
@@ -90,10 +66,9 @@ import { Resource } from "../../http";
|
|
|
90
66
|
import type { Id, RequestOptions, Timestamp } from "../../types";
|
|
91
67
|
import type { Song, SongId } from "./songs";
|
|
92
68
|
/**
|
|
93
|
-
* Primary key of a jam. An INTEGER
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
* strings. `MusicListeningSnapshot.jam_id` is the same integer, so a feed row
|
|
69
|
+
* Primary key of a jam. An INTEGER, like songs, playlists and artists - and
|
|
70
|
+
* unlike `host_id` and the member ids sitting beside it in the very same
|
|
71
|
+
* payload, which are user ids and therefore strings. `MusicListeningSnapshot.jam_id` is the same integer, so a feed row
|
|
97
72
|
* can be matched straight against {@link Jam.id}.
|
|
98
73
|
*/
|
|
99
74
|
export type JamId = number;
|
|
@@ -101,20 +76,19 @@ export type JamId = number;
|
|
|
101
76
|
export type JamQueueMode = "everyone" | "host";
|
|
102
77
|
/** What it takes for a skip to pass. */
|
|
103
78
|
export type JamSkipMode = "majority" | "host" | "anyone";
|
|
104
|
-
/**
|
|
79
|
+
/** Every accepted `queue_mode`. Anything else is a `400`. */
|
|
105
80
|
export declare const JAM_QUEUE_MODES: readonly ["everyone", "host"];
|
|
106
|
-
/**
|
|
81
|
+
/** Every accepted `skip_mode`. Anything else is a `400`. */
|
|
107
82
|
export declare const JAM_SKIP_MODES: readonly ["majority", "host", "anyone"];
|
|
108
83
|
/**
|
|
109
|
-
* How many upcoming entries the
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
* than a guess.
|
|
84
|
+
* How many upcoming entries the realtime state payload carries. Nothing in
|
|
85
|
+
* this file returns them - it is here so a client sizing its "up next" list
|
|
86
|
+
* uses the server's number rather than a guess.
|
|
113
87
|
*/
|
|
114
88
|
export declare const JAM_UPCOMING_LIMIT = 10;
|
|
115
89
|
/**
|
|
116
90
|
* How long a presigned `*_url` in any cross-user payload stays valid, in
|
|
117
|
-
* milliseconds (
|
|
91
|
+
* milliseconds (six hours).
|
|
118
92
|
*
|
|
119
93
|
* The server caches each signature for five hours, so a URL you receive has at
|
|
120
94
|
* least an hour of life left and the SAME string is handed out again across
|
|
@@ -134,11 +108,11 @@ export interface JamMember {
|
|
|
134
108
|
readonly joined_at: Timestamp;
|
|
135
109
|
}
|
|
136
110
|
/**
|
|
137
|
-
* A jam
|
|
111
|
+
* A jam.
|
|
138
112
|
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
113
|
+
* There is no `updated_at`, and `members` is a bespoke five-key object rather
|
|
114
|
+
* than a user record, so none of the base-record guarantees the rest of the
|
|
115
|
+
* API makes apply.
|
|
142
116
|
*
|
|
143
117
|
* `members` comes back ordered by join time, which normally puts the host
|
|
144
118
|
* first - normally, not always. Find the host with {@link jamHost} rather than
|
|
@@ -156,10 +130,10 @@ export interface Jam {
|
|
|
156
130
|
/**
|
|
157
131
|
* `null` while the jam is live.
|
|
158
132
|
*
|
|
159
|
-
* Every route here
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
133
|
+
* Every route here only sees live jams, so an ended jam answers `404` rather
|
|
134
|
+
* than a payload with a timestamp in this field. You will only ever see a
|
|
135
|
+
* non-null value on a copy you were already holding, or on one that arrived
|
|
136
|
+
* over the realtime stream.
|
|
163
137
|
*/
|
|
164
138
|
readonly ended_at: Timestamp | null;
|
|
165
139
|
readonly members: JamMember[];
|
|
@@ -199,26 +173,16 @@ export interface JamSkipVoteResult {
|
|
|
199
173
|
readonly needed: number;
|
|
200
174
|
}
|
|
201
175
|
/**
|
|
202
|
-
* A song as the cross-user payloads render it
|
|
203
|
-
*
|
|
204
|
-
* the track is allowed to see.
|
|
205
|
-
*
|
|
206
|
-
* ## `id` is a number, and every other client says otherwise
|
|
176
|
+
* A song as the cross-user payloads render it: the seven fields somebody who
|
|
177
|
+
* does NOT own the track is allowed to see.
|
|
207
178
|
*
|
|
208
|
-
* `
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
* `songs` has a default `bigint` primary key and `Listening::Snapshot` emits
|
|
213
|
-
* `id: song.id` with no cast, so it arrives as a JSON NUMBER exactly like
|
|
214
|
-
* `Song.id` does everywhere else in the REST API. The mistake is invisible
|
|
215
|
-
* while the field is only rendered or used as a cache key; it bites the first
|
|
216
|
-
* time somebody writes `snapshot.song.id === song.id`, which is always false.
|
|
217
|
-
* Song ids become strings on the CABLE (`position_tick.song_id`), which is
|
|
218
|
-
* where that belief comes from.
|
|
179
|
+
* `id` is a JSON NUMBER here, exactly like `Song.id` everywhere else in the
|
|
180
|
+
* REST API. Song ids become strings only on the realtime stream
|
|
181
|
+
* (`position_tick.song_id`); do not stringify this one, or
|
|
182
|
+
* `snapshot.song.id === song.id` is always false.
|
|
219
183
|
*/
|
|
220
184
|
export interface MusicListeningSong {
|
|
221
|
-
/** Integer song id.
|
|
185
|
+
/** Integer song id. */
|
|
222
186
|
readonly id: number;
|
|
223
187
|
readonly title: string;
|
|
224
188
|
readonly album: string | null;
|
|
@@ -234,16 +198,15 @@ export interface MusicListeningSong {
|
|
|
234
198
|
*
|
|
235
199
|
* The viewer does not own the underlying attachment, so `/media/:id/data`
|
|
236
200
|
* would refuse it - use this string verbatim and never try to re-derive one
|
|
237
|
-
* from the id. `null` is a real outcome: `
|
|
238
|
-
*
|
|
201
|
+
* from the id. `null` is a real outcome: a failed presign yields `null`
|
|
202
|
+
* rather than an error.
|
|
239
203
|
*/
|
|
240
204
|
readonly artwork_url: string | null;
|
|
241
205
|
}
|
|
242
206
|
/**
|
|
243
|
-
* What a friend may see about somebody's playback
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
* TOP LEVEL, not nested.
|
|
207
|
+
* What a friend may see about somebody's playback, and the shape the friends
|
|
208
|
+
* feed pushes over `listening:user:<id>` with a `type: "listening_update"` key
|
|
209
|
+
* merged in AT THE TOP LEVEL, not nested.
|
|
247
210
|
*/
|
|
248
211
|
export interface MusicListeningSnapshot {
|
|
249
212
|
readonly user: {
|
|
@@ -288,12 +251,8 @@ export interface MusicProfileArtist {
|
|
|
288
251
|
readonly play_count: number;
|
|
289
252
|
}
|
|
290
253
|
/**
|
|
291
|
-
* A profile the viewer is allowed to see.
|
|
292
|
-
*
|
|
293
|
-
* All six keys are always present on a visible profile - `MusicProfiles::Builder`
|
|
294
|
-
* builds one literal with no conditionals - which is why they are required here
|
|
295
|
-
* even though both existing clients type every field as optional. See
|
|
296
|
-
* {@link MusicProfile} for why they had to.
|
|
254
|
+
* A profile the viewer is allowed to see. All six keys are always present on
|
|
255
|
+
* a visible profile, which is why they are required here.
|
|
297
256
|
*/
|
|
298
257
|
export interface MusicProfileVisible {
|
|
299
258
|
readonly visible: true;
|
|
@@ -318,10 +277,10 @@ export interface MusicProfileVisible {
|
|
|
318
277
|
*
|
|
319
278
|
* This is not an error and must not be handled as one. It is what a signed-in
|
|
320
279
|
* stranger gets, what a friend of somebody with `share_listening` off gets, and
|
|
321
|
-
* what
|
|
322
|
-
*
|
|
323
|
-
*
|
|
324
|
-
*
|
|
280
|
+
* what you should render as nothing - a private profile is deliberately
|
|
281
|
+
* indistinguishable from an empty one. A real `404` ("User not found.") means
|
|
282
|
+
* the user does not exist; a `401` means you sent no credential, because the
|
|
283
|
+
* route requires authentication.
|
|
325
284
|
*/
|
|
326
285
|
export interface MusicProfileHidden {
|
|
327
286
|
readonly visible: false;
|
|
@@ -329,54 +288,33 @@ export interface MusicProfileHidden {
|
|
|
329
288
|
/**
|
|
330
289
|
* `GET /users/:idOrHandle/music_profile`.
|
|
331
290
|
*
|
|
332
|
-
* A discriminated union
|
|
333
|
-
*
|
|
334
|
-
*
|
|
335
|
-
* five `?` fields). Those types are not wrong about the wire - they simply
|
|
336
|
-
* cannot say that the five fields are present together or absent together, so
|
|
337
|
-
* every read site needs a `?.` that TypeScript can never discharge. Narrow once
|
|
338
|
-
* with {@link isMusicProfileVisible} and the rest is non-optional.
|
|
291
|
+
* A discriminated union: the five content fields are present together or
|
|
292
|
+
* absent together. Narrow once with {@link isMusicProfileVisible} and the rest
|
|
293
|
+
* is non-optional.
|
|
339
294
|
*/
|
|
340
295
|
export type MusicProfile = MusicProfileVisible | MusicProfileHidden;
|
|
341
296
|
/**
|
|
342
297
|
* `GET /music/storage`: bytes of music media stored, against the account's
|
|
343
298
|
* ceiling.
|
|
344
299
|
*
|
|
345
|
-
*
|
|
346
|
-
*
|
|
347
|
-
* The ceiling was `users.music_storage_limit_bytes`, a `NOT NULL` column, so
|
|
348
|
-
* `limit_bytes` was always a number - which is why the native app types it
|
|
349
|
-
* `limit_bytes: number` and has no `unlimited` field at all
|
|
350
|
-
* (`oms-music/src/api/endpoints/musicStorage.ts`). Since the quota catalogue
|
|
351
|
-
* landed (`Quotas::CATALOG`, migration `20260826120000`) an administrator can
|
|
352
|
-
* mark an account unlimited by storing a `QuotaOverride` row with a `NULL`
|
|
353
|
-
* value; the limit then resolves to `Float::INFINITY` and `Quotas.limit_json`
|
|
354
|
-
* serialises it as `null`, because JSON has no infinity.
|
|
355
|
-
*
|
|
300
|
+
* `limit_bytes` IS NULLABLE: an administrator can mark an account unlimited,
|
|
301
|
+
* and the limit is then serialised as `null`, because JSON has no infinity.
|
|
356
302
|
* So read {@link MusicStorageUsage.unlimited} FIRST. A client that divides
|
|
357
303
|
* `used_bytes` by `limit_bytes` renders `NaN%`, and one that reads `null` as
|
|
358
304
|
* `0` shows a permanently full bar to exactly the accounts that were given no
|
|
359
305
|
* ceiling at all. {@link musicStorageRemaining} and
|
|
360
306
|
* {@link musicStorageAffords} answer both questions without the arithmetic.
|
|
307
|
+
* An ordinary account's ceiling is the default of 100 GiB.
|
|
361
308
|
*
|
|
362
|
-
*
|
|
363
|
-
*
|
|
364
|
-
*
|
|
365
|
-
*
|
|
366
|
-
* ## The same number is also in `oms.quotas`
|
|
367
|
-
*
|
|
368
|
-
* `music_storage_bytes` is one of the six resources `GET /quotas` reports, and
|
|
369
|
-
* both routes call `Quotas.limit_for` and `Music::Quota.usage`, so they cannot
|
|
370
|
-
* disagree. Use `oms.quotas.list()` when you want every ceiling at once; use
|
|
371
|
-
* this when you want only this one, or when you are talking to a build older
|
|
372
|
-
* than the catalogue.
|
|
309
|
+
* The same number is reported as `music_storage_bytes` by `GET /quotas`, and
|
|
310
|
+
* the two cannot disagree. Use `oms.quotas.list()` when you want every ceiling
|
|
311
|
+
* at once; use this when you want only this one.
|
|
373
312
|
*/
|
|
374
313
|
export interface MusicStorageUsage {
|
|
375
314
|
/**
|
|
376
315
|
* Sum of the DISTINCT blobs reachable from the account's songs, artists and
|
|
377
316
|
* playlists. Computed live on every call - a blob shared by two records
|
|
378
|
-
* counts once, exactly as it costs once in
|
|
379
|
-
* drift the way the storage tree's cached counters did. It is also not free:
|
|
317
|
+
* counts once, exactly as it costs once in storage. It is also not free:
|
|
380
318
|
* read it on a settings screen, not on a timer.
|
|
381
319
|
*/
|
|
382
320
|
readonly used_bytes: number;
|
|
@@ -387,33 +325,31 @@ export interface MusicStorageUsage {
|
|
|
387
325
|
}
|
|
388
326
|
/** Primary key of a persisted assistant chat. An INTEGER. */
|
|
389
327
|
export type MusicAssistantChatId = number;
|
|
390
|
-
/** Turns of history the server feeds the model
|
|
328
|
+
/** Turns of history the server feeds the model. */
|
|
391
329
|
export declare const MUSIC_ASSISTANT_HISTORY_TURNS = 20;
|
|
392
|
-
/** Messages a chat keeps before the oldest fall off
|
|
330
|
+
/** Messages a chat keeps before the oldest fall off. */
|
|
393
331
|
export declare const MUSIC_ASSISTANT_CHAT_MAX_MESSAGES = 200;
|
|
394
|
-
/** Player actions one answer may carry
|
|
332
|
+
/** Player actions one answer may carry. */
|
|
395
333
|
export declare const MUSIC_ASSISTANT_MAX_ACTIONS = 10;
|
|
396
334
|
/**
|
|
397
|
-
* Largest request body `
|
|
335
|
+
* Largest request body `POST /music_assistant` accepts, in bytes. Over it is
|
|
398
336
|
* `413 "Request too big"`, decided from `Content-Length` before any parsing.
|
|
399
337
|
*/
|
|
400
338
|
export declare const MUSIC_ASSISTANT_MAX_BODY_BYTES: number;
|
|
401
339
|
/**
|
|
402
|
-
* How long a chat may sit idle before it seals itself, in milliseconds
|
|
403
|
-
*
|
|
340
|
+
* How long a chat may sit idle before it seals itself, in milliseconds (two
|
|
341
|
+
* days).
|
|
404
342
|
*
|
|
405
|
-
* It is COMPUTED
|
|
406
|
-
*
|
|
407
|
-
*
|
|
408
|
-
* find out, with a `423`.
|
|
343
|
+
* It is COMPUTED against the clock at read time, never stored, so a summary
|
|
344
|
+
* you cached yesterday can report `read_only: false` for a chat that is now
|
|
345
|
+
* sealed. The `POST` is where you find out, with a `423`.
|
|
409
346
|
*/
|
|
410
347
|
export declare const MUSIC_ASSISTANT_READ_ONLY_AFTER_MS: number;
|
|
411
348
|
/**
|
|
412
349
|
* Default deadline for one assistant generation, in milliseconds.
|
|
413
350
|
*
|
|
414
|
-
* The client's global default is 60 s and a cold model
|
|
415
|
-
*
|
|
416
|
-
* 90 s for the same reason; pass `timeoutMs` to override.
|
|
351
|
+
* The client's global default is 60 s and a cold model routinely beats that
|
|
352
|
+
* while still being on its way to an answer. Pass `timeoutMs` to override.
|
|
417
353
|
*/
|
|
418
354
|
export declare const MUSIC_ASSISTANT_TIMEOUT_MS = 90000;
|
|
419
355
|
/** One turn of a conversation. */
|
|
@@ -441,9 +377,9 @@ export interface MusicAssistantChatDetail extends MusicAssistantChatSummary {
|
|
|
441
377
|
* Snapshot of the caller's player, so the model can answer "pause this" and
|
|
442
378
|
* "who sings this".
|
|
443
379
|
*
|
|
444
|
-
* The server applies a strict whitelist
|
|
445
|
-
*
|
|
446
|
-
*
|
|
380
|
+
* The server applies a strict whitelist; a key that is not one of these nine
|
|
381
|
+
* never reaches the prompt, silently. Every field is optional here because the
|
|
382
|
+
* whitelist permits rather than requires.
|
|
447
383
|
*/
|
|
448
384
|
export interface MusicAssistantPlayerContext {
|
|
449
385
|
readonly song_id?: number | null;
|
|
@@ -469,8 +405,8 @@ export interface MusicAssistantPlaylistRef {
|
|
|
469
405
|
* A player command the server validated and the client executes LOCALLY.
|
|
470
406
|
*
|
|
471
407
|
* Nothing here runs on the server. The songs in `play` and `queue` arrive fully
|
|
472
|
-
* serialised in the `GET /songs` shape and
|
|
473
|
-
*
|
|
408
|
+
* serialised in the `GET /songs` shape and already scoped to what the caller
|
|
409
|
+
* may play, so a client queues them without a second request and without
|
|
474
410
|
* re-checking anything. Values are clamped server-side before they get here:
|
|
475
411
|
* `set_volume` to `[0, 1]`, `set_rate` to `[0.5, 1.5]`, `sleep_timer.minutes`
|
|
476
412
|
* to `[1, 600]`. An action the sanitiser did not recognise is DROPPED rather
|
|
@@ -538,7 +474,7 @@ export type MusicAssistantAction = {
|
|
|
538
474
|
* What `POST /music_assistant` answers.
|
|
539
475
|
*
|
|
540
476
|
* `playlist` and `actions` are OMITTED when the turn produced none - the
|
|
541
|
-
*
|
|
477
|
+
* server only writes the keys it has - so test with `in` or a truthiness
|
|
542
478
|
* check rather than against `null`.
|
|
543
479
|
*/
|
|
544
480
|
export interface MusicAssistantAnswer {
|
|
@@ -565,23 +501,20 @@ export interface SendMusicAssistantMessageInput {
|
|
|
565
501
|
readonly player?: MusicAssistantPlayerContext;
|
|
566
502
|
}
|
|
567
503
|
/**
|
|
568
|
-
* Generations per user per hour, shared by `/music_dj` and `/music_dj/batch
|
|
569
|
-
* (`MusicDjController::HOURLY_CAP`).
|
|
504
|
+
* Generations per user per hour, shared by `/music_dj` and `/music_dj/batch`.
|
|
570
505
|
*
|
|
571
|
-
*
|
|
572
|
-
* `
|
|
573
|
-
*
|
|
574
|
-
* further past the cap and can never recover inside the hour, which is why
|
|
506
|
+
* The counter is incremented by EVERY request - including the ones it then
|
|
507
|
+
* refuses with `429`. A retry loop therefore drives the count further past the
|
|
508
|
+
* cap and can never recover inside the hour, which is why
|
|
575
509
|
* {@link MusicDjNamespace} passes `retry: false` unless you override it.
|
|
576
510
|
*/
|
|
577
511
|
export declare const MUSIC_DJ_HOURLY_CAP = 40;
|
|
578
512
|
/**
|
|
579
|
-
* Default deadline for one DJ generation, in milliseconds.
|
|
580
|
-
*
|
|
581
|
-
* client's 60 s default; the app uses 120 s.
|
|
513
|
+
* Default deadline for one DJ generation, in milliseconds. Writing the script
|
|
514
|
+
* and speaking it takes well past the client's 60 s default.
|
|
582
515
|
*/
|
|
583
516
|
export declare const MUSIC_DJ_TIMEOUT_MS = 120000;
|
|
584
|
-
/** Songs one `/music_dj/batch` set plans at most
|
|
517
|
+
/** Songs one `/music_dj/batch` set plans at most. */
|
|
585
518
|
export declare const MUSIC_DJ_BATCH_SIZE = 4;
|
|
586
519
|
/** `POST /music_dj`: one spoken link between two tracks. */
|
|
587
520
|
export interface MusicDjInterstitial {
|
|
@@ -599,8 +532,8 @@ export interface MusicDjInterstitial {
|
|
|
599
532
|
export interface MusicDjBatch extends MusicDjInterstitial {
|
|
600
533
|
/**
|
|
601
534
|
* The planned tracks, in play order, in the full `GET /songs` shape and
|
|
602
|
-
* already
|
|
603
|
-
* {@link MUSIC_DJ_BATCH_SIZE}: the
|
|
535
|
+
* already scoped to what the caller may play. Between 1 and
|
|
536
|
+
* {@link MUSIC_DJ_BATCH_SIZE}: the server fails rather than answer with an
|
|
604
537
|
* empty set, so this is never `[]`.
|
|
605
538
|
*/
|
|
606
539
|
readonly songs: Song[];
|
|
@@ -621,8 +554,9 @@ export interface MusicDjBatchInput {
|
|
|
621
554
|
readonly batchIndex?: number;
|
|
622
555
|
}
|
|
623
556
|
/**
|
|
624
|
-
* Jams over HTTP. The realtime half lives on the
|
|
625
|
-
* see the module note, and {@link jamStreamName} for the stream to
|
|
557
|
+
* Jams over HTTP. The realtime half lives on the WebSocket stream and is not in
|
|
558
|
+
* this SDK - see the module note, and {@link jamStreamName} for the stream to
|
|
559
|
+
* subscribe to.
|
|
626
560
|
*/
|
|
627
561
|
export declare class MusicJamsNamespace extends Resource {
|
|
628
562
|
/**
|
|
@@ -631,7 +565,7 @@ export declare class MusicJamsNamespace extends Resource {
|
|
|
631
565
|
* Cheap and not cached anywhere, but also not a subscription: it is what you
|
|
632
566
|
* call on app start to rediscover a jam you were already in, and when opening
|
|
633
567
|
* a "join a jam" list. Everything that happens afterwards arrives on the
|
|
634
|
-
*
|
|
568
|
+
* realtime stream, so polling this is the wrong shape.
|
|
635
569
|
*
|
|
636
570
|
* Missing keys are normalised (`current: null`, `joinable: []`) so a caller
|
|
637
571
|
* never has to guard the two separately.
|
|
@@ -659,8 +593,9 @@ export declare class MusicJamsNamespace extends Resource {
|
|
|
659
593
|
* A jam with no active host device is a silent jam: the whole relay rides the
|
|
660
594
|
* host's playback publishes, so proposals and skip votes answer `400 "The
|
|
661
595
|
* host is not playing right now"` until the host's client claims the active
|
|
662
|
-
* device (`claim_active` with `mode: "steal"` on
|
|
663
|
-
* something. Do that immediately after this
|
|
596
|
+
* playback device (a `claim_active` with `mode: "steal"` on the host's
|
|
597
|
+
* playback channel) and plays something. Do that immediately after this
|
|
598
|
+
* returns.
|
|
664
599
|
*
|
|
665
600
|
* General ceiling: 600/min.
|
|
666
601
|
*/
|
|
@@ -701,9 +636,9 @@ export declare class MusicJamsNamespace extends Resource {
|
|
|
701
636
|
* `DELETE /jams/:id` - the host ends the jam for everyone. `200` with a
|
|
702
637
|
* `null` body, NOT the `204` the SDK's other destroys answer with.
|
|
703
638
|
*
|
|
704
|
-
* Identical in effect to a host calling {@link leave}
|
|
705
|
-
*
|
|
706
|
-
*
|
|
639
|
+
* Identical in effect to a host calling {@link leave}. Both set `ended_at`,
|
|
640
|
+
* broadcast `ended`, and re-broadcast every member's feed row so their jam
|
|
641
|
+
* badges drop.
|
|
707
642
|
*
|
|
708
643
|
* @throws {OmsError} `401 "Only the host can end a jam"` - an authorization
|
|
709
644
|
* failure with an authentication status. See {@link join}.
|
|
@@ -745,10 +680,9 @@ export declare class MusicJamsNamespace extends Resource {
|
|
|
745
680
|
*
|
|
746
681
|
* ## The `200` is weaker than it looks
|
|
747
682
|
*
|
|
748
|
-
* Nothing is
|
|
749
|
-
*
|
|
750
|
-
*
|
|
751
|
-
* command onto the HOST's playback stream carrying a fully presigned payload.
|
|
683
|
+
* Nothing is stored here. The server allows the host's playback state to
|
|
684
|
+
* reference your song for 24 hours, then broadcasts a `jam_add_song` command
|
|
685
|
+
* onto the HOST's playback stream carrying a fully presigned payload.
|
|
752
686
|
* The song joins the queue when the host's CLIENT handles that command and
|
|
753
687
|
* republishes its state. A host whose app is backgrounded, disconnected, or
|
|
754
688
|
* simply older than the feature never handles it, and no error comes back to
|
|
@@ -756,8 +690,9 @@ export declare class MusicJamsNamespace extends Resource {
|
|
|
756
690
|
* treating the `200` as confirmation.
|
|
757
691
|
*
|
|
758
692
|
* The song must be the CALLER's. Proposing the host's song, or a third
|
|
759
|
-
* user's, is `404 "Song not found"` - the lookup is scoped to
|
|
760
|
-
* song you can see but do not own does not exist for this
|
|
693
|
+
* user's, is `404 "Song not found"` - the lookup is scoped to your own
|
|
694
|
+
* library, so a song you can see but do not own does not exist for this
|
|
695
|
+
* route.
|
|
761
696
|
*
|
|
762
697
|
* @throws {OmsError} `404 "Jam not found"` (also when you are not a member).
|
|
763
698
|
* @throws {OmsError} `400 "The host picks the music in this jam"` when
|
|
@@ -771,9 +706,9 @@ export declare class MusicJamsNamespace extends Resource {
|
|
|
771
706
|
/**
|
|
772
707
|
* `POST /jams/:id/skip_vote` - votes to skip whatever is playing.
|
|
773
708
|
*
|
|
774
|
-
* Votes are
|
|
775
|
-
*
|
|
776
|
-
*
|
|
709
|
+
* Votes are kept for 15 minutes, per jam AND per CURRENT song, so voting
|
|
710
|
+
* twice is idempotent and **a track change resets the tally silently** - no
|
|
711
|
+
* message says so. Reset any local counter whenever
|
|
777
712
|
* the song id in the jam state changes.
|
|
778
713
|
*
|
|
779
714
|
* The threshold is `1` under `"anyone"` and `floor(members / 2) + 1` under
|
|
@@ -808,8 +743,7 @@ export declare class MusicProfilesNamespace extends Resource {
|
|
|
808
743
|
* `{ "visible": false }` at status `200`, on purpose: a private profile has to
|
|
809
744
|
* look identical to an empty one. Narrow with {@link isMusicProfileVisible}.
|
|
810
745
|
*
|
|
811
|
-
* Authentication is required even though it looks like a public read
|
|
812
|
-
* action is not on `UsersController`'s unauthenticated allowlist, so an
|
|
746
|
+
* Authentication is required even though it looks like a public read: an
|
|
813
747
|
* anonymous call is a `401`, not a hidden profile.
|
|
814
748
|
*
|
|
815
749
|
* Every `*_url` in the answer is presigned and short-lived
|
|
@@ -823,10 +757,7 @@ export declare class MusicProfilesNamespace extends Resource {
|
|
|
823
757
|
*/
|
|
824
758
|
get(idOrHandle: string, options?: RequestOptions): Promise<MusicProfile>;
|
|
825
759
|
}
|
|
826
|
-
/**
|
|
827
|
-
* The music storage meter. **Native app only** - the web frontend has no caller
|
|
828
|
-
* for this route.
|
|
829
|
-
*/
|
|
760
|
+
/** The music storage meter. */
|
|
830
761
|
export declare class MusicStorageNamespace extends Resource {
|
|
831
762
|
/**
|
|
832
763
|
* `GET /music/storage` - bytes of music media stored, against the ceiling.
|
|
@@ -835,7 +766,7 @@ export declare class MusicStorageNamespace extends Resource {
|
|
|
835
766
|
* `limit_bytes`, which is `null` for an unlimited account. See the interface
|
|
836
767
|
* for the whole story.
|
|
837
768
|
*
|
|
838
|
-
* `used_bytes` is
|
|
769
|
+
* `used_bytes` is computed live over the account's distinct blobs, so it is
|
|
839
770
|
* never stale and never free. A settings screen, not a poll.
|
|
840
771
|
*
|
|
841
772
|
* General ceiling: 600/min - this route is NOT covered by the 30/min bucket
|
|
@@ -844,7 +775,7 @@ export declare class MusicStorageNamespace extends Resource {
|
|
|
844
775
|
get(options?: RequestOptions): Promise<MusicStorageUsage>;
|
|
845
776
|
}
|
|
846
777
|
/**
|
|
847
|
-
* Stored assistant sessions: list, reopen, delete.
|
|
778
|
+
* Stored assistant sessions: list, reopen, delete.
|
|
848
779
|
*
|
|
849
780
|
* Reading and deleting live here; WRITING does not. A message is appended by
|
|
850
781
|
* {@link MusicAssistantNamespace.send}, because the only path that may add to a
|
|
@@ -855,10 +786,9 @@ export declare class MusicAssistantChatsNamespace extends Resource {
|
|
|
855
786
|
* `GET /music_assistant/chats` - the caller's sessions, newest activity
|
|
856
787
|
* first, without their messages.
|
|
857
788
|
*
|
|
858
|
-
* A bare array with no paging and no filters: `
|
|
859
|
-
*
|
|
860
|
-
*
|
|
861
|
-
* grows without bound; nothing prunes old chats.
|
|
789
|
+
* A bare array with no paging and no filters: `modifiers[page]` and
|
|
790
|
+
* `search[...]` are ignored rather than rejected. The list grows without
|
|
791
|
+
* bound; nothing prunes old chats.
|
|
862
792
|
*
|
|
863
793
|
* General ceiling: 600/min.
|
|
864
794
|
*/
|
|
@@ -884,8 +814,7 @@ export declare class MusicAssistantChatsNamespace extends Resource {
|
|
|
884
814
|
}
|
|
885
815
|
/**
|
|
886
816
|
* "O Melhor Assistente": a chat that can search the library, build playlists
|
|
887
|
-
* and drive the player.
|
|
888
|
-
* nothing about it is mobile-specific.
|
|
817
|
+
* and drive the player.
|
|
889
818
|
*/
|
|
890
819
|
export declare class MusicAssistantNamespace extends Resource {
|
|
891
820
|
/** Stored sessions: list, reopen, delete. */
|
|
@@ -905,7 +834,7 @@ export declare class MusicAssistantNamespace extends Resource {
|
|
|
905
834
|
*
|
|
906
835
|
* ## Nothing is stored until the model answers
|
|
907
836
|
*
|
|
908
|
-
* The
|
|
837
|
+
* The server runs the generation FIRST and only then creates the chat and
|
|
909
838
|
* appends both messages. So a `502` leaves the chat exactly as it was - no
|
|
910
839
|
* dangling user message, no empty chat on a failed first turn, and a resend
|
|
911
840
|
* that cannot duplicate. That is also why a failure gives you no `chat_id` to
|
|
@@ -917,7 +846,7 @@ export declare class MusicAssistantNamespace extends Resource {
|
|
|
917
846
|
* and is sealed. Open a new one (call again with no `chatId`); there is no
|
|
918
847
|
* unseal. The `read_only` flag is computed, so a cached summary can say
|
|
919
848
|
* `false` and this still fire.
|
|
920
|
-
* - `502` -
|
|
849
|
+
* - `502` - the model refused or fell over. The reply is not partial, it is
|
|
921
850
|
* absent.
|
|
922
851
|
*
|
|
923
852
|
* A body over {@link MUSIC_ASSISTANT_MAX_BODY_BYTES} is `413 "Request too
|
|
@@ -930,7 +859,7 @@ export declare class MusicAssistantNamespace extends Resource {
|
|
|
930
859
|
* finished and stored the turn. Reload with {@link MusicAssistantChatsNamespace.get}
|
|
931
860
|
* before resending.
|
|
932
861
|
*
|
|
933
|
-
* General ceiling: 600/min, and one generation holds a
|
|
862
|
+
* General ceiling: 600/min, and one generation holds a server thread for its
|
|
934
863
|
* whole duration - do not fan these out.
|
|
935
864
|
*/
|
|
936
865
|
send(input: SendMusicAssistantMessageInput, options?: RequestOptions): Promise<MusicAssistantAnswer>;
|
|
@@ -938,9 +867,8 @@ export declare class MusicAssistantNamespace extends Resource {
|
|
|
938
867
|
* `POST /music_assistant` in its STATELESS mode - you own the history, the
|
|
939
868
|
* server stores nothing.
|
|
940
869
|
*
|
|
941
|
-
* This is the older contract,
|
|
942
|
-
*
|
|
943
|
-
* no place to keep a `chat_id` between invocations. The whole transcript
|
|
870
|
+
* This is the older contract, and the right one for a caller that has no
|
|
871
|
+
* place to keep a `chat_id` between invocations. The whole transcript
|
|
944
872
|
* rides in the request every time, so it grows, and the body ceiling
|
|
945
873
|
* ({@link MUSIC_ASSISTANT_MAX_BODY_BYTES}) is a real limit rather than a
|
|
946
874
|
* theoretical one. Only the last {@link MUSIC_ASSISTANT_HISTORY_TURNS}
|
|
@@ -960,15 +888,15 @@ export declare class MusicAssistantNamespace extends Resource {
|
|
|
960
888
|
}
|
|
961
889
|
/**
|
|
962
890
|
* "O Melhor DJ": a written-and-spoken link between tracks, and a whole planned
|
|
963
|
-
* set.
|
|
891
|
+
* set.
|
|
964
892
|
*
|
|
965
893
|
* Both methods pass `retry: false` by default. That is not caution about
|
|
966
894
|
* duplicates - the transport does not replay a `POST` anyway - it is about the
|
|
967
|
-
* one thing it DOES replay: a `429`. The hourly cap here
|
|
968
|
-
*
|
|
969
|
-
*
|
|
970
|
-
*
|
|
971
|
-
*
|
|
895
|
+
* one thing it DOES replay: a `429`. The hourly cap here counts every request
|
|
896
|
+
* including the refused ones, so waiting out a `Retry-After` and asking again
|
|
897
|
+
* pushes the count further past the cap and cannot succeed inside the hour.
|
|
898
|
+
* Pass `retry: {}` to opt back in if you are sure the `429` came from the
|
|
899
|
+
* general per-minute ceiling instead.
|
|
972
900
|
*/
|
|
973
901
|
export declare class MusicDjNamespace extends Resource {
|
|
974
902
|
/**
|
|
@@ -979,12 +907,12 @@ export declare class MusicDjNamespace extends Resource {
|
|
|
979
907
|
* nothing stores it. Decode with {@link musicDjAudioBytes}, or hand
|
|
980
908
|
* {@link musicDjAudioDataUrl} to a player that takes a URI.
|
|
981
909
|
*
|
|
982
|
-
* Both ids are resolved
|
|
983
|
-
* works and a stranger's does not. `previousSongId` is genuinely optional and
|
|
910
|
+
* Both ids are resolved against what the caller may play, so a followed
|
|
911
|
+
* playlist's track works and a stranger's does not. `previousSongId` is genuinely optional and
|
|
984
912
|
* is what lets the script say goodbye to the outgoing track.
|
|
985
913
|
*
|
|
986
|
-
* Generation
|
|
987
|
-
*
|
|
914
|
+
* Generation takes seconds; the deadline defaults to
|
|
915
|
+
* {@link MUSIC_DJ_TIMEOUT_MS}. The
|
|
988
916
|
* intended pattern is to ask for the clip while the current track is still
|
|
989
917
|
* playing and drop it on the boundary, ideally over the outgoing
|
|
990
918
|
* instrumental.
|
|
@@ -1032,27 +960,26 @@ export declare class MusicDjNamespace extends Resource {
|
|
|
1032
960
|
* this class.
|
|
1033
961
|
*/
|
|
1034
962
|
export declare class MusicSocialNamespace extends Resource {
|
|
1035
|
-
/** Shared listening sessions. HTTP half only - the rest is on the
|
|
963
|
+
/** Shared listening sessions. HTTP half only - the rest is on the realtime stream. */
|
|
1036
964
|
readonly jams: MusicJamsNamespace;
|
|
1037
965
|
/** The music card on somebody's profile. */
|
|
1038
966
|
readonly profiles: MusicProfilesNamespace;
|
|
1039
|
-
/** Music bytes stored against the account's ceiling.
|
|
967
|
+
/** Music bytes stored against the account's ceiling. */
|
|
1040
968
|
readonly storage: MusicStorageNamespace;
|
|
1041
|
-
/** The chat assistant, with its stored sessions.
|
|
969
|
+
/** The chat assistant, with its stored sessions. */
|
|
1042
970
|
readonly assistant: MusicAssistantNamespace;
|
|
1043
|
-
/** Scripted and spoken links between tracks.
|
|
971
|
+
/** Scripted and spoken links between tracks. */
|
|
1044
972
|
readonly dj: MusicDjNamespace;
|
|
1045
973
|
constructor(http: ConstructorParameters<typeof Resource>[0]);
|
|
1046
974
|
}
|
|
1047
975
|
/**
|
|
1048
|
-
* The
|
|
976
|
+
* The realtime stream a jam broadcasts on.
|
|
1049
977
|
*
|
|
1050
|
-
* This SDK does not open it - it has no
|
|
1051
|
-
* the contract
|
|
1052
|
-
* drifts. Subscribe with the identifier
|
|
978
|
+
* This SDK does not open it - it has no WebSocket client - but the name is
|
|
979
|
+
* part of the contract. Subscribe with the identifier
|
|
1053
980
|
* `{"channel":"JamChannel","id":<jam id>}` AFTER
|
|
1054
981
|
* {@link MusicJamsNamespace.join} has returned, and treat the subscription as
|
|
1055
|
-
* receive-only
|
|
982
|
+
* receive-only.
|
|
1056
983
|
*/
|
|
1057
984
|
export declare function jamStreamName(jamId: JamId): string;
|
|
1058
985
|
/**
|
|
@@ -1080,10 +1007,9 @@ export declare function jamSkipVotesNeeded(jam: Jam): number;
|
|
|
1080
1007
|
/** Narrows a {@link MusicProfile} to the variant that has any content. */
|
|
1081
1008
|
export declare function isMusicProfileVisible(profile: MusicProfile): profile is MusicProfileVisible;
|
|
1082
1009
|
/**
|
|
1083
|
-
* Picks the best available image for a profile's top artist
|
|
1084
|
-
*
|
|
1085
|
-
*
|
|
1086
|
-
* common - render initials.
|
|
1010
|
+
* Picks the best available image for a profile's top artist: the owner's
|
|
1011
|
+
* upload, then the large Deezer sizes, then the small ones, then Last.fm.
|
|
1012
|
+
* `undefined` when there is nothing, which is common - render initials.
|
|
1087
1013
|
*
|
|
1088
1014
|
* Note that `picture_big` deliberately comes before `picture_xl`: `xl` is a
|
|
1089
1015
|
* 1000px square and these render at avatar size.
|
|
@@ -1100,16 +1026,16 @@ export declare function musicStorageRemaining(usage: MusicStorageUsage): number
|
|
|
1100
1026
|
/**
|
|
1101
1027
|
* Whether `bytes` more would fit. Always true for an unlimited account.
|
|
1102
1028
|
*
|
|
1103
|
-
* Worth calling before an upload: the music quota is checked server-side
|
|
1104
|
-
*
|
|
1105
|
-
*
|
|
1029
|
+
* Worth calling before an upload: the music quota is checked server-side at
|
|
1030
|
+
* attach time, and failing there means the bytes have already crossed the
|
|
1031
|
+
* network.
|
|
1106
1032
|
*/
|
|
1107
1033
|
export declare function musicStorageAffords(usage: MusicStorageUsage, bytes: number): boolean;
|
|
1108
1034
|
/**
|
|
1109
1035
|
* Decodes a DJ clip's `audio_base64` into bytes.
|
|
1110
1036
|
*
|
|
1111
1037
|
* Uses the platform's `atob` when there is one and falls back to a arithmetic
|
|
1112
|
-
* decode when there is not, because this has to work in
|
|
1038
|
+
* decode when there is not, because this has to work in every runtime and
|
|
1113
1039
|
* `atob` is the kind of global that is present in a browser and in Bun, arrived
|
|
1114
1040
|
* in React Native only recently, and is not guaranteed in a Worker-class
|
|
1115
1041
|
* isolate. No `Buffer`, no `node:*`.
|
|
@@ -1122,11 +1048,10 @@ export declare function musicStorageAffords(usage: MusicStorageUsage, bytes: num
|
|
|
1122
1048
|
export declare function musicDjAudioBytes(clip: Pick<MusicDjInterstitial, "audio_base64">): Uint8Array;
|
|
1123
1049
|
/**
|
|
1124
1050
|
* Wraps a DJ clip as a `data:` URI, for a player that takes a URI rather than
|
|
1125
|
-
* bytes - which is most of them
|
|
1051
|
+
* bytes - which is most of them.
|
|
1126
1052
|
*
|
|
1127
1053
|
* The string is roughly a third larger than the audio, and the audio is already
|
|
1128
|
-
* in memory, so this is cheap in every sense that matters at this size. It
|
|
1129
|
-
* NOT work as an `<a download>` target inside a published artifact, and it is
|
|
1054
|
+
* in memory, so this is cheap in every sense that matters at this size. It is
|
|
1130
1055
|
* not a URL anything can fetch twice - it is the bytes, spelled differently.
|
|
1131
1056
|
*/
|
|
1132
1057
|
export declare function musicDjAudioDataUrl(clip: MusicDjInterstitial): string;
|