@omelhorsite/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +321 -0
  2. package/dist/index.js +11589 -0
  3. package/dist/types/auth/device.d.ts +156 -0
  4. package/dist/types/auth/index.d.ts +127 -0
  5. package/dist/types/auth/tokens.d.ts +356 -0
  6. package/dist/types/client.d.ts +133 -0
  7. package/dist/types/errors.d.ts +202 -0
  8. package/dist/types/http.d.ts +204 -0
  9. package/dist/types/index.d.ts +33 -0
  10. package/dist/types/local/index.d.ts +42 -0
  11. package/dist/types/local/password.d.ts +169 -0
  12. package/dist/types/local/qr.d.ts +127 -0
  13. package/dist/types/local/wordlist.d.ts +26 -0
  14. package/dist/types/resources/account.d.ts +296 -0
  15. package/dist/types/resources/chests.d.ts +194 -0
  16. package/dist/types/resources/dynamicQrs.d.ts +172 -0
  17. package/dist/types/resources/forms.d.ts +331 -0
  18. package/dist/types/resources/index.d.ts +30 -0
  19. package/dist/types/resources/ipLookup.d.ts +63 -0
  20. package/dist/types/resources/jobs.d.ts +233 -0
  21. package/dist/types/resources/linkTrees.d.ts +249 -0
  22. package/dist/types/resources/notepads.d.ts +96 -0
  23. package/dist/types/resources/shortLinks.d.ts +248 -0
  24. package/dist/types/resources/storage/upload.d.ts +459 -0
  25. package/dist/types/resources/storage.d.ts +527 -0
  26. package/dist/types/resources/tickets.d.ts +236 -0
  27. package/dist/types/resources/tools/backgroundRemoval.d.ts +99 -0
  28. package/dist/types/resources/tools/captions.d.ts +318 -0
  29. package/dist/types/resources/tools/downloader.d.ts +397 -0
  30. package/dist/types/resources/tools/index.d.ts +215 -0
  31. package/dist/types/resources/tools/jumpstyle.d.ts +194 -0
  32. package/dist/types/resources/tools/transcription.d.ts +178 -0
  33. package/dist/types/resources/tools/upscale.d.ts +94 -0
  34. package/dist/types/resources/tools/vocalSeparation.d.ts +183 -0
  35. package/dist/types/types.d.ts +245 -0
  36. package/package.json +37 -0
@@ -0,0 +1,133 @@
1
+ /**
2
+ * `Oms` - the single entry point of the SDK.
3
+ *
4
+ * Everything a caller can do hangs off one instance, grouped into namespaces by
5
+ * domain. This is the object a model sees first in code mode, so the namespace
6
+ * names are part of the contract: `oms.tools.transcription.create(...)` has to
7
+ * be guessable without reading a page of docs.
8
+ *
9
+ * Constructing it is cheap and does no I/O: it builds an {@link ApiClient} and
10
+ * the namespace objects, nothing else.
11
+ */
12
+ import { AuthNamespace } from "./auth/index";
13
+ import type { TokenSet } from "./auth/tokens";
14
+ import { ApiClient, type TokenProvider } from "./http";
15
+ import { type LocalNamespace } from "./local/index";
16
+ import { AccountNamespace } from "./resources/account";
17
+ import { ChestsNamespace } from "./resources/chests";
18
+ import { DynamicQrsNamespace } from "./resources/dynamicQrs";
19
+ import { FormsNamespace } from "./resources/forms";
20
+ import { IpLookupNamespace } from "./resources/ipLookup";
21
+ import { JobsNamespace } from "./resources/jobs";
22
+ import { LinkTreesNamespace } from "./resources/linkTrees";
23
+ import { NotepadsNamespace } from "./resources/notepads";
24
+ import { ShortLinksNamespace } from "./resources/shortLinks";
25
+ import { StorageNamespace } from "./resources/storage";
26
+ import { TicketsNamespace } from "./resources/tickets";
27
+ import { ToolsNamespace } from "./resources/tools/index";
28
+ import type { FetchLike, RetryOptions } from "./types";
29
+ /**
30
+ * Anything accepted as a credential by {@link Oms}.
31
+ *
32
+ * A bare string is either kind of bearer token the API takes: a legacy opaque
33
+ * `Session` UUID or an OAuth access token. A function is called on every
34
+ * request. A {@link TokenProvider} additionally gets a chance to refresh on a
35
+ * 401 - see `auth/tokens.ts`.
36
+ */
37
+ export type OmsCredential = string | TokenProvider | (() => string | null | Promise<string | null>) | null;
38
+ /** Constructor options for {@link Oms}. */
39
+ export interface OmsOptions {
40
+ /**
41
+ * The credential. Omit it for an anonymous client: several endpoints (short
42
+ * links, notepads, chests, the captcha-gated tools, ip lookup) work without
43
+ * one, at a smaller daily quota.
44
+ */
45
+ readonly token?: OmsCredential;
46
+ /**
47
+ * A provider that can refresh itself. Mutually exclusive with `token`;
48
+ * passing both throws. Build one with `refreshingTokenProvider`.
49
+ */
50
+ readonly tokens?: TokenProvider;
51
+ /** API root. Defaults to `https://backend.omelhorsite.pt`. */
52
+ readonly baseUrl?: string;
53
+ /**
54
+ * The fetch to talk through. Defaults to `globalThis.fetch`. Injecting one is
55
+ * how a Worker adds a cache, how a test swaps in a double, and how the CLI
56
+ * adds a proxy - the SDK never patches a global.
57
+ */
58
+ readonly fetch?: FetchLike;
59
+ /** Headers merged into every request, below per-call headers. */
60
+ readonly headers?: Record<string, string>;
61
+ /** Default deadline for one call including its retries. `0` disables it. */
62
+ readonly timeoutMs?: number;
63
+ /** Default backoff policy, or `false` to never retry. */
64
+ readonly retry?: RetryOptions | false;
65
+ /** Value for the `X-Oms-Client` header, e.g. `"oms-cli/0.3.1"`. */
66
+ readonly clientName?: string;
67
+ }
68
+ /**
69
+ * The omelhorsite API client.
70
+ *
71
+ * ```ts
72
+ * import { Oms } from "@omelhorsite/sdk";
73
+ *
74
+ * const oms = new Oms({ token: "..." });
75
+ * const me = await oms.account.me();
76
+ * const link = await oms.shortLinks.create({ url: "https://example.com" });
77
+ * ```
78
+ *
79
+ * Isolate-safe: no `node:*`, no environment, no stdout. A file is always a
80
+ * value (`Blob` / `Uint8Array` / `ReadableStream`), never a path.
81
+ */
82
+ export declare class Oms {
83
+ /**
84
+ * The transport. Public on purpose: an endpoint the SDK has not wrapped yet
85
+ * is still reachable with `oms.http.get("/some/path")`, which beats forking
86
+ * the SDK to add one call.
87
+ */
88
+ readonly http: ApiClient;
89
+ /** Signing in, refreshing, revoking, and the RFC 8628 device grant. */
90
+ readonly auth: AuthNamespace;
91
+ /** The signed-in user, their profile, and their usage report. */
92
+ readonly account: AccountNamespace;
93
+ /** Support tickets and their message threads. */
94
+ readonly tickets: TicketsNamespace;
95
+ /** The virtual filesystem: nodes, uploads, downloads, sharing grants. */
96
+ readonly storage: StorageNamespace;
97
+ /** Short links and their click statistics. */
98
+ readonly shortLinks: ShortLinksNamespace;
99
+ /** Anonymous shared notepads. */
100
+ readonly notepads: NotepadsNamespace;
101
+ /** QR codes whose target can be changed after printing. */
102
+ readonly dynamicQrs: DynamicQrsNamespace;
103
+ /** Geolocation and network metadata for an IP address. */
104
+ readonly ipLookup: IpLookupNamespace;
105
+ /** Ephemeral drop boxes for passing files between devices. */
106
+ readonly chests: ChestsNamespace;
107
+ /** Hosted forms and their submissions. */
108
+ readonly forms: FormsNamespace;
109
+ /** Link-in-bio pages and their click statistics. */
110
+ readonly linkTrees: LinkTreesNamespace;
111
+ /** Background jobs: listing, polling and watching. There is no cancel. */
112
+ readonly jobs: JobsNamespace;
113
+ /** The metered media tools, each with its own daily quota. */
114
+ readonly tools: ToolsNamespace;
115
+ /**
116
+ * Pure client-side helpers that touch no network and need no credential
117
+ * (password generation, QR encoding). Also exported standalone as `local`,
118
+ * for a caller who wants them without building a client.
119
+ */
120
+ readonly local: LocalNamespace;
121
+ constructor(options?: OmsOptions);
122
+ /** The API root this client talks to, with no trailing slash. */
123
+ get baseUrl(): string;
124
+ /**
125
+ * A copy of this client with a different credential, sharing nothing else.
126
+ *
127
+ * Cheaper and safer than mutating: a token swap mid-flight would let an
128
+ * in-progress request finish under the wrong identity.
129
+ */
130
+ withToken(token: OmsCredential): Oms;
131
+ /** Convenience over {@link withToken} for an OAuth {@link TokenSet}. */
132
+ withTokenSet(tokens: TokenSet): Oms;
133
+ }
@@ -0,0 +1,202 @@
1
+ /**
2
+ * Error taxonomy for the omelhorsite SDK.
3
+ *
4
+ * Every failure that leaves the SDK is an {@link OmsError}. Callers are meant to
5
+ * branch on the class (or on {@link OmsApiError.status}), never on message text -
6
+ * the backend renders human strings in several shapes and they change.
7
+ *
8
+ * The API answers with at least four different error body shapes, so anything
9
+ * that reads an error body must go through {@link normalizeErrorBody}:
10
+ *
11
+ * - a bare JSON string: `"Image too large"` (ResponseHelpers)
12
+ * - a sentence from ActiveModel: `"Name can't be blank and ..."` (error_messages)
13
+ * - an object with `error`: `{"error":"rate_limited","retry_after":37}`
14
+ * - an object of field errors: `{"errors":{"url":["is invalid"]}}`
15
+ * - plain text / HTML: short-link 404 pages, proxy errors
16
+ */
17
+ /** Machine-readable code carried by every SDK error. */
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. */
20
+ export interface OmsErrorContext {
21
+ /** HTTP method of the failing request, when there was one. */
22
+ readonly method?: string;
23
+ /** Absolute URL of the failing request, with the query string. */
24
+ readonly url?: string;
25
+ /** How many attempts were spent before giving up (1 means no retry). */
26
+ readonly attempts?: number;
27
+ /** The underlying failure, when this error wraps another one. */
28
+ readonly cause?: unknown;
29
+ }
30
+ /**
31
+ * Base class for everything the SDK throws.
32
+ *
33
+ * `instanceof OmsError` is the one check that is always safe; the subclasses
34
+ * narrow the reason.
35
+ */
36
+ export declare class OmsError extends Error {
37
+ /**
38
+ * This class's own name, as a LITERAL.
39
+ *
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
44
+ * string literals or property names, so a static literal survives the build.
45
+ *
46
+ * Every subclass shadows this, and `new.target` is the constructor that was
47
+ * actually called, so a subclass still reports its own name without
48
+ * repeating the assignment.
49
+ */
50
+ static readonly errorName: string;
51
+ /** Stable machine-readable reason. Safe to switch on. */
52
+ readonly code: OmsErrorCode;
53
+ /** HTTP method of the failing request, when the error came from one. */
54
+ readonly method: string | undefined;
55
+ /** Absolute URL of the failing request, when the error came from one. */
56
+ readonly url: string | undefined;
57
+ /** Attempts spent before the error was raised. `1` means it was not retried. */
58
+ readonly attempts: number | undefined;
59
+ constructor(message: string, code?: OmsErrorCode, context?: OmsErrorContext);
60
+ /**
61
+ * Whether retrying the exact same call could plausibly succeed. The
62
+ * {@link ApiClient} already retries what it is allowed to retry; this is for
63
+ * callers deciding whether to surface a "try again" affordance.
64
+ */
65
+ get retryable(): boolean;
66
+ /** Plain object for logging. Never includes the token. */
67
+ toJSON(): Record<string, unknown>;
68
+ }
69
+ /**
70
+ * The API answered, and the answer was an error status.
71
+ *
72
+ * `body` is the RAW parsed body exactly as the server sent it (string, array,
73
+ * object or `undefined`). It is deliberately untyped: read it when you know the
74
+ * endpoint, use `message` otherwise.
75
+ */
76
+ export declare class OmsApiError extends OmsError {
77
+ static readonly errorName: string;
78
+ /** HTTP status code. */
79
+ readonly status: number;
80
+ /** Raw parsed response body. Untouched by the normalizer. */
81
+ readonly body: unknown;
82
+ /** Response headers, lowercased keys. Useful for `retry-after` / request ids. */
83
+ readonly headers: Readonly<Record<string, string>>;
84
+ /** Per-field validation messages, when the body carried any. */
85
+ readonly fieldErrors: Readonly<Record<string, string[]>> | undefined;
86
+ constructor(message: string, options: {
87
+ status: number;
88
+ body?: unknown;
89
+ headers?: Record<string, string>;
90
+ code?: OmsErrorCode;
91
+ fieldErrors?: Record<string, string[]>;
92
+ } & OmsErrorContext);
93
+ get retryable(): boolean;
94
+ toJSON(): Record<string, unknown>;
95
+ }
96
+ /**
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
+ */
102
+ export declare class OmsAuthError extends OmsApiError {
103
+ static readonly errorName: string;
104
+ /** True for 401 (no/blown credential), false for 403 (credential is fine, act is not). */
105
+ get authenticationRequired(): boolean;
106
+ }
107
+ /**
108
+ * 429, or a documented daily-quota rejection.
109
+ *
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
114
+ * {@link retryAfterMs}; it is `undefined` in the second case.
115
+ */
116
+ export declare class OmsQuotaError extends OmsApiError {
117
+ static readonly errorName: string;
118
+ /** Milliseconds to wait before retrying, when the server said. */
119
+ readonly retryAfterMs: number | undefined;
120
+ constructor(message: string, options: {
121
+ status: number;
122
+ body?: unknown;
123
+ headers?: Record<string, string>;
124
+ code?: OmsErrorCode;
125
+ retryAfterMs?: number;
126
+ } & OmsErrorContext);
127
+ toJSON(): Record<string, unknown>;
128
+ }
129
+ /**
130
+ * The request did not finish inside its deadline, or the caller's
131
+ * `AbortSignal` fired.
132
+ *
133
+ * `code` is `"timeout"` for a deadline the SDK enforced and `"aborted"` when
134
+ * the caller's own signal aborted; check it before reporting a fault.
135
+ */
136
+ export declare class OmsTimeoutError extends OmsError {
137
+ static readonly errorName: string;
138
+ /** The deadline that expired, in milliseconds, when there was one. */
139
+ readonly timeoutMs: number | undefined;
140
+ constructor(message: string, options?: {
141
+ timeoutMs?: number;
142
+ aborted?: boolean;
143
+ } & OmsErrorContext);
144
+ get retryable(): boolean;
145
+ }
146
+ /**
147
+ * `fetch` itself rejected: DNS, TLS, connection reset, offline. No HTTP status
148
+ * exists because no response was ever received, so a retry is always safe for
149
+ * a read and usually safe for a write that never left the machine.
150
+ */
151
+ export declare class OmsNetworkError extends OmsError {
152
+ static readonly errorName: string;
153
+ constructor(message: string, context?: OmsErrorContext);
154
+ }
155
+ /** Maps an HTTP status onto the coarse machine code. */
156
+ export declare function codeForStatus(status: number): OmsErrorCode;
157
+ /** Result of running an arbitrary error body through {@link normalizeErrorBody}. */
158
+ export interface NormalizedError {
159
+ /** A single human sentence. Never empty. */
160
+ readonly message: string;
161
+ /** A code the server named itself (`{"error":"rate_limited"}`), if any. */
162
+ readonly serverCode: string | undefined;
163
+ /** Per-field messages, when the body was shaped like ActiveModel errors. */
164
+ readonly fieldErrors: Record<string, string[]> | undefined;
165
+ }
166
+ /**
167
+ * Turns any error body the backend can produce into one sentence plus whatever
168
+ * structure was recoverable. This is the ONLY place that guesses at body
169
+ * shapes; resource modules must not re-implement it.
170
+ *
171
+ * Handles, in order: `undefined`/`null`, string (including a JSON-encoded
172
+ * string), array of anything, `{error}`, `{errors}` as array or as a field map,
173
+ * `{message}`, `{detail}`, `{title}`, and finally an opaque object (stringified
174
+ * and truncated).
175
+ *
176
+ * @param body Raw parsed body. Pass exactly what the transport read.
177
+ * @param fallback Sentence to use when nothing readable could be found.
178
+ */
179
+ export declare function normalizeErrorBody(body: unknown, fallback?: string): NormalizedError;
180
+ /**
181
+ * 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.
183
+ *
184
+ * @returns Milliseconds to wait, or `undefined` when the header is absent or junk.
185
+ */
186
+ export declare function parseRetryAfter(value: string | null | undefined, now?: number): number | undefined;
187
+ /**
188
+ * Builds the right {@link OmsApiError} subclass for a response the SDK already
189
+ * read. The transport calls this; resource modules never do.
190
+ *
191
+ * @param status HTTP status code.
192
+ * @param body Raw parsed body, exactly as read.
193
+ * @param context Method, URL, attempt count and response headers.
194
+ */
195
+ export declare function apiErrorFromResponse(status: number, body: unknown, context?: OmsErrorContext & {
196
+ headers?: Record<string, string>;
197
+ }): OmsApiError;
198
+ /**
199
+ * Wraps an unknown thrown value as an {@link OmsError} without losing it.
200
+ * Anything already an OmsError is returned untouched.
201
+ */
202
+ export declare function toOmsError(thrown: unknown, context?: OmsErrorContext): OmsError;
@@ -0,0 +1,204 @@
1
+ /**
2
+ * The transport. Every request the SDK makes goes through {@link ApiClient}.
3
+ *
4
+ * Isolate-safe by construction: it imports nothing, reads no environment, and
5
+ * calls `fetch`, `AbortController`, `FormData`, `Blob` and `setTimeout` only -
6
+ * all of which a Cloudflare Worker provides. `fetch` itself is injected, so a
7
+ * host can wrap it (proxy, cache, test double) without patching a global.
8
+ */
9
+ import { type FetchLike, type FileInput, type FileOutput, type QueryParams, type RequestOptions, type ResolvedRetry, type RetryOptions } from "./types";
10
+ /** Production API root. Override only for a local backend or a test double. */
11
+ export declare const DEFAULT_BASE_URL = "https://backend.omelhorsite.pt";
12
+ /**
13
+ * Supplies the bearer token for each request.
14
+ *
15
+ * Implementations live in `auth/tokens.ts`. The transport never stores a token
16
+ * itself: it asks the provider on every request, so a refresh that happened
17
+ * elsewhere is picked up without rebuilding the client.
18
+ */
19
+ export interface TokenProvider {
20
+ /**
21
+ * Current access token, or `null` when the caller is anonymous. May be async
22
+ * so an implementation can refresh an expired token before answering.
23
+ */
24
+ getToken(): string | null | Promise<string | null>;
25
+ /**
26
+ * Called once when the API answers 401 with the token this provider just
27
+ * gave. An implementation that can refresh should do so and return `true`;
28
+ * the transport then retries the request exactly once. Returning `false` (or
29
+ * not implementing this) lets the {@link OmsAuthError} propagate.
30
+ */
31
+ onUnauthorized?(): boolean | Promise<boolean>;
32
+ }
33
+ /** Anything accepted where a token is expected. */
34
+ export type TokenLike = string | TokenProvider | (() => string | null | Promise<string | null>) | null | undefined;
35
+ /** Constructor options for {@link ApiClient}. */
36
+ export interface ApiClientOptions {
37
+ /** API root. Defaults to {@link DEFAULT_BASE_URL}. */
38
+ readonly baseUrl?: string;
39
+ /** Injected fetch. Defaults to the ambient `globalThis.fetch`. */
40
+ readonly fetch?: FetchLike;
41
+ /** Where the bearer token comes from. */
42
+ readonly tokens?: TokenProvider;
43
+ /** Headers merged into every request, below per-call headers. */
44
+ readonly headers?: Record<string, string>;
45
+ /** Default deadline for one call, retries included. `0` disables it. */
46
+ readonly timeoutMs?: number;
47
+ /** Default backoff policy, or `false` to never retry. */
48
+ readonly retry?: RetryOptions | false;
49
+ /**
50
+ * Value for the `X-Oms-Client` header, e.g. `"oms-cli/0.3.1"`. The SDK does
51
+ * not touch `User-Agent`: browsers forbid setting it and it tells us nothing
52
+ * a dedicated header does not.
53
+ */
54
+ readonly clientName?: string;
55
+ }
56
+ /** Body accepted by `post`/`patch`. `undefined` sends no body at all. */
57
+ export type JsonBody = unknown;
58
+ /** One field of a multipart form. */
59
+ export type FormFieldValue = string | number | boolean | FileInput | null | undefined;
60
+ /**
61
+ * Fields of a multipart form. An array value is appended once per entry with a
62
+ * `[]` suffix, which is how Rails reads a list (`clips[]`).
63
+ */
64
+ export type FormFields = Record<string, FormFieldValue | FormFieldValue[]>;
65
+ /** Options for a request that carries a query string. */
66
+ export interface GetOptions extends RequestOptions {
67
+ readonly query?: QueryParams;
68
+ }
69
+ /**
70
+ * HTTP client for the omelhorsite API.
71
+ *
72
+ * Retry policy, deliberately narrow:
73
+ * - a `fetch` rejection (DNS, TLS, reset) is retried;
74
+ * - `5xx` is retried;
75
+ * - `429` is retried, waiting exactly what `Retry-After` asked for;
76
+ * - every other `4xx` fails immediately, on any method.
77
+ *
78
+ * The policy applies to all verbs, `POST` included. That is the documented
79
+ * behaviour, and it means a `POST` that the server processed before dying with
80
+ * a 502 can be replayed. Pass `retry: false` on any create where a duplicate
81
+ * is worse than a failure.
82
+ */
83
+ export declare class ApiClient {
84
+ /** API root with no trailing slash. */
85
+ readonly baseUrl: string;
86
+ private readonly fetchImpl;
87
+ private readonly tokens;
88
+ private readonly baseHeaders;
89
+ private readonly timeoutMs;
90
+ private readonly retry;
91
+ constructor(options?: ApiClientOptions);
92
+ /** `GET`, parsed as JSON. */
93
+ get<T>(path: string, options?: GetOptions): Promise<T>;
94
+ /** `POST` with a JSON body, parsed as JSON. */
95
+ post<T>(path: string, body?: JsonBody, options?: GetOptions): Promise<T>;
96
+ /** `PATCH` with a JSON body, parsed as JSON. */
97
+ patch<T>(path: string, body?: JsonBody, options?: GetOptions): Promise<T>;
98
+ /** `PUT` with a JSON body, parsed as JSON. */
99
+ put<T>(path: string, body?: JsonBody, options?: GetOptions): Promise<T>;
100
+ /**
101
+ * `DELETE`, parsed as JSON. The API answers `204 No Content` for most
102
+ * destroys, which arrives here as `undefined`; type such calls as
103
+ * `delete<void>(...)`.
104
+ */
105
+ delete<T>(path: string, options?: GetOptions): Promise<T>;
106
+ /**
107
+ * `POST` a `multipart/form-data` body, parsed as JSON. Use this for every
108
+ * endpoint that takes an upload through Rails (the tools). Storage uploads
109
+ * do NOT go through here - they are presigned and go straight to the object
110
+ * store; see `resources/storage/upload.ts`.
111
+ *
112
+ * A {@link FileInput} carrying a `ReadableStream` is buffered into memory
113
+ * before it can be appended, because `FormData` has no streaming entry.
114
+ */
115
+ postForm<T>(path: string, fields: FormFields, options?: GetOptions): Promise<T>;
116
+ /**
117
+ * Escape hatch: performs the request and hands back the raw `Response`
118
+ * without reading it, so a caller can stream (`response.body`) a zip, a
119
+ * media file or an SSE endpoint. Retry and auth still apply.
120
+ *
121
+ * The caller owns the body and must consume or cancel it.
122
+ */
123
+ raw(method: string, path: string, options?: GetOptions & {
124
+ body?: BodyInit;
125
+ }): Promise<Response>;
126
+ /**
127
+ * `GET` that reads the whole response as a {@link FileOutput}, taking the
128
+ * filename from `Content-Disposition` when the server sent one.
129
+ */
130
+ download(path: string, options?: GetOptions): Promise<FileOutput>;
131
+ /** Absolute URL for a path, with the query string applied. */
132
+ url(path: string, query?: QueryParams): string;
133
+ private requestJson;
134
+ /** Performs the request, applying auth, deadline and the retry policy. */
135
+ private send;
136
+ private buildInit;
137
+ private resolveToken;
138
+ }
139
+ /**
140
+ * Base class for every resource namespace.
141
+ *
142
+ * Resource modules extend this instead of writing their own constructor, so
143
+ * every namespace is built the same way and `client.ts` can instantiate them
144
+ * uniformly.
145
+ */
146
+ export declare abstract class Resource {
147
+ protected readonly http: ApiClient;
148
+ constructor(http: ApiClient);
149
+ }
150
+ /**
151
+ * Encodes query parameters the way Rails parses them.
152
+ *
153
+ * - `{ page: 2 }` -> `page=2`
154
+ * - `{ ids: ["a", "b"] }` -> `ids%5B%5D=a&ids%5B%5D=b`
155
+ * - `{ search: { status: "open" } }` -> `search%5Bstatus%5D=open`
156
+ * - `undefined` / `null` values are dropped, never sent as an empty string.
157
+ */
158
+ export declare function encodeQuery(params: QueryParams): string;
159
+ /**
160
+ * Builds the `modifiers[page]` string the backend expects (`"2:100"`).
161
+ * Page size is clamped to the server maximum so a caller cannot silently ask
162
+ * for more and get 500 back without knowing.
163
+ */
164
+ export declare function pageModifier(page?: number, pageSize?: number): string;
165
+ /** Turns a {@link FormFields} bag into a `FormData`, buffering any streams. */
166
+ export declare function buildFormData(fields: FormFields): Promise<FormData>;
167
+ /** Narrows an unknown form value to a {@link FileInput}. */
168
+ export declare function isFileInput(value: unknown): value is FileInput;
169
+ /** Fills in whatever a partial {@link RetryOptions} left out. */
170
+ export declare function resolveRetry(options: RetryOptions | undefined): ResolvedRetry;
171
+ /** Exponential backoff for `attempt` (1-based), with optional jitter. */
172
+ export declare function backoffDelay(attempt: number, retry: ResolvedRetry): number;
173
+ /**
174
+ * Waits, but wakes early and rejects if the caller's signal aborts. Uses only
175
+ * `setTimeout`, which a Worker isolate provides.
176
+ */
177
+ export declare function sleep(ms: number, signal?: AbortSignal): Promise<void>;
178
+ /**
179
+ * Combines a deadline with the caller's signal into one signal.
180
+ *
181
+ * Written by hand rather than with `AbortSignal.any` + `AbortSignal.timeout`
182
+ * so the SDK runs on any runtime that has plain `AbortController`.
183
+ */
184
+ export declare function createDeadline(timeoutMs: number, signal: AbortSignal | undefined): {
185
+ signal: AbortSignal;
186
+ dispose(): void;
187
+ timedOut(): boolean;
188
+ };
189
+ /** Response headers as a plain object with lowercased keys. */
190
+ export declare function headerRecord(headers: Headers): Record<string, string>;
191
+ /**
192
+ * Reads a successful response.
193
+ *
194
+ * `204` and an empty body both come back as `undefined`. A non-JSON body is
195
+ * returned as text, because a handful of endpoints answer `text/plain`.
196
+ */
197
+ export declare function readJson(response: Response): Promise<unknown>;
198
+ /** Reads an error response without ever throwing on a malformed body. */
199
+ export declare function readErrorBody(response: Response): Promise<unknown>;
200
+ /**
201
+ * Pulls the filename out of a `Content-Disposition` header, preferring the
202
+ * RFC 5987 `filename*` form when both are present.
203
+ */
204
+ export declare function filenameFromDisposition(header: string | null): string | undefined;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * `@omelhorsite/sdk` - the TypeScript client for the omelhorsite API.
3
+ *
4
+ * ```ts
5
+ * import { Oms } from "@omelhorsite/sdk";
6
+ *
7
+ * const oms = new Oms({ token: process.env.OMS_TOKEN }); // in HOST code, not here
8
+ * const link = await oms.shortLinks.create({ url: "https://example.com" });
9
+ * ```
10
+ *
11
+ * This package is the product; the CLI and the MCP server are two clients of
12
+ * it. Three rules make that work, and they are not negotiable:
13
+ *
14
+ * 1. It runs in a Cloudflare-Worker-class isolate. No `node:*`, no `process`,
15
+ * no filesystem, no stdout. `fetch` is injectable through the constructor.
16
+ * 2. Files are values - `Blob`, `Uint8Array`, `ReadableStream` - never paths.
17
+ * Turning a path into bytes is the host's job.
18
+ * 3. The TYPES are the public interface. In code mode a model reads the `.d.ts`
19
+ * and nothing else, so a name or a JSDoc line carries as much weight as the
20
+ * behaviour behind it.
21
+ *
22
+ * Everything is re-exported flat. There is no deep-import path into `src/`,
23
+ * so internals can move without breaking a caller.
24
+ */
25
+ export * from "./auth/index";
26
+ export * from "./client";
27
+ export * from "./errors";
28
+ export * from "./http";
29
+ export * from "./local/index";
30
+ export * from "./resources/index";
31
+ export * from "./types";
32
+ import { Oms } from "./client";
33
+ export default Oms;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * The `local` namespace: tools that run entirely on the caller's side.
3
+ *
4
+ * Two of the site's tools never touch the API - the password generator and the
5
+ * QR renderer - and there is no reason to make a network round trip to use
6
+ * them from the SDK. They live here, grouped so they are discoverable next to
7
+ * everything else, and reachable BOTH as `oms.local.password.generate(...)` and
8
+ * as a bare `import { generatePassword } from "@omelhorsite/sdk"`.
9
+ *
10
+ * Nothing in here takes an {@link ApiClient}, so nothing in here can be a
11
+ * {@link Resource}. That is the tell: if a function needs a credential or a
12
+ * base URL, it belongs under `resources/`, not here.
13
+ *
14
+ * Re-exports every sibling module so nobody has to touch this file again.
15
+ */
16
+ import { generatePassphrase, generatePassword, passwordEntropyBits, passwordStrength } from "./password";
17
+ import { encodeQr, qrToDataUri, qrToSvg } from "./qr";
18
+ export * from "./password";
19
+ export * from "./qr";
20
+ /**
21
+ * The grouped form, mounted on the client as `oms.local`.
22
+ *
23
+ * Frozen: it is shared by every client instance, so a mutation would leak
24
+ * across them.
25
+ */
26
+ export declare const local: Readonly<{
27
+ /** Password and passphrase generation, backed by WebCrypto. */
28
+ password: Readonly<{
29
+ generate: typeof generatePassword;
30
+ passphrase: typeof generatePassphrase;
31
+ strength: typeof passwordStrength;
32
+ entropyBits: typeof passwordEntropyBits;
33
+ }>;
34
+ /** QR encoding and SVG rendering. */
35
+ qr: Readonly<{
36
+ encode: typeof encodeQr;
37
+ toSvg: typeof qrToSvg;
38
+ toDataUri: typeof qrToDataUri;
39
+ }>;
40
+ }>;
41
+ /** Type of the grouped {@link local} namespace. */
42
+ export type LocalNamespace = typeof local;