@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.
- package/dist/index.js +4939 -552
- package/dist/types/client.d.ts +60 -3
- package/dist/types/http.d.ts +444 -19
- package/dist/types/index.d.ts +4 -1
- package/dist/types/resources/account.d.ts +66 -3
- package/dist/types/resources/admin.d.ts +1837 -0
- package/dist/types/resources/auth/index.d.ts +39 -0
- package/dist/types/resources/auth/passkeys.d.ts +652 -0
- package/dist/types/resources/auth/sessions.d.ts +847 -0
- package/dist/types/resources/chests.d.ts +54 -3
- package/dist/types/resources/content.d.ts +2970 -0
- package/dist/types/resources/dynamicQrs.d.ts +39 -3
- package/dist/types/resources/forms.d.ts +176 -35
- package/dist/types/resources/index.d.ts +19 -8
- package/dist/types/resources/ipLookup.d.ts +20 -4
- package/dist/types/resources/jobs.d.ts +62 -21
- package/dist/types/resources/library.d.ts +1435 -0
- package/dist/types/resources/linkTrees.d.ts +142 -30
- package/dist/types/resources/media.d.ts +351 -0
- package/dist/types/resources/movies.d.ts +1186 -0
- package/dist/types/resources/music/artists.d.ts +1066 -0
- package/dist/types/resources/music/imports.d.ts +940 -0
- package/dist/types/resources/music/index.d.ts +61 -0
- package/dist/types/resources/music/playlists.d.ts +1026 -0
- package/dist/types/resources/music/social.d.ts +1132 -0
- package/dist/types/resources/music/songs.d.ts +1183 -0
- package/dist/types/resources/notepads.d.ts +4 -1
- package/dist/types/resources/quotas.d.ts +7 -1
- package/dist/types/resources/realtime.d.ts +855 -0
- package/dist/types/resources/shortLinks.d.ts +45 -4
- package/dist/types/resources/social.d.ts +1330 -0
- package/dist/types/resources/storage/upload.d.ts +158 -11
- package/dist/types/resources/storage.d.ts +88 -22
- package/dist/types/resources/tickets.d.ts +82 -3
- package/dist/types/resources/tools/backgroundRemoval.d.ts +18 -3
- package/dist/types/resources/tools/captions.d.ts +448 -21
- package/dist/types/resources/tools/downloader.d.ts +21 -0
- package/dist/types/resources/tools/index.d.ts +57 -15
- package/dist/types/resources/tools/jumpstyle.d.ts +50 -17
- package/dist/types/resources/tools/transcription.d.ts +35 -13
- package/dist/types/resources/tools/upscale.d.ts +23 -3
- package/dist/types/resources/tools/vocalSeparation.d.ts +30 -13
- package/dist/types/types.d.ts +249 -17
- 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
|
+
}
|