@omelhorsite/sdk 0.2.0 → 0.4.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/README.md +112 -130
- package/dist/index.js +4800 -610
- package/dist/types/client.d.ts +60 -3
- package/dist/types/http.d.ts +444 -19
- package/dist/types/index.d.ts +5 -1
- package/dist/types/internal/attachments.d.ts +17 -0
- package/dist/types/internal/helpers.d.ts +9 -0
- package/dist/types/listing.d.ts +90 -0
- package/dist/types/resources/account.d.ts +71 -5
- package/dist/types/resources/admin/authorizedApplications.d.ts +133 -0
- package/dist/types/resources/admin/chests.d.ts +51 -0
- package/dist/types/resources/admin/eventAlerts.d.ts +60 -0
- package/dist/types/resources/admin/identities.d.ts +99 -0
- package/dist/types/resources/admin/index.d.ts +77 -0
- package/dist/types/resources/admin/jobs.d.ts +97 -0
- package/dist/types/resources/admin/myOauthApplications.d.ts +282 -0
- package/dist/types/resources/admin/notepads.d.ts +49 -0
- package/dist/types/resources/admin/oauthApplications.d.ts +309 -0
- package/dist/types/resources/admin/quotas.d.ts +114 -0
- package/dist/types/resources/admin/shortLinks.d.ts +201 -0
- package/dist/types/resources/admin/types.d.ts +222 -0
- package/dist/types/resources/admin/vocalSeparations.d.ts +98 -0
- package/dist/types/resources/admin.d.ts +1841 -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 +844 -0
- package/dist/types/resources/chests.d.ts +54 -3
- package/dist/types/resources/content/analysis.d.ts +62 -0
- package/dist/types/resources/content/blogs.d.ts +471 -0
- package/dist/types/resources/content/feedbacks.d.ts +263 -0
- package/dist/types/resources/content/index.d.ts +52 -0
- package/dist/types/resources/content/intel/articles.d.ts +230 -0
- package/dist/types/resources/content/intel/config.d.ts +135 -0
- package/dist/types/resources/content/intel/index.d.ts +53 -0
- package/dist/types/resources/content/intel/items.d.ts +91 -0
- package/dist/types/resources/content/intel/reports.d.ts +108 -0
- package/dist/types/resources/content/intel/scripts.d.ts +152 -0
- package/dist/types/resources/content/intel/sources.d.ts +236 -0
- package/dist/types/resources/content/intel/stats.d.ts +105 -0
- package/dist/types/resources/content/intel/types.d.ts +86 -0
- package/dist/types/resources/content/jokes.d.ts +93 -0
- package/dist/types/resources/content/notifications.d.ts +147 -0
- package/dist/types/resources/content/serviceUsages.d.ts +73 -0
- package/dist/types/resources/content/servicesStatus.d.ts +194 -0
- package/dist/types/resources/content/siteConfig.d.ts +43 -0
- package/dist/types/resources/content/spaceInvaders.d.ts +154 -0
- package/dist/types/resources/content.d.ts +2775 -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 +69 -25
- package/dist/types/resources/library/annotations.d.ts +162 -0
- package/dist/types/resources/library/books.d.ts +534 -0
- package/dist/types/resources/library/chat.d.ts +259 -0
- package/dist/types/resources/library/index.d.ts +39 -0
- package/dist/types/resources/library/shelves.d.ts +237 -0
- package/dist/types/resources/library/types.d.ts +120 -0
- package/dist/types/resources/library.d.ts +1433 -0
- package/dist/types/resources/linkTrees.d.ts +142 -30
- package/dist/types/resources/media.d.ts +351 -0
- package/dist/types/resources/movies/addons.d.ts +388 -0
- package/dist/types/resources/movies/collections.d.ts +352 -0
- package/dist/types/resources/movies/index.d.ts +29 -0
- package/dist/types/resources/movies/types.d.ts +50 -0
- package/dist/types/resources/movies/watchProgress.d.ts +277 -0
- package/dist/types/resources/movies.d.ts +1160 -0
- package/dist/types/resources/music/artists.d.ts +1068 -0
- package/dist/types/resources/music/imports.d.ts +941 -0
- package/dist/types/resources/music/index.d.ts +61 -0
- package/dist/types/resources/music/playlists.d.ts +1027 -0
- package/dist/types/resources/music/social.d.ts +1132 -0
- package/dist/types/resources/music/songs.d.ts +1167 -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 +49 -5
- package/dist/types/resources/social/groupChats.d.ts +458 -0
- package/dist/types/resources/social/index.d.ts +19 -0
- package/dist/types/resources/social/messages.d.ts +424 -0
- package/dist/types/resources/social/relationships.d.ts +322 -0
- package/dist/types/resources/social/types.d.ts +37 -0
- package/dist/types/resources/social.d.ts +1348 -0
- package/dist/types/resources/storage/upload.d.ts +158 -11
- package/dist/types/resources/storage.d.ts +111 -27
- package/dist/types/resources/tickets.d.ts +101 -13
- 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,17 @@
|
|
|
1
|
+
/** Attachment helpers shared by the message families. Not part of the public surface. */
|
|
2
|
+
import type { ApiClient } from "../http";
|
|
3
|
+
import type { FileInput, NativeFile, RequestOptions } from "../types";
|
|
4
|
+
/**
|
|
5
|
+
* Byte length of an attachment, when it is knowable without reading anything.
|
|
6
|
+
* `undefined` for a stream with no declared `size` and for a picker that
|
|
7
|
+
* reported none.
|
|
8
|
+
*/
|
|
9
|
+
export declare function attachmentSize(file: FileInput | NativeFile): number | undefined;
|
|
10
|
+
/**
|
|
11
|
+
* Follows an attachment redirect. In a browser in cookie mode the redirect
|
|
12
|
+
* to object storage fails CORS and surfaces as a bare network error; that
|
|
13
|
+
* case is turned into an error that says what to do instead.
|
|
14
|
+
*/
|
|
15
|
+
export declare function followAttachment(http: ApiClient, path: string, what: string, options: RequestOptions): Promise<Blob>;
|
|
16
|
+
/** The bearer token the transport would send, or `null` when there is none (cookie mode). */
|
|
17
|
+
export declare function tokenOf(http: ApiClient): Promise<string | null>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Small helpers shared by resource modules. Not part of the public surface. */
|
|
2
|
+
/** Fails fast on a value the server would answer for with a framework error. */
|
|
3
|
+
export declare function assertPresent(field: string, value: string): void;
|
|
4
|
+
/** Copies the keys that were supplied; `undefined` is skipped, an explicit `null` is kept. */
|
|
5
|
+
export declare function pickOptional<T extends object>(source: T, keys: readonly (keyof T & string)[]): Record<string, unknown>;
|
|
6
|
+
/** Normalises a scope list given as an array or as a space/comma separated string. */
|
|
7
|
+
export declare function scopeList(scopes: readonly string[] | string): string[];
|
|
8
|
+
/** Path-safe form of an integer id. */
|
|
9
|
+
export declare function idSegment(id: number): string;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The listing query language every `list()` in the SDK accepts.
|
|
3
|
+
*
|
|
4
|
+
* | wire | meaning |
|
|
5
|
+
* |----------------------------|-----------------------------------------------------------|
|
|
6
|
+
* | `search[col]=v` | partial match; strings are accent- and case-insensitive |
|
|
7
|
+
* | `exact_search[col]=v` | equality; an array is `IN (...)`, `null` is `IS NULL` |
|
|
8
|
+
* | `modifiers[page]=N:SIZE` | 1-based page, `SIZE` capped at 500 |
|
|
9
|
+
* | `modifiers[order]=col:asc` | sort; an unknown column is ignored |
|
|
10
|
+
* | `modifiers[random]=true` | random order; replaces any sort and disables the `ETag` |
|
|
11
|
+
* | `extra_options[key]=v` | endpoint-specific filters, typed per resource |
|
|
12
|
+
*
|
|
13
|
+
* Filter keys are validated by the server: a column outside the endpoint's
|
|
14
|
+
* allowlist is a `400`, never a wider result. Each resource names its columns
|
|
15
|
+
* as a string-literal union so the mistake is caught at compile time instead.
|
|
16
|
+
*
|
|
17
|
+
* Column TYPES are not visible to the compiler. `search` on a number or date
|
|
18
|
+
* column is an exact `IN`, not a prefix; on a string column it compares
|
|
19
|
+
* lower-cased, accent-stripped slugs on both sides.
|
|
20
|
+
*/
|
|
21
|
+
import type { PageParams, Paginated, QueryParams } from "./types";
|
|
22
|
+
/** Columns every listing accepts in `search` and `exactSearch`, whatever else it declares. */
|
|
23
|
+
export declare const BASE_FILTER_COLUMNS: readonly ["id", "created_at", "updated_at"];
|
|
24
|
+
/** One of {@link BASE_FILTER_COLUMNS}. */
|
|
25
|
+
export type BaseFilterColumn = (typeof BASE_FILTER_COLUMNS)[number];
|
|
26
|
+
/** The scalar half of {@link FilterValue}. A `Date` is sent as ISO-8601. */
|
|
27
|
+
export type FilterScalar = string | number | boolean | Date | null;
|
|
28
|
+
/**
|
|
29
|
+
* A filter value. An array is `IN (...)` under `exactSearch` and an OR of
|
|
30
|
+
* partial matches under `search`; `null` means `IS NULL` (only `exactSearch`
|
|
31
|
+
* can express it); `undefined` is not sent.
|
|
32
|
+
*/
|
|
33
|
+
export type FilterValue = FilterScalar | readonly FilterScalar[] | undefined;
|
|
34
|
+
/** Filters keyed by column. `string` is the untyped escape hatch. */
|
|
35
|
+
export type FilterBag<Column extends string = string> = {
|
|
36
|
+
readonly [K in Column]?: FilterValue;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* The parameters every `list()` accepts. Resources extend this with their
|
|
40
|
+
* column union, their `extra_options` shape, and camelCased shortcuts.
|
|
41
|
+
*
|
|
42
|
+
* Shortcuts and buckets may name the same column; the bucket wins, key by
|
|
43
|
+
* key, so `{ userId: "a", exactSearch: { user_id: "b" } }` sends `b`.
|
|
44
|
+
*
|
|
45
|
+
* @typeParam Column columns accepted in `search` / `exactSearch`, on top of
|
|
46
|
+
* {@link BaseFilterColumn}.
|
|
47
|
+
* @typeParam Extra the `extra_options` shape. Defaults to `never`, which makes
|
|
48
|
+
* `extraOptions` unsettable on the endpoints that declare none.
|
|
49
|
+
*/
|
|
50
|
+
export interface ListParams<Column extends string = string, Extra extends object = never> extends PageParams {
|
|
51
|
+
/** Partial match per column. */
|
|
52
|
+
readonly search?: FilterBag<Column | BaseFilterColumn>;
|
|
53
|
+
/** Equality per column. Use it for ids, enums and foreign keys. */
|
|
54
|
+
readonly exactSearch?: FilterBag<Column | BaseFilterColumn>;
|
|
55
|
+
/**
|
|
56
|
+
* Random order. The shuffle is redrawn on every request, so pages overlap;
|
|
57
|
+
* use it for "give me N rows", not for walking a listing.
|
|
58
|
+
*/
|
|
59
|
+
readonly random?: boolean;
|
|
60
|
+
/** Endpoint-specific filters. Typed per resource. */
|
|
61
|
+
readonly extraOptions?: Extra;
|
|
62
|
+
}
|
|
63
|
+
/** What a resource adds to a caller's {@link ListParams} before encoding. */
|
|
64
|
+
export interface ListQueryBase {
|
|
65
|
+
/** Sort applied when the caller gave none. */
|
|
66
|
+
readonly order?: string;
|
|
67
|
+
/** Shortcut-derived `search` keys. The caller's bucket wins. */
|
|
68
|
+
readonly search?: FilterBag;
|
|
69
|
+
/** Shortcut-derived `exact_search` keys. The caller's bucket wins. */
|
|
70
|
+
readonly exactSearch?: FilterBag;
|
|
71
|
+
/** Shortcut-derived `extra_options` keys. The caller's bucket wins. */
|
|
72
|
+
readonly extraOptions?: FilterBag;
|
|
73
|
+
/** Top-level query keys outside the DSL, copied verbatim. */
|
|
74
|
+
readonly top?: QueryParams;
|
|
75
|
+
}
|
|
76
|
+
/** The page a loader is asked for. */
|
|
77
|
+
export interface PageAt {
|
|
78
|
+
readonly page: number;
|
|
79
|
+
readonly pageSize: number;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Encodes one page of a listing as a query bag. Pass `at: undefined` for an
|
|
83
|
+
* endpoint that must see the whole scope rather than a page.
|
|
84
|
+
*/
|
|
85
|
+
export declare function listQuery(params: ListParams<string, object>, at: PageAt | undefined, base?: ListQueryBase): QueryParams;
|
|
86
|
+
/**
|
|
87
|
+
* Loads the first page of a listing and returns it as a {@link Paginated}
|
|
88
|
+
* whose `next()` fetches the following pages at the same size.
|
|
89
|
+
*/
|
|
90
|
+
export declare function paginate<T>(params: PageParams, defaultPageSize: number, load: (at: PageAt) => Promise<readonly T[] | undefined>): Promise<Paginated<T>>;
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
* that a stored credential is still alive.
|
|
8
8
|
*/
|
|
9
9
|
import { type ApiClient, Resource } from "../http";
|
|
10
|
-
import type {
|
|
10
|
+
import type { ListParams } from "../listing";
|
|
11
|
+
import type { BaseRecord, FileInput, Id, Paginated, RequestOptions, Timestamp } from "../types";
|
|
11
12
|
/**
|
|
12
13
|
* A user as the API renders them.
|
|
13
14
|
*
|
|
@@ -178,8 +179,10 @@ export interface AccountSession extends BaseRecord {
|
|
|
178
179
|
/** The owner, rendered inline. */
|
|
179
180
|
readonly user?: User;
|
|
180
181
|
}
|
|
182
|
+
/** Filter columns of `GET /sessions`, on top of {@link BASE_FILTER_COLUMNS}. */
|
|
183
|
+
export declare const ACCOUNT_SESSION_FILTER_COLUMNS: readonly ["user_id"];
|
|
181
184
|
/** Filters for {@link AccountSessionsNamespace.list}. */
|
|
182
|
-
export interface ListAccountSessionsParams extends
|
|
185
|
+
export interface ListAccountSessionsParams extends ListParams<(typeof ACCOUNT_SESSION_FILTER_COLUMNS)[number]> {
|
|
183
186
|
/** Administrators only: someone else's sessions. */
|
|
184
187
|
readonly userId?: Id;
|
|
185
188
|
}
|
|
@@ -283,11 +286,74 @@ export declare class AccountNamespace extends Resource {
|
|
|
283
286
|
/**
|
|
284
287
|
* `GET /users/:id/picture` - the avatar bytes.
|
|
285
288
|
*
|
|
286
|
-
*
|
|
287
|
-
*
|
|
288
|
-
*
|
|
289
|
+
* SENT WITH NO CREDENTIAL AT ALL, and that is the point of this method rather
|
|
290
|
+
* than an oversight.
|
|
291
|
+
*
|
|
292
|
+
* The endpoint is anonymous by design: `UsersController` lists `picture` in
|
|
293
|
+
* `allow_unauthenticated_access`, and `User.viewable_by` is `->(user) { all }`,
|
|
294
|
+
* so a signed-in caller and a stranger resolve the same row and get the same
|
|
295
|
+
* bytes. Sending a credential buys nothing, and it is what breaks the call.
|
|
296
|
+
*
|
|
297
|
+
* Why it breaks. The action answers `302` to `minio.omelhorsite.pt` with a
|
|
298
|
+
* presigned URL, and `fetch` follows that hop. Per the Fetch standard, when a
|
|
299
|
+
* CORS request is redirected cross-origin and the request's origin already
|
|
300
|
+
* differs from the current URL's origin, the origin is replaced by an opaque
|
|
301
|
+
* one - so the second hop reaches the store with `Origin: null`. MinIO
|
|
302
|
+
* answers a null origin with `Access-Control-Allow-Origin: *`. A wildcard is
|
|
303
|
+
* illegal for a credentialed request no matter what
|
|
304
|
+
* `Access-Control-Allow-Credentials` says, so a client built with
|
|
305
|
+
* `sessionCookie: true` - the production web app - would have the browser
|
|
306
|
+
* reject the response before any JavaScript saw it. Every avatar on the page
|
|
307
|
+
* would fail, and fail as an opaque "Failed to fetch".
|
|
308
|
+
*
|
|
309
|
+
* Dropping the credential removes the wildcard problem entirely: an
|
|
310
|
+
* uncredentialed request accepts `*`, so this behaves identically in a
|
|
311
|
+
* browser, in Bun and in a Worker, in cookie mode and in token mode.
|
|
312
|
+
*
|
|
313
|
+
* Going around the transport costs the usual thing, the same trade
|
|
314
|
+
* `storage.download` makes: no retry, no per-call deadline, and only the
|
|
315
|
+
* caller's `signal` is honoured.
|
|
316
|
+
*
|
|
317
|
+
* Prefer {@link pictureUrl} when the avatar is going into an `<img>`. This
|
|
318
|
+
* method is for when the bytes themselves are wanted - a re-upload, a cache,
|
|
319
|
+
* a file written to disk.
|
|
320
|
+
*
|
|
321
|
+
* @throws {OmsApiError} 404 when the user does not exist OR has no avatar
|
|
322
|
+
* attached. The two are not distinguishable from the status alone.
|
|
289
323
|
*/
|
|
290
324
|
picture(id: Id, options?: RequestOptions): Promise<Blob>;
|
|
325
|
+
/**
|
|
326
|
+
* Absolute URL of a user's avatar, for an `<img>`, a CSS `background-image`,
|
|
327
|
+
* or anywhere else the platform fetches the bytes for you.
|
|
328
|
+
*
|
|
329
|
+
* Synchronous, and it has to stay that way. This gets called once per row
|
|
330
|
+
* while rendering a friends list, a member picker or a message thread; an
|
|
331
|
+
* async URL would turn every avatar into a state update and a second paint.
|
|
332
|
+
*
|
|
333
|
+
* It can be synchronous because the route carries no credential: `picture` is
|
|
334
|
+
* in `allow_unauthenticated_access` and `User.viewable_by` is `all`, so there
|
|
335
|
+
* is nothing to resolve and nothing to leak. The URL is safe to put in
|
|
336
|
+
* markup, to log, and to hand to someone else.
|
|
337
|
+
*
|
|
338
|
+
* ```tsx
|
|
339
|
+
* <img src={oms.account.pictureUrl(user.id)} alt={user.handle} />
|
|
340
|
+
* ```
|
|
341
|
+
*
|
|
342
|
+
* Do NOT add a `crossorigin` attribute. Without one the element makes a
|
|
343
|
+
* no-cors request and the `302` to the object store is followed with no CORS
|
|
344
|
+
* check at all, which is why this path has always worked in the web app.
|
|
345
|
+
* `crossorigin="use-credentials"` re-creates exactly the failure
|
|
346
|
+
* {@link picture} documents, and `crossorigin="anonymous"` only buys the
|
|
347
|
+
* ability to read the pixels back out of a canvas.
|
|
348
|
+
*
|
|
349
|
+
* A user with no avatar answers 404, so give the element an `onError` that
|
|
350
|
+
* falls back to initials rather than assuming every id has an image.
|
|
351
|
+
*
|
|
352
|
+
* The `302` itself carries `Cache-Control: private, max-age=300` while the
|
|
353
|
+
* presigned target is good for six hours, so a re-render inside five minutes
|
|
354
|
+
* costs nothing and a cached redirect can never outlive its signature.
|
|
355
|
+
*/
|
|
356
|
+
pictureUrl(id: Id): string;
|
|
291
357
|
/** `POST /users/:id/follow` - returns the followed user's updated profile. */
|
|
292
358
|
follow(id: Id, options?: RequestOptions): Promise<UserProfile>;
|
|
293
359
|
/**
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/** `oms.admin.authorizedApplications` - the applications you gave access to your account. */
|
|
2
|
+
import { Resource } from "../../http";
|
|
3
|
+
import type { RequestOptions, Timestamp } from "../../types";
|
|
4
|
+
import type { OauthApprovalStatus } from "./types";
|
|
5
|
+
/**
|
|
6
|
+
* An application holding a live token for YOUR account.
|
|
7
|
+
*
|
|
8
|
+
* This is OAuth going OUT (a third party acting in your account), which is the
|
|
9
|
+
* opposite direction from {@link LinkedIdentity} - logging IN with Google or
|
|
10
|
+
* Spotify. Two things with similar names that live in the same settings tab.
|
|
11
|
+
*/
|
|
12
|
+
export interface AuthorizedApplication {
|
|
13
|
+
/**
|
|
14
|
+
* The **application** id, not a token id, and an integer like every
|
|
15
|
+
* `oauth_applications` primary key. Revocation is per client on purpose: a
|
|
16
|
+
* person thinks "stop that application", not "kill token 4712".
|
|
17
|
+
*/
|
|
18
|
+
readonly id: number;
|
|
19
|
+
readonly client_id: string;
|
|
20
|
+
readonly name: string;
|
|
21
|
+
/**
|
|
22
|
+
* The scopes of **your tokens**, not of the client's registration.
|
|
23
|
+
*
|
|
24
|
+
* The question this list answers is "what can that application do in MY
|
|
25
|
+
* account", and a client registered for eight scopes may hold a token for
|
|
26
|
+
* two. The union across your tokens, ordered by the server's own scope list
|
|
27
|
+
* so the same set always renders in the same order whatever order the client
|
|
28
|
+
* asked in.
|
|
29
|
+
*/
|
|
30
|
+
readonly scopes: string[];
|
|
31
|
+
/**
|
|
32
|
+
* The client's CURRENT review state, which is not the same question as
|
|
33
|
+
* whether it has access.
|
|
34
|
+
*
|
|
35
|
+
* A client that was approved and later rejected still holds live tokens until
|
|
36
|
+
* they expire, and this listing shows them: it queries the token table
|
|
37
|
+
* directly and never goes through the approval gate, because the person whose
|
|
38
|
+
* account it is has more right to see the access than anyone.
|
|
39
|
+
*/
|
|
40
|
+
readonly approval_status: OauthApprovalStatus;
|
|
41
|
+
/**
|
|
42
|
+
* True for a client this project SHIPS, read off the pinned `client_id` list
|
|
43
|
+
* (`oms-cli`, `oms-mcp`) rather than off `owner_id IS NULL`.
|
|
44
|
+
*
|
|
45
|
+
* The backend deliberately uses the pinned list here, because NULL owner also
|
|
46
|
+
* means "orphaned when its owner deleted their account", and this is the
|
|
47
|
+
* screen where a person decides what to cut off. {@link isShippedClient}
|
|
48
|
+
* computes the same answer from `client_id` alone.
|
|
49
|
+
*/
|
|
50
|
+
readonly first_party: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* How many unrevoked tokens this client holds for you.
|
|
53
|
+
*
|
|
54
|
+
* "Unrevoked", NOT "unexpired", and the difference matters: refresh tokens
|
|
55
|
+
* are on, and a row whose two-hour access token expired an hour ago still
|
|
56
|
+
* buys a fresh one on demand. Counting only unexpired rows would hide exactly
|
|
57
|
+
* the access that most needs revoking.
|
|
58
|
+
*/
|
|
59
|
+
readonly token_count: number;
|
|
60
|
+
/**
|
|
61
|
+
* `created_at` of the most recent of those tokens, `null` if there are none.
|
|
62
|
+
*
|
|
63
|
+
* Read it as "last time this renewed its access", NOT as "authorised since":
|
|
64
|
+
* every refresh writes a new token row, so this moves forward on its own
|
|
65
|
+
* while the client keeps working. The list is sorted by this, newest first.
|
|
66
|
+
*/
|
|
67
|
+
readonly last_authorized_at: Timestamp | null;
|
|
68
|
+
}
|
|
69
|
+
/** What {@link AuthorizedApplicationsNamespace.revoke} answers with. */
|
|
70
|
+
export interface AuthorizedApplicationRevocation {
|
|
71
|
+
/** The application id you asked about, echoed back. */
|
|
72
|
+
readonly id: number;
|
|
73
|
+
/** How many live tokens were killed. `0` when there was nothing to kill. */
|
|
74
|
+
readonly revoked_tokens: number;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* `oms.admin.authorizedApplications` - "which applications have access to my
|
|
78
|
+
* account", and the button that takes it away.
|
|
79
|
+
*
|
|
80
|
+
* Any authenticated user, about their own account only. Nothing here can touch
|
|
81
|
+
* another person's grants: every write is filtered by BOTH the application id
|
|
82
|
+
* and the caller, so an id belonging to somebody else's client can only ever
|
|
83
|
+
* revoke rows the caller owns, which is none.
|
|
84
|
+
*
|
|
85
|
+
* Without this pair of calls, consent would be a one-way door: the device
|
|
86
|
+
* approval page hands out a credential that outlives the browser session, and
|
|
87
|
+
* every consent screen in this product promises the access can be withdrawn
|
|
88
|
+
* later from account settings. These two calls are that promise.
|
|
89
|
+
*/
|
|
90
|
+
export declare class AuthorizedApplicationsNamespace extends Resource {
|
|
91
|
+
/**
|
|
92
|
+
* `GET /authorized_applications` - every application holding a live token for
|
|
93
|
+
* you, most recently renewed first.
|
|
94
|
+
*
|
|
95
|
+
* Always `200`, `[]` included. No pagination: this list has units, not pages.
|
|
96
|
+
* The response is enveloped and this method unwraps it.
|
|
97
|
+
*
|
|
98
|
+
* The listing does NOT filter by approval state. See
|
|
99
|
+
* {@link AuthorizedApplication.approval_status}.
|
|
100
|
+
*/
|
|
101
|
+
list(options?: RequestOptions): Promise<AuthorizedApplication[]>;
|
|
102
|
+
/**
|
|
103
|
+
* `DELETE /authorized_applications/:id` - cuts one application off your
|
|
104
|
+
* account.
|
|
105
|
+
*
|
|
106
|
+
* **Idempotent by construction, and it never answers `404`.** Revoking access
|
|
107
|
+
* that is already gone is a `200` with `revoked_tokens: 0`: your intent
|
|
108
|
+
* ("this must not have access") is satisfied either way, and a `404` for an
|
|
109
|
+
* unknown id would answer "does this client exist?" to anyone willing to
|
|
110
|
+
* count upwards. So a `200` here does not prove the client existed.
|
|
111
|
+
*
|
|
112
|
+
* **What actually dies**, which is more than it looks:
|
|
113
|
+
*
|
|
114
|
+
* - every unrevoked access token of yours for that client. A refresh token is
|
|
115
|
+
* not a row of its own in this system, it is a column ON the access token
|
|
116
|
+
* row, so revoking the row kills the refresh token with it. That is the
|
|
117
|
+
* whole point: a half-done revoke leaves the client walking back in on its
|
|
118
|
+
* next refresh;
|
|
119
|
+
* - every access grant of yours for it;
|
|
120
|
+
* - every device grant you already approved but whose client has not polled
|
|
121
|
+
* the token endpoint yet. Those are tokens waiting to be minted and are
|
|
122
|
+
* easy to forget, so they are deleted outright - a missing device code is
|
|
123
|
+
* the terminal `invalid_grant` a polling client needs to see.
|
|
124
|
+
*
|
|
125
|
+
* Strictly your own rows. Killing every grant a client holds across all users
|
|
126
|
+
* is an administrator's action
|
|
127
|
+
* ({@link AdminOauthApplicationsNamespace.revokeTokens}).
|
|
128
|
+
*
|
|
129
|
+
* The tokens are counted BEFORE the writes, because afterwards there is
|
|
130
|
+
* nothing left to count.
|
|
131
|
+
*/
|
|
132
|
+
revoke(id: number | string, options?: RequestOptions): Promise<AuthorizedApplicationRevocation>;
|
|
133
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/** `oms.admin.chests` - aggregate chest statistics. Administrators only. */
|
|
2
|
+
import { Resource } from "../../http";
|
|
3
|
+
import type { RequestOptions } from "../../types";
|
|
4
|
+
import type { AdminDailyCount } from "./types";
|
|
5
|
+
/** What {@link AdminChestsNamespace.stats} answers with. Counts only, never a chest. */
|
|
6
|
+
export interface AdminChestStats {
|
|
7
|
+
/** Chests that have not expired. */
|
|
8
|
+
readonly active_count: number;
|
|
9
|
+
/** Creation is refused server-wide once `active_count` reaches it. */
|
|
10
|
+
readonly active_limit: number;
|
|
11
|
+
/** Entries in active chests, split by kind. */
|
|
12
|
+
readonly entries_file: number;
|
|
13
|
+
readonly entries_note: number;
|
|
14
|
+
/** Sum of `current_size` across active chests. */
|
|
15
|
+
readonly active_size_bytes: number;
|
|
16
|
+
readonly created_last_1h: number;
|
|
17
|
+
readonly created_last_24h: number;
|
|
18
|
+
readonly created_last_7d: number;
|
|
19
|
+
/** Rounded to two decimals; `0` when there are no active chests. */
|
|
20
|
+
readonly avg_entries_per_chest: number;
|
|
21
|
+
/** Rounded to whole bytes; `0` when there are no active chests. */
|
|
22
|
+
readonly avg_chest_size_bytes: number;
|
|
23
|
+
/** Active chests with an owner, and without one. */
|
|
24
|
+
readonly active_auth_count: number;
|
|
25
|
+
readonly active_anon_count: number;
|
|
26
|
+
/** Active chests expiring within the next 15 minutes. */
|
|
27
|
+
readonly expiring_soon: number;
|
|
28
|
+
/**
|
|
29
|
+
* Creations per day. Counted over ALL chests, expired ones included, unlike
|
|
30
|
+
* every other number here.
|
|
31
|
+
*/
|
|
32
|
+
readonly creations_daily: AdminDailyCount[];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* `oms.admin.chests` - **administrators only**. Aggregate chest statistics.
|
|
36
|
+
*
|
|
37
|
+
* `stats` is the ONLY route: there is no admin listing of chests and no way to
|
|
38
|
+
* read one from here. A chest is opened by knowing its code, and the admin
|
|
39
|
+
* surface deliberately does not become a second way in.
|
|
40
|
+
*/
|
|
41
|
+
export declare class AdminChestsNamespace extends Resource {
|
|
42
|
+
/**
|
|
43
|
+
* `GET /admin/chests/stats`.
|
|
44
|
+
*
|
|
45
|
+
* Several full-table aggregates in one request. Cheap enough for a dashboard,
|
|
46
|
+
* not cheap enough for a tight poll.
|
|
47
|
+
*
|
|
48
|
+
* @throws {OmsAuthError} 403 for a non-admin.
|
|
49
|
+
*/
|
|
50
|
+
stats(options?: RequestOptions): Promise<AdminChestStats>;
|
|
51
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/** `oms.admin.eventAlerts` - the Discord alert catalogue. Administrators only. */
|
|
2
|
+
import { Resource } from "../../http";
|
|
3
|
+
import type { RequestOptions } from "../../types";
|
|
4
|
+
/** One event in the alert catalogue. */
|
|
5
|
+
export interface AdminEventAlert {
|
|
6
|
+
/** Stable identifier, e.g. `"oauth_client_created"`. */
|
|
7
|
+
readonly event: string;
|
|
8
|
+
/** Short human label. */
|
|
9
|
+
readonly label: string;
|
|
10
|
+
/** What the event means and when it fires. */
|
|
11
|
+
readonly description: string;
|
|
12
|
+
/**
|
|
13
|
+
* The fields the Discord message carries, in order. Always starts with
|
|
14
|
+
* `"Actor"`, and when {@link AdminEventAlert.includes_geo} is true the next
|
|
15
|
+
* three are `"IP"`, `"Country"` and `"Network"`.
|
|
16
|
+
*/
|
|
17
|
+
readonly fields: string[];
|
|
18
|
+
/** Whether the message carries the actor's IP and its geo enrichment. */
|
|
19
|
+
readonly includes_geo: boolean;
|
|
20
|
+
/** Whether this particular event is currently switched on. */
|
|
21
|
+
readonly enabled: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* What {@link AdminEventAlertsNamespace.list} answers with.
|
|
25
|
+
*
|
|
26
|
+
* Self-describing on purpose: the catalogue is built by the server, so adding
|
|
27
|
+
* or removing an event needs no client change. Render the array, do not
|
|
28
|
+
* hardcode the events.
|
|
29
|
+
*/
|
|
30
|
+
export interface AdminEventAlertsCatalog {
|
|
31
|
+
/** Whether alerts are actually being sent right now. */
|
|
32
|
+
readonly delivering: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Whether a webhook URL is configured at all.
|
|
35
|
+
*
|
|
36
|
+
* The two booleans are not the same question, and the pair is the diagnosis:
|
|
37
|
+
* `webhook_configured: false` means nothing was ever set up, while
|
|
38
|
+
* `webhook_configured: true` with `delivering: false` means it is configured
|
|
39
|
+
* and switched off (a non-production environment, typically).
|
|
40
|
+
*/
|
|
41
|
+
readonly webhook_configured: boolean;
|
|
42
|
+
readonly events: AdminEventAlert[];
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* `oms.admin.eventAlerts` - **administrators only**. The catalogue of activity
|
|
46
|
+
* alerts sent to Discord.
|
|
47
|
+
*
|
|
48
|
+
* Read-only, and there is exactly one route. Nothing here switches an event on
|
|
49
|
+
* or off: `enabled` is decided by the server's configuration, and the only way
|
|
50
|
+
* to change it is to change that. This answers "what would be reported, and is
|
|
51
|
+
* anything being reported at all".
|
|
52
|
+
*/
|
|
53
|
+
export declare class AdminEventAlertsNamespace extends Resource {
|
|
54
|
+
/**
|
|
55
|
+
* `GET /admin/event_alerts`.
|
|
56
|
+
*
|
|
57
|
+
* @throws {OmsAuthError} 403 for a non-admin.
|
|
58
|
+
*/
|
|
59
|
+
list(options?: RequestOptions): Promise<AdminEventAlertsCatalog>;
|
|
60
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/** `oms.admin.identities` - the social logins linked to your account. */
|
|
2
|
+
import { Resource } from "../../http";
|
|
3
|
+
import type { ListParams } from "../../listing";
|
|
4
|
+
import type { Id, Paginated, RequestOptions, Timestamp } from "../../types";
|
|
5
|
+
/** The identity providers this server accepts. */
|
|
6
|
+
export declare const IDENTITY_PROVIDERS: readonly ["google_oauth2", "github", "spotify"];
|
|
7
|
+
/**
|
|
8
|
+
* One of {@link IDENTITY_PROVIDERS}. Note `"google_oauth2"`, not `"google"`:
|
|
9
|
+
* it is the exact value the server stores and matches on.
|
|
10
|
+
*/
|
|
11
|
+
export type IdentityProvider = (typeof IDENTITY_PROVIDERS)[number];
|
|
12
|
+
/**
|
|
13
|
+
* A social login linked to your account.
|
|
14
|
+
*
|
|
15
|
+
* This is OAuth coming IN - signing in with Google, GitHub or Spotify - and it
|
|
16
|
+
* is the opposite direction from {@link AuthorizedApplication}.
|
|
17
|
+
*
|
|
18
|
+
* Seven fields and NOTHING else, which is the interesting part: the server also
|
|
19
|
+
* holds `uid`, `oauth_token`, `oauth_refresh_token`, `oauth_expires_at` and the
|
|
20
|
+
* entire `raw_info` payload from the provider, and none of them cross the wire.
|
|
21
|
+
* There is no endpoint that will hand you a provider token.
|
|
22
|
+
*/
|
|
23
|
+
export interface LinkedIdentity {
|
|
24
|
+
/** A **string** id, 12 characters. `identities` is not one of the integer tables. */
|
|
25
|
+
readonly id: Id;
|
|
26
|
+
readonly provider: IdentityProvider;
|
|
27
|
+
/**
|
|
28
|
+
* The address the provider asserted, or `null` when it asserted none.
|
|
29
|
+
*
|
|
30
|
+
* Not necessarily the account's own email, and never proof of it: linking a
|
|
31
|
+
* provider to an existing account does not touch `email_verified_at`.
|
|
32
|
+
*/
|
|
33
|
+
readonly email: string | null;
|
|
34
|
+
/** Display name from the provider, or `null`. */
|
|
35
|
+
readonly name: string | null;
|
|
36
|
+
/** Provider avatar URL, or `null`. A remote URL, not something this API serves. */
|
|
37
|
+
readonly avatar_url: string | null;
|
|
38
|
+
readonly created_at: Timestamp;
|
|
39
|
+
readonly updated_at: Timestamp;
|
|
40
|
+
}
|
|
41
|
+
/** Filter columns of `GET /identities`, on top of {@link BASE_FILTER_COLUMNS}. */
|
|
42
|
+
export declare const LINKED_IDENTITY_FILTER_COLUMNS: readonly ["user_id"];
|
|
43
|
+
/** Filters for {@link LinkedIdentitiesNamespace.list}. */
|
|
44
|
+
export interface ListLinkedIdentitiesParams extends ListParams<(typeof LINKED_IDENTITY_FILTER_COLUMNS)[number]> {
|
|
45
|
+
/** Defaults to `"created_at:desc"`. */
|
|
46
|
+
readonly order?: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* `oms.admin.identities` - the Google, GitHub and Spotify logins linked to
|
|
50
|
+
* YOUR account.
|
|
51
|
+
*
|
|
52
|
+
* Any authenticated user, and strictly their own rows: the listing is narrowed
|
|
53
|
+
* to the caller and being an administrator buys nothing extra here. There is no
|
|
54
|
+
* admin view of other people's identities anywhere in this API.
|
|
55
|
+
*
|
|
56
|
+
* **Linking a new provider is not in this SDK and cannot be.** It is a browser
|
|
57
|
+
* redirect flow (`GET /auth/link/:provider` into the provider and back through
|
|
58
|
+
* `/auth/:provider/callback`), it depends on a single-use nonce held in a
|
|
59
|
+
* server-side session, and it ends by redirecting to an allowlisted origin or
|
|
60
|
+
* to the `omsmusic://` scheme. A host that needs it opens a browser; there is
|
|
61
|
+
* nothing here to call. UNLINKING, which is the destructive half, is
|
|
62
|
+
* {@link destroy}.
|
|
63
|
+
*/
|
|
64
|
+
export declare class LinkedIdentitiesNamespace extends Resource {
|
|
65
|
+
/**
|
|
66
|
+
* `GET /identities` - your linked providers.
|
|
67
|
+
*
|
|
68
|
+
* A bare JSON array, not an envelope, unlike the two OAuth application
|
|
69
|
+
* listings above. This one goes through the generic list DSL, so it paginates
|
|
70
|
+
* (default page size applies even when you do not ask) and it answers ETag
|
|
71
|
+
* and `304`.
|
|
72
|
+
*
|
|
73
|
+
* In practice this returns at most three rows, one per provider, since
|
|
74
|
+
* `(provider, uid)` is unique and a person has one account per provider. The
|
|
75
|
+
* pagination is the framework's, not a hint that the list is long.
|
|
76
|
+
*/
|
|
77
|
+
list(params?: ListLinkedIdentitiesParams, options?: RequestOptions): Promise<Paginated<LinkedIdentity>>;
|
|
78
|
+
/**
|
|
79
|
+
* `DELETE /identities/:id` - unlinks a provider. Answers `204`, empty.
|
|
80
|
+
*
|
|
81
|
+
* Only your own: the row is looked up inside your own scope, so somebody
|
|
82
|
+
* else's identity id is a `404` and never a `403`.
|
|
83
|
+
*
|
|
84
|
+
* **This is the last-credential footgun.** Nothing here checks that you still
|
|
85
|
+
* have another way in. An account created through a provider gets a random
|
|
86
|
+
* UUID as its password, which nobody knows, so unlinking the only identity on
|
|
87
|
+
* such an account can lock it out until a password reset is done through
|
|
88
|
+
* email. Check what else the account has - a password, a passkey, another
|
|
89
|
+
* provider - before calling this.
|
|
90
|
+
*
|
|
91
|
+
* It does not revoke anything at the provider, and it does not touch the
|
|
92
|
+
* sessions that identity was used to create. Those keep working; this only
|
|
93
|
+
* removes the link.
|
|
94
|
+
*
|
|
95
|
+
* @throws {OmsApiError} 404 `"Resource not found"` (a bare JSON string, not
|
|
96
|
+
* the structured body the `/oauth_applications` routes use).
|
|
97
|
+
*/
|
|
98
|
+
destroy(id: Id, options?: RequestOptions): Promise<void>;
|
|
99
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/** The `admin` namespace: OAuth client management and the operator surface. */
|
|
2
|
+
import { Resource } from "../../http";
|
|
3
|
+
import { AuthorizedApplicationsNamespace } from "./authorizedApplications";
|
|
4
|
+
import { AdminChestsNamespace } from "./chests";
|
|
5
|
+
import { AdminEventAlertsNamespace } from "./eventAlerts";
|
|
6
|
+
import { LinkedIdentitiesNamespace } from "./identities";
|
|
7
|
+
import { AdminJobsNamespace } from "./jobs";
|
|
8
|
+
import { MyOauthApplicationsNamespace } from "./myOauthApplications";
|
|
9
|
+
import { AdminNotepadsNamespace } from "./notepads";
|
|
10
|
+
import { AdminOauthApplicationsNamespace } from "./oauthApplications";
|
|
11
|
+
import { AdminQuotasNamespace } from "./quotas";
|
|
12
|
+
import { AdminShortLinksNamespace } from "./shortLinks";
|
|
13
|
+
import { AdminVocalSeparationsNamespace } from "./vocalSeparations";
|
|
14
|
+
export * from "./authorizedApplications";
|
|
15
|
+
export * from "./chests";
|
|
16
|
+
export * from "./eventAlerts";
|
|
17
|
+
export * from "./identities";
|
|
18
|
+
export * from "./jobs";
|
|
19
|
+
export * from "./myOauthApplications";
|
|
20
|
+
export * from "./notepads";
|
|
21
|
+
export * from "./oauthApplications";
|
|
22
|
+
export * from "./quotas";
|
|
23
|
+
export * from "./shortLinks";
|
|
24
|
+
export * from "./types";
|
|
25
|
+
export * from "./vocalSeparations";
|
|
26
|
+
/**
|
|
27
|
+
* The `admin` namespace, reachable as `oms.admin`.
|
|
28
|
+
*
|
|
29
|
+
* A container and nothing else: it has no methods of its own, because the
|
|
30
|
+
* eleven routes underneath it answer to three different publics and putting a
|
|
31
|
+
* bare `list()` here would hide which one a caller had reached. Read the module
|
|
32
|
+
* documentation at the top of this file for the table.
|
|
33
|
+
*
|
|
34
|
+
* The short version, and the rule to check a call site against:
|
|
35
|
+
*
|
|
36
|
+
* ```ts
|
|
37
|
+
* // Any authenticated user, about themselves:
|
|
38
|
+
* await oms.admin.myApplications.list(); // clients I registered
|
|
39
|
+
* await oms.admin.authorizedApplications.list(); // apps I gave access to
|
|
40
|
+
* await oms.admin.identities.list(); // logins linked to my account
|
|
41
|
+
*
|
|
42
|
+
* // Administrators only. Everything below answers 403 to everybody else.
|
|
43
|
+
* await oms.admin.oauthApplications.pending(); // the review queue
|
|
44
|
+
* await oms.admin.quotas.get("someone"); // somebody else's ceilings
|
|
45
|
+
* await oms.admin.jobs.list(); // every job on the server
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* A client that is not sure whether the signed-in person is an administrator
|
|
49
|
+
* should read `group` off `oms.account` once and branch on it, rather than
|
|
50
|
+
* calling an `/admin/*` route to find out: the `403` is real, cheap to trigger
|
|
51
|
+
* and easy to mistake for a broken credential.
|
|
52
|
+
*/
|
|
53
|
+
export declare class AdminNamespace extends Resource {
|
|
54
|
+
/** Your own registered OAuth clients. Any authenticated user. */
|
|
55
|
+
readonly myApplications: MyOauthApplicationsNamespace;
|
|
56
|
+
/** Applications holding a token for your account. Any authenticated user. */
|
|
57
|
+
readonly authorizedApplications: AuthorizedApplicationsNamespace;
|
|
58
|
+
/** Social logins linked to your account. Any authenticated user. */
|
|
59
|
+
readonly identities: LinkedIdentitiesNamespace;
|
|
60
|
+
/** The OAuth client registry and review queue. **Administrators only.** */
|
|
61
|
+
readonly oauthApplications: AdminOauthApplicationsNamespace;
|
|
62
|
+
/** Another person's quota ceilings. **Administrators only.** */
|
|
63
|
+
readonly quotas: AdminQuotasNamespace;
|
|
64
|
+
/** Every background job on the server. **Administrators only.** */
|
|
65
|
+
readonly jobs: AdminJobsNamespace;
|
|
66
|
+
/** Every public short link and its traffic. **Administrators only.** */
|
|
67
|
+
readonly shortLinks: AdminShortLinksNamespace;
|
|
68
|
+
/** Every vocal separation run on the server. **Administrators only.** */
|
|
69
|
+
readonly vocalSeparations: AdminVocalSeparationsNamespace;
|
|
70
|
+
/** Aggregate chest statistics. **Administrators only.** */
|
|
71
|
+
readonly chests: AdminChestsNamespace;
|
|
72
|
+
/** Aggregate notepad statistics. **Administrators only.** */
|
|
73
|
+
readonly notepads: AdminNotepadsNamespace;
|
|
74
|
+
/** The Discord alert catalogue. **Administrators only.** */
|
|
75
|
+
readonly eventAlerts: AdminEventAlertsNamespace;
|
|
76
|
+
constructor(http: ConstructorParameters<typeof Resource>[0]);
|
|
77
|
+
}
|