@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.
- package/README.md +4 -4
- package/dist/index.js +4 -4
- package/dist/types/auth/device.d.ts +1 -1
- package/dist/types/auth/index.d.ts +2 -2
- package/dist/types/auth/tokens.d.ts +15 -15
- package/dist/types/client.d.ts +10 -10
- package/dist/types/errors.d.ts +12 -15
- package/dist/types/http.d.ts +74 -118
- package/dist/types/index.d.ts +1 -2
- package/dist/types/local/qr.d.ts +1 -1
- package/dist/types/local/wordlist.d.ts +2 -3
- package/dist/types/resources/account.d.ts +14 -17
- package/dist/types/resources/auth/index.d.ts +1 -1
- package/dist/types/resources/auth/passkeys.d.ts +127 -163
- package/dist/types/resources/auth/sessions.d.ts +110 -152
- package/dist/types/resources/chests.d.ts +27 -31
- package/dist/types/resources/dynamicQrs.d.ts +29 -45
- package/dist/types/resources/forms.d.ts +37 -58
- package/dist/types/resources/jobs.d.ts +28 -40
- package/dist/types/resources/media.d.ts +48 -61
- package/dist/types/resources/music/artists.d.ts +179 -245
- package/dist/types/resources/music/imports.d.ts +181 -210
- package/dist/types/resources/music/index.d.ts +8 -7
- package/dist/types/resources/music/playlists.d.ts +77 -110
- package/dist/types/resources/music/social.d.ts +153 -228
- package/dist/types/resources/music/songs.d.ts +160 -206
- package/dist/types/resources/realtime.d.ts +75 -88
- package/dist/types/resources/shortLinks.d.ts +33 -45
- package/dist/types/resources/storage/upload.d.ts +42 -56
- package/dist/types/resources/storage.d.ts +71 -104
- package/dist/types/resources/tools/backgroundRemoval.d.ts +11 -13
- package/dist/types/resources/tools/captions.d.ts +107 -135
- package/dist/types/resources/tools/upscale.d.ts +12 -16
- package/dist/types/types.d.ts +29 -38
- 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, //
|
|
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 `"
|
|
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
|
|
198
|
-
|
|
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
|
@@ -12835,7 +12835,7 @@ class MusicPlaylistsNamespace extends Resource {
|
|
|
12835
12835
|
async reorder(id, songIds, options = {}) {
|
|
12836
12836
|
const ids = integerIds(songIds, "songIds");
|
|
12837
12837
|
if (ids.length === 0) {
|
|
12838
|
-
throw new TypeError("reorder needs the complete desired order and refuses an empty array: the
|
|
12838
|
+
throw new TypeError("reorder needs the complete desired order and refuses an empty array: the server answers 500 for it, " + "not 400.");
|
|
12839
12839
|
}
|
|
12840
12840
|
await this.http.post(`/playlists/${encodeURIComponent(String(id))}/reorder`, { song_ids: ids }, options);
|
|
12841
12841
|
}
|
|
@@ -12958,7 +12958,7 @@ function integerIds(ids, field) {
|
|
|
12958
12958
|
return ids.map((raw, index) => {
|
|
12959
12959
|
const value = typeof raw === "string" ? Number(raw) : raw;
|
|
12960
12960
|
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
|
|
12961
|
+
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
12962
|
}
|
|
12963
12963
|
return value;
|
|
12964
12964
|
});
|
|
@@ -13553,7 +13553,7 @@ class CableConnectionImpl {
|
|
|
13553
13553
|
const identifier = JSON.stringify(params);
|
|
13554
13554
|
const registration = { handlers, live: true };
|
|
13555
13555
|
if (this.subs.has(identifier)) {
|
|
13556
|
-
throw new OmsNetworkError(`Already subscribed to ${identifier}.
|
|
13556
|
+
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
13557
|
}
|
|
13558
13558
|
this.subs.set(identifier, registration);
|
|
13559
13559
|
if (this.welcomed)
|
|
@@ -14861,7 +14861,7 @@ class CaptionsNamespace extends Resource {
|
|
|
14861
14861
|
}
|
|
14862
14862
|
async createChunked(input, options = {}) {
|
|
14863
14863
|
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
|
|
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 the ~100 MB request cap, or read the video into a Uint8Array first " + "(Expo: `new File(uri).bytes()`) and pass that.", "invalid_request");
|
|
14865
14865
|
}
|
|
14866
14866
|
const { onProgress, onPart, ...request } = options;
|
|
14867
14867
|
const { blob } = await readFileInput(input.video);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* OAuth 2.0 Device Authorization Grant (RFC 8628).
|
|
3
3
|
*
|
|
4
|
-
* This is how a
|
|
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
|
-
/**
|
|
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 `
|
|
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 (
|
|
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
|
|
11
|
-
*
|
|
12
|
-
* - an OAuth 2 / OIDC access token
|
|
13
|
-
*
|
|
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
|
|
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: `
|
|
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
|
|
91
|
-
*
|
|
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
|
-
*
|
|
308
|
-
*
|
|
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
|
|
320
|
-
*
|
|
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
|
|
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,
|
package/dist/types/client.d.ts
CHANGED
|
@@ -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
|
-
*
|
|
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
|
-
* //
|
|
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
|
|
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
|
|
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
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
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
|
|
181
|
+
* The WebSocket connection: playback handoff, jams, notifications, job
|
|
182
182
|
* progress. Opens nothing until {@link RealtimeNamespace.connect} is called,
|
|
183
|
-
* and wants a
|
|
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;
|
package/dist/types/errors.d.ts
CHANGED
|
@@ -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"`
|
|
12
|
-
* - a sentence
|
|
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
|
|
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
|
|
42
|
-
*
|
|
43
|
-
*
|
|
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
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
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
|
|
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;
|
|
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
|
*/
|