@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.
Files changed (96) hide show
  1. package/README.md +112 -130
  2. package/dist/index.js +4800 -610
  3. package/dist/types/client.d.ts +60 -3
  4. package/dist/types/http.d.ts +444 -19
  5. package/dist/types/index.d.ts +5 -1
  6. package/dist/types/internal/attachments.d.ts +17 -0
  7. package/dist/types/internal/helpers.d.ts +9 -0
  8. package/dist/types/listing.d.ts +90 -0
  9. package/dist/types/resources/account.d.ts +71 -5
  10. package/dist/types/resources/admin/authorizedApplications.d.ts +133 -0
  11. package/dist/types/resources/admin/chests.d.ts +51 -0
  12. package/dist/types/resources/admin/eventAlerts.d.ts +60 -0
  13. package/dist/types/resources/admin/identities.d.ts +99 -0
  14. package/dist/types/resources/admin/index.d.ts +77 -0
  15. package/dist/types/resources/admin/jobs.d.ts +97 -0
  16. package/dist/types/resources/admin/myOauthApplications.d.ts +282 -0
  17. package/dist/types/resources/admin/notepads.d.ts +49 -0
  18. package/dist/types/resources/admin/oauthApplications.d.ts +309 -0
  19. package/dist/types/resources/admin/quotas.d.ts +114 -0
  20. package/dist/types/resources/admin/shortLinks.d.ts +201 -0
  21. package/dist/types/resources/admin/types.d.ts +222 -0
  22. package/dist/types/resources/admin/vocalSeparations.d.ts +98 -0
  23. package/dist/types/resources/admin.d.ts +1841 -0
  24. package/dist/types/resources/auth/index.d.ts +39 -0
  25. package/dist/types/resources/auth/passkeys.d.ts +652 -0
  26. package/dist/types/resources/auth/sessions.d.ts +844 -0
  27. package/dist/types/resources/chests.d.ts +54 -3
  28. package/dist/types/resources/content/analysis.d.ts +62 -0
  29. package/dist/types/resources/content/blogs.d.ts +471 -0
  30. package/dist/types/resources/content/feedbacks.d.ts +263 -0
  31. package/dist/types/resources/content/index.d.ts +52 -0
  32. package/dist/types/resources/content/intel/articles.d.ts +230 -0
  33. package/dist/types/resources/content/intel/config.d.ts +135 -0
  34. package/dist/types/resources/content/intel/index.d.ts +53 -0
  35. package/dist/types/resources/content/intel/items.d.ts +91 -0
  36. package/dist/types/resources/content/intel/reports.d.ts +108 -0
  37. package/dist/types/resources/content/intel/scripts.d.ts +152 -0
  38. package/dist/types/resources/content/intel/sources.d.ts +236 -0
  39. package/dist/types/resources/content/intel/stats.d.ts +105 -0
  40. package/dist/types/resources/content/intel/types.d.ts +86 -0
  41. package/dist/types/resources/content/jokes.d.ts +93 -0
  42. package/dist/types/resources/content/notifications.d.ts +147 -0
  43. package/dist/types/resources/content/serviceUsages.d.ts +73 -0
  44. package/dist/types/resources/content/servicesStatus.d.ts +194 -0
  45. package/dist/types/resources/content/siteConfig.d.ts +43 -0
  46. package/dist/types/resources/content/spaceInvaders.d.ts +154 -0
  47. package/dist/types/resources/content.d.ts +2775 -0
  48. package/dist/types/resources/dynamicQrs.d.ts +39 -3
  49. package/dist/types/resources/forms.d.ts +176 -35
  50. package/dist/types/resources/index.d.ts +19 -8
  51. package/dist/types/resources/ipLookup.d.ts +20 -4
  52. package/dist/types/resources/jobs.d.ts +69 -25
  53. package/dist/types/resources/library/annotations.d.ts +162 -0
  54. package/dist/types/resources/library/books.d.ts +534 -0
  55. package/dist/types/resources/library/chat.d.ts +259 -0
  56. package/dist/types/resources/library/index.d.ts +39 -0
  57. package/dist/types/resources/library/shelves.d.ts +237 -0
  58. package/dist/types/resources/library/types.d.ts +120 -0
  59. package/dist/types/resources/library.d.ts +1433 -0
  60. package/dist/types/resources/linkTrees.d.ts +142 -30
  61. package/dist/types/resources/media.d.ts +351 -0
  62. package/dist/types/resources/movies/addons.d.ts +388 -0
  63. package/dist/types/resources/movies/collections.d.ts +352 -0
  64. package/dist/types/resources/movies/index.d.ts +29 -0
  65. package/dist/types/resources/movies/types.d.ts +50 -0
  66. package/dist/types/resources/movies/watchProgress.d.ts +277 -0
  67. package/dist/types/resources/movies.d.ts +1160 -0
  68. package/dist/types/resources/music/artists.d.ts +1068 -0
  69. package/dist/types/resources/music/imports.d.ts +941 -0
  70. package/dist/types/resources/music/index.d.ts +61 -0
  71. package/dist/types/resources/music/playlists.d.ts +1027 -0
  72. package/dist/types/resources/music/social.d.ts +1132 -0
  73. package/dist/types/resources/music/songs.d.ts +1167 -0
  74. package/dist/types/resources/notepads.d.ts +4 -1
  75. package/dist/types/resources/quotas.d.ts +7 -1
  76. package/dist/types/resources/realtime.d.ts +855 -0
  77. package/dist/types/resources/shortLinks.d.ts +49 -5
  78. package/dist/types/resources/social/groupChats.d.ts +458 -0
  79. package/dist/types/resources/social/index.d.ts +19 -0
  80. package/dist/types/resources/social/messages.d.ts +424 -0
  81. package/dist/types/resources/social/relationships.d.ts +322 -0
  82. package/dist/types/resources/social/types.d.ts +37 -0
  83. package/dist/types/resources/social.d.ts +1348 -0
  84. package/dist/types/resources/storage/upload.d.ts +158 -11
  85. package/dist/types/resources/storage.d.ts +111 -27
  86. package/dist/types/resources/tickets.d.ts +101 -13
  87. package/dist/types/resources/tools/backgroundRemoval.d.ts +18 -3
  88. package/dist/types/resources/tools/captions.d.ts +448 -21
  89. package/dist/types/resources/tools/downloader.d.ts +21 -0
  90. package/dist/types/resources/tools/index.d.ts +57 -15
  91. package/dist/types/resources/tools/jumpstyle.d.ts +50 -17
  92. package/dist/types/resources/tools/transcription.d.ts +35 -13
  93. package/dist/types/resources/tools/upscale.d.ts +23 -3
  94. package/dist/types/resources/tools/vocalSeparation.d.ts +30 -13
  95. package/dist/types/types.d.ts +249 -17
  96. 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 { BaseRecord, FileInput, Id, Paginated, PageParams, RequestOptions, Timestamp } from "../types";
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 PageParams {
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
- * Answers 302 towards object storage and `fetch` follows it; the platform
287
- * drops `Authorization` on the cross-origin hop, so the credential never
288
- * reaches the storage host. Answers 404 when the user has no avatar.
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
+ }