@omelhorsite/sdk 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/index.js +4 -4
- package/dist/types/auth/device.d.ts +1 -1
- package/dist/types/auth/index.d.ts +2 -2
- package/dist/types/auth/tokens.d.ts +15 -15
- package/dist/types/client.d.ts +10 -10
- package/dist/types/errors.d.ts +12 -15
- package/dist/types/http.d.ts +74 -118
- package/dist/types/index.d.ts +1 -2
- package/dist/types/local/qr.d.ts +1 -1
- package/dist/types/local/wordlist.d.ts +2 -3
- package/dist/types/resources/account.d.ts +14 -17
- package/dist/types/resources/auth/index.d.ts +1 -1
- package/dist/types/resources/auth/passkeys.d.ts +127 -163
- package/dist/types/resources/auth/sessions.d.ts +110 -152
- package/dist/types/resources/chests.d.ts +27 -31
- package/dist/types/resources/dynamicQrs.d.ts +29 -45
- package/dist/types/resources/forms.d.ts +37 -58
- package/dist/types/resources/jobs.d.ts +28 -40
- package/dist/types/resources/media.d.ts +48 -61
- package/dist/types/resources/music/artists.d.ts +179 -245
- package/dist/types/resources/music/imports.d.ts +181 -210
- package/dist/types/resources/music/index.d.ts +8 -7
- package/dist/types/resources/music/playlists.d.ts +77 -110
- package/dist/types/resources/music/social.d.ts +153 -228
- package/dist/types/resources/music/songs.d.ts +160 -206
- package/dist/types/resources/realtime.d.ts +75 -88
- package/dist/types/resources/shortLinks.d.ts +33 -45
- package/dist/types/resources/storage/upload.d.ts +42 -56
- package/dist/types/resources/storage.d.ts +71 -104
- package/dist/types/resources/tools/backgroundRemoval.d.ts +11 -13
- package/dist/types/resources/tools/captions.d.ts +107 -135
- package/dist/types/resources/tools/upscale.d.ts +12 -16
- package/dist/types/types.d.ts +29 -38
- package/package.json +1 -1
|
@@ -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
|
|
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
|
|
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
|
|
132
|
-
*
|
|
133
|
-
*
|
|
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.
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
* the
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
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.
|
|
181
|
-
*
|
|
182
|
-
*
|
|
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
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
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
|
-
*
|
|
24
|
-
*
|
|
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
|
|
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
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
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
|
|
46
|
-
*
|
|
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
|
|
79
|
-
*
|
|
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
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
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
|
|
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}.
|
|
110
|
-
*
|
|
111
|
-
*
|
|
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.
|
|
117
|
-
*
|
|
118
|
-
*
|
|
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`:
|
|
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
|
|
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:
|
|
150
|
-
*
|
|
151
|
-
*
|
|
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
|
|
11
|
-
*
|
|
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
|
-
*
|
|
39
|
-
*
|
|
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
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
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
|
|
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:
|
|
109
|
-
*
|
|
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
|
|
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:
|
|
157
|
-
*
|
|
158
|
-
*
|
|
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}:
|
|
194
|
-
*
|
|
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
|
|
212
|
-
*
|
|
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
|
-
*
|
|
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.
|
|
244
|
-
*
|
|
245
|
-
*
|
|
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
|
-
/**
|
|
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
|
|
270
|
-
*
|
|
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
|
-
*
|
|
294
|
-
*
|
|
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
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
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
|
|
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
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
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
|
-
*
|
|
80
|
-
*
|
|
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
|
|
89
|
-
* `"
|
|
90
|
-
*
|
|
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.
|
|
97
|
-
*
|
|
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]`.
|
|
107
|
-
*
|
|
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
|
|
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
|
|
120
|
-
*
|
|
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
|
|
217
|
-
*
|
|
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
|
|
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:
|
|
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
|
|
273
|
-
*
|
|
274
|
-
*
|
|
275
|
-
*
|
|
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;
|