@omelhorsite/sdk 0.3.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 +113 -131
- package/dist/index.js +1049 -1246
- 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 +2 -2
- package/dist/types/internal/attachments.d.ts +17 -0
- package/dist/types/internal/helpers.d.ts +9 -0
- package/dist/types/listing.d.ts +90 -0
- 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 +19 -19
- package/dist/types/resources/admin/authorizedApplications.d.ts +133 -0
- package/dist/types/resources/admin/chests.d.ts +51 -0
- package/dist/types/resources/admin/eventAlerts.d.ts +60 -0
- package/dist/types/resources/admin/identities.d.ts +99 -0
- package/dist/types/resources/admin/index.d.ts +77 -0
- package/dist/types/resources/admin/jobs.d.ts +97 -0
- package/dist/types/resources/admin/myOauthApplications.d.ts +282 -0
- package/dist/types/resources/admin/notepads.d.ts +49 -0
- package/dist/types/resources/admin/oauthApplications.d.ts +309 -0
- package/dist/types/resources/admin/quotas.d.ts +114 -0
- package/dist/types/resources/admin/shortLinks.d.ts +201 -0
- package/dist/types/resources/admin/types.d.ts +222 -0
- package/dist/types/resources/admin/vocalSeparations.d.ts +98 -0
- package/dist/types/resources/admin.d.ts +17 -13
- 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 +116 -161
- package/dist/types/resources/chests.d.ts +27 -31
- package/dist/types/resources/content/analysis.d.ts +62 -0
- package/dist/types/resources/content/blogs.d.ts +471 -0
- package/dist/types/resources/content/feedbacks.d.ts +263 -0
- package/dist/types/resources/content/index.d.ts +52 -0
- package/dist/types/resources/content/intel/articles.d.ts +230 -0
- package/dist/types/resources/content/intel/config.d.ts +135 -0
- package/dist/types/resources/content/intel/index.d.ts +53 -0
- package/dist/types/resources/content/intel/items.d.ts +91 -0
- package/dist/types/resources/content/intel/reports.d.ts +108 -0
- package/dist/types/resources/content/intel/scripts.d.ts +152 -0
- package/dist/types/resources/content/intel/sources.d.ts +236 -0
- package/dist/types/resources/content/intel/stats.d.ts +105 -0
- package/dist/types/resources/content/intel/types.d.ts +86 -0
- package/dist/types/resources/content/jokes.d.ts +93 -0
- package/dist/types/resources/content/notifications.d.ts +147 -0
- package/dist/types/resources/content/serviceUsages.d.ts +73 -0
- package/dist/types/resources/content/servicesStatus.d.ts +194 -0
- package/dist/types/resources/content/siteConfig.d.ts +43 -0
- package/dist/types/resources/content/spaceInvaders.d.ts +154 -0
- package/dist/types/resources/content.d.ts +41 -236
- 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 +35 -44
- package/dist/types/resources/library/annotations.d.ts +162 -0
- package/dist/types/resources/library/books.d.ts +534 -0
- package/dist/types/resources/library/chat.d.ts +259 -0
- package/dist/types/resources/library/index.d.ts +39 -0
- package/dist/types/resources/library/shelves.d.ts +237 -0
- package/dist/types/resources/library/types.d.ts +120 -0
- package/dist/types/resources/library.d.ts +20 -22
- package/dist/types/resources/media.d.ts +48 -61
- package/dist/types/resources/movies/addons.d.ts +388 -0
- package/dist/types/resources/movies/collections.d.ts +352 -0
- package/dist/types/resources/movies/index.d.ts +29 -0
- package/dist/types/resources/movies/types.d.ts +50 -0
- package/dist/types/resources/movies/watchProgress.d.ts +277 -0
- package/dist/types/resources/movies.d.ts +27 -53
- package/dist/types/resources/music/artists.d.ts +182 -246
- package/dist/types/resources/music/imports.d.ts +190 -218
- package/dist/types/resources/music/index.d.ts +8 -7
- package/dist/types/resources/music/playlists.d.ts +85 -117
- package/dist/types/resources/music/social.d.ts +153 -228
- package/dist/types/resources/music/songs.d.ts +165 -227
- package/dist/types/resources/realtime.d.ts +75 -88
- package/dist/types/resources/shortLinks.d.ts +38 -47
- package/dist/types/resources/social/groupChats.d.ts +458 -0
- package/dist/types/resources/social/index.d.ts +19 -0
- package/dist/types/resources/social/messages.d.ts +424 -0
- package/dist/types/resources/social/relationships.d.ts +322 -0
- package/dist/types/resources/social/types.d.ts +37 -0
- package/dist/types/resources/social.d.ts +21 -3
- package/dist/types/resources/storage/upload.d.ts +42 -56
- package/dist/types/resources/storage.d.ts +94 -109
- package/dist/types/resources/tickets.d.ts +19 -10
- 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
|
@@ -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
|
*/
|
package/dist/types/http.d.ts
CHANGED
|
@@ -8,11 +8,10 @@
|
|
|
8
8
|
*
|
|
9
9
|
* ## Three runtimes, and where they stop agreeing
|
|
10
10
|
*
|
|
11
|
-
* The same transport runs in a browser
|
|
12
|
-
*
|
|
13
|
-
* `
|
|
14
|
-
*
|
|
15
|
-
* rather than a `try` and a shrug:
|
|
11
|
+
* The same transport runs in a browser, in React Native and in Bun or a Worker
|
|
12
|
+
* isolate. They agree on `fetch`, `AbortController`, `Headers`, `FormData` and
|
|
13
|
+
* `setTimeout`. They do NOT agree on three things, each of which has a named
|
|
14
|
+
* capability check here rather than a `try` and a shrug:
|
|
16
15
|
*
|
|
17
16
|
* | capability | browser | React Native | Worker / Bun |
|
|
18
17
|
* | --------------------------------- | ------- | ------------ | ------------ |
|
|
@@ -32,7 +31,7 @@ export declare const DEFAULT_BASE_URL = "https://backend.omelhorsite.pt";
|
|
|
32
31
|
*
|
|
33
32
|
* Answered by probing the globals, never by sniffing a platform name, and
|
|
34
33
|
* recomputed on every call so a polyfill installed after import is seen. See
|
|
35
|
-
* the table in the module note for how the three
|
|
34
|
+
* the table in the module note for how the three runtimes score.
|
|
36
35
|
*/
|
|
37
36
|
export interface TransportCapabilities {
|
|
38
37
|
/** `fetch` hands back a readable body that can be consumed as it arrives. */
|
|
@@ -51,9 +50,7 @@ export declare function transportCapabilities(): TransportCapabilities;
|
|
|
51
50
|
* UI, and it has a hard "no" on React Native. RN's `fetch` is its
|
|
52
51
|
* `XMLHttpRequest` with a whatwg-fetch shim over it: the whole body is
|
|
53
52
|
* accumulated by the native layer and handed over at the end, `response.body`
|
|
54
|
-
* is `undefined`, and there is no `ReadableStream` in the runtime at all
|
|
55
|
-
* confirmed by grep over `oms-music/src`, which mentions neither
|
|
56
|
-
* `ReadableStream` nor `getReader` anywhere.
|
|
53
|
+
* is `undefined`, and there is no `ReadableStream` in the runtime at all.
|
|
57
54
|
*
|
|
58
55
|
* That is not a gap to polyfill. Nothing that runs in JS can make the native
|
|
59
56
|
* networking layer emit partial bodies, and the shims that claim to (RN's
|
|
@@ -79,10 +76,9 @@ export declare function transportCapabilities(): TransportCapabilities;
|
|
|
79
76
|
* is to call it and use this only to decide what the UI PROMISES: a typing
|
|
80
77
|
* indicator that never types is worse than a spinner that admits it is waiting.
|
|
81
78
|
*
|
|
82
|
-
* The consumer
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
* `streamText` only promise decoded text in order.
|
|
79
|
+
* The typical consumer reads an SSE-shaped body (`data: {"delta": "..."}`
|
|
80
|
+
* lines) off `POST /books/:id/chat`. Framing the lines is the caller's job;
|
|
81
|
+
* this and `streamText` only promise decoded text in order.
|
|
86
82
|
*
|
|
87
83
|
* The three probes are all needed. `ReadableStream` existing does not mean
|
|
88
84
|
* `fetch` produces one (a polyfilled global over RN's fetch is exactly that
|
|
@@ -93,7 +89,7 @@ export declare function transportCapabilities(): TransportCapabilities;
|
|
|
93
89
|
export declare function supportsResponseStreaming(): boolean;
|
|
94
90
|
/**
|
|
95
91
|
* Whether `XMLHttpRequest` is available, which is the only route to byte-level
|
|
96
|
-
* UPLOAD progress
|
|
92
|
+
* UPLOAD progress on any runtime.
|
|
97
93
|
*
|
|
98
94
|
* True in a browser and in React Native (RN's networking is XHR underneath and
|
|
99
95
|
* `xhr.upload.onprogress` fires there); false in a Worker-class isolate and in
|
|
@@ -209,7 +205,7 @@ export type JsonBody = unknown;
|
|
|
209
205
|
export type FormFieldValue = string | number | boolean | FileInput | NativeFile | null | undefined;
|
|
210
206
|
/**
|
|
211
207
|
* Fields of a multipart form. An array value is appended once per entry with a
|
|
212
|
-
* `[]` suffix, which is how
|
|
208
|
+
* `[]` suffix (`clips[]`), which is how the API reads a list.
|
|
213
209
|
*/
|
|
214
210
|
export type FormFields = Record<string, FormFieldValue | FormFieldValue[]>;
|
|
215
211
|
/** Options for a request that carries a query string. */
|
|
@@ -238,12 +234,11 @@ export interface GetOptions extends RequestOptions {
|
|
|
238
234
|
* it never saw, so replaying it is how one `create` call becomes two records.
|
|
239
235
|
* Safe methods carry no such risk, which is the whole reason the split exists.
|
|
240
236
|
*
|
|
241
|
-
* `429` is the exception, and it is safe on every method because
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
* performed, and waiting out `Retry-After` and trying again is exactly right.
|
|
237
|
+
* `429` is the exception, and it is safe on every method because this API only
|
|
238
|
+
* ever answers one BEFORE performing the request: a rate-limited request is
|
|
239
|
+
* refused, never carried out. A 429 is therefore proof the request was refused
|
|
240
|
+
* rather than performed, and waiting out `Retry-After` and trying again is
|
|
241
|
+
* exactly right.
|
|
247
242
|
*
|
|
248
243
|
* ## Opting a mutator back in
|
|
249
244
|
*
|
|
@@ -262,45 +257,18 @@ export interface GetOptions extends RequestOptions {
|
|
|
262
257
|
* notepad) under a fresh random identifier on each attempt.
|
|
263
258
|
*
|
|
264
259
|
* This is narrower than the SDK's 0.2.0 behaviour, which retried 5xx on every
|
|
265
|
-
* verb.
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
*
|
|
269
|
-
*
|
|
270
|
-
* `
|
|
271
|
-
*
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
*
|
|
275
|
-
*
|
|
276
|
-
*
|
|
277
|
-
* That rule is right for what it governs and wrong to copy here, for one
|
|
278
|
-
* reason: it sits under react-query, where every retried operation is a QUERY.
|
|
279
|
-
* "Repeat any transport error" is safe when the thing being repeated is a read.
|
|
280
|
-
* This SDK carries the writes too, and the app's own mutations do NOT go
|
|
281
|
-
* through that policy. Applying it verbatim would replay a `POST /songs` whose
|
|
282
|
-
* answer was lost on a lift ride and mint the record twice, which is precisely
|
|
283
|
-
* the failure the method split above exists to prevent. So the SDK keeps the
|
|
284
|
-
* axis the app does not have to think about (the METHOD) and agrees with it on
|
|
285
|
-
* the axis it does: a `4xx` is never retried anywhere.
|
|
286
|
-
*
|
|
287
|
-
* On `429` the two genuinely disagree, and the disagreement is deliberate on
|
|
288
|
-
* both sides. The app declines because its ceiling-aware screens would rather
|
|
289
|
-
* show "slow down" at once than sit on a hidden `Retry-After` sleep, and
|
|
290
|
-
* because react-query re-throws a parked error before the network is even
|
|
291
|
-
* consulted. The SDK retries because it also serves the CLI and the MCP server,
|
|
292
|
-
* where the right move on a rate limit is to wait the header out and continue,
|
|
293
|
-
* and because this backend's `429` provably precedes the write (Rack::Attack in
|
|
294
|
-
* middleware, `too_many_requests!` ahead of every guarded action). A mobile
|
|
295
|
-
* host that wants the app's behaviour asks for it per call - `retry: false` -
|
|
296
|
-
* or, at the client, gets the closest match with `new Oms({ retry: { maxAttempts: 2 } })`:
|
|
297
|
-
* one extra attempt, safe methods only, exactly the app's shape.
|
|
298
|
-
*
|
|
299
|
-
* One consequence to design around rather than discover: a retried `429` obeys
|
|
300
|
-
* `Retry-After`, this API sets it from a one-minute window, and `timeoutMs`
|
|
301
|
-
* bounds ONE attempt rather than the call. A rate-limited call can therefore
|
|
302
|
-
* take minutes of wall clock. Anything with a user watching it should pass a
|
|
303
|
-
* `signal` it can abort, or turn retrying off.
|
|
260
|
+
* verb.
|
|
261
|
+
*
|
|
262
|
+
* ## Rate limits and wall clock
|
|
263
|
+
*
|
|
264
|
+
* A retried `429` obeys `Retry-After`, this API sets it from a one-minute
|
|
265
|
+
* window, and `timeoutMs` bounds ONE attempt rather than the call. A
|
|
266
|
+
* rate-limited call can therefore take minutes of wall clock. A UI with a
|
|
267
|
+
* person watching it may rather show "slow down" at once than sit on a hidden
|
|
268
|
+
* sleep: pass a `signal` it can abort, turn retrying off per call with
|
|
269
|
+
* `retry: false`, or cap it at the client with
|
|
270
|
+
* `new Oms({ retry: { maxAttempts: 2 } })` - one extra attempt, safe methods
|
|
271
|
+
* only.
|
|
304
272
|
*/
|
|
305
273
|
export declare class ApiClient {
|
|
306
274
|
/** API root with no trailing slash. */
|
|
@@ -328,7 +296,7 @@ export declare class ApiClient {
|
|
|
328
296
|
delete<T>(path: string, options?: GetOptions): Promise<T>;
|
|
329
297
|
/**
|
|
330
298
|
* `POST` a `multipart/form-data` body, parsed as JSON. Use this for every
|
|
331
|
-
* endpoint that takes
|
|
299
|
+
* endpoint that takes a multipart upload (the tools). Storage uploads
|
|
332
300
|
* do NOT go through here - they are presigned and go straight to the object
|
|
333
301
|
* store; see `resources/storage/upload.ts`.
|
|
334
302
|
*
|
|
@@ -345,7 +313,7 @@ export declare class ApiClient {
|
|
|
345
313
|
*
|
|
346
314
|
* `response.body` is NOT a promise this method can make: React Native has no
|
|
347
315
|
* `ReadableStream` and leaves it undefined, so any code reaching for
|
|
348
|
-
* `.body.getReader()` here works in
|
|
316
|
+
* `.body.getReader()` here works in a browser and in Bun and throws on a
|
|
349
317
|
* phone. Test with {@link supportsResponseStreaming} first, or use
|
|
350
318
|
* {@link ApiClient.streamText}, which contains that fork already.
|
|
351
319
|
*/
|
|
@@ -359,7 +327,7 @@ export declare class ApiClient {
|
|
|
359
327
|
* This is the primitive a streaming endpoint is built on. It promises exactly
|
|
360
328
|
* two things - decoded text, in order, with nothing lost - and deliberately
|
|
361
329
|
* promises nothing about chunk boundaries, because they are not the same on
|
|
362
|
-
* the three
|
|
330
|
+
* the three runtimes:
|
|
363
331
|
*
|
|
364
332
|
* - browser and Bun: one yield per network chunk, as it lands;
|
|
365
333
|
* - React Native: ONE yield, containing everything, after the server has
|
|
@@ -370,20 +338,18 @@ export declare class ApiClient {
|
|
|
370
338
|
* So a caller must not assume a chunk is a frame, a line, or a whole
|
|
371
339
|
* anything: a `data:` line can arrive split across two chunks, and on RN a
|
|
372
340
|
* hundred of them arrive as one string. Buffer, then split on your own
|
|
373
|
-
* delimiter.
|
|
374
|
-
*
|
|
375
|
-
*
|
|
341
|
+
* delimiter. The book chat endpoint, for instance, answers SSE `data:` lines
|
|
342
|
+
* carrying `{ delta, done, error }`; framing them belongs to the caller, not
|
|
343
|
+
* here.
|
|
376
344
|
*
|
|
377
|
-
* ## The silence limit
|
|
345
|
+
* ## The silence limit
|
|
378
346
|
*
|
|
379
|
-
* A
|
|
380
|
-
*
|
|
381
|
-
*
|
|
382
|
-
*
|
|
383
|
-
*
|
|
384
|
-
*
|
|
385
|
-
* to sit well clear of a cold model's first token; 45s is the number the
|
|
386
|
-
* frontend settled on and the default here.
|
|
347
|
+
* A server can answer `200` and then say nothing for minutes, and
|
|
348
|
+
* `await reader.read()` has no deadline of its own. `timeoutMs` does not
|
|
349
|
+
* help: it is disposed once the headers arrive (it has to be, or no stream
|
|
350
|
+
* could outlive it). `silenceTimeoutMs` bounds the gap BETWEEN chunks instead
|
|
351
|
+
* and raises {@link OmsTimeoutError} when nothing arrives for that long. It
|
|
352
|
+
* has to sit well clear of a cold model's first token; 45s is the default.
|
|
387
353
|
*
|
|
388
354
|
* Pass `0` to disable it, and mean it: an unbounded read is a spinner with no
|
|
389
355
|
* way out. It does not apply on the buffered path, where the single `text()`
|
|
@@ -437,29 +403,25 @@ export declare abstract class Resource {
|
|
|
437
403
|
constructor(http: ApiClient);
|
|
438
404
|
}
|
|
439
405
|
/**
|
|
440
|
-
* The
|
|
406
|
+
* The API's null sentinel: a single backspace character, `U+0008`.
|
|
441
407
|
*
|
|
442
408
|
* A query string has no way to say `null`. `?parent_id=` is the empty string,
|
|
443
409
|
* `?parent_id=null` is the four-letter word "null", and omitting the key
|
|
444
410
|
* entirely says something else again. So the API picked a character no real
|
|
445
|
-
* value ever contains and decodes it back to
|
|
446
|
-
*
|
|
447
|
-
*
|
|
448
|
-
*
|
|
449
|
-
*
|
|
450
|
-
*
|
|
451
|
-
*
|
|
452
|
-
* Where that `nil` lands is what makes it worth having. `Searchable.exact_search`
|
|
453
|
-
* is `where(params)`, so `exact_search[parent_id]` set to the sentinel becomes
|
|
454
|
-
* `WHERE parent_id IS NULL` - the only way to ask for the storage root nodes,
|
|
455
|
-
* for a comment with no parent, for anything unassigned.
|
|
411
|
+
* value ever contains and decodes it back to null on arrival, inside every
|
|
412
|
+
* filter bucket and in the handful of body fields that accept it.
|
|
413
|
+
*
|
|
414
|
+
* Where that null lands is what makes it worth having: `exact_search[parent_id]`
|
|
415
|
+
* set to the sentinel becomes `WHERE parent_id IS NULL` - the only way to ask
|
|
416
|
+
* for the storage root nodes, for a comment with no parent, for anything
|
|
417
|
+
* unassigned.
|
|
456
418
|
*
|
|
457
419
|
* Exported because it is part of the wire format, not because you should need
|
|
458
420
|
* it: {@link encodeQuery} writes it for you whenever a query value is `null`.
|
|
459
421
|
*/
|
|
460
422
|
export declare const NULL_SENTINEL = "\b";
|
|
461
423
|
/**
|
|
462
|
-
* Encodes query parameters the way
|
|
424
|
+
* Encodes query parameters the way the API parses them.
|
|
463
425
|
*
|
|
464
426
|
* - `{ page: 2 }` -> `page=2`
|
|
465
427
|
* - `{ ids: ["a", "b"] }` -> `ids%5B%5D=a&ids%5B%5D=b`
|
|
@@ -476,16 +438,14 @@ export declare const NULL_SENTINEL = "\b";
|
|
|
476
438
|
* - `undefined` means "I am not filtering on this column". Dropping the key is
|
|
477
439
|
* the correct encoding.
|
|
478
440
|
* - `null` means "filter where this column IS NULL". There is no literal for
|
|
479
|
-
* that in a URL, so it goes out as {@link NULL_SENTINEL} and the
|
|
480
|
-
* turns it back into
|
|
441
|
+
* that in a URL, so it goes out as {@link NULL_SENTINEL} and the server
|
|
442
|
+
* turns it back into null.
|
|
481
443
|
*
|
|
482
|
-
* Encoding `null` as "drop the key"
|
|
483
|
-
*
|
|
484
|
-
*
|
|
485
|
-
*
|
|
486
|
-
*
|
|
487
|
-
* other end, and is why `CrudActions#reject_unknown_filter_keys!` now 400s on a
|
|
488
|
-
* key it does not recognise rather than quietly widening the query.
|
|
444
|
+
* Encoding `null` as "drop the key" is the dangerous direction. The filter
|
|
445
|
+
* simply vanishes and the endpoint answers with the UNFILTERED set: a request
|
|
446
|
+
* for the root of somebody's drive comes back as their entire tree. For the
|
|
447
|
+
* same reason the API answers `400` to a filter key it does not recognise
|
|
448
|
+
* rather than quietly widening the query.
|
|
489
449
|
*
|
|
490
450
|
* The sentinel is written at every depth, even though the server only decodes
|
|
491
451
|
* it one level inside a filter bucket (`search`, `exact_search`, `modifiers`,
|
|
@@ -495,20 +455,17 @@ export declare const NULL_SENTINEL = "\b";
|
|
|
495
455
|
*
|
|
496
456
|
* ## Dates
|
|
497
457
|
*
|
|
498
|
-
* A `Date`
|
|
499
|
-
*
|
|
500
|
-
*
|
|
501
|
-
*
|
|
502
|
-
*
|
|
503
|
-
* the value and turns an unparseable one into `nil`, which silently drops that
|
|
504
|
-
* side of the range. Bodies need no equivalent branch, because `JSON.stringify`
|
|
505
|
-
* already calls `Date.prototype.toJSON` and emits the same string.
|
|
458
|
+
* A `Date` is sent as its ISO-8601 string, which is what the server's date
|
|
459
|
+
* filters parse. An unparseable value is silently treated as absent, which
|
|
460
|
+
* drops that side of the range. Bodies need no equivalent branch, because
|
|
461
|
+
* `JSON.stringify` already calls `Date.prototype.toJSON` and emits the same
|
|
462
|
+
* string.
|
|
506
463
|
*
|
|
507
464
|
* ## The brackets are percent-encoded, and that is load-bearing
|
|
508
465
|
*
|
|
509
466
|
* `search[title]` goes out as `search%5Btitle%5D`, never as raw `[` and `]`.
|
|
510
|
-
* Both parse identically
|
|
511
|
-
* tidies away on a quiet afternoon. It is not, and the reason is iOS.
|
|
467
|
+
* Both parse identically on the server, so this looks like the kind of noise
|
|
468
|
+
* someone tidies away on a quiet afternoon. It is not, and the reason is iOS.
|
|
512
469
|
*
|
|
513
470
|
* `[` and `]` are not legal in a URI query (RFC 3986 reserves them for the host
|
|
514
471
|
* component). Every browser tolerates them; Apple's URL stack does not. Give
|
|
@@ -534,16 +491,16 @@ export declare function encodeQuery(params: QueryParams): string;
|
|
|
534
491
|
* asked for again.
|
|
535
492
|
*
|
|
536
493
|
* `PUT` and `DELETE` are idempotent by RFC 9110 and are still absent, because
|
|
537
|
-
* idempotent is not the same as harmless to replay HERE.
|
|
538
|
-
*
|
|
539
|
-
*
|
|
540
|
-
*
|
|
494
|
+
* idempotent is not the same as harmless to replay HERE. A `DELETE` answers
|
|
495
|
+
* `404` the second time, so one retried after a torn connection reports "not
|
|
496
|
+
* found" for a row it deleted perfectly well - a success turned into an error
|
|
497
|
+
* the caller then acts on.
|
|
541
498
|
*/
|
|
542
499
|
export declare const SAFE_METHODS: ReadonlySet<string>;
|
|
543
500
|
/** True when {@link SAFE_METHODS} contains `method`, case-insensitively. */
|
|
544
501
|
export declare function isSafeMethod(method: string): boolean;
|
|
545
502
|
/**
|
|
546
|
-
* Builds the `modifiers[page]` string the
|
|
503
|
+
* Builds the `modifiers[page]` string the API expects (`"2:100"`).
|
|
547
504
|
*
|
|
548
505
|
* Both halves go through `resolvePageSize` / `resolvePageNumber`, which is the
|
|
549
506
|
* same pair `createPage` uses. That is the point: the size on the wire and the
|
|
@@ -552,9 +509,8 @@ export declare function isSafeMethod(method: string): boolean;
|
|
|
552
509
|
* told `hasMore: false` while 700 rows sit behind it.
|
|
553
510
|
*
|
|
554
511
|
* @throws {TypeError} for a page size that is not a finite number of at least
|
|
555
|
-
* 1. `"1:NaN"` on the wire reads as size `0`
|
|
556
|
-
*
|
|
557
|
-
* and returns the entire table.
|
|
512
|
+
* 1. `"1:NaN"` on the wire reads as size `0` on the server, which then skips
|
|
513
|
+
* pagination altogether and returns the entire table.
|
|
558
514
|
*/
|
|
559
515
|
export declare function pageModifier(page?: number, pageSize?: number): string;
|
|
560
516
|
/**
|
|
@@ -563,8 +519,8 @@ export declare function pageModifier(page?: number, pageSize?: number): string;
|
|
|
563
519
|
* `null` and `undefined` fields are OMITTED, which is the opposite of what
|
|
564
520
|
* {@link encodeQuery} does with `null` and is right for the same reason it is
|
|
565
521
|
* right there: what the receiver reads from an absent field. A multipart body
|
|
566
|
-
* only ever feeds a create here, and an absent field
|
|
567
|
-
*
|
|
522
|
+
* only ever feeds a create here, and an absent field is read as null on the
|
|
523
|
+
* server - already the value a sentinel would decode to, so writing one would
|
|
568
524
|
* add a step that changes nothing. In a query the absent key means "no filter",
|
|
569
525
|
* which is a different answer entirely.
|
|
570
526
|
*
|
|
@@ -609,7 +565,7 @@ export declare function backoffDelay(attempt: number, retry: ResolvedRetry): num
|
|
|
609
565
|
export declare function sleep(ms: number, signal?: AbortSignal): Promise<void>;
|
|
610
566
|
/**
|
|
611
567
|
* How long {@link ApiClient.streamText} will wait for the NEXT chunk before it
|
|
612
|
-
* gives up: 45 seconds
|
|
568
|
+
* gives up: 45 seconds.
|
|
613
569
|
*
|
|
614
570
|
* It is a silence limit, not a total: a stream that keeps producing runs as
|
|
615
571
|
* long as it likes. The value has to clear a cold model's first token (the
|
package/dist/types/index.d.ts
CHANGED
|
@@ -8,8 +8,7 @@
|
|
|
8
8
|
* const link = await oms.shortLinks.create({ url: "https://example.com" });
|
|
9
9
|
* ```
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
* it. Three rules make that work, and they are not negotiable:
|
|
11
|
+
* Three rules shape the package, and they are not negotiable:
|
|
13
12
|
*
|
|
14
13
|
* 1. It runs in a Cloudflare-Worker-class isolate. No `node:*`, no `process`,
|
|
15
14
|
* no filesystem, no stdout. `fetch` is injectable through the constructor.
|
|
@@ -29,6 +28,7 @@ export * from "./auth/index";
|
|
|
29
28
|
export * from "./client";
|
|
30
29
|
export * from "./errors";
|
|
31
30
|
export * from "./http";
|
|
31
|
+
export * from "./listing";
|
|
32
32
|
export * from "./local/index";
|
|
33
33
|
export * from "./resources/index";
|
|
34
34
|
export * from "./types";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Attachment helpers shared by the message families. Not part of the public surface. */
|
|
2
|
+
import type { ApiClient } from "../http";
|
|
3
|
+
import type { FileInput, NativeFile, RequestOptions } from "../types";
|
|
4
|
+
/**
|
|
5
|
+
* Byte length of an attachment, when it is knowable without reading anything.
|
|
6
|
+
* `undefined` for a stream with no declared `size` and for a picker that
|
|
7
|
+
* reported none.
|
|
8
|
+
*/
|
|
9
|
+
export declare function attachmentSize(file: FileInput | NativeFile): number | undefined;
|
|
10
|
+
/**
|
|
11
|
+
* Follows an attachment redirect. In a browser in cookie mode the redirect
|
|
12
|
+
* to object storage fails CORS and surfaces as a bare network error; that
|
|
13
|
+
* case is turned into an error that says what to do instead.
|
|
14
|
+
*/
|
|
15
|
+
export declare function followAttachment(http: ApiClient, path: string, what: string, options: RequestOptions): Promise<Blob>;
|
|
16
|
+
/** The bearer token the transport would send, or `null` when there is none (cookie mode). */
|
|
17
|
+
export declare function tokenOf(http: ApiClient): Promise<string | null>;
|