@omelhorsite/sdk 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +4 -4
  2. package/dist/index.js +4 -4
  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 +181 -210
  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 +107 -135
  33. package/dist/types/resources/tools/upscale.d.ts +12 -16
  34. package/dist/types/types.d.ts +29 -38
  35. package/package.json +1 -1
@@ -31,7 +31,7 @@ export interface Chest extends BaseRecord {
31
31
  readonly expires_at: Timestamp;
32
32
  /** Owner, when the chest was created by a signed-in user. */
33
33
  readonly creator_id?: Id | null;
34
- /** Present on every read: `find_or_create` renders the `:extended` view. */
34
+ /** Present on every read. */
35
35
  readonly chest_entries?: ChestEntry[];
36
36
  }
37
37
  /** One item inside a chest: a note, or a file. */
@@ -112,7 +112,7 @@ export declare class ChestEntriesNamespace extends Resource {
112
112
  constructor(http: ApiClient);
113
113
  /**
114
114
  * Adds an entry. A note is one request; a file goes through
115
- * {@link createWithUpload}, because a chest never takes bytes through Rails.
115
+ * {@link createWithUpload}, because a chest never takes bytes through the API.
116
116
  *
117
117
  * ```ts
118
118
  * await oms.chests.entries.create({ chestId, name: "notes", content: "..." });
@@ -128,9 +128,9 @@ export declare class ChestEntriesNamespace extends Resource {
128
128
  * 3. the PUT goes straight to object storage, with no `Authorization`;
129
129
  * 4. `POST /chest_entries/:id/attach_blob` binds the bytes to the entry.
130
130
  *
131
- * Step 2 may be called ONCE per entry: a second call raises an unhandled
132
- * `ArgumentError` server-side and comes back as a 500, so a naive retry is
133
- * worse than useless. The SDK therefore treats the whole thing as atomic -
131
+ * Step 2 may be called ONCE per entry: a second call comes back as a 500, so
132
+ * a naive retry is worse than useless. The SDK therefore treats the whole
133
+ * thing as atomic -
134
134
  * anything that fails after step 1 destroys the half-built entry (releasing
135
135
  * the space it reserved) before rethrowing, so a retry starts clean.
136
136
  *
@@ -141,28 +141,25 @@ export declare class ChestEntriesNamespace extends Resource {
141
141
  /**
142
142
  * `GET /chest_entries/:id/data` - the entry's bytes.
143
143
  *
144
- * SENT WITH NO CREDENTIAL, deliberately. `ChestEntriesController` lists
145
- * `data` in `allow_unauthenticated_access`, and the action itself is three
146
- * lines: find the entry by id, check that something is attached, redirect.
147
- * It never looks at the chest name, the chest token, or who is asking. The
148
- * ENTRY ID IS THE WHOLE CAPABILITY - which is worth knowing for its own sake,
149
- * and which also means a credential on this request could not possibly change
150
- * the answer.
151
- *
152
- * That matters because sending one breaks the call in a browser. The action
153
- * answers `302` to `minio.omelhorsite.pt`, and following that hop replaces the
154
- * request's origin with an opaque one (Fetch standard: a cross-origin
155
- * redirect of a CORS request whose origin already differs from the current
156
- * URL's origin), so the store sees `Origin: null` and answers
157
- * `Access-Control-Allow-Origin: *`. Wildcard plus credentials is illegal, so a
158
- * client built with `sessionCookie: true` - the production web app - would
159
- * have the browser reject the bytes with an opaque "Failed to fetch". Asking
160
- * anonymously sidesteps it: `*` is fine for an uncredentialed request.
161
- *
162
- * Two shapes come back and both are handled here. Against MinIO it is the
163
- * `302`. Against a Disk service (dev, test) presigning raises `ArgumentError`
164
- * and the controller falls back to `send_data`, so the bytes arrive inline
165
- * from Rails with a `Content-Disposition`. Either way this returns the bytes.
144
+ * SENT WITH NO CREDENTIAL, deliberately. The endpoint checks only that the
145
+ * entry exists and has bytes attached - never the chest name, the chest
146
+ * token, or who is asking. The ENTRY ID IS THE WHOLE CAPABILITY - which is
147
+ * worth knowing for its own sake, and which also means a credential on this
148
+ * request could not possibly change the answer.
149
+ *
150
+ * That matters because sending one breaks the call in a browser. The
151
+ * endpoint answers `302` to the object store, and following that hop
152
+ * replaces the request's origin with an opaque one (Fetch standard: a
153
+ * cross-origin redirect of a CORS request whose origin already differs from
154
+ * the current URL's origin), so the store sees `Origin: null` and answers
155
+ * `Access-Control-Allow-Origin: *`. Wildcard plus credentials is illegal, so
156
+ * a client built with `sessionCookie: true` would have the browser reject
157
+ * the bytes with an opaque "Failed to fetch". Asking anonymously sidesteps
158
+ * it: `*` is fine for an uncredentialed request.
159
+ *
160
+ * Two shapes come back and both are handled here: the `302` to the object
161
+ * store, or the bytes inline with a `Content-Disposition`. Either way this
162
+ * returns the bytes.
166
163
  *
167
164
  * Going around the transport costs the usual thing: no retry, no per-call
168
165
  * deadline, only the caller's `signal`. Use {@link downloadUrl} when the
@@ -177,10 +174,9 @@ export declare class ChestEntriesNamespace extends Resource {
177
174
  * new tab.
178
175
  *
179
176
  * Synchronous and credential-free, because the endpoint is: the entry id is
180
- * the only thing it checks. The frontend's older helper appended a `?token=`
181
- * here; this deliberately does not, because a session token in a URL that
182
- * ends up in markup, in a shared link and in an access log buys precisely
183
- * nothing on a route that never reads it.
177
+ * the only thing it checks. No `?token=` is appended, because a session
178
+ * token in a URL that ends up in markup, in a shared link and in an access
179
+ * log buys precisely nothing on a route that never reads it.
184
180
  *
185
181
  * Treat the URL as a bearer capability all the same. Anyone holding it can
186
182
  * pull the file until the chest expires, so it is exactly as shareable as the
@@ -2,9 +2,9 @@
2
2
  * The `dynamicQrs` namespace: QR codes whose destination can be changed after
3
3
  * the code has been printed.
4
4
  *
5
- * Under the hood each one is a `ShortLink` in the reserved `"qr"` namespace
6
- * with a server-minted UUID endpoint, plus the styling the renderer needs. It
7
- * is a separate resource because the endpoint is not user-chosen, the payload
5
+ * Each one is a short link in the reserved `"qr"` namespace with a
6
+ * server-minted UUID endpoint, plus the styling a renderer needs. It is a
7
+ * separate resource because the endpoint is not user-chosen, the payload
8
8
  * carries `settings`, and the plain short-link listing filters system
9
9
  * namespaces out - a dynamic QR will never appear in `oms.shortLinks.list()`.
10
10
  *
@@ -20,30 +20,28 @@ import { type ShortLinkId, type ShortLinkStats } from "./shortLinks";
20
20
  /**
21
21
  * The reserved short-link namespace every dynamic QR lives in.
22
22
  *
23
- * `ShortLink::DYNAMIC_QR_NAMESPACE`. It is not a user choice and it never
24
- * changes on a record, which is why {@link DynamicQr.namespace} is typed as
25
- * this literal rather than as a string.
23
+ * It is not a user choice and it never changes on a record, which is why
24
+ * {@link DynamicQr.namespace} is typed as this literal rather than as a string.
26
25
  */
27
26
  export declare const DYNAMIC_QR_NAMESPACE = "qr";
28
27
  /** Public prefix a dynamic QR resolves under. */
29
28
  export declare const DYNAMIC_QR_BASE_URL = "https://omelhor.site/qr";
30
- /** Module shapes `DynamicQrs::SettingsSanitizer` accepts. Anything else is dropped. */
29
+ /** Module shapes the server accepts. Anything else is dropped. */
31
30
  export type DynamicQrStyle = "classic" | "rounded" | "dots" | "extraRounded" | "classy" | "classyRounded";
32
31
  /**
33
32
  * Styling of a dynamic QR.
34
33
  *
35
- * The backend runs this bag through `DynamicQrs::SettingsSanitizer`, which
36
- * **silently drops** every key it does not recognise and every value that fails
37
- * its check - a bad `style`, a colour that is not `#rrggbb`. An unknown or
38
- * malformed key is therefore a no-op, not an error, and the only way to know
39
- * what stuck is to read `settings` back off the response.
34
+ * The server **silently drops** every key it does not recognise and every
35
+ * value that fails its check - a bad `style`, a colour that is not `#rrggbb`.
36
+ * An unknown or malformed key is therefore a no-op, not an error, and the only
37
+ * way to know what stuck is to read `settings` back off the response.
40
38
  *
41
39
  * The two exceptions that DO fail loudly are `logo` and `bg_image`: a value
42
40
  * that is neither `null`/`""` nor a `data:image/...` URI under the size cap is
43
41
  * a 400.
44
42
  *
45
- * The SDK does not render any of this; it is what the web tool's renderer
46
- * consumes. `oms.local.qr` draws a plain symbol from the matrix instead.
43
+ * The SDK does not render any of this. `oms.local.qr` draws a plain symbol
44
+ * from the matrix instead.
47
45
  */
48
46
  export interface DynamicQrSettings {
49
47
  /** Module shape. Values outside {@link DynamicQrStyle} are dropped. */
@@ -75,51 +73,38 @@ export interface DynamicQrSettings {
75
73
  /** How the background image sits against `bg_color`. Anything but `"replace"` reads as `"behind"`. */
76
74
  readonly bg_image_mode?: "replace" | "behind";
77
75
  /**
78
- * The stored bag is free-form JSON, so a code saved by an older version of
79
- * the web tool can carry keys this interface does not name.
76
+ * The stored bag is free-form JSON, so a code saved by an older client can
77
+ * carry keys this interface does not name.
80
78
  */
81
79
  readonly [key: string]: unknown;
82
80
  }
83
81
  /**
84
82
  * A dynamic QR code.
85
83
  *
86
- * `DynamicQrBlueprint` renders `ApplicationBlueprint`'s three automatic keys
87
- * (`id`, `created_at`, `updated_at`) plus exactly five more, and that is the
88
- * whole record. Two keys a client migrating off the old web service will
89
- * expect are NOT here and never were on this endpoint: `website_id` and
90
- * `website_managed`. They are residue of the websites feature, which was
91
- * extracted out of this backend entirely - there is no such column on
92
- * `short_links` and no such field on any blueprint, so anything declaring them
93
- * has been reading `undefined`.
94
- *
95
- * The blueprint is also never resolved automatically. A dynamic QR IS a
96
- * `ShortLink`, and `ShortLinkBlueprint` already owns that name with a
97
- * different shape (associations, no `settings`), so every call site passes
98
- * this blueprint explicitly. That is why the two records disagree about which
99
- * fields exist even though they are rows in one table.
84
+ * Eight keys, and that is the whole record. There is no `website_id` and no
85
+ * `website_managed`. A dynamic QR is a short link, but the two records carry
86
+ * different fields: this one has `settings` and no associations.
100
87
  */
101
88
  export interface DynamicQr extends Omit<BaseRecord, "id"> {
102
- /** Integer primary key: a dynamic QR is a `short_links` row. See {@link ShortLinkId}. */
89
+ /** Integer primary key: a dynamic QR is a short link. See {@link ShortLinkId}. */
103
90
  readonly id: number;
104
91
  /** Current destination. Changing it re-points every printed copy at once. */
105
92
  readonly url: string;
106
93
  /** Server-assigned UUID the QR image encodes. Not choosable, not renameable. */
107
94
  readonly endpoint: string;
108
95
  /**
109
- * Always {@link DYNAMIC_QR_NAMESPACE}. The controller writes it on create
110
- * and nothing can change it afterwards, and the listing scope filters on it,
111
- * so a record that reached you through this namespace cannot hold anything
112
- * else.
96
+ * Always {@link DYNAMIC_QR_NAMESPACE}. Set on create, never changeable, and
97
+ * the listing filters on it, so a record that reached you through this
98
+ * namespace cannot hold anything else.
113
99
  */
114
100
  readonly namespace: typeof DYNAMIC_QR_NAMESPACE;
115
101
  /**
116
- * Owner. The column is nullable because anonymous short links exist, but
117
- * every route on this resource requires a credential and the controller
118
- * always sets the owner, so in practice this is never `null` for a dynamic
119
- * QR.
102
+ * Owner. Nullable because anonymous short links exist, but every route on
103
+ * this resource requires a credential and always sets the owner, so in
104
+ * practice this is never `null` for a dynamic QR.
120
105
  */
121
106
  readonly user_id: Id | null;
122
- /** Never `null`: the blueprint substitutes `{}` for an unset bag. */
107
+ /** Never `null`: `{}` for an unset bag. */
123
108
  readonly settings: DynamicQrSettings & JsonObject;
124
109
  }
125
110
  /** Arguments for creating a dynamic QR. */
@@ -132,7 +117,7 @@ export interface CreateDynamicQrInput {
132
117
  /**
133
118
  * Fields that can change afterwards.
134
119
  *
135
- * `settings` is **merged** into the stored bag by the backend, not replaced, so
120
+ * `settings` is **merged** into the stored bag server-side, not replaced, so
136
121
  * an update can never unset a key by omitting it. To clear one, send it
137
122
  * explicitly with the value that means empty (`null` for `logo`/`bg_image`).
138
123
  */
@@ -146,10 +131,9 @@ export declare class DynamicQrsNamespace extends Resource {
146
131
  * `GET /dynamic_qrs` - every code you own, newest first.
147
132
  *
148
133
  * Returns a plain array rather than a page object, and that is not an
149
- * oversight: this controller does not use `CrudActions` and ignores
150
- * `modifiers[page]` entirely, so it always answers with the complete set. A
151
- * `Paginated` here would be a fiction with a `next()` that refetched
152
- * everything.
134
+ * oversight: the endpoint ignores `modifiers[page]` entirely and always
135
+ * answers with the complete set. A `Paginated` here would be a fiction with
136
+ * a `next()` that refetched everything.
153
137
  *
154
138
  * @throws {OmsAuthError} 401 when anonymous.
155
139
  */
@@ -7,16 +7,12 @@
7
7
  * an anonymous respondent hits. The SDK exposes both; the public calls work
8
8
  * without a credential unless the form turns `settings.require_login` on.
9
9
  *
10
- * The endpoint is not a column on the form: it lives on a short link paired
11
- * with it, which is why renaming it is a real operation and why availability
12
- * has its own lookup.
10
+ * The endpoint belongs to a short link paired with the form, which is why
11
+ * renaming it is a real operation and why availability has its own lookup.
13
12
  */
14
13
  import { type ApiClient, Resource } from "../http";
15
14
  import type { BaseRecord, FileInput, Id, Json, RequestOptions, Timestamp } from "../types";
16
- /**
17
- * The reserved short-link namespace a published form is served under.
18
- * `Form::NAMESPACE` / `ShortLink::FORM_NAMESPACE`.
19
- */
15
+ /** The reserved short-link namespace a published form is served under. */
20
16
  export declare const FORM_NAMESPACE = "f";
21
17
  /**
22
18
  * Public prefix a published form resolves under, and the prefix
@@ -35,9 +31,8 @@ export type FormSchemaFieldType = "short_text" | "long_text" | "email" | "number
35
31
  * READ back off a form.
36
32
  *
37
33
  * `id` is not optional here even though it is optional when writing: the
38
- * sanitiser mints `SecureRandom.uuid` for any option that arrives without one,
39
- * so a stored option always has one. Write with
40
- * {@link FormSchemaFieldOptionInput}.
34
+ * server mints a UUID for any option that arrives without one, so a stored
35
+ * option always has one. Write with {@link FormSchemaFieldOptionInput}.
41
36
  */
42
37
  export interface FormSchemaFieldOption {
43
38
  /** Stable within the form. */
@@ -54,13 +49,13 @@ export interface FormSchemaFieldOptionInput {
54
49
  *
55
50
  * `id` is the key answers are filed under - NOT the label.
56
51
  *
57
- * Four of these keys are non-optional because `Forms::InputSanitizer#field`
58
- * writes them on EVERY field it keeps, whatever arrived: `id` (minted when
59
- * absent), `type`, `label` and `description` (both coerced with `.to_s`, so an
60
- * absent one is stored as `""`, not dropped) and `required` (cast to a real
61
- * boolean). The three that stay optional are genuinely absent from the stored
62
- * object when unused: `placeholder` is only kept when present, `options` only
63
- * for the three choice types, and `min`/`max` only for `number`.
52
+ * Five of these keys are non-optional because the server writes them on EVERY
53
+ * field it keeps, whatever arrived: `id` (minted when absent), `type`, `label`
54
+ * and `description` (an absent one is stored as `""`, not dropped) and
55
+ * `required` (always a real boolean). The rest are genuinely absent from the
56
+ * stored object when unused: `placeholder` is only kept when present,
57
+ * `options` only for the three choice types, and `min`/`max` only for
58
+ * `number`.
64
59
  *
65
60
  * Write with {@link FormSchemaFieldInput}, where all of that is optional.
66
61
  */
@@ -84,8 +79,8 @@ export interface FormSchemaField {
84
79
  * One field as WRITTEN.
85
80
  *
86
81
  * Every key but `type` may be omitted. `type` may not: a field whose type is
87
- * not one of `Form::FIELD_TYPES` is dropped from the schema in silence, which
88
- * looks exactly like a field that was never sent.
82
+ * not one of {@link FormSchemaFieldType} is dropped from the schema in
83
+ * silence, which looks exactly like a field that was never sent.
89
84
  *
90
85
  * A {@link FormSchemaField} read off a form is assignable here, so the
91
86
  * read-edit-write round trip needs no mapping.
@@ -105,8 +100,8 @@ export interface FormSchemaFieldInput {
105
100
  }
106
101
  /**
107
102
  * The field definition of a form, as read. Always `{ fields: [...] }`, never
108
- * `null` and never a bare array: the column is `NOT NULL DEFAULT
109
- * '{"fields":[]}'` and the sanitiser rebuilds the envelope on every write.
103
+ * `null` and never a bare array: a new form starts with an empty envelope and
104
+ * the server rebuilds it on every write.
110
105
  */
111
106
  export interface FormSchema {
112
107
  readonly fields: FormSchemaField[];
@@ -114,8 +109,8 @@ export interface FormSchema {
114
109
  /**
115
110
  * The field definition as written. The server rebuilds it from scratch keeping
116
111
  * only the keys {@link FormSchemaFieldInput} names, so anything extra is lost
117
- * without a word - and a write that is not a Hash at all is silently read as
118
- * `{ fields: [] }`, which empties the form rather than failing.
112
+ * without a word - and a write that is not an object at all is silently read
113
+ * as `{ fields: [] }`, which empties the form rather than failing.
119
114
  */
120
115
  export interface FormSchemaInput {
121
116
  readonly fields: FormSchemaFieldInput[];
@@ -153,10 +148,9 @@ export interface FormSettings {
153
148
  /**
154
149
  * A hosted form, owner view.
155
150
  *
156
- * One shape, not two: `FormsController` renders `form.render` with no view on
157
- * index, show, create AND update, so the `:extended` view `ApplicationBlueprint`
158
- * declares is never reached here and there is no richer variant to ask for.
159
- * Every key below is therefore on every response.
151
+ * One shape, not two: index, show, create AND update all answer the same
152
+ * record, and there is no richer variant to ask for. Every key below is on
153
+ * every response.
160
154
  */
161
155
  export interface Form extends BaseRecord {
162
156
  readonly user_id: Id;
@@ -180,19 +174,14 @@ export interface Form extends BaseRecord {
180
174
  readonly published_at: Timestamp | null;
181
175
  /** Bumped by every `getPublic` call, the SDK's included. Never `null`. */
182
176
  readonly views_count: number;
183
- /**
184
- * Answers recorded. Computed per request - batched into one grouped COUNT
185
- * for a whole listing, one COUNT for a single render - so it is always
186
- * current and never cached.
187
- */
177
+ /** Answers recorded. Computed per request, so it is always current. */
188
178
  readonly submissions_count: number;
189
179
  }
190
180
  /**
191
181
  * The reduced form a public respondent is allowed to see.
192
182
  *
193
- * NOT a subset of {@link Form}: the controller builds this hash by hand rather
194
- * than rendering a blueprint view, so it carries `require_login` - which is not
195
- * a field on `Form` at all, only a key inside `settings` - and carries no
183
+ * NOT a subset of {@link Form}: it carries `require_login` - which is not a
184
+ * field on `Form` at all, only a key inside `settings` - and carries no
196
185
  * timestamps, no `user_id`, no counts and no `status`. Seven keys, always all
197
186
  * seven.
198
187
  */
@@ -208,14 +197,10 @@ export interface PublicForm {
208
197
  /**
209
198
  * One answered form.
210
199
  *
211
- * Deliberately has no `updated_at`: a submission is never edited, and
212
- * `FormSubmissionBlueprint` is the one blueprint in the API that inherits
213
- * `Blueprinter::Base` directly rather than `ApplicationBlueprint`, precisely so
214
- * that the automatic `updated_at` cannot creep in. Do not add it here on the
215
- * assumption that every record has one.
200
+ * Deliberately has no `updated_at`: a submission is never edited. Do not add
201
+ * it here on the assumption that every record has one.
216
202
  *
217
- * The other seven keys are all declared unconditionally, so all seven are
218
- * always present; four of them are nullable columns.
203
+ * All seven keys are always present; four of them are nullable.
219
204
  */
220
205
  export interface FormSubmission {
221
206
  readonly id: Id;
@@ -240,23 +225,18 @@ export interface FormSubmission {
240
225
  /** Parsed from the respondent's user agent. `null` when unparseable. */
241
226
  readonly device_name: string | null;
242
227
  /**
243
- * When the answers were recorded. The controller writes `Time.current` on
244
- * every submission it creates, so this is `null` only for a row predating
245
- * that - but the column is nullable, so check before formatting it.
228
+ * When the answers were recorded. Set on every submission the API creates,
229
+ * so this is `null` only for an old row - but it is nullable, so check
230
+ * before formatting it.
246
231
  */
247
232
  readonly completed_at: Timestamp | null;
248
233
  readonly created_at: Timestamp;
249
234
  }
250
- /**
251
- * What `POST /form_attachments` answers with.
252
- *
253
- * Built by hand in the controller rather than by a blueprint, so this is the
254
- * literal four-key hash it renders and there is no `created_at` to read.
255
- */
235
+ /** What `POST /form_attachments` answers with. Four keys, no `created_at`. */
256
236
  export interface FormAttachment {
257
237
  readonly id: Id;
258
238
  readonly filename: string;
259
- /** One of `FormAttachment::ALLOWED_TYPES`; a save with anything else is a 400. */
239
+ /** JPEG, PNG, WebP, GIF or HEIC; a save with anything else is a 400. */
260
240
  readonly content_type: string;
261
241
  /** Absolute URL that serves the bytes inline, no credential required. */
262
242
  readonly url: string;
@@ -266,8 +246,8 @@ export interface FormAttachment {
266
246
  * conditional and mutually exclusive.
267
247
  *
268
248
  * `reason` appears only on the rejected branch and only ever holds
269
- * `"invalid"` - the controller has a single rejection reason for forms,
270
- * covering both a bad shape and a reserved word. (Link trees, which look
249
+ * `"invalid"` - the server has a single rejection reason for forms, covering
250
+ * both a bad shape and a reserved word. (Link trees, which look
271
251
  * identical, do distinguish the two; see `LinkTreeSlugAvailability`.)
272
252
  * `suggestions` appears only on the well-formed-but-taken branch.
273
253
  */
@@ -289,10 +269,9 @@ export interface FormEndpointAvailability {
289
269
  */
290
270
  export interface CreateFormInput {
291
271
  /**
292
- * Optional, despite being the thing a person names the form by: the
293
- * controller runs it through `.to_s.strip` and the model only validates its
294
- * LENGTH (200 maximum), so an omitted title saves an untitled form rather
295
- * than failing. Pass one.
272
+ * Optional, despite being the thing a person names the form by: the server
273
+ * trims it and only validates its LENGTH (200 maximum), so an omitted title
274
+ * saves an untitled form rather than failing. Pass one.
296
275
  */
297
276
  readonly title?: string;
298
277
  /**
@@ -11,11 +11,10 @@
11
11
  * {@link JobsNamespace.wait}, so the polling policy lives here once. Do not
12
12
  * write a second polling loop inside a tool module.
13
13
  *
14
- * Only two tools enqueue through the generic `jobs` table - background removal
15
- * and upscale. The other five are polled by re-reading their own row, which is
16
- * still not a reason to write a loop there: {@link pollUntilTerminal} is the
17
- * same engine with a different `poll` function, and that is what those modules
18
- * call.
14
+ * Only two tools hand back a generic job - background removal and upscale.
15
+ * The other five are polled by re-reading their own record, which is still not
16
+ * a reason to write a loop there: {@link pollUntilTerminal} is the same engine
17
+ * with a different `poll` function, and that is what those modules call.
19
18
  *
20
19
  * The loop is deliberately dumb and bounded:
21
20
  *
@@ -47,7 +46,7 @@ import { Resource } from "../http";
47
46
  import type { ListParams } from "../listing";
48
47
  import type { BaseRecord, Id, Json, JobStatus, Paginated, Progress, RequestOptions, Timestamp, WaitOptions } from "../types";
49
48
  /**
50
- * The five status strings, spelled the way the backend spells them.
49
+ * The five status strings, spelled the way the API spells them.
51
50
  *
52
51
  * `complete`, not `completed`. `canceled`, one L. Reach for this object instead
53
52
  * of typing the literal: a loop that waits for `"completed"` waits forever.
@@ -71,31 +70,24 @@ export declare function isJobTerminal(status: string): boolean;
71
70
  /**
72
71
  * A background job.
73
72
  *
74
- * `JobBlueprint` declares thirteen fields and nothing else, so EVERY key below
75
- * is present on every response. A `?` here would mean "the server sometimes
76
- * leaves this out", and it never does; what varies is the VALUE, because most
77
- * of these are nullable columns that fill in as the job moves.
73
+ * EVERY key below is present on every response. A `?` here would mean "the
74
+ * server sometimes leaves this out", and it never does; what varies is the
75
+ * VALUE, because most of these are nullable and fill in as the job moves.
78
76
  *
79
- * Two keys are deliberately NOT here, and a client migrating off the old web
80
- * service will expect them: `updater_id` and `destroyer_id`. Both columns
81
- * exist on the `jobs` table and both are indexed, but `JobBlueprint` renders
82
- * NEITHER, so anything declaring them has been reading `undefined` for as long
83
- * as it has existed. Declaring them here would only move the lie.
77
+ * There is no `updater_id` and no `destroyer_id`; anything declaring them
78
+ * reads `undefined`.
84
79
  */
85
80
  export interface Job extends BaseRecord {
86
81
  readonly status: JobStatus;
87
82
  /**
88
- * Feature-level kind of the run. `Job::JOB_TYPES` holds exactly two strings:
89
- * `"omsvs"` (vocal separation) and `"unknown"`, which is the column default
90
- * every generic enqueue gets - the upscale and background-removal proxies
91
- * included. It is NOT the worker's class name, and a third value cannot
92
- * appear without a model change, because an inclusion validation rejects it.
83
+ * Feature-level kind of the run: `"omsvs"` (vocal separation) or
84
+ * `"unknown"`, which is what every generic enqueue gets - the upscale and
85
+ * background-removal runs included. It is NOT the name of the work done.
93
86
  */
94
87
  readonly job_type: string;
95
88
  /**
96
- * Enqueue-time arguments. The column is `jsonb DEFAULT '{}'`, so a row whose
97
- * enqueuer wrote nothing carries `{}` rather than `null`. Shape depends on
98
- * `job_type`.
89
+ * Enqueue-time arguments. `{}` rather than `null` when the enqueuer wrote
90
+ * nothing. Shape depends on `job_type`.
99
91
  */
100
92
  readonly payload: Json;
101
93
  /** Set when a worker claimed the job; `null` while it is still `"pending"`. */
@@ -103,22 +95,20 @@ export interface Job extends BaseRecord {
103
95
  /** Set when the job reached a terminal state, cancellation included. */
104
96
  readonly finished_at: Timestamp | null;
105
97
  /**
106
- * Percentage, an integer in `[0, 100]`. The column is `NOT NULL DEFAULT 0`
107
- * and the model validates the range, so this is a real number from the
108
- * moment the row exists: `0` means "not started", never "unknown".
98
+ * Percentage, an integer in `[0, 100]`. A real number from the moment the
99
+ * row exists: `0` means "not started", never "unknown".
109
100
  */
110
101
  readonly progress: number;
111
102
  /**
112
103
  * Failure message once `status === "failed"` - and ALSO the reason once
113
- * `"canceled"`, because `Job#cancel!` writes it into this same column. A
104
+ * `"canceled"`, because a cancellation writes its reason here too. A
114
105
  * non-null `error` therefore does not by itself mean the work failed. Read
115
106
  * `status`.
116
107
  */
117
108
  readonly error: string | null;
118
109
  /**
119
- * Whatever the worker returned, stored by `ApplicationJob`'s
120
- * `around_perform`. Shape depends on `job_type`, and the two proxies worth
121
- * naming both answer an object carrying a signed download link:
110
+ * Whatever the work returned. Shape depends on `job_type`, and the two
111
+ * tools worth naming both answer an object carrying a signed download link:
122
112
  *
123
113
  * - upscale: `{ upscale_id, result_url }`;
124
114
  * - background removal: `{ background_removal_id, result_url }`.
@@ -213,9 +203,8 @@ export declare class JobsNamespace extends Resource {
213
203
  * an anonymous caller sees an empty page - never a 401, because the scope is
214
204
  * empty rather than forbidden.
215
205
  *
216
- * @throws {OmsApiError} 400 naming the key when a filter is not on the
217
- * controller's allowlist (`id`, `job_type`, `status`, `created_at`,
218
- * `updated_at`, `finished_at`).
206
+ * @throws {OmsApiError} 400 naming the key when a filter is not one of
207
+ * `id`, `job_type`, `status`, `created_at`, `updated_at`, `finished_at`.
219
208
  */
220
209
  list(params?: ListJobsParams, options?: RequestOptions): Promise<Paginated<Job>>;
221
210
  /**
@@ -227,7 +216,7 @@ export declare class JobsNamespace extends Resource {
227
216
  *
228
217
  * @throws {OmsApiError} 404 when the job is gone, which for a finished job
229
218
  * also happens once its retention window expires. A wrong, expired or
230
- * missing watch token is the same 404, not a 401: the controller never says
219
+ * missing watch token is the same 404, not a 401: the server never says
231
220
  * whether the id exists.
232
221
  */
233
222
  get(ref: JobRef | Id, options?: RequestOptions): Promise<Job>;
@@ -265,13 +254,12 @@ export declare function jobRef(ref: JobRef | Id): JobRef;
265
254
  * Renders a job as a {@link Progress}.
266
255
  *
267
256
  * `total` is 100 rather than `undefined` because `progress` is a percentage the
268
- * server always has: the column is `NOT NULL DEFAULT 0`, so there is no
269
- * "unknown" to be honest about.
257
+ * server always has: there is no "unknown" to be honest about.
270
258
  *
271
259
  * The `typeof` guard is not defensive typing for its own sake. `Job.progress`
272
- * is declared non-nullable because the column is, but this function is also
273
- * handed rows that came off `JobChannel` and rows a host deserialised itself,
274
- * and reading `undefined` as `NaN%` would put a broken number on a progress
275
- * bar rather than a zero.
260
+ * is declared non-nullable, but this function is also handed rows that came
261
+ * off the realtime job channel and rows a host deserialised itself, and
262
+ * reading `undefined` as `NaN%` would put a broken number on a progress bar
263
+ * rather than a zero.
276
264
  */
277
265
  export declare function jobProgress(job: Job): Progress;