@omelhorsite/sdk 0.3.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.
Files changed (92) hide show
  1. package/README.md +113 -131
  2. package/dist/index.js +1049 -1246
  3. package/dist/types/auth/device.d.ts +1 -1
  4. package/dist/types/auth/index.d.ts +2 -2
  5. package/dist/types/auth/tokens.d.ts +15 -15
  6. package/dist/types/client.d.ts +10 -10
  7. package/dist/types/errors.d.ts +12 -15
  8. package/dist/types/http.d.ts +74 -118
  9. package/dist/types/index.d.ts +2 -2
  10. package/dist/types/internal/attachments.d.ts +17 -0
  11. package/dist/types/internal/helpers.d.ts +9 -0
  12. package/dist/types/listing.d.ts +90 -0
  13. package/dist/types/local/qr.d.ts +1 -1
  14. package/dist/types/local/wordlist.d.ts +2 -3
  15. package/dist/types/resources/account.d.ts +19 -19
  16. package/dist/types/resources/admin/authorizedApplications.d.ts +133 -0
  17. package/dist/types/resources/admin/chests.d.ts +51 -0
  18. package/dist/types/resources/admin/eventAlerts.d.ts +60 -0
  19. package/dist/types/resources/admin/identities.d.ts +99 -0
  20. package/dist/types/resources/admin/index.d.ts +77 -0
  21. package/dist/types/resources/admin/jobs.d.ts +97 -0
  22. package/dist/types/resources/admin/myOauthApplications.d.ts +282 -0
  23. package/dist/types/resources/admin/notepads.d.ts +49 -0
  24. package/dist/types/resources/admin/oauthApplications.d.ts +309 -0
  25. package/dist/types/resources/admin/quotas.d.ts +114 -0
  26. package/dist/types/resources/admin/shortLinks.d.ts +201 -0
  27. package/dist/types/resources/admin/types.d.ts +222 -0
  28. package/dist/types/resources/admin/vocalSeparations.d.ts +98 -0
  29. package/dist/types/resources/admin.d.ts +17 -13
  30. package/dist/types/resources/auth/index.d.ts +1 -1
  31. package/dist/types/resources/auth/passkeys.d.ts +127 -163
  32. package/dist/types/resources/auth/sessions.d.ts +116 -161
  33. package/dist/types/resources/chests.d.ts +27 -31
  34. package/dist/types/resources/content/analysis.d.ts +62 -0
  35. package/dist/types/resources/content/blogs.d.ts +471 -0
  36. package/dist/types/resources/content/feedbacks.d.ts +263 -0
  37. package/dist/types/resources/content/index.d.ts +52 -0
  38. package/dist/types/resources/content/intel/articles.d.ts +230 -0
  39. package/dist/types/resources/content/intel/config.d.ts +135 -0
  40. package/dist/types/resources/content/intel/index.d.ts +53 -0
  41. package/dist/types/resources/content/intel/items.d.ts +91 -0
  42. package/dist/types/resources/content/intel/reports.d.ts +108 -0
  43. package/dist/types/resources/content/intel/scripts.d.ts +152 -0
  44. package/dist/types/resources/content/intel/sources.d.ts +236 -0
  45. package/dist/types/resources/content/intel/stats.d.ts +105 -0
  46. package/dist/types/resources/content/intel/types.d.ts +86 -0
  47. package/dist/types/resources/content/jokes.d.ts +93 -0
  48. package/dist/types/resources/content/notifications.d.ts +147 -0
  49. package/dist/types/resources/content/serviceUsages.d.ts +73 -0
  50. package/dist/types/resources/content/servicesStatus.d.ts +194 -0
  51. package/dist/types/resources/content/siteConfig.d.ts +43 -0
  52. package/dist/types/resources/content/spaceInvaders.d.ts +154 -0
  53. package/dist/types/resources/content.d.ts +41 -236
  54. package/dist/types/resources/dynamicQrs.d.ts +29 -45
  55. package/dist/types/resources/forms.d.ts +37 -58
  56. package/dist/types/resources/jobs.d.ts +35 -44
  57. package/dist/types/resources/library/annotations.d.ts +162 -0
  58. package/dist/types/resources/library/books.d.ts +534 -0
  59. package/dist/types/resources/library/chat.d.ts +259 -0
  60. package/dist/types/resources/library/index.d.ts +39 -0
  61. package/dist/types/resources/library/shelves.d.ts +237 -0
  62. package/dist/types/resources/library/types.d.ts +120 -0
  63. package/dist/types/resources/library.d.ts +20 -22
  64. package/dist/types/resources/media.d.ts +48 -61
  65. package/dist/types/resources/movies/addons.d.ts +388 -0
  66. package/dist/types/resources/movies/collections.d.ts +352 -0
  67. package/dist/types/resources/movies/index.d.ts +29 -0
  68. package/dist/types/resources/movies/types.d.ts +50 -0
  69. package/dist/types/resources/movies/watchProgress.d.ts +277 -0
  70. package/dist/types/resources/movies.d.ts +27 -53
  71. package/dist/types/resources/music/artists.d.ts +182 -246
  72. package/dist/types/resources/music/imports.d.ts +190 -218
  73. package/dist/types/resources/music/index.d.ts +8 -7
  74. package/dist/types/resources/music/playlists.d.ts +85 -117
  75. package/dist/types/resources/music/social.d.ts +153 -228
  76. package/dist/types/resources/music/songs.d.ts +165 -227
  77. package/dist/types/resources/realtime.d.ts +75 -88
  78. package/dist/types/resources/shortLinks.d.ts +38 -47
  79. package/dist/types/resources/social/groupChats.d.ts +458 -0
  80. package/dist/types/resources/social/index.d.ts +19 -0
  81. package/dist/types/resources/social/messages.d.ts +424 -0
  82. package/dist/types/resources/social/relationships.d.ts +322 -0
  83. package/dist/types/resources/social/types.d.ts +37 -0
  84. package/dist/types/resources/social.d.ts +21 -3
  85. package/dist/types/resources/storage/upload.d.ts +42 -56
  86. package/dist/types/resources/storage.d.ts +94 -109
  87. package/dist/types/resources/tickets.d.ts +19 -10
  88. package/dist/types/resources/tools/backgroundRemoval.d.ts +11 -13
  89. package/dist/types/resources/tools/captions.d.ts +107 -135
  90. package/dist/types/resources/tools/upscale.d.ts +12 -16
  91. package/dist/types/types.d.ts +29 -38
  92. 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
- * Five endpoint families with one thing in common: not one of them is a CRUD
6
- * resource. Every one is a bespoke controller with a hand-written hash for a
7
- * body, so nothing here goes through Blueprinter, nothing here carries the
8
- * `id`/`created_at`/`updated_at` base fields as a matter of course, and none of
9
- * it accepts the list DSL (`search[...]`, `exact_search[...]`,
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
- * ## Only two of the five exist in the web frontend
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 ActionCable, on
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
- * `JamChannel` declares no client actions at all, which is why every mutation
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.** `JamChannel` authorizes on
48
- * membership, so a subscription opened before `POST /jams/:id/join` has
49
- * returned is answered with `reject_subscription`. A rejection later in the
50
- * session means the jam ended or you were dropped - clear local state, do
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
- * Not one of these paths has a `Rack::Attack` rule of its own, so all of them
61
- * sit under the general authenticated ceiling of **600 requests a minute**,
62
- * keyed by the literal `Authorization` header. The single extra ceiling is
63
- * application-level and lives in `MusicDjController`: forty generations per
64
- * user per hour shared between `/music_dj` and `/music_dj/batch`, counted in
65
- * the Rails cache. It is counted per REQUEST, before the work and before the
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
- * `Authentication#enforce_oauth_scope!` denies by default: a Doorkeeper token
72
- * reaches an action only when its controller declared an `oauth_scope` for it.
73
- * None of these five controllers declares one, so a CLI or MCP host holding an
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`** - `JamsController` uses `unauthorized!` for
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 (`jams` has a default `bigint` id), like
94
- * songs, playlists and artists - and unlike `host_id` and the member ids
95
- * sitting beside it in the very same payload, which are user ids and therefore
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
- /** Everything `Jam::QUEUE_MODES` accepts. Anything else is a `400`. */
79
+ /** Every accepted `queue_mode`. Anything else is a `400`. */
105
80
  export declare const JAM_QUEUE_MODES: readonly ["everyone", "host"];
106
- /** Everything `Jam::SKIP_MODES` accepts. Anything else is a `400`. */
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 cable's state payload carries
110
- * (`Jams::Serializer::UPCOMING_LIMIT`). Nothing in this file returns them - it
111
- * is here so a client sizing its "up next" list uses the server's number rather
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 (`MediaUrls::EXPIRY`, six hours).
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, as `Jams::Serializer.jam_hash` renders it.
111
+ * A jam.
138
112
  *
139
- * This is NOT a Blueprinter view. There is no `updated_at` here even though the
140
- * table has one, and `members` is a bespoke five-key hash rather than a user
141
- * view, so none of the base-record guarantees the rest of the API makes apply.
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 scopes to `Jam.active` (`ended_at IS NULL`), so an ended
160
- * jam answers `404` rather than a payload with a timestamp in this field. You
161
- * will only ever see a non-null value on a copy you were already holding, or
162
- * on one that arrived over the cable.
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
- * (`Listening::Snapshot.song_hash`): the seven fields somebody who does NOT own
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
- * `oms-music/src/domain/song.ts` types `SnapshotSong.id` as `string`, the web
209
- * frontend's `ListeningSong.id` is a `string`, and `docs/api-social-jams.md`
210
- * writes `id: string; // Song id (stringly numeric)` and repeats it in gotcha
211
- * 1 ("song ids are strings"). **All three are wrong about this payload.**
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. See the note above about three clients typing it wrong. */
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: `MediaUrls.for_attachment` swallows
238
- * a presign failure and returns nothing rather than raising.
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
- * (`Listening::Snapshot.for_user`), and the shape the friends feed pushes over
245
- * `listening:user:<id>` with a `type: "listening_update"` key merged in AT THE
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 the client contract asks you to render as nothing - a private profile is
322
- * deliberately indistinguishable from an empty one. A real `404` ("User not
323
- * found.") means the user does not exist; a `401` means you sent no credential,
324
- * because `music_profile` is not on the unauthenticated allowlist.
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 rather than the "everything optional" object both
333
- * existing clients use (`MusicProfile` in `oms-music/src/domain/social.ts` and
334
- * in the frontend's `SocialMusicService.ts`, both with `visible: boolean` and
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
- * ## `limit_bytes` IS NULLABLE, and it did not use to be
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
- * An ordinary account is unaffected: with no override row the limit is the
363
- * catalogue default of 100 GiB - the same number the old column defaulted to,
364
- * and `quotas_test.rb` pins the two together so they cannot drift apart.
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 object storage - so it can never
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 (`Responder::MAX_HISTORY`). */
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 (`AssistantChat::MAX_MESSAGES`). */
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 (`Responder::MAX_ACTIONS`). */
332
+ /** Player actions one answer may carry. */
395
333
  export declare const MUSIC_ASSISTANT_MAX_ACTIONS = 10;
396
334
  /**
397
- * Largest request body `MusicAssistantController` accepts, in bytes. Over it is
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
- * (`AssistantChat::READ_ONLY_AFTER`, two days).
340
+ * How long a chat may sit idle before it seals itself, in milliseconds (two
341
+ * days).
404
342
  *
405
- * It is COMPUTED, never persisted - no job runs, `read_only?` is a comparison
406
- * against the clock - so a summary you cached yesterday can report
407
- * `read_only: false` for a chat that is now sealed. The `POST` is where you
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 behind OpenRouter
415
- * routinely beats that while still being on its way to an answer. The app uses
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 (`MusicAssistantController#player_context`);
445
- * a key that is not one of these nine never reaches the prompt, silently. Every
446
- * field is optional here because the whitelist permits rather than requires.
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 have already been through
473
- * `viewable_by`, so a client queues them without a second request and without
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
- * controller only writes the keys it has - so test with `in` or a truthiness
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
- * Enforced in the controller with a cache counter rather than by
572
- * `Rack::Attack`, and the counter is incremented by EVERY request - including
573
- * the ones it then refuses with `429`. A retry loop therefore drives the count
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. A script from the
580
- * free LLM plus a couple of seconds of local text-to-speech takes well past the
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 (`BatchPlanner::BATCH_SIZE`). */
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 through `viewable_by`. Between 1 and
603
- * {@link MUSIC_DJ_BATCH_SIZE}: the planner raises rather than answer with an
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 cable and is not in this SDK -
625
- * see the module note, and {@link jamStreamName} for the stream to subscribe 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
- * cable, so polling this is the wrong shape.
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 `PlaybackChannel`) and plays
663
- * something. Do that immediately after this returns.
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}, which is what the web
705
- * UI's "End jam" button actually does. Both set `ended_at`, broadcast
706
- * `ended`, and re-broadcast every member's feed row so their jam badges drop.
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 written to the database here. The server records the song in a
749
- * 24-hour cache allowlist (so the host's playback state is allowed to
750
- * reference a song the host does not own), then broadcasts a `jam_add_song`
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 `user_id`, so a
760
- * song you can see but do not own does not exist for this route.
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 a set of user ids in a 15-minute cache entry keyed by jam AND by
775
- * the CURRENT song, so voting twice is idempotent and **a track change resets
776
- * the tally silently** - no message says so. Reset any local counter whenever
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 - the
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 a live `SUM` over the account's distinct blobs, so it 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. **Native app only.**
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: `AssistantChat` is not a CRUD
859
- * resource, so `modifiers[page]` and `search[...]` are not read (and, unlike
860
- * a real index, not rejected either - they are simply ignored). The list
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. **Native app only** among the shipped clients, but
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 controller runs the generation FIRST and only then creates the chat and
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` - OpenRouter refused or fell over. The reply is not partial, it is
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 Puma thread for its
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, kept alive for the app builds already in
942
- * people's hands, and it is the right one for a CLI or an MCP host that has
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. **Native app only** among the shipped clients.
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 is a cache counter the
968
- * controller increments on every request including the refused ones, so waiting
969
- * out a `Retry-After` and asking again pushes the count further past the cap
970
- * and cannot succeed inside the hour. Pass `retry: {}` to opt back in if you
971
- * are sure the `429` came from `Rack::Attack` instead.
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 through `viewable_by`, so a followed playlist's track
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 is a free-tier LLM call followed by local text-to-speech, so it
987
- * takes seconds; the deadline defaults to {@link MUSIC_DJ_TIMEOUT_MS}. The
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 cable. */
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. Native app only. */
967
+ /** Music bytes stored against the account's ceiling. */
1040
968
  readonly storage: MusicStorageNamespace;
1041
- /** The chat assistant, with its stored sessions. Native app only. */
969
+ /** The chat assistant, with its stored sessions. */
1042
970
  readonly assistant: MusicAssistantNamespace;
1043
- /** Scripted and spoken links between tracks. Native app only. */
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 ActionCable stream a jam broadcasts on (`Jam.stream_for`).
976
+ * The realtime stream a jam broadcasts on.
1049
977
  *
1050
- * This SDK does not open it - it has no cable client - but the name is part of
1051
- * the contract and hard-coding `` `jam:${id}` `` in three clients is how it
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: `JamChannel` has no client actions.
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, in the order both
1084
- * shipped clients use: the owner's upload, then the large Deezer sizes, then
1085
- * the small ones, then Last.fm. `undefined` when there is nothing, which is
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 under
1104
- * an advisory lock at attach time, and failing there means the bytes have
1105
- * already crossed the network.
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 all three clients and
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, `expo-audio` included.
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 does
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;