@omelhorsite/sdk 0.1.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 (36) hide show
  1. package/README.md +321 -0
  2. package/dist/index.js +11589 -0
  3. package/dist/types/auth/device.d.ts +156 -0
  4. package/dist/types/auth/index.d.ts +127 -0
  5. package/dist/types/auth/tokens.d.ts +356 -0
  6. package/dist/types/client.d.ts +133 -0
  7. package/dist/types/errors.d.ts +202 -0
  8. package/dist/types/http.d.ts +204 -0
  9. package/dist/types/index.d.ts +33 -0
  10. package/dist/types/local/index.d.ts +42 -0
  11. package/dist/types/local/password.d.ts +169 -0
  12. package/dist/types/local/qr.d.ts +127 -0
  13. package/dist/types/local/wordlist.d.ts +26 -0
  14. package/dist/types/resources/account.d.ts +296 -0
  15. package/dist/types/resources/chests.d.ts +194 -0
  16. package/dist/types/resources/dynamicQrs.d.ts +172 -0
  17. package/dist/types/resources/forms.d.ts +331 -0
  18. package/dist/types/resources/index.d.ts +30 -0
  19. package/dist/types/resources/ipLookup.d.ts +63 -0
  20. package/dist/types/resources/jobs.d.ts +233 -0
  21. package/dist/types/resources/linkTrees.d.ts +249 -0
  22. package/dist/types/resources/notepads.d.ts +96 -0
  23. package/dist/types/resources/shortLinks.d.ts +248 -0
  24. package/dist/types/resources/storage/upload.d.ts +459 -0
  25. package/dist/types/resources/storage.d.ts +527 -0
  26. package/dist/types/resources/tickets.d.ts +236 -0
  27. package/dist/types/resources/tools/backgroundRemoval.d.ts +99 -0
  28. package/dist/types/resources/tools/captions.d.ts +318 -0
  29. package/dist/types/resources/tools/downloader.d.ts +397 -0
  30. package/dist/types/resources/tools/index.d.ts +215 -0
  31. package/dist/types/resources/tools/jumpstyle.d.ts +194 -0
  32. package/dist/types/resources/tools/transcription.d.ts +178 -0
  33. package/dist/types/resources/tools/upscale.d.ts +94 -0
  34. package/dist/types/resources/tools/vocalSeparation.d.ts +183 -0
  35. package/dist/types/types.d.ts +245 -0
  36. package/package.json +37 -0
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Password and passphrase generation. Local, offline, no credential.
3
+ *
4
+ * Randomness comes from `crypto.getRandomValues`, which every target runtime
5
+ * has (browser, Worker, Bun, Node 19+). `Math.random` is NEVER acceptable here
6
+ * and no fallback to it exists: if the platform has no WebCrypto, these
7
+ * functions throw rather than quietly producing a guessable string.
8
+ *
9
+ * Selecting a character from an alphabet must use rejection sampling, not
10
+ * `random % alphabet.length`: the modulo skews the distribution towards the
11
+ * first `2^n mod len` characters, which is exactly the bias an attacker's
12
+ * dictionary is built around.
13
+ */
14
+ export { EFF_LONG_WORDLIST } from "./wordlist";
15
+ /** Which character classes a generated password may draw from. */
16
+ export interface PasswordAlphabet {
17
+ /** `a-z`. Defaults to true. */
18
+ readonly lowercase?: boolean;
19
+ /** `A-Z`. Defaults to true. */
20
+ readonly uppercase?: boolean;
21
+ /** `0-9`. Defaults to true. */
22
+ readonly digits?: boolean;
23
+ /** Punctuation. Defaults to true. See {@link SYMBOLS} for what is in it. */
24
+ readonly symbols?: boolean;
25
+ /**
26
+ * Drop characters that are hard to tell apart when read aloud or off a
27
+ * screen: `0O1lI|`. Defaults to false. Costs about 0.4 bits per character at
28
+ * the full alphabet, which four extra characters of length more than repay.
29
+ */
30
+ readonly avoidAmbiguous?: boolean;
31
+ /**
32
+ * Extra characters to allow, beyond the classes above. Duplicates - of each
33
+ * other or of a class already enabled - are collapsed, so a character cannot
34
+ * be listed twice and skew the draw towards itself.
35
+ */
36
+ readonly extra?: string;
37
+ }
38
+ /** Options for {@link generatePassword}. */
39
+ export interface GeneratePasswordOptions extends PasswordAlphabet {
40
+ /** Characters to produce. Defaults to 20. */
41
+ readonly length?: number;
42
+ /**
43
+ * Guarantee at least one character from every enabled class.
44
+ *
45
+ * Defaults to true because password policies demand it. It costs a little
46
+ * entropy: the result is a uniform draw from a smaller set, not from the
47
+ * full alphabet. {@link passwordEntropyBits} accounts for the alphabet only,
48
+ * so it slightly overstates a password generated this way.
49
+ *
50
+ * `extra` is not a class and is never forced.
51
+ */
52
+ readonly requireEachClass?: boolean;
53
+ }
54
+ /** Options for {@link generatePassphrase}. */
55
+ export interface GeneratePassphraseOptions {
56
+ /** Words to join. Defaults to 5, which is the point where these get strong. */
57
+ readonly words?: number;
58
+ /** Separator between words. Defaults to `"-"`. */
59
+ readonly separator?: string;
60
+ /** Capitalise the first letter of each word. Defaults to false. */
61
+ readonly capitalize?: boolean;
62
+ /**
63
+ * Append a random digit to one of the words, for policies that demand one.
64
+ * Worth about 3.3 bits plus the choice of which word; it is a compliance
65
+ * feature, not a security one.
66
+ */
67
+ readonly includeNumber?: boolean;
68
+ /**
69
+ * Word list to draw from. Defaults to {@link EFF_LONG_WORDLIST}. Supply your
70
+ * own to generate in another language - the strength then follows YOUR list's
71
+ * size, so a 200-word list makes a weak passphrase however many words you ask
72
+ * for. Duplicate entries are not removed and would bias the draw.
73
+ */
74
+ readonly wordlist?: readonly string[];
75
+ }
76
+ /** How strong a password looks, for a meter in a UI. */
77
+ export interface PasswordStrength {
78
+ /** Shannon entropy of the generator that could have produced it, in bits. */
79
+ readonly bits: number;
80
+ /** Coarse bucket derived from `bits`, for colouring a bar. */
81
+ readonly label: "very-weak" | "weak" | "fair" | "strong" | "very-strong";
82
+ /** Which classes appear in the string. */
83
+ readonly classes: {
84
+ readonly lowercase: boolean;
85
+ readonly uppercase: boolean;
86
+ readonly digits: boolean;
87
+ /** True for any character that is not an ASCII letter or digit, accents included. */
88
+ readonly symbols: boolean;
89
+ };
90
+ /** Distinct characters used. A long password of two characters is not long. */
91
+ readonly uniqueChars: number;
92
+ }
93
+ /**
94
+ * Generates a random password.
95
+ *
96
+ * ```ts
97
+ * generatePassword(); // 20 chars, all classes
98
+ * generatePassword({ length: 32, symbols: false }); // alphanumeric only
99
+ * generatePassword({ length: 16, avoidAmbiguous: true }); // safe to read aloud
100
+ * ```
101
+ *
102
+ * @throws {RangeError} when `length` is not a positive integer, when the
103
+ * options leave no characters to draw from, or when `requireEachClass` needs
104
+ * more characters than `length` allows.
105
+ * @throws {Error} when the runtime has no `crypto.getRandomValues`.
106
+ */
107
+ export declare function generatePassword(options?: GeneratePasswordOptions): string;
108
+ /**
109
+ * Generates a passphrase from a word list.
110
+ *
111
+ * ```ts
112
+ * generatePassphrase(); // "cactus-mural-...-..."
113
+ * generatePassphrase({ words: 7, separator: " " });
114
+ * ```
115
+ *
116
+ * Words are drawn WITH replacement, so a word can repeat. That is deliberate:
117
+ * drawing without replacement would make each word depend on the ones before
118
+ * it and quietly lower the entropy of the phrase.
119
+ *
120
+ * @throws {RangeError} when `words` is not a positive integer or the word list
121
+ * is empty.
122
+ * @throws {Error} when the runtime has no `crypto.getRandomValues`.
123
+ */
124
+ export declare function generatePassphrase(options?: GeneratePassphraseOptions): string;
125
+ /**
126
+ * Describes a password's strength.
127
+ *
128
+ * This is an ENTROPY ESTIMATE of the alphabet, not a crack-time prediction: it
129
+ * cannot tell that `"Password123!"` is in every dictionary on earth, and it
130
+ * will happily call it fair. Present it as a hint, never as a verdict, and
131
+ * never as a gate on what a user may choose.
132
+ *
133
+ * A passphrase is measured by its characters, not by its words, so
134
+ * {@link generatePassphrase} output reads as far stronger here than its real
135
+ * per-word entropy. Use `words * log2(wordlist.length)` for those instead.
136
+ */
137
+ export declare function passwordStrength(password: string): PasswordStrength;
138
+ /**
139
+ * Bits of entropy in `length` characters drawn uniformly from an alphabet of
140
+ * `alphabetSize`: `length * log2(alphabetSize)`.
141
+ *
142
+ * Returns `0` rather than throwing for a degenerate input (empty password, an
143
+ * alphabet of one character), because a one-character alphabet genuinely
144
+ * carries no information and a meter should show zero, not blow up.
145
+ */
146
+ export declare function passwordEntropyBits(length: number, alphabetSize: number): number;
147
+ /**
148
+ * Builds the character pool a {@link PasswordAlphabet} describes.
149
+ *
150
+ * Exported so a caller can show the user exactly what the generator will draw
151
+ * from, and so the tests can assert the ambiguity filter.
152
+ *
153
+ * Returns an empty string when the options enable nothing - it describes, it
154
+ * does not validate. {@link generatePassword} is where that becomes an error.
155
+ */
156
+ export declare function buildAlphabet(options?: PasswordAlphabet): string;
157
+ /**
158
+ * Uniform random integer in `[0, max)` from `crypto.getRandomValues`, using
159
+ * rejection sampling so the distribution has no modulo bias.
160
+ *
161
+ * The loop is unbounded on purpose. It rejects at most `max / 2^32` of its
162
+ * draws, which for every alphabet in this module is far below one in a
163
+ * thousand, so it terminates immediately in practice and stays correct rather
164
+ * than falling back to a biased answer after N tries.
165
+ *
166
+ * @throws {RangeError} when `max` is not an integer in `[1, 2^32]`.
167
+ * @throws {Error} when the runtime has no `crypto.getRandomValues`.
168
+ */
169
+ export declare function randomInt(max: number): number;
@@ -0,0 +1,127 @@
1
+ /**
2
+ * QR code encoding. Local, offline, no credential.
3
+ *
4
+ * This module encodes a payload into a module matrix and renders it as SVG.
5
+ * That is the whole isolate-safe surface: SVG is text, so it works in a Worker,
6
+ * in the CLI and in a browser alike.
7
+ *
8
+ * Raster output (PNG, JPEG) is deliberately NOT here. It needs a canvas or an
9
+ * image encoder, neither of which every target runtime has, and the host
10
+ * already knows which it owns. Hand the host the matrix or the SVG and let it
11
+ * rasterise.
12
+ *
13
+ * Encoding a QR symbol correctly (mode selection, Reed-Solomon over GF(256),
14
+ * mask scoring against the four penalty rules) is not something to hand-roll,
15
+ * so the encoder is `uqr`: MIT, zero runtime dependencies, pure TypeScript, and
16
+ * it imports no `node:*` builtin and touches no DOM - which is why it, rather
17
+ * than the older `qrcode-generator`, is the one dependency the core has. The
18
+ * rendering below is ours, because `uqr`'s own `renderSVG` emits one `<rect>`
19
+ * per module and offers no margin, shape or transparency control.
20
+ *
21
+ * Note the split of responsibilities with `oms.dynamicQrs`: this module draws
22
+ * the image, that namespace manages the redirect the image points at. For a
23
+ * dynamic code, encode `oms.dynamicQrs.publicUrl(qr)` here - never `qr.url`, or
24
+ * the whole point of a re-pointable code is lost.
25
+ */
26
+ /** Error-correction level. Higher survives more damage and more logo. */
27
+ export type QrErrorCorrection = "L" | "M" | "Q" | "H";
28
+ /** Options for {@link encodeQr}. */
29
+ export interface EncodeQrOptions {
30
+ /** Defaults to `"M"`. Use `"H"` when a logo covers the middle. */
31
+ readonly ecc?: QrErrorCorrection;
32
+ /**
33
+ * Force a symbol version (1 to 40). Omit to let the encoder pick the
34
+ * smallest that fits, which is almost always what you want. Forcing a
35
+ * version that the payload does not fit in is a {@link RangeError}, not a
36
+ * silent upgrade.
37
+ */
38
+ readonly version?: number;
39
+ }
40
+ /** An encoded QR symbol, as a square grid of modules. */
41
+ export interface QrMatrix {
42
+ /** Modules per side, quiet zone excluded. `21 + 4 * (version - 1)`. */
43
+ readonly size: number;
44
+ /**
45
+ * Row-major, `size * size` entries. `true` is a dark module.
46
+ *
47
+ * Flat rather than nested so it can be walked without allocating a row array
48
+ * per line; index `y * size + x`.
49
+ */
50
+ readonly modules: ReadonlyArray<boolean>;
51
+ readonly version: number;
52
+ readonly ecc: QrErrorCorrection;
53
+ }
54
+ /** Options for {@link qrToSvg}. */
55
+ export interface QrSvgOptions {
56
+ /**
57
+ * Quiet zone in modules. Defaults to 4, which is what the specification
58
+ * requires; scanners genuinely fail without it.
59
+ */
60
+ readonly margin?: number;
61
+ /** Dark module colour. Defaults to `"#000000"`. */
62
+ readonly color?: string;
63
+ /**
64
+ * Light module colour. Defaults to `"#ffffff"`. Pass `"transparent"` for a
65
+ * background-free symbol; contrast is then the caller's problem, and a dark
66
+ * symbol on a dark page does not scan.
67
+ */
68
+ readonly background?: string;
69
+ /**
70
+ * Pixel size of the `width`/`height` attributes. Omit to emit a `viewBox`
71
+ * only, which scales to whatever box it is dropped into.
72
+ */
73
+ readonly size?: number;
74
+ /**
75
+ * Module shape. `"square"` is the safe default; `"rounded"` and `"dots"`
76
+ * shrink the effective dark area and can push a low-ECC symbol below what a
77
+ * phone camera will read. Raise `ecc` when you use them.
78
+ */
79
+ readonly shape?: "square" | "rounded" | "dots";
80
+ }
81
+ /**
82
+ * Encodes a payload into a QR matrix.
83
+ *
84
+ * ```ts
85
+ * const qr = encodeQr("https://omelhor.site/abc");
86
+ * qr.size; // 25 for a version-2 symbol
87
+ * qr.modules[y * qr.size + x]; // true where the module is dark
88
+ * ```
89
+ *
90
+ * The matrix carries NO quiet zone: {@link qrToSvg} adds one, and a caller
91
+ * rendering the matrix by hand must add its own or the symbol will not scan.
92
+ *
93
+ * @param data The payload. A URL, plain text, a `WIFI:` string, whatever. The
94
+ * encoder picks the mode (numeric, alphanumeric, byte) that fits it best.
95
+ * @throws {RangeError} when the payload does not fit at the requested version
96
+ * and error-correction level, or when `version` is outside 1-40.
97
+ */
98
+ export declare function encodeQr(data: string, options?: EncodeQrOptions): QrMatrix;
99
+ /**
100
+ * Renders a matrix, or a payload, as an SVG document string.
101
+ *
102
+ * ```ts
103
+ * const svg = qrToSvg("https://omelhor.site/abc", { ecc: "H", size: 512 });
104
+ * ```
105
+ *
106
+ * Passing a payload string encodes it first, so {@link EncodeQrOptions} is
107
+ * accepted here too; passing an already-encoded {@link QrMatrix} ignores those
108
+ * fields, because the symbol is already fixed.
109
+ *
110
+ * Colours are escaped before they reach an attribute. They routinely come from
111
+ * a `DynamicQrSettings` bag that a user typed, and an unescaped `"` there would
112
+ * let that user close the attribute and write markup of their own into a page
113
+ * that inlines the result.
114
+ *
115
+ * @throws {RangeError} propagated from {@link encodeQr}, or when `margin` or
116
+ * `size` is negative.
117
+ */
118
+ export declare function qrToSvg(input: QrMatrix | string, options?: QrSvgOptions & EncodeQrOptions): string;
119
+ /**
120
+ * Same as {@link qrToSvg}, wrapped in a `data:image/svg+xml` URI ready for an
121
+ * `<img src>` or a CSS background.
122
+ *
123
+ * Percent-encoded rather than base64: `btoa` is not on every runtime this core
124
+ * targets, the encoding survives being pasted into a stylesheet, and it stays
125
+ * readable in a diff.
126
+ */
127
+ export declare function qrToDataUri(input: QrMatrix | string, options?: QrSvgOptions & EncodeQrOptions): string;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * The word list {@link generatePassphrase} draws from by default.
3
+ *
4
+ * This is the EFF "long" list: 7776 words (6^5, one per five-dice roll),
5
+ * published for exactly this purpose. Every entry is lowercase, at least three
6
+ * characters, and no entry shares its first three characters with another,
7
+ * which is what makes a passphrase unambiguous to type and to read back over a
8
+ * phone. Four entries carry a hyphen ("drop-down", "felt-tip", "t-shirt",
9
+ * "yo-yo"), so do not assume the separator cannot appear inside a word.
10
+ *
11
+ * 7776 words is log2(7776) = 12.925 bits per word, so the default five-word
12
+ * passphrase carries about 64.6 bits - stronger than a ten-character random
13
+ * password over the full printable alphabet, and far easier to remember.
14
+ *
15
+ * Source: https://www.eff.org/files/2016/07/18/eff_large_wordlist.txt
16
+ * License: CC-BY-3.0 (Electronic Frontier Foundation).
17
+ *
18
+ * It lives in its own module because it is 60 KB of data and it would bury the
19
+ * few dozen lines of actual logic in `password.ts`. Nothing here is
20
+ * platform-specific, so it is isolate-safe like the rest of `local/`.
21
+ *
22
+ * This file is DATA, copied verbatim from `frontend/lib/crypto/wordlist.ts` -
23
+ * the same list the web app's vault draws from. Keep the two in step rather
24
+ * than editing either by hand.
25
+ */
26
+ export declare const EFF_LONG_WORDLIST: readonly string[];
@@ -0,0 +1,296 @@
1
+ /**
2
+ * The `account` namespace: the signed-in user, other users' public profiles,
3
+ * the usage report behind the quota bars, and the sessions a credential can
4
+ * see.
5
+ *
6
+ * `GET /account` is the canonical "who am I" call and the cheapest way to check
7
+ * that a stored credential is still alive.
8
+ */
9
+ import { type ApiClient, Resource } from "../http";
10
+ import type { BaseRecord, FileInput, Id, Paginated, PageParams, RequestOptions, Timestamp } from "../types";
11
+ /**
12
+ * A user as the API renders them.
13
+ *
14
+ * Most fields are conditional: the blueprint hides `email` and `gender` unless
15
+ * they are public or you are the owner or an administrator, and hides
16
+ * `group`, `last_seen_at`, `sessions_count` and `deactivated_at` from everyone
17
+ * but an administrator. An absent key therefore means "not visible to you",
18
+ * never "empty".
19
+ */
20
+ export interface User extends BaseRecord {
21
+ /** Stable identifier. This is the OIDC `sub` claim. Never key on the handle. */
22
+ readonly id: Id;
23
+ /** Login name. Mutable: display it, do not store it as a foreign key. */
24
+ readonly handle: string;
25
+ readonly name?: string | null;
26
+ readonly bio?: string | null;
27
+ /** ISO 3166-1 alpha-2, as the user set it. */
28
+ readonly country_code?: string | null;
29
+ readonly email_is_public?: boolean;
30
+ readonly gender_is_public?: boolean;
31
+ readonly library_public?: boolean;
32
+ readonly library_name?: string | null;
33
+ readonly library_description?: string | null;
34
+ /** Visible when public, or to the owner and administrators. */
35
+ readonly email?: string | null;
36
+ /** Visible when public, or to the owner and administrators. */
37
+ readonly gender?: string | null;
38
+ /** Privilege group, e.g. `"admin"`. Owner and administrators only. */
39
+ readonly group?: string | null;
40
+ /** Owner and administrators only. */
41
+ readonly allowed_to_use_spotify?: boolean;
42
+ /** Owner and administrators only: whether friends see this user's playback. */
43
+ readonly share_listening?: boolean;
44
+ /** Administrators only. */
45
+ readonly last_seen_at?: Timestamp | null;
46
+ /** Administrators only. */
47
+ readonly sessions_count?: number;
48
+ /** Administrators only. Non-null once the account is deactivated. */
49
+ readonly deactivated_at?: Timestamp | null;
50
+ }
51
+ /**
52
+ * The `:profile` view: everything in {@link User} plus the social counters.
53
+ * Returned by `profile`, `byHandle`, `follow` and `unfollow`.
54
+ */
55
+ export interface UserProfile extends User {
56
+ readonly followers_count: number;
57
+ readonly following_count: number;
58
+ /** Whether the CALLER follows this user. `false` for an anonymous caller. */
59
+ readonly is_following: boolean;
60
+ /** `created_at` again, as an explicit ISO-8601 string. */
61
+ readonly member_since: Timestamp;
62
+ }
63
+ /** One hit from {@link AccountNamespace.search}. Deliberately three fields. */
64
+ export interface UserSearchResult {
65
+ readonly id: Id;
66
+ readonly handle: string;
67
+ readonly name?: string | null;
68
+ }
69
+ /**
70
+ * Fields a user may change on their own account.
71
+ *
72
+ * Anything not listed here is dropped in silence and the call still answers
73
+ * 200, so compare the returned {@link User} rather than trusting the status.
74
+ * The avatar is not here: it is multipart, through
75
+ * {@link AccountNamespace.updatePicture}.
76
+ */
77
+ export interface UpdateAccountInput {
78
+ readonly handle?: string;
79
+ readonly name?: string;
80
+ readonly bio?: string;
81
+ readonly countryCode?: string;
82
+ readonly emailIsPublic?: boolean;
83
+ readonly genderIsPublic?: boolean;
84
+ readonly gender?: string;
85
+ readonly libraryPublic?: boolean;
86
+ readonly libraryName?: string;
87
+ readonly libraryDescription?: string;
88
+ /** Whether friends may see what you are listening to. */
89
+ readonly shareListening?: boolean;
90
+ }
91
+ /** One extension bucket of {@link AccountStorageUsage.top_extensions}. */
92
+ export interface AccountExtensionUsage {
93
+ /** Lowercased extension with no dot, or `""` for a file that has none. */
94
+ readonly ext: string;
95
+ readonly count: number;
96
+ readonly bytes: number;
97
+ }
98
+ /** One row of {@link AccountStorageUsage.biggest_files}. */
99
+ export interface AccountBiggestFile {
100
+ readonly id: Id;
101
+ readonly name: string;
102
+ readonly size: number;
103
+ readonly parent_id: Id | null;
104
+ }
105
+ /** One row of {@link AccountStorageUsage.biggest_folders}. */
106
+ export interface AccountBiggestFolder {
107
+ readonly id: Id;
108
+ readonly name: string;
109
+ /** Sum of the file descendants, computed live. */
110
+ readonly size: number;
111
+ }
112
+ /** The storage section of {@link AccountUsage}. */
113
+ export interface AccountStorageUsage {
114
+ readonly used_bytes: number;
115
+ /** The account's own ceiling, not the global default. */
116
+ readonly max_bytes: number;
117
+ readonly file_count: number;
118
+ readonly directory_count: number;
119
+ /** Up to six, biggest first. */
120
+ readonly top_extensions: AccountExtensionUsage[];
121
+ /** Up to five, biggest first. */
122
+ readonly biggest_files: AccountBiggestFile[];
123
+ /** Up to five direct children of the home folder, biggest first. */
124
+ readonly biggest_folders: AccountBiggestFolder[];
125
+ }
126
+ /**
127
+ * `GET /account/usage`: what the account has spent, per area.
128
+ *
129
+ * This is a bespoke report, not the daily tool quotas - each metered tool
130
+ * reports its own ceiling through its `quota()` call. There is also a row
131
+ * ceiling (250 000 nodes) that this report does not carry.
132
+ */
133
+ export interface AccountUsage {
134
+ readonly user: {
135
+ readonly id: Id;
136
+ readonly handle: string;
137
+ readonly name: string | null;
138
+ };
139
+ readonly storage: AccountStorageUsage;
140
+ readonly music: {
141
+ readonly songs: number;
142
+ readonly playlists: number;
143
+ readonly play_events_total: number;
144
+ readonly play_events_30d: number;
145
+ };
146
+ readonly tickets: {
147
+ readonly open: number;
148
+ readonly closed: number;
149
+ };
150
+ readonly messages: {
151
+ readonly sent_30d: number;
152
+ readonly received_30d: number;
153
+ readonly unread: number;
154
+ };
155
+ readonly short_links: {
156
+ readonly total: number;
157
+ readonly total_clicks: number;
158
+ };
159
+ }
160
+ /**
161
+ * One sign-in. The token itself is never rendered here: it is handed out once,
162
+ * at `POST /sessions`, and never again.
163
+ */
164
+ export interface AccountSession extends BaseRecord {
165
+ readonly user_id: Id;
166
+ readonly ip_address?: string | null;
167
+ readonly user_agent?: string | null;
168
+ /** Caller-set label, e.g. `"laptop"`. */
169
+ readonly name?: string | null;
170
+ /** Caller-set kind, e.g. `"cli"`. `"teapot"` suppresses login alerts. */
171
+ readonly device_type?: string | null;
172
+ readonly description?: string | null;
173
+ /** Rewritten on every authenticated request this session makes. */
174
+ readonly last_used_at?: Timestamp | null;
175
+ /** The owner, rendered inline. */
176
+ readonly user?: User;
177
+ }
178
+ /** Filters for {@link AccountSessionsNamespace.list}. */
179
+ export interface ListAccountSessionsParams extends PageParams {
180
+ /** Administrators only: someone else's sessions. */
181
+ readonly userId?: Id;
182
+ }
183
+ /** Fields that can change on a session after it exists. */
184
+ export interface UpdateAccountSessionInput {
185
+ readonly name?: string;
186
+ /** `"teapot"` silences the login and activity alerts for this session. */
187
+ readonly deviceType?: string;
188
+ readonly description?: string;
189
+ }
190
+ /**
191
+ * Sessions of the current credential, reachable as `oms.account.sessions`.
192
+ *
193
+ * A session is the legacy credential: an opaque UUID with no scopes and no
194
+ * expiry. Every login mints a new row, so a client that signs in on each
195
+ * invocation fills this list up; persist the token instead.
196
+ */
197
+ export declare class AccountSessionsNamespace extends Resource {
198
+ /**
199
+ * `GET /sessions` - your sessions, one row per sign-in. An administrator
200
+ * sees everyone's and can narrow with `userId`.
201
+ */
202
+ list(params?: ListAccountSessionsParams, options?: RequestOptions): Promise<Paginated<AccountSession>>;
203
+ /** `GET /sessions/mine` - the session the current credential resolves to. */
204
+ current(options?: RequestOptions): Promise<AccountSession>;
205
+ /**
206
+ * `PATCH /sessions/:id` - renames a session, or relabels its device.
207
+ *
208
+ * This is the only session call that honours the `:id` in the path.
209
+ */
210
+ update(id: Id, input: UpdateAccountSessionInput, options?: RequestOptions): Promise<AccountSession>;
211
+ /**
212
+ * `DELETE /sessions/:id` - ends the session THIS credential is using.
213
+ *
214
+ * There is no argument on purpose. The endpoint never reads the `:id` in the
215
+ * path: it destroys `Current.session`, whatever id you send. Revoking
216
+ * another device's session is not possible through the API today, and a
217
+ * method that appeared to do it would silently log the caller out instead.
218
+ *
219
+ * After this resolves the credential is dead; build a new client with a new
220
+ * token rather than reusing this one.
221
+ *
222
+ * Costs a `GET /sessions/mine` first. The real id is sent even though the
223
+ * endpoint ignores it, so the call stays correct if that is ever fixed.
224
+ */
225
+ revokeCurrent(options?: RequestOptions): Promise<void>;
226
+ }
227
+ /** The `account` namespace, reachable as `oms.account`. */
228
+ export declare class AccountNamespace extends Resource {
229
+ /** Sessions: listing, relabelling, and ending the current one. */
230
+ readonly sessions: AccountSessionsNamespace;
231
+ constructor(http: ApiClient);
232
+ /**
233
+ * `GET /account` - the user the current credential belongs to.
234
+ *
235
+ * @throws {OmsAuthError} 401 when the credential is missing or dead.
236
+ */
237
+ me(options?: RequestOptions): Promise<User>;
238
+ /**
239
+ * `PATCH /users/:id` against your own id. Pass only the fields you are
240
+ * changing; the API leaves the rest alone.
241
+ *
242
+ * Costs an extra `GET /account` first, because the endpoint is addressed by
243
+ * id and the SDK holds no identity of its own. Unknown fields are dropped in
244
+ * silence, so read the returned {@link User} to see what actually changed.
245
+ */
246
+ update(input: UpdateAccountInput, options?: RequestOptions): Promise<User>;
247
+ /**
248
+ * `PATCH /users/:id` with a multipart body - replaces the avatar.
249
+ *
250
+ * The image is re-encoded server-side and capped at 1024px, so send the
251
+ * original rather than a thumbnail. Costs an extra `GET /account`, same as
252
+ * {@link update}.
253
+ */
254
+ updatePicture(picture: FileInput, options?: RequestOptions): Promise<User>;
255
+ /**
256
+ * `GET /account/usage` - consumption per area, for the bars the CLI prints
257
+ * before starting an expensive job.
258
+ */
259
+ usage(options?: RequestOptions): Promise<AccountUsage>;
260
+ /** `GET /users/:id` - another user, by stable id. Requires a credential. */
261
+ get(id: Id, options?: RequestOptions): Promise<User>;
262
+ /**
263
+ * `GET /users/by_handle/:handle` - the public profile of a handle. Works
264
+ * anonymously. Handles are mutable, so resolve once and keep the id.
265
+ */
266
+ byHandle(handle: string, options?: RequestOptions): Promise<UserProfile>;
267
+ /**
268
+ * `GET /users/:id/profile` - the public profile with follow counters. Works
269
+ * anonymously, and accepts a handle in place of an id.
270
+ */
271
+ profile(id: Id, options?: RequestOptions): Promise<UserProfile>;
272
+ /**
273
+ * `GET /users/search` - handle and name substring search, for a picker.
274
+ *
275
+ * Answers an empty list for a query under two characters, and never more
276
+ * than eight hits: it is a lookup, not an enumeration, and there is no
277
+ * paging. Throttled to 30 a minute per IP even when authenticated.
278
+ */
279
+ search(query: string, options?: RequestOptions): Promise<UserSearchResult[]>;
280
+ /**
281
+ * `GET /users/:id/picture` - the avatar bytes.
282
+ *
283
+ * Answers 302 towards object storage and `fetch` follows it; the platform
284
+ * drops `Authorization` on the cross-origin hop, so the credential never
285
+ * reaches the storage host. Answers 404 when the user has no avatar.
286
+ */
287
+ picture(id: Id, options?: RequestOptions): Promise<Blob>;
288
+ /** `POST /users/:id/follow` - returns the followed user's updated profile. */
289
+ follow(id: Id, options?: RequestOptions): Promise<UserProfile>;
290
+ /**
291
+ * `DELETE /users/:id/follow` - returns the unfollowed user's updated
292
+ * profile. Idempotent: unfollowing someone you do not follow still answers
293
+ * 200.
294
+ */
295
+ unfollow(id: Id, options?: RequestOptions): Promise<UserProfile>;
296
+ }