@omelhorsite/sdk 0.4.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +4 -4
  2. package/dist/index.js +59 -52
  3. package/dist/types/auth/device.d.ts +1 -1
  4. package/dist/types/auth/index.d.ts +2 -2
  5. package/dist/types/auth/tokens.d.ts +15 -15
  6. package/dist/types/client.d.ts +10 -10
  7. package/dist/types/errors.d.ts +12 -15
  8. package/dist/types/http.d.ts +74 -118
  9. package/dist/types/index.d.ts +1 -2
  10. package/dist/types/local/qr.d.ts +1 -1
  11. package/dist/types/local/wordlist.d.ts +2 -3
  12. package/dist/types/resources/account.d.ts +14 -17
  13. package/dist/types/resources/auth/index.d.ts +1 -1
  14. package/dist/types/resources/auth/passkeys.d.ts +127 -163
  15. package/dist/types/resources/auth/sessions.d.ts +110 -152
  16. package/dist/types/resources/chests.d.ts +27 -31
  17. package/dist/types/resources/dynamicQrs.d.ts +29 -45
  18. package/dist/types/resources/forms.d.ts +37 -58
  19. package/dist/types/resources/jobs.d.ts +28 -40
  20. package/dist/types/resources/media.d.ts +48 -61
  21. package/dist/types/resources/music/artists.d.ts +179 -245
  22. package/dist/types/resources/music/imports.d.ts +160 -303
  23. package/dist/types/resources/music/index.d.ts +8 -7
  24. package/dist/types/resources/music/playlists.d.ts +77 -110
  25. package/dist/types/resources/music/social.d.ts +153 -228
  26. package/dist/types/resources/music/songs.d.ts +160 -206
  27. package/dist/types/resources/realtime.d.ts +75 -88
  28. package/dist/types/resources/shortLinks.d.ts +33 -45
  29. package/dist/types/resources/storage/upload.d.ts +42 -56
  30. package/dist/types/resources/storage.d.ts +71 -104
  31. package/dist/types/resources/tools/backgroundRemoval.d.ts +11 -13
  32. package/dist/types/resources/tools/captions.d.ts +120 -135
  33. package/dist/types/resources/tools/index.d.ts +4 -0
  34. package/dist/types/resources/tools/srMachine.d.ts +114 -0
  35. package/dist/types/resources/tools/upscale.d.ts +12 -16
  36. package/dist/types/types.d.ts +29 -38
  37. package/package.json +1 -1
@@ -0,0 +1,114 @@
1
+ /** The `tools.srMachine` namespace: fetch a track's audio, artwork and metadata by URL, and transcode audio to Opus. Administrators only. */
2
+ import { Resource } from "../../http";
3
+ import type { FileInput, FileOutput, NativeFile, RequestOptions } from "../../types";
4
+ /** What `GET /s_r_machine/metadata` answers. Two keys, both nullable. */
5
+ export interface SRMachineMetadata {
6
+ readonly title: string | null;
7
+ readonly artist: string | null;
8
+ }
9
+ /**
10
+ * The SR Machine helpers, reachable as `oms.tools.srMachine`.
11
+ *
12
+ * ## Admin only, and the check is blunt
13
+ *
14
+ * Every route answers `403 "You SHALL NOT use this resource"` to anyone who is
15
+ * not an administrator. There is no allowlist, no scope and no per-user
16
+ * quota.
17
+ *
18
+ * ## What it is
19
+ *
20
+ * Four unrelated primitives left over from the "slowed + reverb" video tool:
21
+ * fetch the artwork behind a URL, fetch its audio, read its title and artist,
22
+ * and transcode an arbitrary audio blob to Opus. Nothing here touches the
23
+ * library - no song is created, nothing is stored, and the bytes come back in
24
+ * the response body. If you want a track IN the library, use
25
+ * `oms.music.imports.create()` instead; this is the raw pipe.
26
+ *
27
+ * Three of the four fetch a caller-supplied URL and hold a server thread while
28
+ * they do it, exactly like `oms.music.imports.previewPlaylist()` - but
29
+ * they have no budget of their own, so the only ceiling is the general
30
+ * 600/min. The admin gate is what stands in for a budget here. Do not build a
31
+ * batch loop on top of these.
32
+ *
33
+ * A YouTube URL carrying `?list=` is truncated at the `?list=` before the fetch,
34
+ * so a link copied from inside a playlist resolves to the single video rather
35
+ * than the playlist. That happens server-side, in all three fetchers.
36
+ *
37
+ * All three fetchers respond with `Content-Disposition: attachment` and a
38
+ * fixed filename (`artwork.jpg`, `audio.opus`), so `FileOutput.filename` is
39
+ * that constant rather than anything derived from the source.
40
+ */
41
+ export declare class SRMachineNamespace extends Resource {
42
+ /**
43
+ * `GET /s_r_machine/metadata` - the title and artist read off a URL.
44
+ *
45
+ * Both keys can be `null` for a source that carries no tags; it is a
46
+ * best-effort read, not a lookup.
47
+ *
48
+ * Not retried by default: it parks a server thread for up to 60 seconds,
49
+ * and a failure means the source refused.
50
+ *
51
+ * @throws {OmsAuthError} 403 `"You SHALL NOT use this resource"` for a
52
+ * non-admin.
53
+ * @throws {OmsApiError} 400 `"url is not allowed"` for a URL that is not
54
+ * public http(s); 500 when the fetch itself fails - an upstream failure
55
+ * surfaces as a server error here, not as a 502.
56
+ */
57
+ metadata(url: string, options?: RequestOptions): Promise<SRMachineMetadata>;
58
+ /**
59
+ * `GET /s_r_machine/artwork` - the cover behind a URL, as `image/jpeg`.
60
+ *
61
+ * Buffered fully into memory in every runtime, React Native included. It is a
62
+ * cover, so that is fine; {@link SRMachineNamespace.audio} is where it is not.
63
+ *
64
+ * @throws {OmsAuthError} 403 for a non-admin.
65
+ * @throws {OmsApiError} 400 `"url is not allowed"`; 500 on a fetch failure.
66
+ */
67
+ artwork(url: string, options?: RequestOptions): Promise<FileOutput>;
68
+ /**
69
+ * `GET /s_r_machine/audio` - the audio behind a URL, as `audio/opus`.
70
+ *
71
+ * The whole track is downloaded server-side, held in memory there, and sent
72
+ * back in one body which this then buffers into memory again on the client.
73
+ * Nothing streams. On a phone that is a whole track in the JavaScript heap,
74
+ * and there is no signed-URL alternative here the way there is for library
75
+ * media - this endpoint has no storage node behind it. Reach for it on
76
+ * desktop, think twice on React Native, and never for a batch.
77
+ *
78
+ * Generous `timeoutMs` by default because a long track legitimately takes
79
+ * minutes.
80
+ *
81
+ * @throws {OmsAuthError} 403 for a non-admin.
82
+ * @throws {OmsApiError} 400 `"url is not allowed"`; 500 on a fetch failure.
83
+ */
84
+ audio(url: string, options?: RequestOptions): Promise<FileOutput>;
85
+ /**
86
+ * `POST /s_r_machine/convert-opus` - transcode an audio file to Opus.
87
+ *
88
+ * Multipart, field name `file`, and the only method in this namespace that
89
+ * uploads. The response is `audio/opus` bytes, not JSON.
90
+ *
91
+ * Works on all three runtimes: a React Native `{ uri, name, type }` descriptor
92
+ * goes into the `FormData` verbatim and is streamed off disk by the native
93
+ * layer, while a browser or Bun caller passes a `FileInput` carrying a Blob
94
+ * or a `Uint8Array`. A `ReadableStream` is buffered first, because
95
+ * `FormData` has no streaming entry.
96
+ *
97
+ * The upload has no client-side size cap here because the server declares
98
+ * none - but the CDN in front of the API rejects a request body over roughly
99
+ * 100 MB with a 413 that never reaches it. There is no chunked path for this
100
+ * route, so a file above that simply cannot go through it.
101
+ *
102
+ * The server reads the whole part into memory before transcoding, so a large
103
+ * input is a large allocation on both sides.
104
+ *
105
+ * @throws {OmsAuthError} 403 `"You SHALL NOT use this resource"` for a
106
+ * non-admin.
107
+ * @throws {OmsApiError} 500 when no `file` part was sent or when the input
108
+ * cannot be transcoded. Neither is a graceful 400.
109
+ * @throws {TypeError} when a React Native descriptor is passed on a runtime
110
+ * whose `FormData` is the web one, which would otherwise upload the literal
111
+ * text `"[object Object]"` and answer 500.
112
+ */
113
+ convertToOpus(file: FileInput | NativeFile, options?: RequestOptions): Promise<FileOutput>;
114
+ }
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * Upscaling: enlarges an image without turning it to mush.
3
3
  *
4
- * Same shape as background removal: `POST /upscales` enqueues a proxy job and
4
+ * Same shape as background removal: `POST /upscales` enqueues a job and
5
5
  * answers with a row plus a `job_id` and, when anonymous, a `watch_token`.
6
6
  *
7
- * Backend limits: 20 MiB, and the scale must be one the upscaler advertises.
7
+ * Limits: 20 MiB, and the scale must be one of `"2"`, `"3"`, `"4"`.
8
8
  *
9
- * Like background removal, this tool is not metered by the `Quotas` catalogue,
10
- * so there is no `quota()` to call first.
9
+ * Like background removal, this tool has no daily quota, so there is no
10
+ * `quota()` to call first.
11
11
  */
12
12
  import { Resource } from "../../http";
13
13
  import type { FileInput, Id, RequestOptions } from "../../types";
@@ -15,7 +15,7 @@ import { type ToolCaptcha, type ToolJobHandle, type ToolRecord, type ToolRunOpti
15
15
  /**
16
16
  * Enlargement factor, as the string the API expects.
17
17
  *
18
- * A string and not a number because the backend compares it against an
18
+ * A string and not a number because the server compares it against an
19
19
  * allow-list of strings; `4` and `"4"` are not the same request.
20
20
  */
21
21
  export type UpscaleScale = "2" | "3" | "4";
@@ -23,19 +23,15 @@ export type UpscaleScale = "2" | "3" | "4";
23
23
  * An upscale run.
24
24
  *
25
25
  * Both routes that answer with one - `POST /upscales` and `GET /upscales/:id` -
26
- * render the `:extended` view, so `result_url` is always PRESENT and simply
27
- * `null` until the run completes. There is no default-view variant of this
28
- * record reachable through the API.
26
+ * answer the same shape, so `result_url` is always PRESENT and simply `null`
27
+ * until the run completes.
29
28
  *
30
29
  * `progress_percent`, inherited from {@link ToolRecord}, is never sent for this
31
- * tool: `UpscaleBlueprint` has no such field. Progress for an upscale lives on
32
- * the {@link Job} row that {@link UpscaleCreated.job_id} names.
30
+ * tool. Progress for an upscale lives on the {@link Job} row that
31
+ * {@link UpscaleCreated.job_id} names.
33
32
  */
34
33
  export interface Upscale extends ToolRecord {
35
- /**
36
- * One of `"2"`, `"3"`, `"4"` - a string, because the column is a string and
37
- * the allow-list is `%w[2 3 4]`. Never `null`: `NOT NULL DEFAULT '4'`.
38
- */
34
+ /** One of `"2"`, `"3"`, `"4"` - a string. Never `null`; defaults to `"4"`. */
39
35
  readonly scale: string;
40
36
  /**
41
37
  * Signed URL of the enlarged PNG, or `null`. `null` covers three different
@@ -49,9 +45,9 @@ export interface Upscale extends ToolRecord {
49
45
  export type UpscaleCreated = Upscale & ToolJobHandle;
50
46
  /** Arguments for starting a run. */
51
47
  export interface CreateUpscaleInput extends ToolCaptcha {
52
- /** The image. Backend cap: 20 MiB. */
48
+ /** The image. Cap: 20 MiB. */
53
49
  readonly file: FileInput;
54
- /** Defaults to `"4"`, which is what the backend picks when none is sent. */
50
+ /** Defaults to `"4"`, which is what the server picks when none is sent. */
55
51
  readonly scale?: UpscaleScale;
56
52
  }
57
53
  /** The `upscale` tool, reachable as `oms.tools.upscale`. */
@@ -4,7 +4,7 @@
4
4
  * Nothing here touches the platform: no `node:*`, no `process`, no `console`.
5
5
  * Files are normally values (Blob / Uint8Array / ReadableStream), never paths -
6
6
  * the core has no filesystem, and turning a path into a {@link FileInput} is the
7
- * CLI's job.
7
+ * host's job.
8
8
  *
9
9
  * React Native is the one exception, and it is the platform's exception rather
10
10
  * than a relaxation of ours: a file the user picked there is a
@@ -31,9 +31,8 @@ export type FetchLike = (input: string, init?: RequestInit) => Promise<Response>
31
31
  /**
32
32
  * A file picked on React Native, exactly as the platform hands it over.
33
33
  *
34
- * This is the shape `expo-file-system`'s picker returns and the shape the app
35
- * already builds by hand (`oms-music/src/features/settings/pickers.ts`,
36
- * `features/playlist/artworkPicker.ts`), and it is a DESCRIPTOR, not bytes: the
34
+ * This is the shape `expo-file-system`'s picker returns, and it is a
35
+ * DESCRIPTOR, not bytes: the
37
36
  * URI is a `file://`, `content://` or `ph://` handle into the device, and
38
37
  * nothing in JavaScript can turn it into a `Blob` without a native module.
39
38
  *
@@ -66,10 +65,9 @@ export interface NativeFile {
66
65
  /** Filename the server should store. RN sends it as the part's `filename`. */
67
66
  readonly name: string;
68
67
  /**
69
- * MIME type. Pickers report `""` for some `content://` URIs, which is why the
70
- * app falls back to a per-kind constant before it gets here; do the same, as
71
- * Rails infers the container format from the part's content type for several
72
- * of the tools.
68
+ * MIME type. Pickers report `""` for some `content://` URIs; fall back to a
69
+ * per-kind constant before it gets here, as the server infers the container
70
+ * format from the part's content type for several of the tools.
73
71
  */
74
72
  readonly type?: string;
75
73
  /** Byte length when the picker reported one. Ignored by RN, used by the SDK. */
@@ -97,7 +95,7 @@ export declare function isNativeFile(value: unknown): value is NativeFile;
97
95
  * multipart form bodies have to be materialised: {@link readFileInput} buffers
98
96
  * a stream into a Blob before it can be appended to a `FormData`. For anything
99
97
  * large, prefer the storage direct-upload path, which streams straight to the
100
- * object store and never passes through Rails.
98
+ * object store.
101
99
  *
102
100
  * On React Native there is no need to wrap a picked file in one of these at
103
101
  * all: pass the picked `{ uri, name, type }` object straight into the form bag
@@ -171,10 +169,8 @@ export declare function file(data: Blob | Uint8Array | ReadableStream<Uint8Array
171
169
  *
172
170
  * It ticks once per COMPLETED transfer, never per byte, and that is a property
173
171
  * of `fetch` rather than a decision this SDK is free to revisit. No `fetch` -
174
- * browser, React Native or Worker - exposes request-body progress. The web
175
- * frontend gets a real byte counter in its 36 `onUploadProgress` call sites
176
- * because axios is XHR underneath, and XHR is the only API that has ever
177
- * reported bytes as they leave.
172
+ * browser, React Native or Worker - exposes request-body progress. XHR is the
173
+ * only API that has ever reported bytes as they leave.
178
174
  *
179
175
  * There is therefore ONE mechanism in this SDK, not two: `resources/storage/upload.ts`
180
176
  * ticks per finished transfer (one per 32 MiB part on the multipart tier, one
@@ -282,17 +278,17 @@ export declare const DEFAULT_RETRY: ResolvedRetry;
282
278
  /**
283
279
  * One value in a query string.
284
280
  *
285
- * Nested objects and arrays are encoded the way Rails reads them
281
+ * Nested objects and arrays are encoded the way the API reads them
286
282
  * (`search[status]=open`, `ids[]=1&ids[]=2`). Three values do NOT encode
287
283
  * literally, and `encodeQuery` in `http.ts` carries the full argument:
288
284
  *
289
285
  * - `undefined` is dropped. It means "I am not filtering on this column".
290
- * - `null` is sent as the backend's `\b` null sentinel and comes back out of
291
- * `CrudActions` as SQL `NULL`. It means "filter where this column IS NULL".
292
- * The two are not interchangeable, and getting them the wrong way round is
293
- * the difference between one folder and somebody's entire tree.
294
- * - a `Date` is sent as its ISO-8601 string, which is the only shape the Rails
295
- * date filters parse (`String#to_date_safe`).
286
+ * - `null` is sent as the API's `\b` null sentinel and is read as SQL `NULL`.
287
+ * It means "filter where this column IS NULL". The two are not
288
+ * interchangeable, and getting them the wrong way round is the difference
289
+ * between one folder and somebody's entire tree.
290
+ * - a `Date` is sent as its ISO-8601 string, which is the only shape the date
291
+ * filters parse.
296
292
  */
297
293
  export type QueryValue = string | number | boolean | Date | null | undefined | QueryValue[] | {
298
294
  [key: string]: QueryValue;
@@ -300,11 +296,10 @@ export type QueryValue = string | number | boolean | Date | null | undefined | Q
300
296
  /** A bag of query parameters. */
301
297
  export type QueryParams = Record<string, QueryValue>;
302
298
  /**
303
- * Hard ceiling the backend applies to a page size, mirroring
304
- * `QueryModifier::MAX_PAGE_SIZE`.
299
+ * Hard ceiling the API applies to a page size.
305
300
  *
306
- * The server clamps silently - `size = [size, MAX_PAGE_SIZE].min` - so asking
307
- * for 1200 returns 500 rows and no indication that a ceiling was hit. The SDK
301
+ * The server clamps silently, so asking for 1200 returns 500 rows and no
302
+ * indication that a ceiling was hit. The SDK
308
303
  * therefore clamps to the same number BEFORE the request, so that the size it
309
304
  * reports back in {@link Paginated.pageSize} is the size the rows were actually
310
305
  * counted against. See {@link resolvePageSize}.
@@ -316,8 +311,7 @@ export declare const MAX_PAGE_SIZE = 500;
316
311
  * Deliberately below {@link MAX_PAGE_SIZE}: a `list()` is usually the first
317
312
  * screen of something, and 500 rows of expanded records is a slow first paint.
318
313
  * Note this is NOT the server's own default - a request with no page modifier
319
- * at all gets `QueryModifier::DEFAULT_PAGE_SIZE` (500) forced on it by
320
- * `CrudActions#index_modifiers_params` - but the SDK always sends one.
314
+ * at all gets 500 - but the SDK always sends one.
321
315
  */
322
316
  export declare const DEFAULT_PAGE_SIZE = 100;
323
317
  /**
@@ -332,11 +326,9 @@ export declare const DEFAULT_PAGE_SIZE = 100;
332
326
  * `hasMore: false`, dropping 700 rows without a word.
333
327
  * - **not a usable size at all** (`NaN`, `Infinity`, zero, negative) throws.
334
328
  * There is nothing sensible to clamp such a value to, and it is not merely
335
- * wrong on the client: `pageModifier` would put `"1:NaN"` on the wire,
336
- * `QueryModifier#apply_pagination` reads that as size `0`, bails out before
337
- * `limit`/`offset` are applied, and the endpoint answers with the WHOLE
338
- * table. A typo would turn a listing into an unbounded scan holding a Puma
339
- * thread and a DB connection.
329
+ * wrong on the client: `pageModifier` would put `"1:NaN"` on the wire, the
330
+ * server reads that as size `0`, skips pagination, and the endpoint answers
331
+ * with the WHOLE table. A typo would turn a listing into an unbounded scan.
340
332
  *
341
333
  * @throws {TypeError} when `pageSize` is not a finite number of at least 1.
342
334
  */
@@ -370,11 +362,10 @@ export interface PageParams {
370
362
  * A size the server could not parse is NOT clamped, it throws: `0`, a
371
363
  * negative, `NaN` and `Infinity` all raise a `TypeError` before the request
372
364
  * is built. This is deliberate and it is not defensive tidiness. `"1:NaN"`
373
- * on the wire makes `QueryModifier#apply_pagination` read the size as zero
374
- * and bail out before `limit`/`offset` are applied, so the endpoint answers
375
- * with the WHOLE table: one typo turns a listing into an unbounded scan
376
- * holding a Puma thread and a database connection. Failing at the call site
377
- * is the only place that mistake is still cheap.
365
+ * on the wire is read as size zero and disables pagination, so the endpoint
366
+ * answers with the WHOLE table: one typo turns a listing into an unbounded
367
+ * scan. Failing at the call site is the only place that mistake is still
368
+ * cheap.
378
369
  *
379
370
  * Narrower than 0.2.0, which clamped `0` to 1 and let `NaN` through onto
380
371
  * the wire. See {@link resolvePageSize}.
@@ -459,8 +450,8 @@ export interface QuotaStatus {
459
450
  /**
460
451
  * How a long-running server-side job reports itself.
461
452
  *
462
- * These are the five strings `Job::STATUSES` holds, spelled exactly as the
463
- * backend spells them: `"complete"` and `"canceled"`, not `"completed"` and
453
+ * These are the five strings the API uses, spelled exactly as it spells
454
+ * them: `"complete"` and `"canceled"`, not `"completed"` and
464
455
  * `"cancelled"`. Compare against `JOB_STATUS` / `isJobTerminal` from the jobs
465
456
  * namespace rather than against a literal you typed from memory - a wait loop
466
457
  * that tests for `"completed"` never ends.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omelhorsite/sdk",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "TypeScript SDK for the omelhorsite API. Isolate-safe: no node builtins, no environment access, no stdout.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",