@omelhorsite/sdk 0.4.0 → 0.4.1

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 (35) hide show
  1. package/README.md +4 -4
  2. package/dist/index.js +4 -4
  3. package/dist/types/auth/device.d.ts +1 -1
  4. package/dist/types/auth/index.d.ts +2 -2
  5. package/dist/types/auth/tokens.d.ts +15 -15
  6. package/dist/types/client.d.ts +10 -10
  7. package/dist/types/errors.d.ts +12 -15
  8. package/dist/types/http.d.ts +74 -118
  9. package/dist/types/index.d.ts +1 -2
  10. package/dist/types/local/qr.d.ts +1 -1
  11. package/dist/types/local/wordlist.d.ts +2 -3
  12. package/dist/types/resources/account.d.ts +14 -17
  13. package/dist/types/resources/auth/index.d.ts +1 -1
  14. package/dist/types/resources/auth/passkeys.d.ts +127 -163
  15. package/dist/types/resources/auth/sessions.d.ts +110 -152
  16. package/dist/types/resources/chests.d.ts +27 -31
  17. package/dist/types/resources/dynamicQrs.d.ts +29 -45
  18. package/dist/types/resources/forms.d.ts +37 -58
  19. package/dist/types/resources/jobs.d.ts +28 -40
  20. package/dist/types/resources/media.d.ts +48 -61
  21. package/dist/types/resources/music/artists.d.ts +179 -245
  22. package/dist/types/resources/music/imports.d.ts +181 -210
  23. package/dist/types/resources/music/index.d.ts +8 -7
  24. package/dist/types/resources/music/playlists.d.ts +77 -110
  25. package/dist/types/resources/music/social.d.ts +153 -228
  26. package/dist/types/resources/music/songs.d.ts +160 -206
  27. package/dist/types/resources/realtime.d.ts +75 -88
  28. package/dist/types/resources/shortLinks.d.ts +33 -45
  29. package/dist/types/resources/storage/upload.d.ts +42 -56
  30. package/dist/types/resources/storage.d.ts +71 -104
  31. package/dist/types/resources/tools/backgroundRemoval.d.ts +11 -13
  32. package/dist/types/resources/tools/captions.d.ts +107 -135
  33. package/dist/types/resources/tools/upscale.d.ts +12 -16
  34. package/dist/types/types.d.ts +29 -38
  35. package/package.json +1 -1
@@ -8,14 +8,13 @@
8
8
  *
9
9
  * ## What a credential actually is
10
10
  *
11
- * A `Session` row, and nothing more. `POST /sessions` writes one and hands back
12
- * its `token`, which is a `SecureRandom.uuid`. That UUID IS the credential.
11
+ * An opaque UUID, and nothing more. `POST /sessions` mints one and hands it
12
+ * back as `token`. That UUID IS the credential.
13
13
  *
14
14
  * There is no JWT, no signature to verify, no `exp`, no refresh token and no
15
- * rotation. A session token never expires on its own: it lives until the row is
16
- * deleted, which happens on sign-out, when an administrator deactivates the
17
- * account (`User#deactivate!` runs `sessions.delete_all`), or when someone
18
- * deletes it in the database. Do not build refresh logic against this - there
15
+ * rotation. A session token never expires on its own: it lives until the
16
+ * session is deleted, which happens on sign-out or when an administrator
17
+ * deactivates the account. Do not build refresh logic against this - there
19
18
  * is nothing to refresh, and a client that "renews" by signing in again just
20
19
  * accumulates rows in the user's device list and fires a login alert each time.
21
20
  *
@@ -25,24 +24,22 @@
25
24
  *
26
25
  * ## Three ways the server reads it, and the one that bites
27
26
  *
28
- * `Session.candidate_tokens` collects, in this order:
27
+ * The server looks for the token, in this order, in:
29
28
  *
30
29
  * 1. the `Authorization` header,
31
30
  * 2. the `token` request parameter (query string or body),
32
31
  * 3. the `oms_session` cookie.
33
32
  *
34
- * and `Session.resolve_from_request` tries each until one resolves to a LIVE
35
- * row, so a stale header no longer permanently shadows a good cookie on API
36
- * requests. (`ApplicationCable::Connection` is the exception: the WebSocket
37
- * handshake takes the FIRST candidate, not the first live one, so a stale
38
- * header there really does beat a good `?token=`.)
33
+ * and tries each until one resolves to a LIVE session, so a stale header does
34
+ * not permanently shadow a good cookie on API requests. (The WebSocket
35
+ * handshake is the exception: it takes the FIRST candidate, not the first
36
+ * live one, so a stale header there really does beat a good `?token=`.)
39
37
  *
40
- * The header is parsed as `header["Bearer:".length..]`, which is a BLIND SLICE
41
- * OF THE FIRST SEVEN CHARACTERS. Nothing checks that those seven characters
42
- * spell anything:
38
+ * The header is read by slicing off its FIRST SEVEN CHARACTERS, whatever they
39
+ * are. Nothing checks that those seven characters spell anything:
43
40
  *
44
41
  * - `Bearer <token>` works (7 chars: `Bearer` plus the space),
45
- * - `Bearer:<token>` also works, which is where the constant's name comes from,
42
+ * - `Bearer:<token>` also works, since the slice is seven characters either way,
46
43
  * - a bare token with NO prefix does NOT work. Its first seven characters are
47
44
  * eaten, the remainder matches no row, and the request is answered as
48
45
  * anonymous. The failure is a 401 on an endpoint that needs auth, or - far
@@ -63,17 +60,16 @@
63
60
  * `SameSite=Lax`, `path=/`, a one-year expiry and NO `Domain` attribute, which
64
61
  * makes it host-only: it belongs to `backend.omelhorsite.pt` alone and is never
65
62
  * sent to a sibling subdomain. `omelhorsite.pt` and `backend.omelhorsite.pt`
66
- * share a registrable domain, so a call from the web app is cross-ORIGIN but
67
- * same-SITE, and `SameSite=Lax` still lets the cookie ride along. A page on a
68
- * genuinely different site (the `pages.dev` staging build, where `pages.dev` is
69
- * a public suffix) can never receive it, no CORS header can change that, and
70
- * such a page must use token mode instead.
63
+ * share a registrable domain, so a call from a page on `omelhorsite.pt` is
64
+ * cross-ORIGIN but same-SITE, and `SameSite=Lax` still lets the cookie ride
65
+ * along. A page on a genuinely different site (a `pages.dev` preview, say,
66
+ * where `pages.dev` is a public suffix) can never receive it, no CORS header
67
+ * can change that, and such a page must use token mode instead.
71
68
  *
72
69
  * ## No CSRF token exists
73
70
  *
74
- * The backend is an `ActionController::API` and `protect_from_forgery` is never
75
- * enabled. There is no CSRF token to fetch, no header to echo, and nothing in
76
- * this SDK that omits one. For browsers the entire cross-site defence is
71
+ * The API issues none. There is no CSRF token to fetch, no header to echo, and
72
+ * nothing in this SDK that omits one. For browsers the entire cross-site defence is
77
73
  * `SameSite=Lax` on the cookie; bearer clients are unaffected because a
78
74
  * cross-site page cannot make the browser attach an `Authorization` header.
79
75
  *
@@ -88,11 +84,7 @@
88
84
  * `.update()`, `.follow()`, `.picture()` - the user read and write surface.
89
85
  *
90
86
  * `DELETE /users/:id` is also absent, and that one is not a delegation: the
91
- * route cannot succeed for anybody. `UsersController#destroy` checks for an
92
- * administrator and then calls `super`, and `CrudActions#destroy` asks
93
- * `resource.destroyable_by?(Current.user)` - which on `User` is
94
- * `alias destroyable_by? creatable_by?`, and `creatable_by?` returns `false`
95
- * unconditionally. Every caller, administrator included, gets
87
+ * route cannot succeed for anybody. Every caller, administrator included, gets
96
88
  * `401 "You are not authorized to destroy this resource"`. Use
97
89
  * {@link AuthSessionsNamespace.deactivateUser} for the operational need, or
98
90
  * {@link AuthSessionsNamespace.deleteAccountStart} for a user deleting
@@ -114,8 +106,7 @@ import type { Id, Paginated, RequestOptions } from "../../types";
114
106
  export declare const SESSION_COOKIE_NAME = "oms_session";
115
107
  /**
116
108
  * The seven characters the server slices off the `Authorization` header before
117
- * looking the token up, spelled the way the Rails source spells them
118
- * (`"Bearer:".length`).
109
+ * looking the token up: the length of `"Bearer:"`.
119
110
  *
120
111
  * Present so the number 7 appears somewhere other than a comment. The transport
121
112
  * writes `"Bearer "` (with a space), which is the same length; both forms work
@@ -123,7 +114,7 @@ export declare const SESSION_COOKIE_NAME = "oms_session";
123
114
  */
124
115
  export declare const SESSION_BEARER_PREFIX_LENGTH = 7;
125
116
  /**
126
- * Digits in an email verification code (`EmailVerification::CODE_LENGTH`).
117
+ * Digits in an email verification code.
127
118
  *
128
119
  * Six, numeric only, zero-padded. This is a deliberate product decision on this
129
120
  * project rather than an accident: a code a person can read off a phone and
@@ -132,19 +123,17 @@ export declare const SESSION_BEARER_PREFIX_LENGTH = 7;
132
123
  */
133
124
  export declare const VERIFICATION_CODE_LENGTH = 6;
134
125
  /**
135
- * Wrong guesses an issued code survives (`EmailVerification::MAX_ATTEMPTS`).
126
+ * Wrong guesses an issued code survives.
136
127
  *
137
128
  * This is the counterweight to a six-digit code, and it is per CODE, not per IP:
138
- * rack-attack only throttles by address, so an attacker rotating through a
139
- * botnet would otherwise walk a million-key space at 10 guesses a minute per
129
+ * the request throttle only counts by address, so an attacker rotating through
130
+ * a botnet would otherwise walk a million-key space at 10 guesses a minute per
140
131
  * address. The budget closes that regardless of where the guesses come from.
141
132
  *
142
133
  * The exact arithmetic, because off-by-one matters when you are deciding
143
- * whether to let a user try again: `register_failed_attempt` destroys the code
144
- * when `attempts + 1 >= MAX_ATTEMPTS`, starting from `attempts = 0`. So four
145
- * wrong guesses are survivable and the FIFTH burns the code. Burning is
146
- * permanent - the row is deleted, not locked - and it also fires a
147
- * `verification_burned` security alert to the owner. The user's only route
134
+ * whether to let a user try again: four wrong guesses are survivable and the
135
+ * FIFTH burns the code. Burning is permanent - the code is deleted, not locked
136
+ * - and it also sends the owner a security alert. The user's only route
148
137
  * forward is a fresh `*_start` call, which is throttled at 4 a minute and 20 an
149
138
  * hour per IP, so a client that lets someone mash a code field will lock them
150
139
  * out of the flow for the rest of the hour.
@@ -154,18 +143,15 @@ export declare const VERIFICATION_CODE_LENGTH = 6;
154
143
  */
155
144
  export declare const VERIFICATION_CODE_MAX_ATTEMPTS = 5;
156
145
  /**
157
- * How long an issued code stays valid (`EmailVerification::EXPIRES_IN`), in
158
- * milliseconds. Fifteen minutes.
146
+ * How long an issued code stays valid, in milliseconds. Fifteen minutes.
159
147
  *
160
- * Expiry is enforced by an `active` scope plus an opportunistic purge on every
161
- * issue and every verify, so an expired code behaves exactly like a wrong one:
148
+ * An expired code behaves exactly like a wrong one:
162
149
  * `404 "Invalid Verification"`, indistinguishable from the status alone. Show
163
150
  * the user a countdown rather than making them find out.
164
151
  */
165
152
  export declare const VERIFICATION_CODE_TTL_MS: number;
166
153
  /**
167
- * How long an OAuth handoff ticket stays valid (`SessionsController::TICKET_TTL`),
168
- * in milliseconds. Two minutes.
154
+ * How long an OAuth handoff ticket stays valid, in milliseconds. Two minutes.
169
155
  *
170
156
  * The signature window is only half the story - the ticket is also one-time.
171
157
  * See {@link AuthSessionsNamespace.adopt}.
@@ -179,10 +165,10 @@ export declare const OAUTH_TICKET_TTL_MS: number;
179
165
  * the user can rename it afterwards through `oms.account.sessions.update()`.
180
166
  * The list is mostly a joke, with one entry that is not:
181
167
  *
182
- * **`"teapot"` suppresses alerts.** `Session#alert_login` and
183
- * `#alert_returning_activity` both bail out for a teapot session, which is how
184
- * the backend's own background jobs sign in without paging the owner on every
185
- * run. Do not relabel a real user's device as a teapot to quieten notifications:
168
+ * **`"teapot"` suppresses alerts.** A teapot session fires neither the login
169
+ * alert nor the returning-activity alert, which is what an unattended
170
+ * automation wants. Do not relabel a real user's device as a teapot to
171
+ * quieten notifications:
186
172
  * you are turning off the only signal that a stolen token is being used.
187
173
  */
188
174
  export declare const SESSION_DEVICE_TYPES: readonly ["tablet", "console", "fridge", "teapot", "toaster", "air_conditioner", "car", "blender", "vacuum_cleaner", "washing_machine", "lawn_mower", "microwave", "hair_dryer", "electric_toothbrush", "desktop", "laptop", "television", "mobile", "space_ship", "time_machine", "hoverboard", "teleporter", "magic_carpet", "unicorn", "flying_broom", "submarine", "hot_air_balloon", "keychain", "alarm_clock", "radio", "record_player", "other"];
@@ -198,18 +184,18 @@ export type SessionDeviceType = (typeof SESSION_DEVICE_TYPES)[number];
198
184
  * the ten requests a minute the IP is allowed. A user who pastes a code with a
199
185
  * trailing space should not lose a fifth of their budget to whitespace.
200
186
  *
201
- * The server normalises with `strip`, so surrounding whitespace is forgiven
202
- * there; this returns `false` for it anyway, so a caller can trim before
187
+ * The server trims surrounding whitespace, so it is forgiven there; this
188
+ * returns `false` for it anyway, so a caller can trim before
203
189
  * sending rather than relying on the remote side to be lenient.
204
190
  */
205
191
  export declare function isVerificationCode(value: string): boolean;
206
192
  /** Credentials for {@link AuthSessionsNamespace.signIn}. */
207
193
  export interface SignInInput {
208
- /** Normalised server-side with `strip.downcase`; send it as the user typed it. */
194
+ /** Trimmed and lowercased server-side; send it as the user typed it. */
209
195
  readonly email: string;
210
196
  /**
211
- * Compared with `User.authenticate_by`, which is timing-safe: a wrong
212
- * password and an unknown address take the same time and give the same
197
+ * Compared in constant time: a wrong password and an unknown address take
198
+ * the same time and give the same
213
199
  * message, so this endpoint cannot be used to test whether an account exists.
214
200
  */
215
201
  readonly password: string;
@@ -217,15 +203,13 @@ export interface SignInInput {
217
203
  /**
218
204
  * What `POST /sessions` answers with: the session record plus, ONCE, the token.
219
205
  *
220
- * This is `SessionBlueprint`'s `:token` view, which is the base view plus one
221
- * field - Blueprinter views inherit, they do not replace - so everything an
222
- * ordinary {@link AccountSession} carries is here too, including the inlined
223
- * `user`. That inline user saves a round trip: there is no need to call
224
- * `oms.account.me()` straight after signing in.
206
+ * Everything an ordinary {@link AccountSession} carries is here too, including
207
+ * the inlined `user`, plus `token`. That inline user saves a round trip: there
208
+ * is no need to call `oms.account.me()` straight after signing in.
225
209
  *
226
210
  * `token` appears in this response and in NO other. Nothing else in the API
227
- * ever renders it again: `GET /sessions` and `GET /sessions/mine` return the
228
- * base view, which has no `token` field. Lose it and the only way back is to
211
+ * ever renders it again: `GET /sessions` and `GET /sessions/mine` never
212
+ * include a `token` field. Lose it and the only way back is to
229
213
  * sign in again, minting another row.
230
214
  */
231
215
  export interface SignedInSession extends AccountSession {
@@ -233,7 +217,7 @@ export interface SignedInSession extends AccountSession {
233
217
  * The credential. A bare UUID, no prefix.
234
218
  *
235
219
  * Store it where the platform stores secrets (Keychain / Keystore via
236
- * SecureStore on React Native, the OS keyring for the CLI). Do NOT store it
220
+ * SecureStore on React Native, the OS keyring on a desktop). Do NOT store it
237
221
  * when you are in cookie mode - see {@link AuthSessionsNamespace.signIn}.
238
222
  */
239
223
  readonly token: string;
@@ -267,7 +251,7 @@ export interface SignUpInput {
267
251
  readonly code: string;
268
252
  /**
269
253
  * Display name, 1 to 50 characters. The `handle` is NOT settable here: the
270
- * server generates one from this name in a `before_create` hook. Change it
254
+ * server generates one from this name. Change it
271
255
  * afterwards with `oms.account.update({ handle })`.
272
256
  */
273
257
  readonly name: string;
@@ -322,7 +306,7 @@ export declare class AuthSessionsNamespace extends Resource {
322
306
  *
323
307
  * ## What to do with the answer, per mode
324
308
  *
325
- * **Token mode** (React Native, the CLI, anything not served from
309
+ * **Token mode** (React Native, Bun, anything not served from
326
310
  * `omelhorsite.pt`): store `token` in the platform's secret store and build a
327
311
  * client with it. The client you called this on has no credential, and adding
328
312
  * one to an existing client is not possible - `Oms` takes its token at
@@ -354,9 +338,6 @@ export declare class AuthSessionsNamespace extends Resource {
354
338
  * re-creates precisely the XSS-exfiltratable copy the cookie mode exists to
355
339
  * eliminate, and it also gives you a second credential that outlives the
356
340
  * first: sign out, and the cookie dies while the stored token keeps working.
357
- * The web app is explicit about this - `persistSessionToken` writes only a
358
- * non-sensitive `authed` flag when `isCookieAuth()`, and actively purges any
359
- * legacy token it finds.
360
341
  *
361
342
  * Note that an `Oms` cannot be both: passing `sessionCookie: true` together
362
343
  * with a token throws a `TypeError` at construction, deliberately, so that no
@@ -364,14 +345,13 @@ export declare class AuthSessionsNamespace extends Resource {
364
345
  *
365
346
  * ## Cost and failure
366
347
  *
367
- * Throttled to **10 POSTs per minute per IP** (`login/ip`), which is a
368
- * password-guessing bound and is keyed by address, so several users behind
369
- * one NAT share it. The throttle matches a normalised path, so `/sessions/`,
370
- * `//sessions` and `/sessions.json` all count against the same bucket - that
371
- * gap was closed.
348
+ * Throttled to **10 POSTs per minute per IP**, which is a password-guessing
349
+ * bound and is keyed by address, so several users behind one NAT share it.
350
+ * The throttle matches a normalised path, so `/sessions/`, `//sessions` and
351
+ * `/sessions.json` all count against the same bucket.
372
352
  *
373
- * Every successful sign-in creates a row AND fires a Discord alert to the
374
- * owner. Signing in once per process invocation is how a device list fills up
353
+ * Every successful sign-in creates a session AND sends the owner a login
354
+ * alert. Signing in once per process invocation is how a device list fills up
375
355
  * with a hundred identical entries; persist the token instead.
376
356
  *
377
357
  * Retries: an ambiguous network failure is NOT replayed, because this is a
@@ -389,8 +369,7 @@ export declare class AuthSessionsNamespace extends Resource {
389
369
  *
390
370
  * @throws {OmsAuthError} 401 `"Invalid email address or password."` for a
391
371
  * wrong password, an unknown address, and a deactivated account alike. The
392
- * three are not distinguishable, on purpose. (Deactivation is enforced as a
393
- * validation on `Session` create, so it fails at the same place.)
372
+ * three are not distinguishable, on purpose.
394
373
  * @throws {OmsQuotaError} 429 once the per-IP login budget is spent.
395
374
  */
396
375
  signIn(input: SignInInput, options?: RequestOptions): Promise<SignedInSession>;
@@ -399,12 +378,10 @@ export declare class AuthSessionsNamespace extends Resource {
399
378
  *
400
379
  * ## THE `:id` IS IGNORED. THIS ALWAYS DESTROYS THE CALLING SESSION.
401
380
  *
402
- * `SessionsController#destroy` does not look the path segment up. It does not
403
- * call `resource`. It reads `Current.session`, destroys that, clears the
404
- * cookie and answers `204`. So `DELETE /sessions/<any string at all>` means
405
- * "log ME out", and there is no way through this API to revoke a different
406
- * device. The web app's own "sign out this other device" button has always
407
- * signed the user out of the browser they clicked it in.
381
+ * The server never looks the path segment up. It destroys the calling
382
+ * session, clears the cookie and answers `204`. So
383
+ * `DELETE /sessions/<any string at all>` means "log ME out", and there is no
384
+ * way through this API to revoke a different device.
408
385
  *
409
386
  * That is why this method takes no id. A signature that accepted one would be
410
387
  * describing behaviour the server does not have, and the mistake it invites -
@@ -412,7 +389,7 @@ export declare class AuthSessionsNamespace extends Resource {
412
389
  * with a `204` that looks like success.
413
390
  *
414
391
  * To actually end someone else's sessions there is exactly one lever, and it
415
- * is administrative: {@link deactivateUser} runs `sessions.delete_all` on the
392
+ * is administrative: {@link deactivateUser} ends every session of the
416
393
  * target.
417
394
  *
418
395
  * ## What it does on the wire
@@ -444,20 +421,19 @@ export declare class AuthSessionsNamespace extends Resource {
444
421
  /**
445
422
  * `GET /sessions/mine` - the session the current credential resolves to.
446
423
  *
447
- * The cheapest liveness check there is, and the one the web app and the
448
- * native app both boot with: a `200` means the stored credential still names
449
- * a row, a `401` means it does not and the user must sign in again. Identical
424
+ * The cheapest liveness check there is, and the one an app should boot with:
425
+ * a `200` means the stored credential still names a live session, a `401`
426
+ * means it does not and the user must sign in again. Identical
450
427
  * to `oms.account.sessions.current()`; both are here because "am I still
451
428
  * signed in" belongs to the sign-in lifecycle and "which devices are signed
452
429
  * in" belongs to the account screen.
453
430
  *
454
- * Returns the base `SessionBlueprint` view, with the owner inlined under
455
- * `user` and WITHOUT `token`. There is no route that hands a token back.
431
+ * Returns the session with the owner inlined under `user` and WITHOUT
432
+ * `token`. There is no route that hands a token back.
456
433
  *
457
434
  * `/sessions/mine` is the whole spelling. There is NO `GET /sessions/current`:
458
- * `resources :sessions` is declared `only: [:index, :create, :update,
459
- * :destroy]`, so `show` is not routed and a GET to `/sessions/current` is a
460
- * 404. (It IS a live path on DELETE, where it is the placeholder id
435
+ * `GET /sessions/:id` is not routed at all, so a GET to `/sessions/current`
436
+ * is a 404. (It IS a live path on DELETE, where it is the placeholder id
461
437
  * {@link signOut} uses, which is exactly the sort of coincidence that makes
462
438
  * the wrong spelling look plausible.)
463
439
  *
@@ -481,8 +457,8 @@ export declare class AuthSessionsNamespace extends Resource {
481
457
  *
482
458
  * The last step of the browser OAuth flow. The provider round trip happens on
483
459
  * the API host; its callback redirects the browser back to
484
- * `https://omelhorsite.pt/account/oauth/callback?ticket=...` (hardcoded to
485
- * `Rails.configuration.frontend_url`, not configurable per client), and the
460
+ * `https://omelhorsite.pt/account/oauth/callback?ticket=...` (fixed
461
+ * server-side, not configurable per client), and the
486
462
  * page hands that ticket here. The ticket exists so the session token itself
487
463
  * never travels in a URL, a browser history entry or a `Referer`.
488
464
  *
@@ -493,10 +469,9 @@ export declare class AuthSessionsNamespace extends Resource {
493
469
  *
494
470
  * ## MUST NOT BE RETRIED, and this method enforces that
495
471
  *
496
- * The ticket is one-time on the server. Redemption is claimed atomically with
497
- * `Rails.cache.write(..., unless_exist: true)` before the session is adopted,
498
- * and a second presentation of the same ticket gets the same `401 "Invalid or
499
- * expired ticket."` as a forged one. So a retry after an ambiguous failure -
472
+ * The ticket is one-time on the server. Redemption is claimed atomically
473
+ * before the session is adopted, and a second presentation of the same
474
+ * ticket gets the same `401 "Invalid or expired ticket."` as a forged one. So a retry after an ambiguous failure -
500
475
  * a torn connection, a lost response - burns the ticket and reports a login
501
476
  * failure for a login that actually SUCCEEDED. The user is left staring at an
502
477
  * error page while the browser quietly holds a valid session cookie.
@@ -505,12 +480,6 @@ export declare class AuthSessionsNamespace extends Resource {
505
480
  * back on. If the call fails ambiguously, the honest recovery is to check
506
481
  * {@link current} before deciding anything: if it answers, you are signed in.
507
482
  *
508
- * The app-side documentation (`oms-music/docs/auth-account.md`, section 6)
509
- * says the ticket is "not single-use server-side" and that the web enforces
510
- * single use client-side with a sessionStorage nonce. THAT IS OUT OF DATE.
511
- * The Rails code enforces it, and it is the enforcement that makes a retry
512
- * destructive. When the doc and the Rails disagree, the Rails wins.
513
- *
514
483
  * Tickets are also short-lived, {@link OAUTH_TICKET_TTL_MS} (two minutes), so
515
484
  * do not stash one to redeem later.
516
485
  *
@@ -522,7 +491,7 @@ export declare class AuthSessionsNamespace extends Resource {
522
491
  * `GET /sessions/oauth_ticket` - mints a short-lived ticket for the current
523
492
  * session, so the session token itself never crosses a subdomain boundary.
524
493
  *
525
- * Only the web app needs this, and only for one thing: linking an OAuth
494
+ * Only a browser page needs this, and only for one thing: linking an OAuth
526
495
  * provider to an account that is already signed in. That flow is a full-page
527
496
  * navigation to `backend.omelhorsite.pt/auth/link/<provider>`, and a
528
497
  * navigation cannot carry an `Authorization` header. The cookie is host-only
@@ -530,8 +499,8 @@ export declare class AuthSessionsNamespace extends Resource {
530
499
  * `?token=<the session token>` in a URL that lands in browser history and in
531
500
  * a `Referer`, which is exactly what this endpoint exists to avoid.
532
501
  *
533
- * Native and CLI clients have no such constraint and do not need this: they
534
- * hold the token already.
502
+ * A token-mode client has no such constraint and does not need this: it
503
+ * holds the token already.
535
504
  *
536
505
  * The result is scoped to the `oauth` purpose and expires after
537
506
  * {@link OAUTH_TICKET_TTL_MS}. It authenticates nothing else - an API call
@@ -562,9 +531,9 @@ export declare class AuthSessionsNamespace extends Resource {
562
531
  * is a deliberate trade for a usable signup form, and it is why
563
532
  * {@link resetPasswordStart} does the opposite.
564
533
  *
565
- * Issuing a code DELETES any live code for the same address and reason
566
- * (`where(reason:, email:).delete_all` before insert). One code per flow per
567
- * address, always. A user who asks for a second code and then types the first
534
+ * Issuing a code DELETES any live code for the same address and flow. One
535
+ * code per flow per address, always. A user who asks for a second code and
536
+ * then types the first
568
537
  * one gets `404 "Invalid Verification"` and, worse, spends one of the five
569
538
  * guesses belonging to the code they cannot see. Tell them the old code is
570
539
  * dead when they request a new one.
@@ -589,9 +558,8 @@ export declare class AuthSessionsNamespace extends Resource {
589
558
  *
590
559
  * No session is created and no token is returned. The account exists and the
591
560
  * caller is still anonymous. Follow it immediately with {@link signIn} using
592
- * the same email and password - that is what both the web app and the native
593
- * app do, and forgetting it is the classic "signup worked but the app is
594
- * still on the login screen" bug.
561
+ * the same email and password; forgetting it is the classic "signup worked
562
+ * but the app is still on the login screen" bug.
595
563
  *
596
564
  * ```ts
597
565
  * await oms.sessions.signUpStart(email);
@@ -600,12 +568,11 @@ export declare class AuthSessionsNamespace extends Resource {
600
568
  * const session = await oms.sessions.signIn({ email, password });
601
569
  * ```
602
570
  *
603
- * `handle` cannot be chosen here even though the column exists: the parameter
604
- * is not permitted on this action, and a `before_create` hook generates one
605
- * from `name`. Let the user change it afterwards with
571
+ * `handle` cannot be chosen here: the parameter is ignored, and the server
572
+ * generates one from `name`. Let the user change it afterwards with
606
573
  * `oms.account.update({ handle })`, where 15 characters is the ceiling.
607
574
  *
608
- * Consuming the code also stamps `email_verified_at`, inside the same create.
575
+ * Consuming the code also marks the address as verified.
609
576
  * The address is proven, so a freshly signed-up account is never in the
610
577
  * "verify your email" limbo.
611
578
  *
@@ -634,8 +601,7 @@ export declare class AuthSessionsNamespace extends Resource {
634
601
  * present this result to the user as confirmation that mail is on its way to
635
602
  * a real account, because it is not evidence of that.
636
603
  *
637
- * A real send also fires a `password_reset_started` security alert to the
638
- * owner.
604
+ * A real send also sends the owner a security alert.
639
605
  *
640
606
  * Same throttle family as every other `*_start`: **4 a minute and 20 an hour
641
607
  * per IP**, shared.
@@ -656,7 +622,7 @@ export declare class AuthSessionsNamespace extends Resource {
656
622
  * other sessions ({@link signOut} only ends the caller's). Escalating to an
657
623
  * administrator and {@link deactivateUser} is the only lever that clears them.
658
624
  *
659
- * Consuming the code stamps `email_verified_at`: proving control of the
625
+ * Consuming the code marks the address as verified: proving control of the
660
626
  * mailbox verifies the address even if it never was verified before.
661
627
  *
662
628
  * Throttled to **10 a minute per IP**, shared with the other `*_end`
@@ -675,9 +641,8 @@ export declare class AuthSessionsNamespace extends Resource {
675
641
  * `POST /users/update_email_start` - emails TWO codes: one to the address
676
642
  * currently on the account, one to the address it is moving to.
677
643
  *
678
- * Requires a live session. One HTTP request, two `EmailVerification` rows,
679
- * two different reasons (`email_update_prev` and `email_update_new`), and
680
- * {@link changeEmailComplete} needs both codes back. Proving control of the
644
+ * Requires a live session. One HTTP request, two codes, and
645
+ * {@link changeEmailComplete} needs both back. Proving control of the
681
646
  * new mailbox alone is not enough: an attacker sitting on a hijacked session
682
647
  * would otherwise move the account to an address they own and lock the real
683
648
  * owner out permanently.
@@ -706,17 +671,16 @@ export declare class AuthSessionsNamespace extends Resource {
706
671
  *
707
672
  * Requires a live session; answers `200` with the updated {@link User}.
708
673
  *
709
- * Both codes are checked BEFORE either is consumed (the controller verifies
710
- * twice with `destroy: false`, then verifies again to consume), so getting
711
- * one right and one wrong burns neither. What it does still cost is an
712
- * attempt against BOTH live codes: a wrong guess charges
713
- * `register_failed_attempt` on the code for that reason, so a user typing the
714
- * two codes into the wrong boxes spends one of the five guesses on each. With
674
+ * Both codes are checked BEFORE either is consumed, so getting one right and
675
+ * one wrong burns neither. What it does still cost is an attempt against
676
+ * BOTH live codes: a wrong guess counts against the code it was meant for,
677
+ * so a user typing the two codes into the wrong boxes spends one of the five
678
+ * guesses on each. With
715
679
  * two codes in play the per-code budget is easier to exhaust than anywhere
716
680
  * else in this family - validate with {@link isVerificationCode} first, and
717
681
  * label the two inputs unmistakably.
718
682
  *
719
- * Consuming both stamps `email_verified_at`, since both mailboxes are proven.
683
+ * Consuming both marks the address as verified, since both mailboxes are proven.
720
684
  *
721
685
  * Throttled to **10 a minute per IP**, shared with the other `*_end`
722
686
  * endpoints.
@@ -745,19 +709,15 @@ export declare class AuthSessionsNamespace extends Resource {
745
709
  * Answers `200` with the bare string `"User deletion instructions sent."`.
746
710
  * Shared `*_start` throttle: **4 a minute and 20 an hour per IP**.
747
711
  *
748
- * Included here even though it is the one pair of routes the sibling
749
- * documentation does not list, because nothing else in the SDK covers it and
750
- * a user who cannot delete their account has no exit.
751
- *
752
712
  * @throws {OmsAuthError} 401 without a live session.
753
713
  */
754
714
  deleteAccountStart(options?: RequestOptions): Promise<string>;
755
715
  /**
756
716
  * `POST /users/destroy_end` - presents the code and DESTROYS THE ACCOUNT.
757
717
  *
758
- * Requires a live session. Irreversible: `user.destroy` runs, taking the
759
- * user's sessions, files, music library and everything else that cascades
760
- * from the row. There is no soft-delete on this path and no undo.
718
+ * Requires a live session. Irreversible: it takes the user's sessions,
719
+ * files, music library and everything else with it. There is no soft-delete
720
+ * on this path and no undo.
761
721
  * {@link deactivateUser} is the reversible operation, and it is
762
722
  * administrators only.
763
723
  *
@@ -771,32 +731,30 @@ export declare class AuthSessionsNamespace extends Resource {
771
731
  * @throws {OmsAuthError} 401 without a live session.
772
732
  * @throws {OmsApiError} 404 `"Invalid Verification"` for a wrong, expired or
773
733
  * burned code.
774
- * @throws {OmsApiError} 500 with the model's error messages when the record
775
- * could not be destroyed - a foreign key that refused to cascade. The
776
- * account survives; the code does not.
734
+ * @throws {OmsApiError} 500 with the server's error messages when the
735
+ * account could not be destroyed. The account survives; the code does not.
777
736
  */
778
737
  deleteAccountComplete(code: string, options?: RequestOptions): Promise<void>;
779
738
  /**
780
739
  * `GET /users` - the user roster.
781
740
  *
782
741
  * Requires a credential, and any authenticated account can enumerate the
783
- * whole table: `User.viewable_by` is `->(user) { all }`. What an ordinary
784
- * caller does NOT get is the privileged columns - `group`, `email`, `gender`,
742
+ * whole roster. What an ordinary caller does NOT get is the privileged
743
+ * columns - `group`, `email`, `gender`,
785
744
  * `last_seen_at`, `sessions_count`, `deactivated_at` and
786
745
  * `allowed_to_use_spotify` are all rendered conditionally, so an absent key
787
746
  * means "not visible to you", never "empty".
788
747
  *
789
- * This used to be anonymous and is not any more, precisely so that the roster
790
- * could not be harvested. For a picker, prefer `oms.account.search()`: it is
791
- * anonymous, capped at eight rows, and returns only id, handle and name.
748
+ * For a picker, prefer `oms.account.search()`: it is anonymous, capped at
749
+ * eight rows, and returns only id, handle and name.
792
750
  *
793
751
  * Only `name` and `handle` are filterable. Any other key is a `400 "Unknown
794
752
  * search filter"` - this DSL fails closed rather than ignoring what it does
795
753
  * not recognise.
796
754
  *
797
- * Deactivated accounts are NOT filtered out of this listing (the `active`
798
- * scope is applied by `users#search`, not by the index), so a roster shows
799
- * them; an administrator can tell by `deactivated_at`, and nobody else can.
755
+ * Deactivated accounts are NOT filtered out of this listing (unlike
756
+ * `oms.account.search()`), so a roster shows them; an administrator can tell
757
+ * by `deactivated_at`, and nobody else can.
800
758
  *
801
759
  * Index responses carry an `ETag`, so a repeat can answer `304` with no body.
802
760
  * Counts against the general authenticated ceiling, 600 a minute.
@@ -807,10 +765,10 @@ export declare class AuthSessionsNamespace extends Resource {
807
765
  *
808
766
  * ## This is also the only way to revoke somebody's sessions
809
767
  *
810
- * `User#deactivate!` stamps `deactivated_at` and runs `sessions.delete_all`
811
- * in the same transaction, so every device the target is signed in on is
812
- * logged out at once, and `Session`'s create validation then refuses to mint
813
- * a new one. It is the single lever in this API that ends a session other
768
+ * Deactivation stamps `deactivated_at` and ends every session of the target
769
+ * at once, so every device they are signed in on is logged out, and a new
770
+ * sign-in is refused. It is the single lever in this API that ends a session
771
+ * other
814
772
  * than the caller's own - {@link signOut} cannot, and neither can anything in
815
773
  * `oms.account.sessions`. If a token has leaked, this is the response.
816
774
  *