@omelhorsite/sdk 0.4.0 → 0.4.2

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 (37) hide show
  1. package/README.md +4 -4
  2. package/dist/index.js +59 -52
  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 +160 -303
  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 +120 -135
  33. package/dist/types/resources/tools/index.d.ts +4 -0
  34. package/dist/types/resources/tools/srMachine.d.ts +114 -0
  35. package/dist/types/resources/tools/upscale.d.ts +12 -16
  36. package/dist/types/types.d.ts +29 -38
  37. package/package.json +1 -1
package/README.md CHANGED
@@ -39,7 +39,7 @@ const oms = new Oms({
39
39
  baseUrl: "http://localhost:3000", // defaults to https://backend.omelhorsite.pt
40
40
  fetch: myFetch, // defaults to globalThis.fetch
41
41
  headers: { "X-Trace": id }, // merged under per-call headers
42
- timeoutMs: 30_000, // whole call, retries included; 0 disables
42
+ timeoutMs: 30_000, // per attempt; 0 disables
43
43
  retry: { maxAttempts: 3 }, // or false to never retry
44
44
  clientName: "my-worker/1.0", // becomes X-Oms-Client
45
45
  });
@@ -186,7 +186,7 @@ const done = await oms.tools.transcription.run(
186
186
  `run` is `create` plus `jobs.wait`. Use `create` on hosts with a wall-clock
187
187
  budget or nowhere to hold a wait: start the job, keep the id, pick it up later.
188
188
 
189
- Waiting resolves for both `"completed"` and `"failed"`: a failed job is an
189
+ Waiting resolves for both `"complete"` and `"failed"`: a failed job is an
190
190
  answer, not a transport error. Check the status before reading the result.
191
191
 
192
192
  ```ts
@@ -194,8 +194,8 @@ const job = await oms.jobs.wait({ id: started.job_id!, watchToken: started.watch
194
194
  if (job.status === "failed") throw new Error(job.error ?? "the job failed");
195
195
  ```
196
196
 
197
- A finished tool row says `status: "complete"`; a finished row in the job table
198
- says `"completed"`; the downloader says `"done"`. Compare against the exported
197
+ A finished job says `status: "complete"`, not `"completed"`, and the
198
+ downloader spells its own terminal state `"done"`. Compare against the exported
199
199
  constants, never against a literal.
200
200
 
201
201
  Check the quota before starting something expensive:
package/dist/index.js CHANGED
@@ -12560,11 +12560,9 @@ function songImportProgress(record) {
12560
12560
 
12561
12561
  class MusicImportsNamespace extends Resource {
12562
12562
  spotify;
12563
- srMachine;
12564
12563
  constructor(http) {
12565
12564
  super(http);
12566
12565
  this.spotify = new SpotifySyncNamespace(http);
12567
- this.srMachine = new SRMachineNamespace(http);
12568
12566
  }
12569
12567
  async list(params = {}, options = {}) {
12570
12568
  const base = {
@@ -12658,48 +12656,6 @@ class SpotifySyncNamespace extends Resource {
12658
12656
  };
12659
12657
  }
12660
12658
  }
12661
-
12662
- class SRMachineNamespace extends Resource {
12663
- async metadata(url, options = {}) {
12664
- return this.http.get("/s_r_machine/metadata", {
12665
- timeoutMs: 120000,
12666
- ...options,
12667
- query: { url },
12668
- retry: options.retry ?? false
12669
- });
12670
- }
12671
- async artwork(url, options = {}) {
12672
- return this.http.download("/s_r_machine/artwork", {
12673
- timeoutMs: 120000,
12674
- ...options,
12675
- query: { url },
12676
- retry: options.retry ?? false
12677
- });
12678
- }
12679
- async audio(url, options = {}) {
12680
- return this.http.download("/s_r_machine/audio", {
12681
- timeoutMs: 600000,
12682
- ...options,
12683
- query: { url },
12684
- retry: options.retry ?? false
12685
- });
12686
- }
12687
- async convertToOpus(file2, options = {}) {
12688
- const form = await buildFormData({ file: file2 });
12689
- const response = await this.http.raw("POST", "/s_r_machine/convert-opus", {
12690
- timeoutMs: 600000,
12691
- ...options,
12692
- body: form
12693
- });
12694
- const data = await response.blob();
12695
- return {
12696
- data,
12697
- filename: filenameFromDisposition(response.headers.get("content-disposition")),
12698
- contentType: response.headers.get("content-type") ?? undefined,
12699
- size: data.size
12700
- };
12701
- }
12702
- }
12703
12659
  function spotifySyncProgress(status) {
12704
12660
  const playlists = status.sync_progress?.playlists ?? [];
12705
12661
  let loaded = 0;
@@ -12835,7 +12791,7 @@ class MusicPlaylistsNamespace extends Resource {
12835
12791
  async reorder(id, songIds, options = {}) {
12836
12792
  const ids = integerIds(songIds, "songIds");
12837
12793
  if (ids.length === 0) {
12838
- throw new TypeError("reorder needs the complete desired order and refuses an empty array: the backend raises ArgumentError " + "for it, which surfaces as a 500 rather than a 400.");
12794
+ throw new TypeError("reorder needs the complete desired order and refuses an empty array: the server answers 500 for it, " + "not 400.");
12839
12795
  }
12840
12796
  await this.http.post(`/playlists/${encodeURIComponent(String(id))}/reorder`, { song_ids: ids }, options);
12841
12797
  }
@@ -12958,7 +12914,7 @@ function integerIds(ids, field) {
12958
12914
  return ids.map((raw, index) => {
12959
12915
  const value = typeof raw === "string" ? Number(raw) : raw;
12960
12916
  if (typeof value !== "number" || !Number.isInteger(value)) {
12961
- throw new TypeError(`${field}[${index}] is ${JSON.stringify(raw)}, which is not an integer id. Song ids are integers on this ` + "API, and the backend matches them by identity: a string id matches no row, so the request would " + "succeed and change nothing.");
12917
+ throw new TypeError(`${field}[${index}] is ${JSON.stringify(raw)}, which is not an integer id. Song ids are integers on this ` + "API and are matched by identity: a string id matches no row, so the request would succeed and " + "change nothing.");
12962
12918
  }
12963
12919
  return value;
12964
12920
  });
@@ -13553,7 +13509,7 @@ class CableConnectionImpl {
13553
13509
  const identifier = JSON.stringify(params);
13554
13510
  const registration = { handlers, live: true };
13555
13511
  if (this.subs.has(identifier)) {
13556
- throw new OmsNetworkError(`Already subscribed to ${identifier}. ActionCable keys subscriptions by identifier, so a second one would shadow the first: reuse the handle, or unsubscribe before resubscribing.`);
13512
+ throw new OmsNetworkError(`Already subscribed to ${identifier}. Subscriptions are keyed by identifier, so a second one would shadow the first: reuse the handle, or unsubscribe before resubscribing.`);
13557
13513
  }
13558
13514
  this.subs.set(identifier, registration);
13559
13515
  if (this.welcomed)
@@ -14818,23 +14774,29 @@ class CaptionsNamespace extends Resource {
14818
14774
  return this.http.get(`/caption_jobs/${encodeURIComponent(id)}`, options);
14819
14775
  }
14820
14776
  async transcribe(id, input, options = {}) {
14821
- const started = await this.http.post(`/caption_jobs/${encodeURIComponent(id)}/transcribe`, {
14777
+ const started = await this.startTranscribe(id, input, options);
14778
+ return this.settle(id, started, options, "the transcription");
14779
+ }
14780
+ async startTranscribe(id, input, options = {}) {
14781
+ return this.http.post(`/caption_jobs/${encodeURIComponent(id)}/transcribe`, {
14822
14782
  start: input.start,
14823
14783
  end: input.end,
14824
14784
  ...input.language === undefined ? {} : { language: input.language }
14825
14785
  }, { ...options, retry: options.retry ?? false });
14826
- return this.settle(id, started, options, "the transcription");
14827
14786
  }
14828
14787
  async render(id, input = {}, options = {}) {
14788
+ const started = await this.startRender(id, input, options);
14789
+ return this.settle(id, started, options, "the render");
14790
+ }
14791
+ async startRender(id, input = {}, options = {}) {
14829
14792
  const words = input.words ?? (await this.get(id, options)).words ?? [];
14830
14793
  if (words.length === 0) {
14831
14794
  throw new OmsError(`Caption job ${id} has no words to render. Transcribe a window first with transcribe(), ` + `or pass an edited list as \`words\`.`, "conflict");
14832
14795
  }
14833
- const started = await this.http.post(`/caption_jobs/${encodeURIComponent(id)}/render`, {
14796
+ return this.http.post(`/caption_jobs/${encodeURIComponent(id)}/render`, {
14834
14797
  words,
14835
14798
  ...input.style === undefined ? {} : { style: input.style }
14836
14799
  }, { ...options, retry: options.retry ?? false });
14837
- return this.settle(id, started, options, "the render");
14838
14800
  }
14839
14801
  async delete(id, options = {}) {
14840
14802
  await this.http.delete(`/caption_jobs/${encodeURIComponent(id)}`, options);
@@ -14861,7 +14823,7 @@ class CaptionsNamespace extends Resource {
14861
14823
  }
14862
14824
  async createChunked(input, options = {}) {
14863
14825
  if (isNativeFile(input.video.data)) {
14864
- throw new OmsError(`Cannot chunk-upload "${input.video.filename}": it is a React Native file descriptor ` + `(${input.video.data.uri}), and the chunked path has to slice the bytes. Use create() for a file ` + "under Cloudflare's ~100 MB request cap, or read the video into a Uint8Array first " + "(Expo: `new File(uri).bytes()`) and pass that.", "invalid_request");
14826
+ throw new OmsError(`Cannot chunk-upload "${input.video.filename}": it is a React Native file descriptor ` + `(${input.video.data.uri}), and the chunked path has to slice the bytes. Use create() for a file ` + "under the ~100 MB request cap, or read the video into a Uint8Array first " + "(Expo: `new File(uri).bytes()`) and pass that.", "invalid_request");
14865
14827
  }
14866
14828
  const { onProgress, onPart, ...request } = options;
14867
14829
  const { blob } = await readFileInput(input.video);
@@ -15136,6 +15098,49 @@ class UpscaleNamespace extends Resource {
15136
15098
  }
15137
15099
  }
15138
15100
 
15101
+ // src/resources/tools/srMachine.ts
15102
+ class SRMachineNamespace extends Resource {
15103
+ async metadata(url, options = {}) {
15104
+ return this.http.get("/s_r_machine/metadata", {
15105
+ timeoutMs: 120000,
15106
+ ...options,
15107
+ query: { url },
15108
+ retry: options.retry ?? false
15109
+ });
15110
+ }
15111
+ async artwork(url, options = {}) {
15112
+ return this.http.download("/s_r_machine/artwork", {
15113
+ timeoutMs: 120000,
15114
+ ...options,
15115
+ query: { url },
15116
+ retry: options.retry ?? false
15117
+ });
15118
+ }
15119
+ async audio(url, options = {}) {
15120
+ return this.http.download("/s_r_machine/audio", {
15121
+ timeoutMs: 600000,
15122
+ ...options,
15123
+ query: { url },
15124
+ retry: options.retry ?? false
15125
+ });
15126
+ }
15127
+ async convertToOpus(file2, options = {}) {
15128
+ const form = await buildFormData({ file: file2 });
15129
+ const response = await this.http.raw("POST", "/s_r_machine/convert-opus", {
15130
+ timeoutMs: 600000,
15131
+ ...options,
15132
+ body: form
15133
+ });
15134
+ const data = await response.blob();
15135
+ return {
15136
+ data,
15137
+ filename: filenameFromDisposition(response.headers.get("content-disposition")),
15138
+ contentType: response.headers.get("content-type") ?? undefined,
15139
+ size: data.size
15140
+ };
15141
+ }
15142
+ }
15143
+
15139
15144
  // src/resources/tools/vocalSeparation.ts
15140
15145
  function vocalSeparationProgress(record) {
15141
15146
  const base = toolProgress(record);
@@ -15267,6 +15272,7 @@ class ToolsNamespace extends Resource {
15267
15272
  captions;
15268
15273
  jumpstyle;
15269
15274
  downloader;
15275
+ srMachine;
15270
15276
  constructor(http) {
15271
15277
  super(http);
15272
15278
  this.backgroundRemoval = new BackgroundRemovalNamespace(http);
@@ -15276,6 +15282,7 @@ class ToolsNamespace extends Resource {
15276
15282
  this.captions = new CaptionsNamespace(http);
15277
15283
  this.jumpstyle = new JumpstyleNamespace(http);
15278
15284
  this.downloader = new DownloaderNamespace(http);
15285
+ this.srMachine = new SRMachineNamespace(http);
15279
15286
  }
15280
15287
  }
15281
15288
 
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * OAuth 2.0 Device Authorization Grant (RFC 8628).
3
3
  *
4
- * This is how a CLI or an MCP server signs a person in without ever handling
4
+ * This is how a terminal or a headless client signs a person in without ever handling
5
5
  * their password: the client asks for a code, the person opens a URL in a real
6
6
  * browser and approves, and the client polls the token endpoint until the
7
7
  * approval lands.
@@ -36,7 +36,7 @@ export * from "./device";
36
36
  export * from "./tokens";
37
37
  /** Who the current credential belongs to. */
38
38
  export interface WhoAmI {
39
- /** `users.id`. The stable identifier; matches the OIDC `sub` claim. */
39
+ /** The stable user identifier; matches the OIDC `sub` claim. */
40
40
  readonly id: string;
41
41
  /** Current handle. Mutable - never key anything on it. */
42
42
  readonly handle: string;
@@ -107,7 +107,7 @@ export declare class AuthNamespace extends Resource {
107
107
  }, options?: RequestOptions): Promise<void>;
108
108
  /**
109
109
  * Reads the OIDC claims of the current credential from
110
- * `GET /oauth/userinfo`. `sub` is `users.id`.
110
+ * `GET /oauth/userinfo`. `sub` is the user's stable `id`.
111
111
  *
112
112
  * Needs the `openid` scope; without it the answer is 403. Members whose
113
113
  * value is null or empty are omitted from the response, so read defensively.
@@ -2,15 +2,15 @@
2
2
  * Token providers: where the transport gets a bearer token from.
3
3
  *
4
4
  * The core has no storage. A provider is either a constant, or a thing the
5
- * host wired to its own store (the CLI's config file, a Worker KV namespace, a
5
+ * host wired to its own store (a config file, a Worker KV namespace, a
6
6
  * browser's memory). Nothing here reads a file or an environment variable.
7
7
  *
8
8
  * Two credential shapes exist today and both are just bearer tokens on the
9
9
  * wire:
10
- * - a legacy opaque session token (a UUID minted by `Session`), which never
11
- * expires and carries no scopes;
12
- * - an OAuth 2 / OIDC access token from doorkeeper, which does expire and does
13
- * carry scopes, and which comes with a refresh token.
10
+ * - a legacy opaque session token (a UUID), which never expires and carries no
11
+ * scopes;
12
+ * - an OAuth 2 / OIDC access token, which does expire and does carry scopes,
13
+ * and which comes with a refresh token.
14
14
  *
15
15
  * {@link TokenSet} models the second. The first is just a string.
16
16
  *
@@ -23,7 +23,7 @@ import { OmsError } from "../errors";
23
23
  import { type ApiClient, type TokenProvider } from "../http";
24
24
  import type { RequestOptions } from "../types";
25
25
  /**
26
- * An OAuth 2 token response, as doorkeeper returns it.
26
+ * An OAuth 2 token response, as the token endpoint returns it.
27
27
  *
28
28
  * `expiresAt` is absolute epoch milliseconds, not the `expires_in` seconds the
29
29
  * server sends, so a stored set stays correct across a restart.
@@ -45,8 +45,8 @@ export interface TokenSet {
45
45
  /** Claims the SDK reads out of an OIDC id token. */
46
46
  export interface IdentityClaims {
47
47
  /**
48
- * Stable user identifier: `users.id`. Never the handle and never the email,
49
- * both of which the user can change.
48
+ * Stable user identifier: the user's `id`, as `oms.account.me()` reports it.
49
+ * Never the handle and never the email, both of which the user can change.
50
50
  */
51
51
  readonly sub: string;
52
52
  readonly iss?: string;
@@ -87,8 +87,8 @@ export declare const DEFAULT_REFRESH_SKEW_MS = 60000;
87
87
  /**
88
88
  * Wraps a constant token. This is what `new Oms({ token })` builds.
89
89
  *
90
- * Accepts both credential kinds: an opaque session UUID and a doorkeeper
91
- * access token look identical on the wire.
90
+ * Accepts both credential kinds: an opaque session UUID and an OAuth access
91
+ * token look identical on the wire.
92
92
  */
93
93
  export declare function staticToken(token: string | null): TokenProvider;
94
94
  /**
@@ -304,8 +304,8 @@ export declare class OmsOAuthError extends OmsError {
304
304
  * Recognises an OAuth error inside whatever the transport threw.
305
305
  *
306
306
  * Deliberately narrow: only 400 and 401 bodies are read as OAuth errors. A 429
307
- * comes from rack-attack with the body `{"error":"rate_limited"}`, and that
308
- * `error` key is NOT an OAuth code - reading it as one abandons a perfectly
307
+ * carries the body `{"error":"rate_limited"}`, and that `error` key is NOT an
308
+ * OAuth code - reading it as one abandons a perfectly
309
309
  * live device flow. It stays an {@link OmsQuotaError} and the caller handles
310
310
  * it as a rate limit.
311
311
  *
@@ -316,8 +316,8 @@ export declare function oauthErrorFrom(thrown: unknown): OmsOAuthError | undefin
316
316
  export interface InsufficientScope {
317
317
  /**
318
318
  * The scopes the endpoint needed. EMPTY when the server named none, which
319
- * means the endpoint has not been opened to OAuth clients at all - a backend
320
- * gap, not a client bug. The two cases must read differently to the user.
319
+ * means the endpoint accepts no OAuth token at all - a server-side gap, not
320
+ * a client bug. The two cases must read differently to the user.
321
321
  */
322
322
  readonly required: string[];
323
323
  /** The `realm` parameter, when present. */
@@ -342,7 +342,7 @@ export declare function readInsufficientScope(error: unknown): InsufficientScope
342
342
  *
343
343
  * The OAuth endpoints do not take JSON, which is why this exists next to
344
344
  * `ApiClient.post` rather than using it. Blank values are dropped rather than
345
- * sent empty, because doorkeeper reads `""` as a present-but-invalid parameter.
345
+ * sent empty, because the server reads `""` as a present-but-invalid parameter.
346
346
  *
347
347
  * Retries are OFF and stay off. Replaying `POST /oauth/token` after a lost
348
348
  * response is not safe: the server may have rotated the refresh token already,
@@ -41,7 +41,7 @@ import type { FetchLike, RetryOptions } from "./types";
41
41
  * Anything accepted as a credential by {@link Oms}.
42
42
  *
43
43
  * A bare string is either kind of bearer token the API takes: a legacy opaque
44
- * `Session` UUID or an OAuth access token. A function is called on every
44
+ * session UUID or an OAuth access token. A function is called on every
45
45
  * request. A {@link TokenProvider} additionally gets a chance to refresh on a
46
46
  * 401 - see `auth/tokens.ts`.
47
47
  */
@@ -66,7 +66,7 @@ export interface OmsOptions {
66
66
  * by name.
67
67
  *
68
68
  * ```ts
69
- * // in the omelhorsite web app, served from the same site as the API
69
+ * // on a first-party page, served from the same site as the API
70
70
  * const oms = new Oms({ sessionCookie: true });
71
71
  * ```
72
72
  */
@@ -75,13 +75,13 @@ export interface OmsOptions {
75
75
  readonly baseUrl?: string;
76
76
  /**
77
77
  * The fetch to talk through. Defaults to `globalThis.fetch`. Injecting one is
78
- * how a Worker adds a cache, how a test swaps in a double, and how the CLI
78
+ * how a Worker adds a cache, how a test swaps in a double, and how a host
79
79
  * adds a proxy - the SDK never patches a global.
80
80
  */
81
81
  readonly fetch?: FetchLike;
82
82
  /** Headers merged into every request, below per-call headers. */
83
83
  readonly headers?: Record<string, string>;
84
- /** Default deadline for one call including its retries. `0` disables it. */
84
+ /** Default deadline for one attempt; a retry gets a fresh one. `0` disables it. */
85
85
  readonly timeoutMs?: number;
86
86
  /** Default backoff policy, or `false` to never retry. */
87
87
  readonly retry?: RetryOptions | false;
@@ -103,10 +103,10 @@ export interface OmsOptions {
103
103
  *
104
104
  * ## Two credentials, two namespaces
105
105
  *
106
- * `oms.sessions` mints the opaque `Session` token the website and the mobile
107
- * apps use, which carries the whole account. `oms.auth` runs OAuth, whose
108
- * tokens are scoped and, because `enforce_oauth_scope!` denies by omission,
109
- * cannot reach most of the API at all. `oms.realtime` accepts only the first
106
+ * `oms.sessions` mints the opaque session token, which carries the whole
107
+ * account. `oms.auth` runs OAuth, whose tokens are scoped and, because an
108
+ * endpoint with no declared scope refuses every OAuth token, cannot reach most
109
+ * of the API at all. `oms.realtime` accepts only the first
110
110
  * kind. Picking the wrong one shows up as a `403 insufficient_scope`, or on the
111
111
  * cable as a connection that is silently anonymous.
112
112
  *
@@ -178,9 +178,9 @@ export declare class Oms {
178
178
  /** OAuth client registration for anyone, plus the `/admin/*` routes. */
179
179
  readonly admin: AdminNamespace;
180
180
  /**
181
- * The ActionCable connection: playback handoff, jams, notifications, job
181
+ * The WebSocket connection: playback handoff, jams, notifications, job
182
182
  * progress. Opens nothing until {@link RealtimeNamespace.connect} is called,
183
- * and wants a `Session` token rather than the client's own credential - see
183
+ * and wants a session token rather than the client's own credential - see
184
184
  * that method for why.
185
185
  */
186
186
  readonly realtime: RealtimeNamespace;
@@ -8,15 +8,15 @@
8
8
  * The API answers with at least four different error body shapes, so anything
9
9
  * that reads an error body must go through {@link normalizeErrorBody}:
10
10
  *
11
- * - a bare JSON string: `"Image too large"` (ResponseHelpers)
12
- * - a sentence from ActiveModel: `"Name can't be blank and ..."` (error_messages)
11
+ * - a bare JSON string: `"Image too large"`
12
+ * - a validation sentence: `"Name can't be blank and ..."`
13
13
  * - an object with `error`: `{"error":"rate_limited","retry_after":37}`
14
14
  * - an object of field errors: `{"errors":{"url":["is invalid"]}}`
15
15
  * - plain text / HTML: short-link 404 pages, proxy errors
16
16
  */
17
17
  /** Machine-readable code carried by every SDK error. */
18
18
  export type OmsErrorCode = "api_error" | "unauthorized" | "forbidden" | "not_found" | "conflict" | "invalid_request" | "quota_exceeded" | "rate_limited" | "server_error" | "timeout" | "aborted" | "network" | "unsupported" | "unknown";
19
- /** Extra context attached to an error, useful for logs and for the CLI. */
19
+ /** Extra context attached to an error, useful for logs. */
20
20
  export interface OmsErrorContext {
21
21
  /** HTTP method of the failing request, when there was one. */
22
22
  readonly method?: string;
@@ -38,9 +38,9 @@ export declare class OmsError extends Error {
38
38
  * This class's own name, as a LITERAL.
39
39
  *
40
40
  * `this.name = new.target.name` would be the obvious way to do this and it
41
- * is wrong here: `bun build --minify` renames the classes, so the shipped
42
- * `oms` binary reported `name: "A"` in its JSON error envelope while a dev
43
- * run reported `OmsNetworkError`. A minifier renames identifiers, never
41
+ * is wrong here: `bun build --minify` renames the classes, so a minified
42
+ * build reported `name: "A"` in its JSON error envelope while a dev run
43
+ * reported `OmsNetworkError`. A minifier renames identifiers, never
44
44
  * string literals or property names, so a static literal survives the build.
45
45
  *
46
46
  * Every subclass shadows this, and `new.target` is the constructor that was
@@ -95,9 +95,6 @@ export declare class OmsApiError extends OmsError {
95
95
  }
96
96
  /**
97
97
  * 401 or 403: the credential is missing, expired, or not allowed to do this.
98
- *
99
- * The CLI turns this into "run `oms auth login`"; the MCP server turns it into
100
- * a device-flow prompt.
101
98
  */
102
99
  export declare class OmsAuthError extends OmsApiError {
103
100
  static readonly errorName: string;
@@ -107,10 +104,10 @@ export declare class OmsAuthError extends OmsApiError {
107
104
  /**
108
105
  * 429, or a documented daily-quota rejection.
109
106
  *
110
- * Two different producers land here and they do not look alike:
111
- * rack-attack answers `{"error":"rate_limited","retry_after":37}` with a
112
- * `Retry-After` header, while a controller quota gate answers a bare string
113
- * such as `"Daily edit quota reached (5/day)"` with no header at all. Read
107
+ * Two different producers land here and they do not look alike: a rate limit
108
+ * answers `{"error":"rate_limited","retry_after":37}` with a `Retry-After`
109
+ * header, while a daily quota answers a bare string such as
110
+ * `"Daily edit quota reached (5/day)"` with no header at all. Read
114
111
  * {@link retryAfterMs}; it is `undefined` in the second case.
115
112
  */
116
113
  export declare class OmsQuotaError extends OmsApiError {
@@ -160,7 +157,7 @@ export interface NormalizedError {
160
157
  readonly message: string;
161
158
  /** A code the server named itself (`{"error":"rate_limited"}`), if any. */
162
159
  readonly serverCode: string | undefined;
163
- /** Per-field messages, when the body was shaped like ActiveModel errors. */
160
+ /** Per-field messages, when the body was a field-to-messages map. */
164
161
  readonly fieldErrors: Record<string, string[]> | undefined;
165
162
  }
166
163
  /**
@@ -179,7 +176,7 @@ export interface NormalizedError {
179
176
  export declare function normalizeErrorBody(body: unknown, fallback?: string): NormalizedError;
180
177
  /**
181
178
  * Reads a `Retry-After` header. RFC 9110 allows both delay-seconds and an
182
- * HTTP-date; rack-attack sends seconds, but a proxy in front may not.
179
+ * HTTP-date; the API sends seconds, but a proxy in front may not.
183
180
  *
184
181
  * @returns Milliseconds to wait, or `undefined` when the header is absent or junk.
185
182
  */