@omelhorsite/sdk 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/index.js +4939 -552
  2. package/dist/types/client.d.ts +60 -3
  3. package/dist/types/http.d.ts +444 -19
  4. package/dist/types/index.d.ts +4 -1
  5. package/dist/types/resources/account.d.ts +66 -3
  6. package/dist/types/resources/admin.d.ts +1837 -0
  7. package/dist/types/resources/auth/index.d.ts +39 -0
  8. package/dist/types/resources/auth/passkeys.d.ts +652 -0
  9. package/dist/types/resources/auth/sessions.d.ts +847 -0
  10. package/dist/types/resources/chests.d.ts +54 -3
  11. package/dist/types/resources/content.d.ts +2970 -0
  12. package/dist/types/resources/dynamicQrs.d.ts +39 -3
  13. package/dist/types/resources/forms.d.ts +176 -35
  14. package/dist/types/resources/index.d.ts +19 -8
  15. package/dist/types/resources/ipLookup.d.ts +20 -4
  16. package/dist/types/resources/jobs.d.ts +62 -21
  17. package/dist/types/resources/library.d.ts +1435 -0
  18. package/dist/types/resources/linkTrees.d.ts +142 -30
  19. package/dist/types/resources/media.d.ts +351 -0
  20. package/dist/types/resources/movies.d.ts +1186 -0
  21. package/dist/types/resources/music/artists.d.ts +1066 -0
  22. package/dist/types/resources/music/imports.d.ts +940 -0
  23. package/dist/types/resources/music/index.d.ts +61 -0
  24. package/dist/types/resources/music/playlists.d.ts +1026 -0
  25. package/dist/types/resources/music/social.d.ts +1132 -0
  26. package/dist/types/resources/music/songs.d.ts +1183 -0
  27. package/dist/types/resources/notepads.d.ts +4 -1
  28. package/dist/types/resources/quotas.d.ts +7 -1
  29. package/dist/types/resources/realtime.d.ts +855 -0
  30. package/dist/types/resources/shortLinks.d.ts +45 -4
  31. package/dist/types/resources/social.d.ts +1330 -0
  32. package/dist/types/resources/storage/upload.d.ts +158 -11
  33. package/dist/types/resources/storage.d.ts +88 -22
  34. package/dist/types/resources/tickets.d.ts +82 -3
  35. package/dist/types/resources/tools/backgroundRemoval.d.ts +18 -3
  36. package/dist/types/resources/tools/captions.d.ts +448 -21
  37. package/dist/types/resources/tools/downloader.d.ts +21 -0
  38. package/dist/types/resources/tools/index.d.ts +57 -15
  39. package/dist/types/resources/tools/jumpstyle.d.ts +50 -17
  40. package/dist/types/resources/tools/transcription.d.ts +35 -13
  41. package/dist/types/resources/tools/upscale.d.ts +23 -3
  42. package/dist/types/resources/tools/vocalSeparation.d.ts +30 -13
  43. package/dist/types/types.d.ts +249 -17
  44. package/package.json +2 -1
@@ -0,0 +1,1837 @@
1
+ /**
2
+ * The `admin` namespace: OAuth client management and the operator surface.
3
+ *
4
+ * ## Three publics live in this one file. Do not confuse them.
5
+ *
6
+ * The routes below arrive as one list from the router and read as one feature,
7
+ * but they answer to three completely different callers. Every sub-namespace
8
+ * here is named so that the caller is legible from the call site alone:
9
+ *
10
+ * | reachable as | who may call it | what it is |
11
+ * | ---------------------------------- | -------------------------- | ---------- |
12
+ * | `oms.admin.myApplications` | any authenticated user | the OAuth clients **you registered**, and the only place a `client_secret` is ever handed out |
13
+ * | `oms.admin.authorizedApplications` | any authenticated user | the applications **you gave access to your account**, and the button that takes it back |
14
+ * | `oms.admin.identities` | any authenticated user | the Google/GitHub/Spotify logins **linked to your account** |
15
+ * | `oms.admin.oauthApplications` | **administrators only** | the review queue and the registry of every client on the server |
16
+ * | `oms.admin.quotas` | **administrators only** | another person's ceilings |
17
+ * | `oms.admin.jobs` | **administrators only** | every background job on the server |
18
+ * | `oms.admin.shortLinks` | **administrators only** | every public short link, and its traffic |
19
+ * | `oms.admin.vocalSeparations` | **administrators only** | every separation run on the server |
20
+ * | `oms.admin.chests` | **administrators only** | aggregate chest statistics |
21
+ * | `oms.admin.notepads` | **administrators only** | aggregate notepad statistics |
22
+ * | `oms.admin.eventAlerts` | **administrators only** | the Discord alert catalogue |
23
+ *
24
+ * The rule to remember: **a sub-namespace whose class name starts with `Admin`
25
+ * is administrator-only**, and everything under it answers `403` to everybody
26
+ * else. The three that are not administrator-only are
27
+ * {@link MyOauthApplicationsNamespace},
28
+ * {@link AuthorizedApplicationsNamespace} and
29
+ * {@link LinkedIdentitiesNamespace}, and they are here because they are the
30
+ * other two thirds of the same OAuth story, not because they need privilege.
31
+ *
32
+ * The naming collision they are here to prevent is real and expensive:
33
+ * `myApplications.destroy(id)` deletes a client **you own**, while
34
+ * `oauthApplications.destroy(id)` deletes **anybody's** client on the whole
35
+ * server, and both take the same integer. One is a tidy-up, the other is an
36
+ * outage for whoever was using it.
37
+ *
38
+ * ## Registration is open; being usable is not
39
+ *
40
+ * This is a product decision of this project and it is not the OAuth default,
41
+ * so it is worth stating plainly before you build anything on top:
42
+ *
43
+ * > **Any authenticated user may register an OAuth client, and nothing they
44
+ * > register works until an administrator approves it.**
45
+ *
46
+ * A freshly registered client is `approval_status: "pending"`. It has a real
47
+ * `client_id`, it shows up in {@link MyOauthApplicationsNamespace.list}, and it
48
+ * **cannot mint a single token**: every grant type funnels through
49
+ * `OauthApplication.by_uid`, which refuses anything that is not `approved`, so
50
+ * a device-flow start against a pending client answers `invalid_client`. There
51
+ * is no partial state, no "works for your own account", no grace period.
52
+ *
53
+ * The reason is anti-phishing. The consent screen renders the client's name
54
+ * right next to the signed-in identity, so an unreviewed client called
55
+ * "omelhorsite Oficial" is a phishing page wearing the owner's brand. That is
56
+ * also why the gate does not stop at registration:
57
+ *
58
+ * - **editing an approved client can un-approve it.** Renaming it, WIDENING its
59
+ * scopes, or moving its `redirect_uri` sends it straight back to `pending`
60
+ * and it stops resolving on the very next request. Narrowing scopes does not.
61
+ * See {@link MyOauthApplicationsNamespace.update}, which is where the whole
62
+ * rule is written down, and {@link editWouldRequeue}, which predicts it
63
+ * before you spend the call.
64
+ * - **approving is receipted.** An administrator who rendered a client and then
65
+ * approves a row that changed underneath gets `409 review_stale` instead of a
66
+ * rubber stamp. See {@link AdminOauthApplicationsNamespace.approve}.
67
+ *
68
+ * ## `403` on the administrator half, and what it looks like
69
+ *
70
+ * Every `/admin/*` route sits behind one `before_action` that answers
71
+ * `403 Forbidden` with the bare JSON string `"Admin access required"` when
72
+ * `Current.user.admin?` is not true. It is not hidden behind a `404` and it is
73
+ * not silently empty, so the SDK does not hide it either: it arrives as an
74
+ * {@link OmsAuthError} with `status === 403`, `code === "forbidden"`,
75
+ * `authenticationRequired === false` and `message === "Admin access required"`.
76
+ *
77
+ * `authenticationRequired` is the field worth branching on. It is `false` here,
78
+ * which means the credential is perfectly good and the ACT is not allowed -
79
+ * re-authenticating changes nothing, and a client that reflexively runs its
80
+ * login flow on any 4xx will loop forever on this one. Check for admin rights
81
+ * once, up front, and degrade the UI; do not discover them per request.
82
+ *
83
+ * There is no endpoint that answers "am I an admin". `GET /account` carries the
84
+ * user's `group`, which is what the web frontend reads.
85
+ *
86
+ * ## Rate limits
87
+ *
88
+ * No `/admin/*` route has a rule of its own: they are all covered by the
89
+ * general authenticated ceiling of **600 requests per minute**. The one
90
+ * genuinely tight budget in this file is on the owner half -
91
+ * {@link MyOauthApplicationsNamespace.create} is capped at **10 per hour and 20
92
+ * per day per owner** - and it is documented on the method.
93
+ */
94
+ import type { Job } from "./jobs";
95
+ import type { QuotaPeriod, QuotaResource, QuotaUnit } from "./quotas";
96
+ import type { VocalSeparation } from "./tools/vocalSeparation";
97
+ import { Resource } from "../http";
98
+ import type { OmsScope } from "../auth/tokens";
99
+ import { type Id, type PageParams, type Paginated, type RequestOptions, type Timestamp } from "../types";
100
+ /**
101
+ * Where a client sits in the review queue.
102
+ *
103
+ * There is no fourth state and in particular there is no "suspended": pulling
104
+ * an approved client back off the air is `"rejected"`, which is why
105
+ * {@link AdminOauthApplicationsNamespace.reject} accepts a client that was
106
+ * already approved.
107
+ *
108
+ * A database check constraint pins the column to exactly these three, so this
109
+ * union is closed rather than widened to `string`.
110
+ */
111
+ export type OauthApprovalStatus = "pending" | "approved" | "rejected";
112
+ /** Every value {@link OauthApprovalStatus} can take, for building filters. */
113
+ export declare const OAUTH_APPROVAL_STATUSES: readonly OauthApprovalStatus[];
114
+ /**
115
+ * A person attached to a client: its owner, or the administrator who decided.
116
+ *
117
+ * Three keys and no more. This is not the full user record - the controllers
118
+ * build it by hand precisely so that reviewing a client does not leak an email
119
+ * address or a session count into an admin panel.
120
+ */
121
+ export interface OauthApplicationParty {
122
+ /** User id. A string, like every user id in this API. */
123
+ readonly id: Id;
124
+ readonly handle: string;
125
+ /** Display name. `null` for an account that never set one. */
126
+ readonly name: string | null;
127
+ }
128
+ /**
129
+ * The shape both halves render for a registered OAuth client.
130
+ *
131
+ * `OauthApplicationsController#summary` and
132
+ * `Admin::OauthApplicationsController#summary` are two methods that emit the
133
+ * same eleven keys on purpose, so one renderer works on both surfaces. The
134
+ * differences are in the VALUES, not the keys, and there are exactly two:
135
+ *
136
+ * - `approved_by` is hardcoded `null` on the owner routes. Which administrator
137
+ * decided what is deliberately withheld from the applicant, so read it as
138
+ * "not disclosed", not as "nobody approved it";
139
+ * - the owner routes only ever show you your own rows, so `owner` there is
140
+ * always you.
141
+ */
142
+ export interface OauthApplicationSummary {
143
+ /**
144
+ * Primary key, and an **integer**. `oauth_applications` is a Doorkeeper
145
+ * table and kept the bigint primary key the gem ships with, so this is one of
146
+ * the handful of ids in this API that is not a string. Do not compare it
147
+ * against an {@link Id}.
148
+ */
149
+ readonly id: number;
150
+ /** The public `client_id`, i.e. the `uid` column. Not a secret. */
151
+ readonly client_id: string;
152
+ /** What the consent screen renders. At most 60 characters. */
153
+ readonly name: string;
154
+ /**
155
+ * Already split. Doorkeeper stores one space-separated string; both
156
+ * controllers call `.to_a` before rendering, so what arrives here is an
157
+ * array and never needs splitting.
158
+ *
159
+ * An EMPTY array would be dangerous rather than harmless - in Doorkeeper a
160
+ * blank scopes column means "every scope the server has", not "none" - which
161
+ * is why both write paths refuse to save one.
162
+ */
163
+ readonly scopes: string[];
164
+ /**
165
+ * `true` for a client that holds a secret. Frozen after registration: see
166
+ * {@link MyOauthApplicationsNamespace.update} for why neither direction is
167
+ * editable.
168
+ */
169
+ readonly confidential: boolean;
170
+ /**
171
+ * Every registered redirect URI, in ONE space-separated string, exactly as
172
+ * Doorkeeper stores it. Use {@link splitRedirectUris} rather than reading it
173
+ * raw.
174
+ *
175
+ * Matching at the authorization endpoint is exact - no wildcards, no prefix
176
+ * match, no fragment - so a URI that looks nearly right matches nothing.
177
+ */
178
+ readonly redirect_uri: string;
179
+ readonly approval_status: OauthApprovalStatus;
180
+ /** When it was approved, `null` while pending or rejected. */
181
+ readonly approved_at: Timestamp | null;
182
+ /** The reason shown to the owner. `null` unless rejected. At most 500 characters. */
183
+ readonly rejection_reason: string | null;
184
+ /**
185
+ * Who registered it. `null` for the clients this project ships itself
186
+ * (`owner_id` is deliberately NULL for those) **and** for a client whose
187
+ * owner deleted their account.
188
+ *
189
+ * Because those two cases are indistinguishable here, `owner === null` is
190
+ * NOT a trust signal. See {@link isShippedClient}.
191
+ */
192
+ readonly owner: OauthApplicationParty | null;
193
+ /**
194
+ * The administrator who approved it, or `null`.
195
+ *
196
+ * Always `null` on {@link MyOauthApplicationsNamespace} regardless of the
197
+ * truth. Populated on {@link AdminOauthApplicationsNamespace}.
198
+ */
199
+ readonly approved_by: OauthApplicationParty | null;
200
+ readonly created_at: Timestamp;
201
+ }
202
+ /**
203
+ * A client YOU registered, as {@link MyOauthApplicationsNamespace} renders it.
204
+ *
205
+ * A distinct name from {@link AdminOauthApplication} even though the keys are
206
+ * identical, so that a function taking one cannot be handed the other by
207
+ * accident. They come from different endpoints with different blast radii.
208
+ */
209
+ export interface OwnedOauthApplication extends OauthApplicationSummary {
210
+ /** Always `null` here. The owner routes never disclose the reviewer. */
211
+ readonly approved_by: null;
212
+ }
213
+ /**
214
+ * The response of the two calls that MINT a client secret:
215
+ * {@link MyOauthApplicationsNamespace.create} and
216
+ * {@link MyOauthApplicationsNamespace.rotateSecret}.
217
+ *
218
+ * `client_secret` is the only value in this whole API you cannot ask for twice.
219
+ * The server hashes secrets (`hash_application_secrets` is on), so the column
220
+ * holds a SHA256 and there is nothing to read back: losing the string means
221
+ * rotating, and rotating breaks whatever was using the old one. Capture it in
222
+ * the same expression that made the call.
223
+ */
224
+ export interface OwnedOauthApplicationWithSecret {
225
+ readonly application: OwnedOauthApplication;
226
+ /**
227
+ * The plaintext secret, ONCE. `null` for a public client, which is most of
228
+ * them: a public client has no secret by design, and `confidential: false`
229
+ * is the normal choice for anything that ships to end users.
230
+ */
231
+ readonly client_secret: string | null;
232
+ }
233
+ /**
234
+ * What {@link MyOauthApplicationsNamespace.destroy} answers with.
235
+ *
236
+ * Note the key: **`client_id`**. The administrator's delete answers the same
237
+ * three values under the key `uid` instead
238
+ * ({@link AdminOauthApplicationDeletion}). Two controllers, two spellings of
239
+ * one column, and nothing normalises them - a shared renderer reading
240
+ * `client_id` shows `undefined` for half the app.
241
+ */
242
+ export interface OwnedOauthApplicationDeletion {
243
+ readonly id: number;
244
+ readonly client_id: string;
245
+ /** Access tokens that were alive and are not any more. `0` is normal. */
246
+ readonly revoked_tokens: number;
247
+ }
248
+ /** Arguments for {@link MyOauthApplicationsNamespace.create}. */
249
+ export interface CreateOauthApplicationInput {
250
+ /**
251
+ * At most 60 characters AFTER normalisation, and normalisation is not a
252
+ * `trim`: the server strips zero-width and bidi characters first, so 60
253
+ * characters of padding is not a 60 character name and a name made only of
254
+ * bidi overrides is refused as blank (`name_required`).
255
+ */
256
+ readonly name: string;
257
+ /**
258
+ * At least one scope the server knows. An unknown scope is **dropped, not
259
+ * refused**, so a typo quietly narrows the client instead of registering
260
+ * something nobody asked for - but if EVERY scope you sent was unknown the
261
+ * result is `400 unknown_scope`.
262
+ *
263
+ * A string is accepted too and is split on whitespace or commas, but pass the
264
+ * array: it is the shape that cannot be misread.
265
+ */
266
+ readonly scopes: readonly (OmsScope | string)[] | string;
267
+ /**
268
+ * `true` to mint a client secret. Defaults to `false`.
269
+ *
270
+ * **This is the only chance you get.** The flag is frozen after registration
271
+ * (see {@link MyOauthApplicationsNamespace.update}), so a client that changes
272
+ * its mind has to be registered again from scratch. Choose `false` for
273
+ * anything that ships to end users - a secret inside a distributed binary is
274
+ * not a secret - and `true` only for something running on a server you
275
+ * control.
276
+ */
277
+ readonly confidential?: boolean;
278
+ /**
279
+ * Every redirect URI, space separated, or omitted.
280
+ *
281
+ * **Omitting it is the right answer for a CLI or a native app**: blank
282
+ * registers the RFC 8252 loopback pair
283
+ * ({@link NATIVE_LOOPBACK_REDIRECT_VALUE}), which is the only shape whose
284
+ * authorization code cannot land anywhere but the requester's own machine.
285
+ *
286
+ * It is otherwise the most dangerous field on the form. Matching is exact,
287
+ * and a redirect URI pointing at something an attacker controls IS account
288
+ * takeover - PKCE does not help, it binds the code to the client that started
289
+ * the flow, not to where the code is delivered. The server refuses anything
290
+ * that is not `https`, not loopback `http`, carries userinfo, carries a
291
+ * wildcard host or has no host at all, and it does so with a `422`
292
+ * (`validation_failed`) rather than by quietly rewriting your value.
293
+ */
294
+ readonly redirect_uri?: string;
295
+ }
296
+ /**
297
+ * Arguments for {@link MyOauthApplicationsNamespace.update}.
298
+ *
299
+ * **An absent key means "leave it alone"; a present key means "write this".**
300
+ * The controller branches on `params.key?`, so sending a field at all is asking
301
+ * for it to be written, and writing the same value it already had still counts
302
+ * as a write for the purposes of the requeue rule below.
303
+ *
304
+ * Never send `null`. The transport encodes `null` in a query as the backend's
305
+ * null sentinel, and in a JSON body it reaches the column as a blanking of a
306
+ * `NOT NULL` field: a `422`, at best.
307
+ */
308
+ export interface UpdateOauthApplicationInput {
309
+ readonly name?: string;
310
+ readonly scopes?: readonly (OmsScope | string)[] | string;
311
+ readonly redirect_uri?: string;
312
+ }
313
+ /** `OauthApplicationsController::NAME_MAX_LENGTH`, measured after normalisation. */
314
+ export declare const OAUTH_APP_NAME_MAX_LENGTH = 60;
315
+ /**
316
+ * `OauthApplication::MAX_PENDING_PER_OWNER`.
317
+ *
318
+ * How many of ONE person's clients may sit in the review queue at once. The
319
+ * sixth answers `429 too_many_pending`, and so does an edit that would send a
320
+ * sixth approved client back into the queue. Deleting a pending client frees
321
+ * its slot immediately.
322
+ */
323
+ export declare const OAUTH_APP_MAX_PENDING = 5;
324
+ /** `Oauth::RedirectUri::MAX_URIS`. More than this is `400 redirect_uri_excessive`. */
325
+ export declare const OAUTH_REDIRECT_URI_MAX_COUNT = 8;
326
+ /** `Oauth::RedirectUri::MAX_LENGTH`, counted across the whole space-separated string. */
327
+ export declare const OAUTH_REDIRECT_URI_MAX_LENGTH = 1024;
328
+ /**
329
+ * `Oauth::RedirectUri::NATIVE_LOOPBACK` - what a blank `redirect_uri` registers.
330
+ *
331
+ * RFC 8252 section 7.3. No port, because the client listens on an ephemeral one
332
+ * and Doorkeeper's `URIChecker` drops the port from both sides before
333
+ * comparing, so `http://127.0.0.1:49731/callback` matches the first entry.
334
+ *
335
+ * Both literals, because `127.0.0.1` and `[::1]` are two different hosts to
336
+ * that comparison and an IPv6-only machine can only bind the second.
337
+ * `localhost` is deliberately absent and registering it is a mistake: `IPAddr`
338
+ * cannot parse a name, so the gem does not treat it as loopback and would then
339
+ * demand an exact port match, which is the one thing an ephemeral port cannot
340
+ * promise.
341
+ */
342
+ export declare const NATIVE_LOOPBACK_REDIRECT_URIS: readonly string[];
343
+ /** {@link NATIVE_LOOPBACK_REDIRECT_URIS} as the single column value the server stores. */
344
+ export declare const NATIVE_LOOPBACK_REDIRECT_VALUE = "http://127.0.0.1/callback http://[::1]/callback";
345
+ /**
346
+ * The `client_id`s this project ships itself, pinned in
347
+ * `Oauth::FirstPartyClients` (`CLI_CLIENT_ID`, `MCP_CLIENT_ID`).
348
+ *
349
+ * Pinned constants rather than values generated per environment, so matching on
350
+ * them is stable across dev, CI and production.
351
+ */
352
+ export declare const SHIPPED_CLIENT_IDS: readonly string[];
353
+ /**
354
+ * True for a client this project ships, by `client_id`.
355
+ *
356
+ * **Use this, not `owner === null`.** A NULL owner means two very different
357
+ * things - "registered by the operator" and "orphaned when its owner deleted
358
+ * their account" - and calling an orphan official is exactly the lie the whole
359
+ * review gate exists to prevent. The backend draws the same distinction
360
+ * (`shipped_by_the_house?` vs `first_party?`) and the consent screen uses the
361
+ * pinned list too.
362
+ */
363
+ export declare function isShippedClient(application: {
364
+ readonly client_id: string;
365
+ }): boolean;
366
+ /**
367
+ * Splits the one space-separated `redirect_uri` column into the URIs it holds.
368
+ *
369
+ * Doorkeeper keeps every registered redirect URI in a single column. Splitting
370
+ * on whitespace is exactly what `Oauth::RedirectUri.normalize` does on the way
371
+ * in, so what comes back out is what was registered, character for character.
372
+ */
373
+ export declare function splitRedirectUris(value: string | null | undefined): string[];
374
+ /**
375
+ * Normalises a redirect URI list the way the server will store it.
376
+ *
377
+ * Split, trim, de-duplicate, join with single spaces. **Nothing else.** No
378
+ * trailing slash is added or removed, no scheme is upgraded, no case is folded:
379
+ * redirect matching is exact, so quietly "fixing" a URI would register
380
+ * something the client can never match and the failure would only appear at the
381
+ * end of a login attempt.
382
+ *
383
+ * A blank result means the server will register
384
+ * {@link NATIVE_LOOPBACK_REDIRECT_VALUE}, which is what
385
+ * {@link registeredRedirectUris} makes explicit.
386
+ */
387
+ export declare function normalizeRedirectUris(raw: string | null | undefined): string;
388
+ /**
389
+ * What the server will actually store for this input, blank included.
390
+ *
391
+ * Use it to compare a form against a record: an empty field and a field holding
392
+ * the loopback pair register the same value, so comparing the raw strings would
393
+ * report a change that is not one.
394
+ */
395
+ export declare function registeredRedirectUris(raw: string | null | undefined): string;
396
+ /**
397
+ * Predicts whether an edit will send an APPROVED client back to the review
398
+ * queue, before the call is made.
399
+ *
400
+ * Losing an approval without being told is the difference between "I did that"
401
+ * and "this is broken": the client keeps its `client_id`, keeps working for
402
+ * about as long as its live tokens last, and then starts answering
403
+ * `invalid_client` with nothing in the request to explain it. Warn first.
404
+ *
405
+ * The rule reproduced here is spread across two places in the backend - a
406
+ * `before_save` on the model covers the name and the scopes, and
407
+ * `OauthApplicationsController#update` covers the redirect URI - and it is:
408
+ *
409
+ * - a client that is not `approved` cannot be sent back to a queue it is
410
+ * already in, so this is always `false` for `pending` and `rejected`;
411
+ * - **any** change of name requeues. The name is what the consent screen shows;
412
+ * - **widening** scopes requeues. Narrowing does not: asking for less than what
413
+ * was already reviewed has nothing left to review;
414
+ * - **any** move of the redirect URI requeues, in either direction. There is no
415
+ * "narrower" destination - a different destination is a different
416
+ * destination, and it is where the authorization code gets delivered.
417
+ *
418
+ * This is a prediction, not the enforcement. The server decides, and the
419
+ * `approval_status` on the response is the answer.
420
+ */
421
+ export declare function editWouldRequeue(application: OauthApplicationSummary, next: {
422
+ readonly name: string;
423
+ readonly scopes: readonly string[];
424
+ readonly redirectUris: string;
425
+ }): boolean;
426
+ /**
427
+ * `oms.admin.myApplications` - the OAuth clients **you registered**.
428
+ *
429
+ * Needs an ordinary authenticated session and nothing more. Every action starts
430
+ * from a relation already narrowed to the caller, so another person's id and an
431
+ * id that was never issued produce the identical `404` and there is no way to
432
+ * probe whether a client exists.
433
+ *
434
+ * **This is not `/oauth/*`.** Doorkeeper's own client CRUD is not mounted at
435
+ * all (`/oauth/applications` is a hard 404); `/oauth_applications` is this
436
+ * application's own JSON API and is authenticated the same way every other
437
+ * endpoint here is. Authentication is by SESSION, deliberately: you do not
438
+ * manage the keys to the house with a key to the house, and an OAuth token
439
+ * cannot reach these routes.
440
+ *
441
+ * Remember the product rule: what you register here does not work until an
442
+ * administrator approves it. See the namespace documentation.
443
+ *
444
+ * Every error on this surface carries a STRUCTURED body -
445
+ * `{ "error": "<code>", "message": "<PT-PT sentence>" }`, plus an `errors`
446
+ * array of model messages on a `422`. That is unusual in this API, where an
447
+ * error is normally a bare JSON string, and it is worth using: read
448
+ * `OmsApiError.body.error` for the code and branch on that. The `message` is
449
+ * written in one language.
450
+ */
451
+ export declare class MyOauthApplicationsNamespace extends Resource {
452
+ /**
453
+ * `GET /oauth_applications` - every client you registered, newest first.
454
+ *
455
+ * Whatever their approval state, on purpose: a pending client has to stay
456
+ * visible to the person waiting on it. There is no pagination, no state
457
+ * filter and no ETag on this route - one person's list has units in it, not
458
+ * pages, and {@link OAUTH_APP_MAX_PENDING} plus the registration throttle
459
+ * keep it that way.
460
+ *
461
+ * The response is enveloped (`{ applications: [...] }`); this method unwraps
462
+ * it. An empty list is `[]`, never `null`.
463
+ *
464
+ * A `client_secret` never appears here. There is exactly one serializer
465
+ * behind this route and it has no branch that could emit one.
466
+ */
467
+ list(options?: RequestOptions): Promise<OwnedOauthApplication[]>;
468
+ /**
469
+ * `GET /oauth_applications/:id` - one of your clients.
470
+ *
471
+ * @throws {OmsApiError} 404 `not_found` for an id that is not yours, which is
472
+ * byte for byte the answer for an id that never existed. The primary key is
473
+ * a walkable integer sequence, so the absence of a `403` here is the point:
474
+ * there is no existence oracle to walk.
475
+ */
476
+ get(id: number | string, options?: RequestOptions): Promise<OwnedOauthApplication>;
477
+ /**
478
+ * `POST /oauth_applications` - registers a client. Answers `201`.
479
+ *
480
+ * The client lands as `pending` and **cannot mint a single token until an
481
+ * administrator approves it**. It does get a real `client_id` immediately,
482
+ * and it appears in {@link list} straight away, so "I have a client_id" is
483
+ * not the same as "I have a working client". Registering also rings a Discord
484
+ * alert on the review queue, because a review gate nobody is told about is a
485
+ * feature that quietly does not work.
486
+ *
487
+ * **The response is the only place `client_secret` will ever exist.** Capture
488
+ * it now; see {@link OwnedOauthApplicationWithSecret}. It is `null` for a
489
+ * public client.
490
+ *
491
+ * **Two different `429`s guard this endpoint and they need opposite
492
+ * reactions:**
493
+ *
494
+ * - rack-attack allows **10 registrations per hour and 20 per day, keyed by
495
+ * the OWNER** (not the session, so logging in again does not buy a fresh
496
+ * budget). It answers `{"error":"rate_limited","retry_after":N}` WITH a
497
+ * `Retry-After` header, so the {@link OmsQuotaError} carries
498
+ * `retryAfterMs`. Waiting fixes it.
499
+ * - the controller refuses a sixth PENDING client with
500
+ * `{"error":"too_many_pending", ...}` and **no** `Retry-After`, so
501
+ * `retryAfterMs` is `undefined`. Waiting does NOT fix that one: a human has
502
+ * to decide on one of the five, or you have to delete one. Read
503
+ * `OmsApiError.body.error` to tell them apart, not the status.
504
+ *
505
+ * Retries are disabled. Both reasons matter: a replay after a lost response
506
+ * mints a SECOND client with a different `client_id`, leaving an orphan in a
507
+ * queue a person has to work through; and the transport retries `429` for
508
+ * every method, which on the `too_many_pending` branch would burn three of
509
+ * the ten hourly registrations on an answer that cannot change.
510
+ *
511
+ * @throws {OmsQuotaError} 429, from either producer above.
512
+ * @throws {OmsApiError} 400 `name_required`, `name_too_long`,
513
+ * `scopes_required`, `unknown_scope` or `redirect_uri_excessive`; 422
514
+ * `validation_failed` with an `errors` array when the redirect URI is a
515
+ * shape this server will not register.
516
+ */
517
+ create(input: CreateOauthApplicationInput, options?: RequestOptions): Promise<OwnedOauthApplicationWithSecret>;
518
+ /**
519
+ * `PATCH /oauth_applications/:id` - edits name, scopes or redirect URIs.
520
+ *
521
+ * **Read {@link editWouldRequeue} before calling this on an approved
522
+ * client.** Renaming it, widening its scopes or moving its redirect URI
523
+ * returns it to `pending`, clears the approval stamps, and stops it resolving
524
+ * on the very next request. That is the anti-phishing rule working, not a
525
+ * bug: without it you could get "A Minha Appzinha" approved and rename it to
526
+ * "omelhorsite Oficial" a minute later, or get a loopback client approved and
527
+ * repoint it at your own server, which since `authorization_code` is enabled
528
+ * means the authorization code itself is delivered to you. The
529
+ * `approval_status` on the response is the authoritative answer.
530
+ *
531
+ * **What is NOT editable, and why the omissions are deliberate:**
532
+ *
533
+ * - `confidential`. Flipping it `true -> false` downgrades authentication for
534
+ * an already-approved client: Doorkeeper authenticates a public client on
535
+ * its `client_id` alone, and a `client_id` is not a secret - it travels in
536
+ * the clear in every device authorization request. The reverse direction is
537
+ * merely broken: secrets are minted on create only, so `false -> true`
538
+ * would 422 on a missing secret. One direction is a security downgrade and
539
+ * the other is a dead end, so the field is frozen; a client that changes its
540
+ * mind registers a new one.
541
+ * - `client_id`. It is the identity the approval was granted to. Editable, it
542
+ * would move an approval onto a different client.
543
+ * - anything approval-shaped. The owner never writes their own verdict.
544
+ *
545
+ * An edit that requeues an approved client SPENDS a slot against
546
+ * {@link OAUTH_APP_MAX_PENDING} and can therefore answer `429
547
+ * too_many_pending`. Editing a client that is already pending, or narrowing
548
+ * an approved client's scopes, costs nothing and keeps working with a full
549
+ * queue - otherwise the ceiling would trap you into being unable to fix the
550
+ * very clients that are waiting.
551
+ *
552
+ * @throws {OmsApiError} 409 `first_party_immutable` for `oms-cli` or
553
+ * `oms-mcp`; 404 `not_found`; 400 for the name and scope codes; 422
554
+ * `validation_failed` for a refused redirect URI.
555
+ * @throws {OmsQuotaError} 429 `too_many_pending`, with no `Retry-After`.
556
+ */
557
+ update(id: number | string, input: UpdateOauthApplicationInput, options?: RequestOptions): Promise<OwnedOauthApplication>;
558
+ /**
559
+ * `DELETE /oauth_applications/:id` - deletes one of your clients.
560
+ *
561
+ * Answers **`200` with a body**, not the `204` most destroys in this API
562
+ * answer, because the count of tokens it just killed is worth reporting. Live
563
+ * tokens, access grants and pending device grants are revoked first and the
564
+ * row goes afterwards.
565
+ *
566
+ * Deleting a pending client frees its queue slot immediately, which is the
567
+ * cure for `too_many_pending`.
568
+ *
569
+ * The body's key is **`client_id`**. The administrator's delete spells the
570
+ * same value `uid`. See {@link OwnedOauthApplicationDeletion}.
571
+ *
572
+ * @throws {OmsApiError} 409 `first_party_immutable` for a shipped client; 404
573
+ * `not_found` otherwise.
574
+ */
575
+ destroy(id: number | string, options?: RequestOptions): Promise<OwnedOauthApplicationDeletion>;
576
+ /**
577
+ * `POST /oauth_applications/:id/rotate_secret` - mints a new client secret.
578
+ *
579
+ * `POST` rather than `PATCH` because it MINTS a value: the response is the
580
+ * only place the new secret ever appears, and the old one stops working the
581
+ * instant this returns.
582
+ *
583
+ * Confidential clients only. It does NOT touch approval (nothing an
584
+ * administrator reviewed has changed, so the anti-phishing callback correctly
585
+ * does not fire) and it does NOT touch live tokens - killing those is a
586
+ * louder, separate decision and it belongs to an administrator
587
+ * ({@link AdminOauthApplicationsNamespace.revokeTokens}).
588
+ *
589
+ * @throws {OmsApiError} 400 `not_confidential` for a public client, which has
590
+ * no secret to rotate; 409 `first_party_immutable` for a shipped client;
591
+ * 404 `not_found`.
592
+ */
593
+ rotateSecret(id: number | string, options?: RequestOptions): Promise<OwnedOauthApplicationWithSecret>;
594
+ }
595
+ /**
596
+ * An application holding a live token for YOUR account.
597
+ *
598
+ * This is OAuth going OUT (a third party acting in your account), which is the
599
+ * opposite direction from {@link LinkedIdentity} - logging IN with Google or
600
+ * Spotify. Two things with similar names that live in the same settings tab.
601
+ */
602
+ export interface AuthorizedApplication {
603
+ /**
604
+ * The **application** id, not a token id, and an integer like every
605
+ * `oauth_applications` primary key. Revocation is per client on purpose: a
606
+ * person thinks "stop the CLI", not "kill token 4712".
607
+ */
608
+ readonly id: number;
609
+ readonly client_id: string;
610
+ readonly name: string;
611
+ /**
612
+ * The scopes of **your tokens**, not of the client's registration.
613
+ *
614
+ * The question this list answers is "what can that application do in MY
615
+ * account", and a client registered for eight scopes may hold a token for
616
+ * two. The union across your tokens, ordered by the server's own scope list
617
+ * so the same set always renders in the same order whatever order the client
618
+ * asked in.
619
+ */
620
+ readonly scopes: string[];
621
+ /**
622
+ * The client's CURRENT review state, which is not the same question as
623
+ * whether it has access.
624
+ *
625
+ * A client that was approved and later rejected still holds live tokens until
626
+ * they expire, and this listing shows them: it queries the token table
627
+ * directly and never goes through the approval gate, because the person whose
628
+ * account it is has more right to see the access than anyone.
629
+ */
630
+ readonly approval_status: OauthApprovalStatus;
631
+ /**
632
+ * True for a client this project SHIPS, read off the pinned `client_id` list
633
+ * (`oms-cli`, `oms-mcp`) rather than off `owner_id IS NULL`.
634
+ *
635
+ * The backend deliberately uses the pinned list here, because NULL owner also
636
+ * means "orphaned when its owner deleted their account", and this is the
637
+ * screen where a person decides what to cut off. {@link isShippedClient}
638
+ * computes the same answer from `client_id` alone.
639
+ */
640
+ readonly first_party: boolean;
641
+ /**
642
+ * How many unrevoked tokens this client holds for you.
643
+ *
644
+ * "Unrevoked", NOT "unexpired", and the difference matters: refresh tokens
645
+ * are on, and a row whose two-hour access token expired an hour ago still
646
+ * buys a fresh one on demand. Counting only unexpired rows would hide exactly
647
+ * the access that most needs revoking.
648
+ */
649
+ readonly token_count: number;
650
+ /**
651
+ * `created_at` of the most recent of those tokens, `null` if there are none.
652
+ *
653
+ * Read it as "last time this renewed its access", NOT as "authorised since":
654
+ * every refresh writes a new token row, so this moves forward on its own
655
+ * while the client keeps working. The list is sorted by this, newest first.
656
+ */
657
+ readonly last_authorized_at: Timestamp | null;
658
+ }
659
+ /** What {@link AuthorizedApplicationsNamespace.revoke} answers with. */
660
+ export interface AuthorizedApplicationRevocation {
661
+ /** The application id you asked about, echoed back. */
662
+ readonly id: number;
663
+ /** How many live tokens were killed. `0` when there was nothing to kill. */
664
+ readonly revoked_tokens: number;
665
+ }
666
+ /**
667
+ * `oms.admin.authorizedApplications` - "which applications have access to my
668
+ * account", and the button that takes it away.
669
+ *
670
+ * Any authenticated user, about their own account only. Nothing here can touch
671
+ * another person's grants: every write is filtered by BOTH the application id
672
+ * and the caller, so an id belonging to somebody else's client can only ever
673
+ * revoke rows the caller owns, which is none.
674
+ *
675
+ * Without this pair of calls, consent would be a one-way door: the device
676
+ * approval page hands out a credential that outlives the browser session, and
677
+ * every consent screen in this product promises the access can be withdrawn
678
+ * later from account settings. These two calls are that promise.
679
+ */
680
+ export declare class AuthorizedApplicationsNamespace extends Resource {
681
+ /**
682
+ * `GET /authorized_applications` - every application holding a live token for
683
+ * you, most recently renewed first.
684
+ *
685
+ * Always `200`, `[]` included. No pagination: this list has units, not pages.
686
+ * The response is enveloped and this method unwraps it.
687
+ *
688
+ * The listing does NOT filter by approval state. See
689
+ * {@link AuthorizedApplication.approval_status}.
690
+ */
691
+ list(options?: RequestOptions): Promise<AuthorizedApplication[]>;
692
+ /**
693
+ * `DELETE /authorized_applications/:id` - cuts one application off your
694
+ * account.
695
+ *
696
+ * **Idempotent by construction, and it never answers `404`.** Revoking access
697
+ * that is already gone is a `200` with `revoked_tokens: 0`: your intent
698
+ * ("this must not have access") is satisfied either way, and a `404` for an
699
+ * unknown id would answer "does this client exist?" to anyone willing to
700
+ * count upwards. So a `200` here does not prove the client existed.
701
+ *
702
+ * **What actually dies**, which is more than it looks:
703
+ *
704
+ * - every unrevoked access token of yours for that client. A refresh token is
705
+ * not a row of its own in this system, it is a column ON the access token
706
+ * row, so revoking the row kills the refresh token with it. That is the
707
+ * whole point: a half-done revoke leaves the client walking back in on its
708
+ * next refresh;
709
+ * - every access grant of yours for it;
710
+ * - every device grant you already approved but whose client has not polled
711
+ * the token endpoint yet. Those are tokens waiting to be minted and are
712
+ * easy to forget, so they are deleted outright - a missing device code is
713
+ * the terminal `invalid_grant` a polling client needs to see.
714
+ *
715
+ * Strictly your own rows. Killing every grant a client holds across all users
716
+ * is an administrator's action
717
+ * ({@link AdminOauthApplicationsNamespace.revokeTokens}).
718
+ *
719
+ * The tokens are counted BEFORE the writes, because afterwards there is
720
+ * nothing left to count.
721
+ */
722
+ revoke(id: number | string, options?: RequestOptions): Promise<AuthorizedApplicationRevocation>;
723
+ }
724
+ /** The identity providers this server accepts. `Identity::PROVIDERS`. */
725
+ export declare const IDENTITY_PROVIDERS: readonly ["google_oauth2", "github", "spotify"];
726
+ /**
727
+ * One of {@link IDENTITY_PROVIDERS}. Note `"google_oauth2"`, not `"google"`:
728
+ * it is the OmniAuth strategy name and it is what the column stores.
729
+ */
730
+ export type IdentityProvider = (typeof IDENTITY_PROVIDERS)[number];
731
+ /**
732
+ * A social login linked to your account.
733
+ *
734
+ * This is OAuth coming IN - signing in with Google, GitHub or Spotify - and it
735
+ * is the opposite direction from {@link AuthorizedApplication}.
736
+ *
737
+ * The blueprint renders seven fields and NOTHING else, which is the interesting
738
+ * part: the row also holds `uid`, `oauth_token`, `oauth_refresh_token`,
739
+ * `oauth_expires_at` and the entire `raw_info` payload from the provider, and
740
+ * none of them cross the wire. There is no endpoint that will hand you a
741
+ * provider token.
742
+ */
743
+ export interface LinkedIdentity {
744
+ /** A **string** id, 12 characters. `identities` is not one of the integer tables. */
745
+ readonly id: Id;
746
+ readonly provider: IdentityProvider;
747
+ /**
748
+ * The address the provider asserted, or `null` when it asserted none.
749
+ *
750
+ * Not necessarily the account's own email, and never proof of it: linking a
751
+ * provider to an existing account does not touch `email_verified_at`.
752
+ */
753
+ readonly email: string | null;
754
+ /** Display name from the provider, or `null`. */
755
+ readonly name: string | null;
756
+ /** Provider avatar URL, or `null`. A remote URL, not something this API serves. */
757
+ readonly avatar_url: string | null;
758
+ readonly created_at: Timestamp;
759
+ readonly updated_at: Timestamp;
760
+ }
761
+ /** Filters for {@link LinkedIdentitiesNamespace.list}. */
762
+ export interface ListLinkedIdentitiesParams extends PageParams {
763
+ /**
764
+ * `modifiers[order]`, e.g. `"created_at:desc"`. Defaults to
765
+ * `"created_at:desc"`.
766
+ */
767
+ readonly order?: string;
768
+ }
769
+ /**
770
+ * `oms.admin.identities` - the Google, GitHub and Spotify logins linked to
771
+ * YOUR account.
772
+ *
773
+ * Any authenticated user, and strictly their own rows: the listing scope is
774
+ * `where(user: Current.user)` and being an administrator buys nothing extra
775
+ * here. There is no admin view of other people's identities anywhere in this
776
+ * API.
777
+ *
778
+ * **Linking a new provider is not in this SDK and cannot be.** It is a browser
779
+ * redirect flow (`GET /auth/link/:provider` into the provider and back through
780
+ * `/auth/:provider/callback`), it depends on a single-use nonce held in a
781
+ * server-side session, and it ends by redirecting to an allowlisted origin or
782
+ * to the `omsmusic://` scheme. A host that needs it opens a browser; there is
783
+ * nothing here to call. UNLINKING, which is the destructive half, is
784
+ * {@link destroy}.
785
+ */
786
+ export declare class LinkedIdentitiesNamespace extends Resource {
787
+ /**
788
+ * `GET /identities` - your linked providers.
789
+ *
790
+ * A bare JSON array, not an envelope, unlike the two OAuth application
791
+ * listings above. This one goes through the generic list DSL, so it paginates
792
+ * (default page size applies even when you do not ask) and it answers ETag
793
+ * and `304`.
794
+ *
795
+ * In practice this returns at most three rows, one per provider, since
796
+ * `(provider, uid)` is unique and a person has one account per provider. The
797
+ * pagination is the framework's, not a hint that the list is long.
798
+ */
799
+ list(params?: ListLinkedIdentitiesParams, options?: RequestOptions): Promise<Paginated<LinkedIdentity>>;
800
+ /**
801
+ * `DELETE /identities/:id` - unlinks a provider. Answers `204`, empty.
802
+ *
803
+ * Only your own: the row is looked up inside your own scope, so somebody
804
+ * else's identity id is a `404` and never a `403`.
805
+ *
806
+ * **This is the last-credential footgun.** Nothing here checks that you still
807
+ * have another way in. An account created through a provider gets a random
808
+ * UUID as its password, which nobody knows, so unlinking the only identity on
809
+ * such an account can lock it out until a password reset is done through
810
+ * email. Check what else the account has - a password, a passkey, another
811
+ * provider - before calling this.
812
+ *
813
+ * It does not revoke anything at the provider, and it does not touch the
814
+ * sessions that identity was used to create. Those keep working; this only
815
+ * removes the link.
816
+ *
817
+ * @throws {OmsApiError} 404 `"Resource not found"` (a bare JSON string, not
818
+ * the structured body the `/oauth_applications` routes use).
819
+ */
820
+ destroy(id: Id, options?: RequestOptions): Promise<void>;
821
+ }
822
+ /**
823
+ * A registered client as an ADMINISTRATOR sees it: same eleven keys as
824
+ * {@link OwnedOauthApplication}, but `approved_by` is real and the row can
825
+ * belong to anybody on the server.
826
+ */
827
+ export interface AdminOauthApplication extends OauthApplicationSummary {
828
+ }
829
+ /**
830
+ * {@link AdminOauthApplication} plus the counters that answer "is this client
831
+ * live right now".
832
+ *
833
+ * Returned by every administrator action EXCEPT `index` and `pending`, which
834
+ * send the summary: the counters cost five aggregate queries per row and a
835
+ * listing does not pay for them.
836
+ */
837
+ export interface AdminOauthApplicationDetail extends AdminOauthApplication {
838
+ /**
839
+ * Unrevoked AND unexpired access tokens. Note the difference from
840
+ * {@link AuthorizedApplication.token_count}, which counts unrevoked only: an
841
+ * expired-but-refreshable token counts there and not here, so this number can
842
+ * read `0` for a client that will be talking to the server again in a second.
843
+ */
844
+ readonly live_token_count: number;
845
+ /** Distinct people behind those live tokens. The blast radius of a revocation. */
846
+ readonly live_token_users: number;
847
+ /** Every token ever minted for this client, revoked and expired included. */
848
+ readonly total_token_count: number;
849
+ /** When the most recent token was minted, `null` if never. */
850
+ readonly last_token_at: Timestamp | null;
851
+ /**
852
+ * Device grants nobody has approved yet (`resource_owner_id IS NULL`), i.e.
853
+ * device flows in progress. Approved-but-uncollected grants are NOT counted
854
+ * here, though a revocation kills those too.
855
+ */
856
+ readonly pending_device_grants: number;
857
+ }
858
+ /** What {@link AdminOauthApplicationsNamespace.pending} answers with. */
859
+ export interface AdminOauthPendingQueue {
860
+ /** Oldest first: it is a queue, not a feed. A newest-first queue starves its own bottom. */
861
+ readonly applications: AdminOauthApplication[];
862
+ /** `applications.length`. Sent so a badge does not have to load the array. */
863
+ readonly count: number;
864
+ }
865
+ /** Arguments for {@link AdminOauthApplicationsNamespace.register}. */
866
+ export interface RegisterOauthApplicationInput {
867
+ /** Normalised then required. See {@link OAUTH_APP_NAME_MAX_LENGTH}. */
868
+ readonly name: string;
869
+ /** Unknown scopes are dropped; an empty result after filtering is a `400`. */
870
+ readonly scopes: readonly (OmsScope | string)[] | string;
871
+ /** Defaults to `false`. Every client this project ships is public. */
872
+ readonly confidential?: boolean;
873
+ /** Blank registers {@link NATIVE_LOOPBACK_REDIRECT_VALUE}. */
874
+ readonly redirect_uri?: string;
875
+ }
876
+ /** What {@link AdminOauthApplicationsNamespace.register} answers with. */
877
+ export interface AdminOauthApplicationWithSecret {
878
+ readonly application: AdminOauthApplicationDetail;
879
+ /** Once, and `null` for a public client. See {@link OwnedOauthApplicationWithSecret}. */
880
+ readonly client_secret: string | null;
881
+ }
882
+ /** Arguments for {@link AdminOauthApplicationsNamespace.reject}. */
883
+ export interface RejectOauthApplicationInput {
884
+ /**
885
+ * Required, non-blank, at most 500 characters. **The owner is shown this
886
+ * text**, so write it for them.
887
+ */
888
+ readonly reason: string;
889
+ /**
890
+ * Kill the client's live tokens as well.
891
+ *
892
+ * Opt-in, and it only decides anything for a client that was NOT approved -
893
+ * rejecting an APPROVED client always revokes, whatever this says, because an
894
+ * administrator withdrawing trust has decided the client should stop acting,
895
+ * not that it should stop acting eventually.
896
+ */
897
+ readonly revoke_tokens?: boolean;
898
+ }
899
+ /** What {@link AdminOauthApplicationsNamespace.approve} and `.reject()` answer with. */
900
+ export interface OauthApplicationReview {
901
+ readonly application: AdminOauthApplicationDetail;
902
+ /** Present on `reject`. Absent on `approve`, which never revokes anything. */
903
+ readonly revoked_tokens?: number;
904
+ }
905
+ /** What {@link AdminOauthApplicationsNamespace.revokeTokens} answers with. */
906
+ export interface OauthTokenRevocation {
907
+ readonly application: AdminOauthApplicationDetail;
908
+ readonly revoked_tokens: number;
909
+ }
910
+ /**
911
+ * What {@link AdminOauthApplicationsNamespace.destroy} answers with.
912
+ *
913
+ * The `client_id` is spelled **`uid`** here and `client_id` on the owner route
914
+ * ({@link OwnedOauthApplicationDeletion}). One column, two controllers, two
915
+ * names, and nothing reconciles them.
916
+ */
917
+ export interface AdminOauthApplicationDeletion {
918
+ readonly id: number;
919
+ /** The `client_id`. Named after the column, not after the protocol. */
920
+ readonly uid: string;
921
+ readonly revoked_tokens: number;
922
+ }
923
+ /**
924
+ * `oms.admin.oauthApplications` - **administrators only**. The review queue and
925
+ * the registry of every OAuth client on the server.
926
+ *
927
+ * Every method here answers `403 "Admin access required"` to a non-admin. See
928
+ * the namespace documentation for the exact error shape and why
929
+ * re-authenticating will not help.
930
+ *
931
+ * This is the other end of {@link MyOauthApplicationsNamespace}: the same
932
+ * table, without the ownership filter. `destroy` here deletes anybody's client
933
+ * and cuts off everyone using it.
934
+ *
935
+ * Together with the self-service surface, this is the ONLY write path into the
936
+ * table: dynamic client registration is off, and Doorkeeper's own application
937
+ * CRUD is not mounted.
938
+ *
939
+ * ## Review receipts, and why a read here is not a pure read
940
+ *
941
+ * {@link list}, {@link pending} and {@link get} each record, in a server-side
942
+ * cache and keyed to the calling administrator, a digest of what they were just
943
+ * shown. {@link approve} then refuses with `409 review_stale` if the row no
944
+ * longer matches.
945
+ *
946
+ * That exists because approving by id approves whatever the row holds when the
947
+ * request lands, not what the queue rendered - and the window between a
948
+ * reviewer's eyes and their click belongs to the applicant, who may edit a
949
+ * pending client freely (they have to be able to: that is how a refused
950
+ * registration gets fixed). Register something innocent, wait to be read,
951
+ * rename it to "omelhorsite Oficial" with a redirect URI you control, and the
952
+ * approval lands on a client nobody reviewed.
953
+ *
954
+ * Two consequences for a client of this SDK:
955
+ *
956
+ * - **calling `approve` without having read the client first is allowed** and
957
+ * behaves exactly as it would with no receipt. No receipt means no
958
+ * contradiction. This layer tightens the reviewed path; the authorisation
959
+ * check is the `403` above, not this;
960
+ * - the digest covers name, scopes, redirect URIs, `confidential` and owner. It
961
+ * deliberately excludes `approval_status`, so approving twice stays
962
+ * idempotent, and the receipt lasts 7 days.
963
+ *
964
+ * {@link reject} and {@link revokeTokens} are NOT gated this way on purpose:
965
+ * refusing or shutting down a client that changed under you is the safe
966
+ * direction, and a shut-down button that can refuse is how a client stays live.
967
+ */
968
+ export declare class AdminOauthApplicationsNamespace extends Resource {
969
+ /**
970
+ * `GET /admin/oauth_applications` - every client on the server, newest first.
971
+ *
972
+ * No pagination and no filter. Records a review receipt for every row
973
+ * returned; see the class documentation.
974
+ *
975
+ * Summaries, not details: no token counters. Use {@link get} for those.
976
+ *
977
+ * @throws {OmsAuthError} 403 for a non-admin.
978
+ */
979
+ list(options?: RequestOptions): Promise<AdminOauthApplication[]>;
980
+ /**
981
+ * `GET /admin/oauth_applications/pending` - the review queue, oldest first.
982
+ *
983
+ * A separate collection route and NOT a filter on {@link list}, so an admin
984
+ * panel can poll one cheap indexed query without carrying the other
985
+ * listing's joins. Ordered by `created_at` then `id`, which makes the order
986
+ * total: two rows can share a timestamp, and an unstable order makes a
987
+ * polling panel jitter.
988
+ *
989
+ * Records a review receipt for every row returned.
990
+ *
991
+ * @throws {OmsAuthError} 403 for a non-admin.
992
+ */
993
+ pending(options?: RequestOptions): Promise<AdminOauthPendingQueue>;
994
+ /**
995
+ * `GET /admin/oauth_applications/:id` - one client, with its token counters.
996
+ *
997
+ * **`id` may be either the numeric primary key or the `client_id`.** The
998
+ * lookup tries the id first and falls back to the `uid`, which is what makes
999
+ * `oms.admin.oauthApplications.get("oms-cli")` work. The owner route has no
1000
+ * such fallback.
1001
+ *
1002
+ * Records a review receipt.
1003
+ *
1004
+ * @throws {OmsApiError} 404 `{ "error": "not_found" }`.
1005
+ * @throws {OmsAuthError} 403 for a non-admin.
1006
+ */
1007
+ get(id: number | string, options?: RequestOptions): Promise<AdminOauthApplicationDetail>;
1008
+ /**
1009
+ * `POST /admin/oauth_applications` - registers a client by hand, already
1010
+ * approved.
1011
+ *
1012
+ * Named `register` and not `create` because it is not the counterpart of
1013
+ * {@link MyOauthApplicationsNamespace.create}: what lands here is **born
1014
+ * `approved`**, with `owner_id` NULL and `approved_by` set to the calling
1015
+ * administrator. An admin registering a client IS the approval; routing them
1016
+ * through their own queue would be theatre. It never appears in
1017
+ * {@link pending}.
1018
+ *
1019
+ * **Answers `200`, not `201`**, unlike the self-service registration. The
1020
+ * controller uses the plain OK helper. Do not branch on the status.
1021
+ *
1022
+ * The response is the ONLY place `client_secret` ever exists. See
1023
+ * {@link OwnedOauthApplicationWithSecret} for why there is nothing to read
1024
+ * back later.
1025
+ *
1026
+ * `confidential` defaults to `false`, which is right for the clients this
1027
+ * surface exists to register: anything that ships to end users cannot keep a
1028
+ * secret.
1029
+ *
1030
+ * Retries are disabled: a replay after a lost response mints a second client
1031
+ * with a second `client_id` and a second secret you never saw.
1032
+ *
1033
+ * @throws {OmsApiError} 400 (bare string) for a blank name, no known scope,
1034
+ * or too many redirect URIs; 422 `validation_failed` with an `errors` array
1035
+ * for a redirect URI this server will not register.
1036
+ * @throws {OmsAuthError} 403 for a non-admin.
1037
+ */
1038
+ register(input: RegisterOauthApplicationInput, options?: RequestOptions): Promise<AdminOauthApplicationWithSecret>;
1039
+ /**
1040
+ * `POST /admin/oauth_applications/:id/approve` - lets the client start
1041
+ * minting tokens.
1042
+ *
1043
+ * Idempotent, and it works from `rejected` as well as from `pending`: there
1044
+ * is no separate rehabilitation action. Approving an already-approved client
1045
+ * answers `200` and deliberately does NOT notify the owner a second time - a
1046
+ * double click is not two decisions.
1047
+ *
1048
+ * **Read the class documentation on review receipts before wiring a retry
1049
+ * around this.** If this administrator rendered the client and it changed
1050
+ * afterwards, the answer is `409 review_stale`, and the body carries the
1051
+ * CURRENT row under `application` so the screen can show what it turned into
1052
+ * rather than sending someone to go and find out. Retrying that verbatim just
1053
+ * gets the same `409`; the fix is to re-read and review again.
1054
+ *
1055
+ * @throws {OmsApiError} 409 `review_stale`; 404 `not_found`; 422
1056
+ * `validation_failed`.
1057
+ * @throws {OmsAuthError} 403 for a non-admin.
1058
+ */
1059
+ approve(id: number | string, options?: RequestOptions): Promise<OauthApplicationReview>;
1060
+ /**
1061
+ * `POST /admin/oauth_applications/:id/reject` - refuses a registration, or
1062
+ * pulls an approved client off the air.
1063
+ *
1064
+ * One action, two buttons. `pending -> rejected` is a refusal at review;
1065
+ * `approved -> rejected` is a suspension, and there is no fourth state to put
1066
+ * a client in.
1067
+ *
1068
+ * **Rejecting shuts the gate but does not by itself kill issued tokens.** A
1069
+ * rejected client can no longer mint, refresh or exchange anything, yet
1070
+ * access tokens already in the wild keep working until they expire - a blast
1071
+ * radius of the two-hour token lifetime. Which is why:
1072
+ *
1073
+ * - `revoke_tokens: true` kills them in the same breath. Opt-in, so refusing
1074
+ * a never-approved registration stays the cheap, quiet operation it should
1075
+ * be;
1076
+ * - a client that WAS approved has its tokens revoked regardless of the flag.
1077
+ *
1078
+ * `reason` is required and the OWNER sees it. Re-rejecting with the same
1079
+ * reason is a no-op notification-wise; changing the wording notifies again.
1080
+ *
1081
+ * Not gated by a review receipt: shutting a client down is always the safe
1082
+ * direction.
1083
+ *
1084
+ * @throws {OmsApiError} 400 `reason_required` for a blank reason; 422
1085
+ * `validation_failed` past 500 characters; 404 `not_found`.
1086
+ * @throws {OmsAuthError} 403 for a non-admin.
1087
+ */
1088
+ reject(id: number | string, input: RejectOauthApplicationInput, options?: RequestOptions): Promise<OauthApplicationReview>;
1089
+ /**
1090
+ * `POST /admin/oauth_applications/:id/revoke_tokens` - kills everything the
1091
+ * client holds, and leaves the client standing.
1092
+ *
1093
+ * The 3am action: the `client_id` is fine, what it is doing is not. Every
1094
+ * live access token dies, every access grant dies, every device grant is
1095
+ * deleted, and the client can be used for a fresh login the second
1096
+ * afterwards. Approval is untouched.
1097
+ *
1098
+ * This is the whole-server version of
1099
+ * {@link AuthorizedApplicationsNamespace.revoke}, which only ever touches the
1100
+ * caller's own tokens. Read `live_token_users` on the detail first to know
1101
+ * how many people you are about to sign out.
1102
+ *
1103
+ * @throws {OmsApiError} 404 `not_found`.
1104
+ * @throws {OmsAuthError} 403 for a non-admin.
1105
+ */
1106
+ revokeTokens(id: number | string, options?: RequestOptions): Promise<OauthTokenRevocation>;
1107
+ /**
1108
+ * `DELETE /admin/oauth_applications/:id` - deletes anybody's client.
1109
+ *
1110
+ * Revokes first, then destroys, so the revocation stamps exist for the moment
1111
+ * in between and the device grants (which hold a restricting foreign key) are
1112
+ * cleared by hand rather than by a cascade.
1113
+ *
1114
+ * This is not the tidy-up that {@link MyOauthApplicationsNamespace.destroy}
1115
+ * is. Deleting a client somebody else registered signs out everyone using it
1116
+ * and there is no undo: the `client_id` is gone and a new registration gets a
1117
+ * new one. {@link revokeTokens} is the reversible version.
1118
+ *
1119
+ * Answers `200` with a body; note the key is `uid`, not `client_id`.
1120
+ *
1121
+ * @throws {OmsApiError} 404 `not_found`.
1122
+ * @throws {OmsAuthError} 403 for a non-admin.
1123
+ */
1124
+ destroy(id: number | string, options?: RequestOptions): Promise<AdminOauthApplicationDeletion>;
1125
+ }
1126
+ /**
1127
+ * How an override behaves.
1128
+ *
1129
+ * - `"default"` DELETES the override row, so the person falls back to the
1130
+ * catalogue default. It does not write a number equal to the default, which
1131
+ * matters the day a default changes;
1132
+ * - `"unlimited"` writes an override with a NULL value, which the server reads
1133
+ * as no ceiling at all;
1134
+ * - `"limit"` writes the number in `value`.
1135
+ */
1136
+ export type AdminQuotaOverrideMode = "default" | "unlimited" | "limit";
1137
+ /** One change to apply. See {@link AdminQuotasNamespace.update}. */
1138
+ export interface AdminQuotaOverride {
1139
+ readonly resource: QuotaResource | string;
1140
+ readonly mode: AdminQuotaOverrideMode;
1141
+ /** Required for `"limit"`, ignored otherwise. Must be `>= 0` and fit in a signed 64-bit integer. */
1142
+ readonly value?: number;
1143
+ }
1144
+ /** The stored override behind a {@link AdminUserQuotaEntry}, if there is one. */
1145
+ export interface AdminQuotaOverrideState {
1146
+ /** The number, or `null` when the override means unlimited. */
1147
+ readonly value: number | null;
1148
+ /** `true` exactly when `value` is `null`. */
1149
+ readonly unlimited: boolean;
1150
+ }
1151
+ /**
1152
+ * One resource, for one person, as an administrator sees it.
1153
+ *
1154
+ * This is the ordinary quota entry that `oms.quotas.list()` returns, plus the
1155
+ * two keys that only make sense while editing: what the default WOULD be, and
1156
+ * what is currently overriding it.
1157
+ */
1158
+ export interface AdminUserQuotaEntry {
1159
+ readonly resource: QuotaResource | string;
1160
+ readonly unit: QuotaUnit | string;
1161
+ readonly period: QuotaPeriod | string;
1162
+ /** Consumption right now, in `unit`. */
1163
+ readonly used: number;
1164
+ /** The effective ceiling, or `null` when unlimited. */
1165
+ readonly limit: number | null;
1166
+ /** `limit - used`, floored at zero. `null` when unlimited. */
1167
+ readonly remaining: number | null;
1168
+ readonly unlimited: boolean;
1169
+ /** The catalogue default for a signed-in user. What `"default"` mode restores. */
1170
+ readonly user_default: number;
1171
+ /** The stored override, or `null` when there is none and the default applies. */
1172
+ readonly override: AdminQuotaOverrideState | null;
1173
+ }
1174
+ /** What {@link AdminQuotasNamespace} returns. */
1175
+ export interface AdminUserQuotas {
1176
+ readonly user_id: Id;
1177
+ readonly handle: string;
1178
+ /**
1179
+ * **Every** resource in the catalogue, including the storage and music
1180
+ * ceilings. Unlike the anonymous answer from `oms.quotas.list()`, nothing is
1181
+ * left out here. Look entries up by `resource`, never by position.
1182
+ */
1183
+ readonly quotas: AdminUserQuotaEntry[];
1184
+ /**
1185
+ * Legacy twin of the `music_storage_bytes` entry's `limit`, `null` when
1186
+ * unlimited. Kept for an older admin bundle that reads it. Prefer the
1187
+ * catalogue entry; this key is on its way out.
1188
+ */
1189
+ readonly music_storage_limit_bytes: number | null;
1190
+ }
1191
+ /**
1192
+ * `oms.admin.quotas` - **administrators only**. Another person's ceilings.
1193
+ *
1194
+ * The person's own view of the same numbers is `oms.quotas.list()`, which needs
1195
+ * no privilege and cannot change anything.
1196
+ */
1197
+ export declare class AdminQuotasNamespace extends Resource {
1198
+ /**
1199
+ * `GET /admin/users/:user/quotas` - the full catalogue for one person.
1200
+ *
1201
+ * **`user` may be a user id OR a handle.** The lookup tries the id first and
1202
+ * then the handle, downcased, which is why an admin tool can take whatever
1203
+ * was typed into a search box.
1204
+ *
1205
+ * @throws {OmsApiError} 404 `"User not found"` (a bare JSON string).
1206
+ * @throws {OmsAuthError} 403 for a non-admin.
1207
+ */
1208
+ get(user: Id | string, options?: RequestOptions): Promise<AdminUserQuotas>;
1209
+ /**
1210
+ * `PUT /admin/users/:user/quotas` - applies a batch of overrides.
1211
+ *
1212
+ * **`PUT`, not `PATCH`.** The route declares only `show` and `update` on a
1213
+ * singular resource, and Rails maps `update` to both verbs, but this SDK
1214
+ * sends the one the frontend has always sent.
1215
+ *
1216
+ * **The batch is NOT atomic, and this is the thing to design around.** The
1217
+ * server loops over `overrides` and writes each one as it goes, with no
1218
+ * transaction around the loop: a bad entry in the middle answers `400` with
1219
+ * everything BEFORE it already written and everything after it untouched. So
1220
+ * a failed call leaves a partial state, and the only reliable way to know
1221
+ * what landed is the answer to a fresh {@link get}. Validate the batch
1222
+ * yourself before sending it, or send one override per call.
1223
+ *
1224
+ * Passing an empty `overrides` array is a legal no-op and a cheap way to read
1225
+ * the quotas back, though {@link get} is the honest way to do that.
1226
+ *
1227
+ * The response is the full, reloaded catalogue, so there is no need to follow
1228
+ * this with a read on the success path.
1229
+ *
1230
+ * @throws {OmsApiError} 400 `"Unknown resource: x"`, `"Invalid mode: x"`, or
1231
+ * `"Invalid value for x"` for a negative number or one past the signed
1232
+ * 64-bit ceiling. All three are bare JSON strings. 404 `"User not found"`.
1233
+ * @throws {OmsAuthError} 403 for a non-admin.
1234
+ */
1235
+ update(user: Id | string, overrides: readonly AdminQuotaOverride[], options?: RequestOptions): Promise<AdminUserQuotas>;
1236
+ }
1237
+ /**
1238
+ * A job row, as `/admin/jobs` renders it.
1239
+ *
1240
+ * Identical to the {@link Job} an ordinary caller reads through `oms.jobs`,
1241
+ * because it is the same blueprint: the only difference is the SCOPE, since
1242
+ * `Job.viewable_by` returns every row for an administrator and only your own
1243
+ * for everybody else.
1244
+ */
1245
+ export type AdminJob = Job;
1246
+ /** Filters for {@link AdminJobsNamespace.list}. */
1247
+ export interface ListAdminJobsParams extends PageParams {
1248
+ /** `exact_search[status]`. An array becomes an `IN`. */
1249
+ readonly status?: string | readonly string[];
1250
+ /** `exact_search[job_type]`. An array becomes an `IN`. */
1251
+ readonly jobType?: string | readonly string[];
1252
+ /** `modifiers[order]`. Defaults to `"created_at:desc"`. */
1253
+ readonly order?: string;
1254
+ }
1255
+ /** What {@link AdminJobsNamespace.cleanupStuck} answers with. */
1256
+ export interface AdminStuckJobCleanup {
1257
+ /** Ids of the jobs that were canceled. String ids: `jobs` is one of the string-keyed tables. */
1258
+ readonly canceled_job_ids: Id[];
1259
+ /** `canceled_job_ids.length`. `0` when there was nothing stuck. */
1260
+ readonly count: number;
1261
+ }
1262
+ /**
1263
+ * `oms.admin.jobs` - **administrators only**. Every background job on the
1264
+ * server.
1265
+ *
1266
+ * The unprivileged half of this is `oms.jobs`, which is the same endpoints
1267
+ * narrowed to the caller's own jobs. What an administrator gains is the scope,
1268
+ * plus {@link cancel} and {@link cleanupStuck}, which need `admin?` on the
1269
+ * model itself and not merely on the route.
1270
+ */
1271
+ export declare class AdminJobsNamespace extends Resource {
1272
+ /**
1273
+ * `GET /admin/jobs` - every job, newest first.
1274
+ *
1275
+ * A bare JSON array through the generic list DSL: it paginates (a default
1276
+ * page size is forced even when you do not ask, so this can never enumerate
1277
+ * the whole table) and it answers ETag and `304`.
1278
+ *
1279
+ * **The filters have to go inside the filter buckets, and the failure mode if
1280
+ * they do not is silent.** `status` and `job_type` are declared as search
1281
+ * columns, which means `exact_search[status]`; a plain top-level
1282
+ * `?status=pending` is read by nothing and you get the unfiltered first page
1283
+ * back, with no error to tell you the narrowing was dropped. The web
1284
+ * frontend's admin service does exactly that today - see the note in the
1285
+ * report accompanying this namespace. This method builds the buckets for you.
1286
+ *
1287
+ * Unknown filter keys inside a bucket DO fail, with a `400`, on purpose: a
1288
+ * dropped filter is a wider result nobody notices.
1289
+ *
1290
+ * @throws {OmsAuthError} 403 for a non-admin.
1291
+ */
1292
+ list(params?: ListAdminJobsParams, options?: RequestOptions): Promise<Paginated<AdminJob>>;
1293
+ /**
1294
+ * `POST /admin/jobs/:id/cancel` - stops a job.
1295
+ *
1296
+ * The row lands on `status: "canceled"` with `error: "Canceled by admin"` and
1297
+ * a `finished_at`, and the change is broadcast over the job channel, so
1298
+ * anything watching that job sees it immediately.
1299
+ *
1300
+ * **This marks the row, it does not reach into the worker.** A job that is
1301
+ * already executing keeps executing until it next looks at its own status;
1302
+ * cancelling is a request, not a kill signal.
1303
+ *
1304
+ * @throws {OmsApiError} 400 `"Already terminal"` for a job that is complete,
1305
+ * failed or already canceled. Idempotency has to be your side: check
1306
+ * `isJobTerminal(job.status)` first rather than swallowing the 400. 404
1307
+ * `"Resource not found"`.
1308
+ * @throws {OmsAuthError} 403 for a non-admin.
1309
+ */
1310
+ cancel(id: Id, options?: RequestOptions): Promise<AdminJob>;
1311
+ /**
1312
+ * `POST /admin/jobs/cleanup_stuck` - cancels every job the server considers
1313
+ * stuck.
1314
+ *
1315
+ * A sweep with NO arguments and no dry run: it decides what is stuck and acts
1316
+ * on all of it in one request. There is no preview and no undo. Read
1317
+ * {@link list} filtered to `"processing"` first if you want to know what you
1318
+ * are about to hit.
1319
+ *
1320
+ * Answers `{ canceled_job_ids, count }`. `count: 0` is the normal, healthy
1321
+ * answer and is not an error.
1322
+ *
1323
+ * Retries are disabled: the sweep is not free, and a replay after a lost
1324
+ * response reports a second, smaller set as if it were the whole answer.
1325
+ *
1326
+ * @throws {OmsAuthError} 403 for a non-admin.
1327
+ */
1328
+ cleanupStuck(options?: RequestOptions): Promise<AdminStuckJobCleanup>;
1329
+ }
1330
+ /**
1331
+ * One day of a 30 day series.
1332
+ *
1333
+ * Every daily series on the administrator surface has **exactly 30 entries,
1334
+ * oldest first, ending today**, with `count: 0` filled in for days that had
1335
+ * nothing. The series is safe to plot without gap filling, and the window is
1336
+ * fixed server-side: there is no parameter to widen it.
1337
+ *
1338
+ * Structurally identical to `ShortLinkDailyClicks` from the `shortLinks`
1339
+ * namespace, and kept separate because half the series here count creations
1340
+ * rather than clicks.
1341
+ */
1342
+ export interface AdminDailyCount {
1343
+ /** `YYYY-MM-DD`. */
1344
+ readonly date: string;
1345
+ readonly count: number;
1346
+ }
1347
+ /** Compact owner object on an admin short link row. `null` for an anonymous link. */
1348
+ export interface AdminShortLinkOwner {
1349
+ readonly id: Id;
1350
+ readonly name: string;
1351
+ readonly handle: string;
1352
+ }
1353
+ /**
1354
+ * A short link as the admin tool sees it.
1355
+ *
1356
+ * This is the blueprint's `:admin` view, which is NOT the shape the ordinary
1357
+ * `shortLinks` namespace returns. The differences are load-bearing:
1358
+ *
1359
+ * - there is **no `updated_at`**, uniquely on this surface;
1360
+ * - there is **no `short_link_clicks` array**. The default view inlines EVERY
1361
+ * click ever recorded, which is a payload hazard on a busy link; here it is
1362
+ * replaced by the two aggregates below;
1363
+ * - the full user record is replaced by the compact {@link AdminShortLinkOwner}.
1364
+ */
1365
+ export interface AdminShortLink {
1366
+ /**
1367
+ * Primary key, and an **integer**: `short_links` kept a bigint primary key
1368
+ * while the `user_id` next to it is a string.
1369
+ */
1370
+ readonly id: number;
1371
+ readonly url: string;
1372
+ readonly endpoint: string;
1373
+ /**
1374
+ * Always `null` or `""` on this surface: the listing, the drilldown and the
1375
+ * delete are all scoped to non-namespaced links so that private chest,
1376
+ * notepad and storage-share URLs never surface here.
1377
+ * {@link AdminShortLinksNamespace.namespaces} is the one exception and it
1378
+ * only returns counts.
1379
+ */
1380
+ readonly namespace: string | null;
1381
+ /** Owner id, or `null` for a link created anonymously. */
1382
+ readonly user_id: Id | null;
1383
+ readonly owner: AdminShortLinkOwner | null;
1384
+ readonly created_at: Timestamp;
1385
+ /** Total clicks. Computed per page in one grouped query, not per row. */
1386
+ readonly click_count: number;
1387
+ readonly last_click_at: Timestamp | null;
1388
+ }
1389
+ /** Filters for {@link AdminShortLinksNamespace.list}. */
1390
+ export interface ListAdminShortLinksParams {
1391
+ /**
1392
+ * `"auth"` for links with an owner, `"anon"` for links without one. Any other
1393
+ * value, including omitting it, means both.
1394
+ */
1395
+ readonly owner?: "auth" | "anon" | "all";
1396
+ /**
1397
+ * Case-insensitive substring matched against the endpoint OR the destination
1398
+ * URL.
1399
+ *
1400
+ * **A plain top-level string, not the `search[column]` bucket the rest of
1401
+ * this API uses.** This controller reads `params[:search]` directly, so
1402
+ * sending a bucket here would be read as a hash and match nothing.
1403
+ */
1404
+ readonly search?: string;
1405
+ }
1406
+ /**
1407
+ * A page of {@link AdminShortLinksNamespace.list}.
1408
+ *
1409
+ * Not a {@link Paginated}, because there is nothing to page through: see
1410
+ * {@link AdminShortLinkPage.limit}.
1411
+ */
1412
+ export interface AdminShortLinkPage {
1413
+ /** At most {@link AdminShortLinkPage.limit} rows, newest first. */
1414
+ readonly items: AdminShortLink[];
1415
+ /** How many links match the filter in total. Frequently larger than `items.length`. */
1416
+ readonly total: number;
1417
+ /**
1418
+ * The hard server-side cap, currently 100.
1419
+ *
1420
+ * **There is no pagination on this endpoint and no way to reach row 101.**
1421
+ * When `total > limit` the rest is simply unreachable through this route; the
1422
+ * only way to find a specific link beyond the cap is to narrow
1423
+ * {@link ListAdminShortLinksParams.search} until it fits.
1424
+ */
1425
+ readonly limit: number;
1426
+ }
1427
+ /** What {@link AdminShortLinksNamespace.stats} answers with. */
1428
+ export interface AdminShortLinkStats {
1429
+ /** Non-namespaced links only, like everything else on this surface. */
1430
+ readonly total_links: number;
1431
+ readonly total_clicks: number;
1432
+ readonly clicks_last_24h: number;
1433
+ readonly clicks_last_7d: number;
1434
+ readonly zero_click_count: number;
1435
+ /** Already a percentage, `0` to `100`, one decimal. Not a fraction. */
1436
+ readonly zero_click_percent: number;
1437
+ /** Rounded to two decimals. `0` when there are no links. */
1438
+ readonly avg_clicks_per_link: number;
1439
+ readonly creations_daily: AdminDailyCount[];
1440
+ readonly clicks_daily: AdminDailyCount[];
1441
+ }
1442
+ /** One row of {@link AdminShortLinksNamespace.namespaces}. */
1443
+ export interface AdminShortLinkNamespaceCount {
1444
+ /**
1445
+ * `null` for user links, or one of the reserved tool namespaces: `"n"`
1446
+ * notepads, `"c"` chests, `"ss"` storage shares, `"qr"` dynamic QR, `"f"`
1447
+ * forms, `"t"` link trees.
1448
+ */
1449
+ readonly namespace: string | null;
1450
+ readonly count: number;
1451
+ }
1452
+ /** Clicks grouped by country, on the admin drilldown. */
1453
+ export interface AdminShortLinkCountryCount {
1454
+ /** ISO 3166-1 alpha-2 as stored at click time. */
1455
+ readonly country: string;
1456
+ readonly count: number;
1457
+ }
1458
+ /** Clicks grouped by browser or app, on the admin drilldown. */
1459
+ export interface AdminShortLinkDeviceCount {
1460
+ readonly device_name: string;
1461
+ readonly count: number;
1462
+ }
1463
+ /**
1464
+ * What {@link AdminShortLinksNamespace.get} answers with.
1465
+ *
1466
+ * Note what is NOT here: no `total_clicks` and no `last_click_at` at the top
1467
+ * level. The controller renders this drilldown with totals suppressed because
1468
+ * the same two numbers are already on `link`. Read them from there.
1469
+ */
1470
+ export interface AdminShortLinkDetail {
1471
+ readonly link: AdminShortLink;
1472
+ readonly clicks_daily: AdminDailyCount[];
1473
+ /** Top 10 countries by clicks, descending. Rows with no country are excluded. */
1474
+ readonly top_countries: AdminShortLinkCountryCount[];
1475
+ /** Top 5 devices by clicks, descending. Rows with no device are excluded. */
1476
+ readonly top_devices: AdminShortLinkDeviceCount[];
1477
+ }
1478
+ /**
1479
+ * `oms.admin.shortLinks` - **administrators only**. Every public short link and
1480
+ * its traffic.
1481
+ *
1482
+ * The unprivileged half is `oms.shortLinks`, which only ever shows the caller's
1483
+ * own links. This one shows everybody's, anonymous ones included, which is the
1484
+ * point: an anonymous short link has no owner to report it.
1485
+ *
1486
+ * **Scoped to non-namespaced links throughout.** Links minted by the internal
1487
+ * tools (notepads, chests, storage shares, dynamic QR, forms, link trees) carry
1488
+ * a namespace and are excluded from {@link list}, {@link get}, {@link stats}
1489
+ * and {@link destroy}, so an admin panel cannot accidentally surface a private
1490
+ * chest URL. {@link namespaces} is the deliberate exception and returns nothing
1491
+ * but counts.
1492
+ */
1493
+ export declare class AdminShortLinksNamespace extends Resource {
1494
+ /**
1495
+ * `GET /admin/short_links` - the newest 100 matching links.
1496
+ *
1497
+ * Read {@link AdminShortLinkPage.limit} before building a table on this: the
1498
+ * cap is hard and there is no page parameter.
1499
+ *
1500
+ * @throws {OmsAuthError} 403 for a non-admin.
1501
+ */
1502
+ list(params?: ListAdminShortLinksParams, options?: RequestOptions): Promise<AdminShortLinkPage>;
1503
+ /**
1504
+ * `GET /admin/short_links/stats` - server-wide totals and two 30 day series.
1505
+ *
1506
+ * @throws {OmsAuthError} 403 for a non-admin.
1507
+ */
1508
+ stats(options?: RequestOptions): Promise<AdminShortLinkStats>;
1509
+ /**
1510
+ * `GET /admin/short_links/namespaces` - how many links each namespace holds.
1511
+ *
1512
+ * The ONE call on this surface that looks past the non-namespaced scope, and
1513
+ * even so it only ever returns counts, never a row. User links come first
1514
+ * (`namespace: null`), then the reserved namespaces alphabetically.
1515
+ *
1516
+ * @throws {OmsAuthError} 403 for a non-admin.
1517
+ */
1518
+ namespaces(options?: RequestOptions): Promise<AdminShortLinkNamespaceCount[]>;
1519
+ /**
1520
+ * `GET /admin/short_links/:id` - one link with its traffic breakdown.
1521
+ *
1522
+ * @throws {OmsApiError} 404 `{ "error": "not_found" }` - which is also the
1523
+ * answer for a link that exists but carries a namespace, since those are
1524
+ * out of scope here.
1525
+ * @throws {OmsAuthError} 403 for a non-admin.
1526
+ */
1527
+ get(id: number | string, options?: RequestOptions): Promise<AdminShortLinkDetail>;
1528
+ /**
1529
+ * `DELETE /admin/short_links/:id` - deletes anybody's short link.
1530
+ *
1531
+ * Answers `200` with `{ id }`, not `204`. The clicks go with it.
1532
+ *
1533
+ * The link stops resolving immediately and there is no undo: the endpoint
1534
+ * becomes free again and somebody else can claim it, which is worth
1535
+ * remembering before deleting something that was printed or posted.
1536
+ *
1537
+ * @throws {OmsApiError} 404 `not_found`, namespaced links included.
1538
+ * @throws {OmsAuthError} 403 for a non-admin.
1539
+ */
1540
+ destroy(id: number | string, options?: RequestOptions): Promise<{
1541
+ readonly id: number;
1542
+ }>;
1543
+ }
1544
+ /**
1545
+ * A separation run as the admin surface renders it.
1546
+ *
1547
+ * The same `:extended` view the tool namespace reads, so the type is the same:
1548
+ * every key of {@link VocalSeparation}, `user_id` and `ip_address` included.
1549
+ * What changes is the SCOPE - an administrator sees every run on the server
1550
+ * rather than their own.
1551
+ */
1552
+ export type AdminVocalSeparation = VocalSeparation;
1553
+ /** Filters for {@link AdminVocalSeparationsNamespace.list}. */
1554
+ export interface ListAdminVocalSeparationsParams extends PageParams {
1555
+ /** `exact_search[status]`. An array becomes an `IN`. */
1556
+ readonly status?: string | readonly string[];
1557
+ /** `exact_search[model_id]`. An array becomes an `IN`. */
1558
+ readonly modelId?: string | readonly string[];
1559
+ /**
1560
+ * `"song"` for runs started from the music library, `"tool"` for uploads.
1561
+ *
1562
+ * A top-level parameter, not a search bucket: the controller reads it by hand
1563
+ * and turns it into a `song_id IS NOT NULL` test. Omitting it means both.
1564
+ */
1565
+ readonly source?: "song" | "tool";
1566
+ /** `exact_search[user_id]`. */
1567
+ readonly userId?: Id;
1568
+ /** `modifiers[order]`. Defaults to `"created_at:desc"`. */
1569
+ readonly order?: string;
1570
+ }
1571
+ /**
1572
+ * `oms.admin.vocalSeparations` - **administrators only**. Every separation run
1573
+ * on the server.
1574
+ *
1575
+ * The unprivileged half is `oms.tools.vocalSeparation`, which is scoped to the
1576
+ * caller's own runs and the songs they own.
1577
+ */
1578
+ export declare class AdminVocalSeparationsNamespace extends Resource {
1579
+ /**
1580
+ * `GET /admin/vocal_separations` - every run, newest first.
1581
+ *
1582
+ * A bare JSON array through the generic list DSL, rendered in the extended
1583
+ * view, with ETag and `304`.
1584
+ *
1585
+ * **This listing is not cheap and the cost is not in the database.** The
1586
+ * extended view computes `progress_percent` by calling the separator sidecar,
1587
+ * synchronously, ONCE PER ROW THAT IS `"processing"`. A page with twenty live
1588
+ * runs is twenty sidecar round trips inside one request, and if the sidecar
1589
+ * is slow or down the whole listing is slow with it. Filter to terminal
1590
+ * statuses when you only want history, and keep the page size modest when you
1591
+ * are polling a dashboard.
1592
+ *
1593
+ * @throws {OmsAuthError} 403 for a non-admin.
1594
+ */
1595
+ list(params?: ListAdminVocalSeparationsParams, options?: RequestOptions): Promise<Paginated<AdminVocalSeparation>>;
1596
+ /**
1597
+ * `GET /admin/vocal_separations/:id` - one run, anybody's.
1598
+ *
1599
+ * @throws {OmsApiError} 404 `"Resource not found"`.
1600
+ * @throws {OmsAuthError} 403 for a non-admin.
1601
+ */
1602
+ get(id: Id, options?: RequestOptions): Promise<AdminVocalSeparation>;
1603
+ /**
1604
+ * `POST /admin/vocal_separations/:id/cancel` - stops a run.
1605
+ *
1606
+ * **The row lands on `"failed"`, not on a cancelled status, and there is no
1607
+ * cancelled status for a separation.** The `error` field is set to
1608
+ * `"Canceled by admin"` and that string is the only way to tell an
1609
+ * administrative stop from a genuine failure. Anything counting failures will
1610
+ * count this, so match on the message if that matters.
1611
+ *
1612
+ * A run attached to a song also clears that song's
1613
+ * `vocal_separation_started_at`, which is what lets the owner start a new
1614
+ * separation instead of being told one is already running.
1615
+ *
1616
+ * Like every cancel in this API, it marks the row rather than reaching into
1617
+ * the worker.
1618
+ *
1619
+ * @throws {OmsApiError} 400 `"Already terminal"`; 404 `"Resource not found"`.
1620
+ * @throws {OmsAuthError} 403 for a non-admin.
1621
+ */
1622
+ cancel(id: Id, options?: RequestOptions): Promise<AdminVocalSeparation>;
1623
+ /**
1624
+ * `DELETE /admin/vocal_separations/:id` - deletes a run. Answers `204`, empty.
1625
+ *
1626
+ * The stems go with it: the attached audio is destroyed with the row, and a
1627
+ * complete run's download URLs stop working immediately. Deleting a run that
1628
+ * is still processing does not stop the worker, it removes the row the worker
1629
+ * is going to write to.
1630
+ *
1631
+ * @throws {OmsApiError} 404 `"Resource not found"`.
1632
+ * @throws {OmsAuthError} 403 for a non-admin.
1633
+ */
1634
+ destroy(id: Id, options?: RequestOptions): Promise<void>;
1635
+ }
1636
+ /** What {@link AdminChestsNamespace.stats} answers with. Counts only, never a chest. */
1637
+ export interface AdminChestStats {
1638
+ /** Chests that have not expired. */
1639
+ readonly active_count: number;
1640
+ /** `Chest::GLOBAL_ACTIVE_LIMIT`. Creation is refused server-wide once `active_count` reaches it. */
1641
+ readonly active_limit: number;
1642
+ /** Entries in active chests, split by kind. */
1643
+ readonly entries_file: number;
1644
+ readonly entries_note: number;
1645
+ /** Sum of `current_size` across active chests. */
1646
+ readonly active_size_bytes: number;
1647
+ readonly created_last_1h: number;
1648
+ readonly created_last_24h: number;
1649
+ readonly created_last_7d: number;
1650
+ /** Rounded to two decimals; `0` when there are no active chests. */
1651
+ readonly avg_entries_per_chest: number;
1652
+ /** Rounded to whole bytes; `0` when there are no active chests. */
1653
+ readonly avg_chest_size_bytes: number;
1654
+ /** Active chests with an owner, and without one. */
1655
+ readonly active_auth_count: number;
1656
+ readonly active_anon_count: number;
1657
+ /** Active chests expiring within the next 15 minutes. */
1658
+ readonly expiring_soon: number;
1659
+ /**
1660
+ * Creations per day. Counted over ALL chests, expired ones included, unlike
1661
+ * every other number here.
1662
+ */
1663
+ readonly creations_daily: AdminDailyCount[];
1664
+ }
1665
+ /** Content length distribution, in characters. */
1666
+ export interface AdminNotepadContentSize {
1667
+ /** Rounded to a whole number. `0` when there are no pads. */
1668
+ readonly avg: number;
1669
+ /** Median. Nearest-rank, not interpolated. */
1670
+ readonly p50: number;
1671
+ readonly p95: number;
1672
+ }
1673
+ /** What {@link AdminNotepadsNamespace.stats} answers with. Counts only, never content. */
1674
+ export interface AdminNotepadStats {
1675
+ readonly total: number;
1676
+ /** Pads whose content starts with the client-side encryption marker. */
1677
+ readonly encrypted_count: number;
1678
+ /** Already a percentage, `0` to `100`, one decimal. */
1679
+ readonly encrypted_percent: number;
1680
+ /** Pads longer than 256 characters, i.e. probably not a stray keystroke. */
1681
+ readonly meaningful_count: number;
1682
+ readonly meaningful_percent: number;
1683
+ readonly created_last_24h: number;
1684
+ readonly created_last_7d: number;
1685
+ readonly created_last_30d: number;
1686
+ readonly content_size: AdminNotepadContentSize;
1687
+ /** Clicks on every `n/` short link, i.e. how often pads were opened through their link. */
1688
+ readonly short_link_clicks_total: number;
1689
+ readonly creations_daily: AdminDailyCount[];
1690
+ }
1691
+ /**
1692
+ * `oms.admin.chests` - **administrators only**. Aggregate chest statistics.
1693
+ *
1694
+ * `stats` is the ONLY route: there is no admin listing of chests and no way to
1695
+ * read one from here. A chest is opened by knowing its code, and the admin
1696
+ * surface deliberately does not become a second way in.
1697
+ */
1698
+ export declare class AdminChestsNamespace extends Resource {
1699
+ /**
1700
+ * `GET /admin/chests/stats`.
1701
+ *
1702
+ * Several full-table aggregates in one request. Cheap enough for a dashboard,
1703
+ * not cheap enough for a tight poll.
1704
+ *
1705
+ * @throws {OmsAuthError} 403 for a non-admin.
1706
+ */
1707
+ stats(options?: RequestOptions): Promise<AdminChestStats>;
1708
+ }
1709
+ /**
1710
+ * `oms.admin.notepads` - **administrators only**. Aggregate notepad statistics.
1711
+ *
1712
+ * `stats` is the ONLY route, for the same reason as
1713
+ * {@link AdminChestsNamespace}: a pad's slug IS its authorisation, so there is
1714
+ * no admin listing that would hand out slugs, and no content crosses the wire
1715
+ * here. Only lengths are measured.
1716
+ */
1717
+ export declare class AdminNotepadsNamespace extends Resource {
1718
+ /**
1719
+ * `GET /admin/notepads/stats`.
1720
+ *
1721
+ * The length distribution is computed by pulling `LENGTH(content)` for every
1722
+ * pad and sorting in Ruby, so this request grows linearly with the number of
1723
+ * pads. It is a dashboard call, not a poll.
1724
+ *
1725
+ * @throws {OmsAuthError} 403 for a non-admin.
1726
+ */
1727
+ stats(options?: RequestOptions): Promise<AdminNotepadStats>;
1728
+ }
1729
+ /** One event in the alert catalogue. */
1730
+ export interface AdminEventAlert {
1731
+ /** Stable identifier, e.g. `"oauth_client_created"`. A Ruby symbol on the server, a string here. */
1732
+ readonly event: string;
1733
+ /** Short human label. */
1734
+ readonly label: string;
1735
+ /** What the event means and when it fires. */
1736
+ readonly description: string;
1737
+ /**
1738
+ * The fields the Discord message carries, in order. Always starts with
1739
+ * `"Actor"`, and when {@link AdminEventAlert.includes_geo} is true the next
1740
+ * three are `"IP"`, `"Country"` and `"Network"`.
1741
+ */
1742
+ readonly fields: string[];
1743
+ /** Whether the message carries the actor's IP and its geo enrichment. */
1744
+ readonly includes_geo: boolean;
1745
+ /** Whether this particular event is currently switched on. */
1746
+ readonly enabled: boolean;
1747
+ }
1748
+ /**
1749
+ * What {@link AdminEventAlertsNamespace.list} answers with.
1750
+ *
1751
+ * Self-describing on purpose: the catalogue is built from the server's own
1752
+ * constant, so adding or removing an event needs no client change. Render the
1753
+ * array, do not hardcode the events.
1754
+ */
1755
+ export interface AdminEventAlertsCatalog {
1756
+ /** Whether alerts are actually being sent right now. */
1757
+ readonly delivering: boolean;
1758
+ /**
1759
+ * Whether a webhook URL is configured at all.
1760
+ *
1761
+ * The two booleans are not the same question, and the pair is the diagnosis:
1762
+ * `webhook_configured: false` means nothing was ever set up, while
1763
+ * `webhook_configured: true` with `delivering: false` means it is configured
1764
+ * and switched off (a non-production environment, typically).
1765
+ */
1766
+ readonly webhook_configured: boolean;
1767
+ readonly events: AdminEventAlert[];
1768
+ }
1769
+ /**
1770
+ * `oms.admin.eventAlerts` - **administrators only**. The catalogue of activity
1771
+ * alerts sent to Discord.
1772
+ *
1773
+ * Read-only, and there is exactly one route. Nothing here switches an event on
1774
+ * or off: `enabled` is decided by the server's configuration, and the only way
1775
+ * to change it is to change that. This answers "what would be reported, and is
1776
+ * anything being reported at all".
1777
+ */
1778
+ export declare class AdminEventAlertsNamespace extends Resource {
1779
+ /**
1780
+ * `GET /admin/event_alerts`.
1781
+ *
1782
+ * @throws {OmsAuthError} 403 for a non-admin.
1783
+ */
1784
+ list(options?: RequestOptions): Promise<AdminEventAlertsCatalog>;
1785
+ }
1786
+ /**
1787
+ * The `admin` namespace, reachable as `oms.admin`.
1788
+ *
1789
+ * A container and nothing else: it has no methods of its own, because the
1790
+ * eleven routes underneath it answer to three different publics and putting a
1791
+ * bare `list()` here would hide which one a caller had reached. Read the module
1792
+ * documentation at the top of this file for the table.
1793
+ *
1794
+ * The short version, and the rule to check a call site against:
1795
+ *
1796
+ * ```ts
1797
+ * // Any authenticated user, about themselves:
1798
+ * await oms.admin.myApplications.list(); // clients I registered
1799
+ * await oms.admin.authorizedApplications.list(); // apps I gave access to
1800
+ * await oms.admin.identities.list(); // logins linked to my account
1801
+ *
1802
+ * // Administrators only. Everything below answers 403 to everybody else.
1803
+ * await oms.admin.oauthApplications.pending(); // the review queue
1804
+ * await oms.admin.quotas.get("someone"); // somebody else's ceilings
1805
+ * await oms.admin.jobs.list(); // every job on the server
1806
+ * ```
1807
+ *
1808
+ * A client that is not sure whether the signed-in person is an administrator
1809
+ * should read `group` off `oms.account` once and branch on it, rather than
1810
+ * calling an `/admin/*` route to find out: the `403` is real, cheap to trigger
1811
+ * and easy to mistake for a broken credential.
1812
+ */
1813
+ export declare class AdminNamespace extends Resource {
1814
+ /** Your own registered OAuth clients. Any authenticated user. */
1815
+ readonly myApplications: MyOauthApplicationsNamespace;
1816
+ /** Applications holding a token for your account. Any authenticated user. */
1817
+ readonly authorizedApplications: AuthorizedApplicationsNamespace;
1818
+ /** Social logins linked to your account. Any authenticated user. */
1819
+ readonly identities: LinkedIdentitiesNamespace;
1820
+ /** The OAuth client registry and review queue. **Administrators only.** */
1821
+ readonly oauthApplications: AdminOauthApplicationsNamespace;
1822
+ /** Another person's quota ceilings. **Administrators only.** */
1823
+ readonly quotas: AdminQuotasNamespace;
1824
+ /** Every background job on the server. **Administrators only.** */
1825
+ readonly jobs: AdminJobsNamespace;
1826
+ /** Every public short link and its traffic. **Administrators only.** */
1827
+ readonly shortLinks: AdminShortLinksNamespace;
1828
+ /** Every vocal separation run on the server. **Administrators only.** */
1829
+ readonly vocalSeparations: AdminVocalSeparationsNamespace;
1830
+ /** Aggregate chest statistics. **Administrators only.** */
1831
+ readonly chests: AdminChestsNamespace;
1832
+ /** Aggregate notepad statistics. **Administrators only.** */
1833
+ readonly notepads: AdminNotepadsNamespace;
1834
+ /** The Discord alert catalogue. **Administrators only.** */
1835
+ readonly eventAlerts: AdminEventAlertsNamespace;
1836
+ constructor(http: ConstructorParameters<typeof Resource>[0]);
1837
+ }