@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,194 @@
1
+ /**
2
+ * The `chests` namespace: short-lived drop boxes for moving files and text
3
+ * between two devices that share nothing else.
4
+ *
5
+ * Two secrets, and they are not the same thing:
6
+ * - the chest NAME is the read capability. Anyone holding it opens the chest
7
+ * and lists its entries. It is the slug in the shareable link.
8
+ * - the chest TOKEN is the owner capability, and it is handed out ONCE, in the
9
+ * 201 that created the chest. Lose it and, unless the creator was signed in,
10
+ * the chest can never be managed again.
11
+ *
12
+ * Chests expire two hours after creation, so any read can legitimately 404 on
13
+ * something that existed a minute ago. Creating one anonymously is throttled
14
+ * to five an hour per IP and gated by a captcha.
15
+ */
16
+ import { type ApiClient, Resource } from "../http";
17
+ import type { BaseRecord, FileInput, Id, OperationOptions, RequestOptions, Timestamp } from "../types";
18
+ /** What an entry holds: a file's bytes, or a piece of text. */
19
+ export type ChestEntryKind = "file" | "note";
20
+ /** A drop box. */
21
+ export interface Chest extends BaseRecord {
22
+ /** Human-readable read capability. Treat it as a secret. */
23
+ readonly name: string;
24
+ /** Whether anyone holding the name may add and remove entries. */
25
+ readonly editable_by_others: boolean;
26
+ /** Ceiling in bytes: 5 GB when created anonymously, 10 GB when signed in. */
27
+ readonly max_size: number;
28
+ /** Bytes already reserved by the entries. */
29
+ readonly current_size: number;
30
+ /** When the chest and everything in it is deleted. */
31
+ readonly expires_at: Timestamp;
32
+ /** Owner, when the chest was created by a signed-in user. */
33
+ readonly creator_id?: Id | null;
34
+ /** Present on every read: `find_or_create` renders the `:extended` view. */
35
+ readonly chest_entries?: ChestEntry[];
36
+ }
37
+ /** One item inside a chest: a note, or a file. */
38
+ export interface ChestEntry extends BaseRecord {
39
+ readonly chest_id: Id;
40
+ readonly kind: ChestEntryKind;
41
+ /** Display name; the filename for a file entry. */
42
+ readonly name: string;
43
+ /** Text of a note. `null` on a file entry. */
44
+ readonly content?: string | null;
45
+ /** Bytes this entry reserves against the chest's ceiling. */
46
+ readonly size: number;
47
+ /** False while a file entry exists but its bytes have not landed yet. */
48
+ readonly data_attached: boolean;
49
+ }
50
+ /** What {@link ChestsNamespace.open} answers with. */
51
+ export interface ChestOpenResult extends Chest {
52
+ /** Endpoint of the `c/` short link pointing at this chest. */
53
+ readonly short_link_endpoint: string | null;
54
+ /**
55
+ * The owner capability. Present ONLY on the call that created the chest.
56
+ * Store it there and then, or lose the ability to manage this chest.
57
+ */
58
+ readonly chest_token?: string;
59
+ /**
60
+ * Whether this call minted the chest (HTTP 201) rather than finding one
61
+ * (HTTP 200). Derived by the SDK from the status code; the body does not
62
+ * say. It is also exactly when `chest_token` is present.
63
+ */
64
+ readonly created: boolean;
65
+ }
66
+ /** Arguments for {@link ChestsNamespace.open}. */
67
+ export interface OpenChestInput {
68
+ /**
69
+ * Name to open. Omit it to be handed your own active chest, minting one if
70
+ * you have none - and that branch is what the throttle and the captcha
71
+ * apply to.
72
+ */
73
+ readonly name?: string;
74
+ /**
75
+ * Turnstile token. Required to MINT a chest anonymously (no `name`, no
76
+ * active chest of your own); ignored otherwise and never needed by a
77
+ * signed-in caller.
78
+ */
79
+ readonly captchaToken?: string;
80
+ }
81
+ /** Arguments for adding an entry to a chest. */
82
+ export interface CreateChestEntryInput {
83
+ readonly chestId: Id;
84
+ /**
85
+ * The owner capability. Not needed when the chest has `editable_by_others`
86
+ * on, or when you are the signed-in creator.
87
+ */
88
+ readonly chestToken?: string;
89
+ /** Display name. Required for a note; defaults to the file's own filename. */
90
+ readonly name?: string;
91
+ /** Text to store. Mutually exclusive with `file`. */
92
+ readonly content?: string;
93
+ /** File to store. Mutually exclusive with `content`. */
94
+ readonly file?: FileInput;
95
+ }
96
+ /** Arguments for the explicit three-step file upload. */
97
+ export interface CreateChestFileInput {
98
+ readonly chestId: Id;
99
+ readonly file: FileInput;
100
+ readonly chestToken?: string;
101
+ /** Overrides the name stored for the entry. Defaults to the filename. */
102
+ readonly name?: string;
103
+ }
104
+ /** Options for the calls that prove ownership of a chest. */
105
+ export interface ChestOwnerOptions extends RequestOptions {
106
+ /** The owner capability, unless you are the signed-in creator. */
107
+ readonly chestToken?: string;
108
+ }
109
+ /** Entries of a chest, reachable as `oms.chests.entries`. */
110
+ export declare class ChestEntriesNamespace extends Resource {
111
+ private readonly uploads;
112
+ constructor(http: ApiClient);
113
+ /**
114
+ * Adds an entry. A note is one request; a file goes through
115
+ * {@link createWithUpload}, because a chest never takes bytes through Rails.
116
+ *
117
+ * ```ts
118
+ * await oms.chests.entries.create({ chestId, name: "notes", content: "..." });
119
+ * await oms.chests.entries.create({ chestId, file: file(bytes, "clip.mov") });
120
+ * ```
121
+ */
122
+ create(input: CreateChestEntryInput, options?: OperationOptions): Promise<ChestEntry>;
123
+ /**
124
+ * Uploads a file the direct way, in four hops:
125
+ *
126
+ * 1. `POST /chest_entries` reserves the space (`kind: "file"`, `size`);
127
+ * 2. `POST /chest_entries/:id/attachment_signed_url` presigns a PUT;
128
+ * 3. the PUT goes straight to object storage, with no `Authorization`;
129
+ * 4. `POST /chest_entries/:id/attach_blob` binds the bytes to the entry.
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 -
134
+ * anything that fails after step 1 destroys the half-built entry (releasing
135
+ * the space it reserved) before rethrowing, so a retry starts clean.
136
+ *
137
+ * The file is buffered whole: the MD5 the presigned signature covers has to
138
+ * be computed over all of it.
139
+ */
140
+ createWithUpload(input: CreateChestFileInput, options?: OperationOptions): Promise<ChestEntry>;
141
+ /**
142
+ * `GET /chest_entries/:id/data` - the entry's bytes.
143
+ *
144
+ * Answers 302 towards object storage and `fetch` follows it. Note that this
145
+ * endpoint checks nothing at all: the entry id alone is enough to download
146
+ * it, with or without the chest name or token.
147
+ */
148
+ download(id: Id, options?: RequestOptions): Promise<Blob>;
149
+ /**
150
+ * `DELETE /chest_entries/:id` - removes an entry and gives its bytes back to
151
+ * the chest's ceiling.
152
+ *
153
+ * Accepts the owner token, and also accepts ANY caller when the chest has
154
+ * `editable_by_others` on.
155
+ */
156
+ delete(id: Id, options?: ChestOwnerOptions): Promise<void>;
157
+ }
158
+ /** The `chests` namespace, reachable as `oms.chests`. */
159
+ export declare class ChestsNamespace extends Resource {
160
+ /** Items inside a chest. */
161
+ readonly entries: ChestEntriesNamespace;
162
+ constructor(http: ApiClient);
163
+ /**
164
+ * `GET /chests/find_or_create` - opens a chest by name, or hands you your
165
+ * own, minting one if you have none.
166
+ *
167
+ * Read {@link ChestOpenResult.chest_token} on the way past: when `created`
168
+ * is true that field is the only copy of the owner capability you will ever
169
+ * be given.
170
+ *
171
+ * ```ts
172
+ * const mine = await oms.chests.open(); // yours, or a new one
173
+ * const theirs = await oms.chests.open({ name }); // someone's, by name
174
+ * ```
175
+ *
176
+ * @throws {OmsApiError} 404 when a named chest is unknown or has expired.
177
+ * @throws {OmsQuotaError} 429 when the global ceiling of 30 live chests is
178
+ * full, or when an anonymous caller has spent the hourly budget of five.
179
+ */
180
+ open(input?: OpenChestInput, options?: RequestOptions): Promise<ChestOpenResult>;
181
+ /**
182
+ * `PATCH /chests/:id/toggle_editable` - flips whether holders of the name
183
+ * may write, or only read.
184
+ *
185
+ * Turning it OFF destroys every file entry in the chest. Notes survive.
186
+ */
187
+ toggleEditable(id: Id, options?: ChestOwnerOptions): Promise<Chest>;
188
+ /**
189
+ * `DELETE /chests/:id/owner_destroy` - destroys the chest and its entries
190
+ * before the expiry. Owner only, proved by the token or by being the
191
+ * signed-in creator.
192
+ */
193
+ delete(id: Id, options?: ChestOwnerOptions): Promise<void>;
194
+ }
@@ -0,0 +1,172 @@
1
+ /**
2
+ * The `dynamicQrs` namespace: QR codes whose destination can be changed after
3
+ * the code has been printed.
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
8
+ * carries `settings`, and the plain short-link listing filters system
9
+ * namespaces out - a dynamic QR will never appear in `oms.shortLinks.list()`.
10
+ *
11
+ * Rendering the image itself is a LOCAL operation with no network: encode
12
+ * `oms.dynamicQrs.publicUrl(qr)` with `oms.local.qr`. This namespace only
13
+ * manages the redirect and its statistics.
14
+ *
15
+ * Every action here requires a credential; there is no anonymous path.
16
+ */
17
+ import { Resource } from "../http";
18
+ import type { BaseRecord, Id, JsonObject, RequestOptions } from "../types";
19
+ import { type ShortLinkId, type ShortLinkStats } from "./shortLinks";
20
+ /** Public prefix a dynamic QR resolves under. */
21
+ export declare const DYNAMIC_QR_BASE_URL = "https://omelhor.site/qr";
22
+ /** Module shapes `DynamicQrs::SettingsSanitizer` accepts. Anything else is dropped. */
23
+ export type DynamicQrStyle = "classic" | "rounded" | "dots" | "extraRounded" | "classy" | "classyRounded";
24
+ /**
25
+ * Styling of a dynamic QR.
26
+ *
27
+ * The backend runs this bag through `DynamicQrs::SettingsSanitizer`, which
28
+ * **silently drops** every key it does not recognise and every value that fails
29
+ * its check - a bad `style`, a colour that is not `#rrggbb`. An unknown or
30
+ * malformed key is therefore a no-op, not an error, and the only way to know
31
+ * what stuck is to read `settings` back off the response.
32
+ *
33
+ * The two exceptions that DO fail loudly are `logo` and `bg_image`: a value
34
+ * that is neither `null`/`""` nor a `data:image/...` URI under the size cap is
35
+ * a 400.
36
+ *
37
+ * The SDK does not render any of this; it is what the web tool's renderer
38
+ * consumes. `oms.local.qr` draws a plain symbol from the matrix instead.
39
+ */
40
+ export interface DynamicQrSettings {
41
+ /** Module shape. Values outside {@link DynamicQrStyle} are dropped. */
42
+ readonly style?: DynamicQrStyle;
43
+ /** Error-correction level. Higher survives a bigger logo. Dropped unless `L`/`M`/`Q`/`H`. */
44
+ readonly error_correction_level?: "L" | "M" | "Q" | "H";
45
+ /** Foreground colour, `#rrggbb` exactly (six digits, leading `#`). Dropped otherwise. */
46
+ readonly fg_color?: string;
47
+ /** Background colour, `#rrggbb` exactly. Dropped otherwise. */
48
+ readonly bg_color?: string;
49
+ /** Foreground opacity, clamped to `[0, 1]`. */
50
+ readonly fg_alpha?: number;
51
+ /** Background opacity, clamped to `[0, 1]`. */
52
+ readonly bg_alpha?: number;
53
+ /** Legacy switch kept for old saved codes; equivalent to `fg_alpha: 0`. */
54
+ readonly fg_transparent?: boolean;
55
+ /** Legacy switch kept for old saved codes; equivalent to `bg_alpha: 0`. */
56
+ readonly bg_transparent?: boolean;
57
+ /**
58
+ * Logo overlaid in the centre, as a `data:image/...` URI under 512 000 bytes.
59
+ * `null` or `""` clears it. Anything else is a 400.
60
+ */
61
+ readonly logo?: string | null;
62
+ /**
63
+ * Background image, as a `data:image/...` URI under 2 048 000 bytes. `null`
64
+ * or `""` clears it. Anything else is a 400.
65
+ */
66
+ readonly bg_image?: string | null;
67
+ /** How the background image sits against `bg_color`. Anything but `"replace"` reads as `"behind"`. */
68
+ readonly bg_image_mode?: "replace" | "behind";
69
+ /**
70
+ * The stored bag is free-form JSON, so a code saved by an older version of
71
+ * the web tool can carry keys this interface does not name.
72
+ */
73
+ readonly [key: string]: unknown;
74
+ }
75
+ /** A dynamic QR code. */
76
+ export interface DynamicQr extends Omit<BaseRecord, "id"> {
77
+ /** Integer primary key: a dynamic QR is a `short_links` row. See {@link ShortLinkId}. */
78
+ readonly id: number;
79
+ /** Current destination. Changing it re-points every printed copy at once. */
80
+ readonly url: string;
81
+ /** Server-assigned UUID the QR image encodes. Not choosable, not renameable. */
82
+ readonly endpoint: string;
83
+ /** Always `"qr"`. */
84
+ readonly namespace: string;
85
+ readonly user_id: Id | null;
86
+ /** Never `null`: the blueprint substitutes `{}` for an unset bag. */
87
+ readonly settings: DynamicQrSettings & JsonObject;
88
+ }
89
+ /** Arguments for creating a dynamic QR. */
90
+ export interface CreateDynamicQrInput {
91
+ /** Absolute `http`/`https` destination. Blank is a 400. */
92
+ readonly url: string;
93
+ /** Initial styling. Unrecognised keys are dropped without complaint. */
94
+ readonly settings?: DynamicQrSettings;
95
+ }
96
+ /**
97
+ * Fields that can change afterwards.
98
+ *
99
+ * `settings` is **merged** into the stored bag by the backend, not replaced, so
100
+ * an update can never unset a key by omitting it. To clear one, send it
101
+ * explicitly with the value that means empty (`null` for `logo`/`bg_image`).
102
+ */
103
+ export interface UpdateDynamicQrInput {
104
+ readonly url?: string;
105
+ readonly settings?: DynamicQrSettings;
106
+ }
107
+ /** The `dynamicQrs` namespace, reachable as `oms.dynamicQrs`. */
108
+ export declare class DynamicQrsNamespace extends Resource {
109
+ /**
110
+ * `GET /dynamic_qrs` - every code you own, newest first.
111
+ *
112
+ * Returns a plain array rather than a page object, and that is not an
113
+ * oversight: this controller does not use `CrudActions` and ignores
114
+ * `modifiers[page]` entirely, so it always answers with the complete set. A
115
+ * `Paginated` here would be a fiction with a `next()` that refetched
116
+ * everything.
117
+ *
118
+ * @throws {OmsAuthError} 401 when anonymous.
119
+ */
120
+ list(options?: RequestOptions): Promise<DynamicQr[]>;
121
+ /**
122
+ * `POST /dynamic_qrs` - mints a code and its permanent endpoint.
123
+ *
124
+ * Retries are off by default: a replayed `POST` after a 502 mints a second
125
+ * code with a second endpoint, and the one that got printed is decided by
126
+ * which response you happened to keep. Pass `retry` explicitly to override.
127
+ *
128
+ * @throws {OmsAuthError} 401 when anonymous.
129
+ * @throws {OmsApiError} 400 when `url` is blank or invalid, or when `logo` /
130
+ * `bg_image` is not a `data:` URI within the size cap.
131
+ */
132
+ create(input: CreateDynamicQrInput, options?: RequestOptions): Promise<DynamicQr>;
133
+ /**
134
+ * `PATCH /dynamic_qrs/:id` - repoints the code or restyles it.
135
+ *
136
+ * This is the whole point of the resource: the printed symbol never changes,
137
+ * only where it lands. `settings` merges; see {@link UpdateDynamicQrInput}.
138
+ *
139
+ * @throws {OmsApiError} 404 when the code is not yours, 400 on a blank URL or
140
+ * an oversized `logo` / `bg_image`.
141
+ */
142
+ update(id: ShortLinkId, input: UpdateDynamicQrInput, options?: RequestOptions): Promise<DynamicQr>;
143
+ /**
144
+ * `DELETE /dynamic_qrs/:id`.
145
+ *
146
+ * Every printed copy dies with it: the endpoint stops resolving and the
147
+ * recorded clicks are destroyed alongside the row. There is no undo and no
148
+ * tombstone redirect.
149
+ *
150
+ * @throws {OmsApiError} 404 when the code is not yours.
151
+ */
152
+ delete(id: ShortLinkId, options?: RequestOptions): Promise<void>;
153
+ /**
154
+ * `GET /dynamic_qrs/:id/stats` - byte-for-byte the same click summary a short
155
+ * link gets, including the fixed 30-day window.
156
+ *
157
+ * @throws {OmsApiError} 404 when the code is not yours.
158
+ */
159
+ stats(id: ShortLinkId, options?: RequestOptions): Promise<ShortLinkStats>;
160
+ /**
161
+ * The URL the printed symbol should encode. Pure string building, no request.
162
+ *
163
+ * Always encode THIS, never `qr.url`: the whole redirect indirection is what
164
+ * makes the destination editable after printing.
165
+ *
166
+ * ```ts
167
+ * const qr = await oms.dynamicQrs.create({ url: "https://example.com" });
168
+ * const svg = oms.local.qr.toSvg(oms.dynamicQrs.publicUrl(qr), { ecc: "H" });
169
+ * ```
170
+ */
171
+ publicUrl(qr: Pick<DynamicQr, "endpoint">): string;
172
+ }