@omelhorsite/sdk 0.3.0 → 0.4.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 (70) hide show
  1. package/README.md +112 -130
  2. package/dist/index.js +1045 -1242
  3. package/dist/types/index.d.ts +1 -0
  4. package/dist/types/internal/attachments.d.ts +17 -0
  5. package/dist/types/internal/helpers.d.ts +9 -0
  6. package/dist/types/listing.d.ts +90 -0
  7. package/dist/types/resources/account.d.ts +5 -2
  8. package/dist/types/resources/admin/authorizedApplications.d.ts +133 -0
  9. package/dist/types/resources/admin/chests.d.ts +51 -0
  10. package/dist/types/resources/admin/eventAlerts.d.ts +60 -0
  11. package/dist/types/resources/admin/identities.d.ts +99 -0
  12. package/dist/types/resources/admin/index.d.ts +77 -0
  13. package/dist/types/resources/admin/jobs.d.ts +97 -0
  14. package/dist/types/resources/admin/myOauthApplications.d.ts +282 -0
  15. package/dist/types/resources/admin/notepads.d.ts +49 -0
  16. package/dist/types/resources/admin/oauthApplications.d.ts +309 -0
  17. package/dist/types/resources/admin/quotas.d.ts +114 -0
  18. package/dist/types/resources/admin/shortLinks.d.ts +201 -0
  19. package/dist/types/resources/admin/types.d.ts +222 -0
  20. package/dist/types/resources/admin/vocalSeparations.d.ts +98 -0
  21. package/dist/types/resources/admin.d.ts +17 -13
  22. package/dist/types/resources/auth/sessions.d.ts +6 -9
  23. package/dist/types/resources/content/analysis.d.ts +62 -0
  24. package/dist/types/resources/content/blogs.d.ts +471 -0
  25. package/dist/types/resources/content/feedbacks.d.ts +263 -0
  26. package/dist/types/resources/content/index.d.ts +52 -0
  27. package/dist/types/resources/content/intel/articles.d.ts +230 -0
  28. package/dist/types/resources/content/intel/config.d.ts +135 -0
  29. package/dist/types/resources/content/intel/index.d.ts +53 -0
  30. package/dist/types/resources/content/intel/items.d.ts +91 -0
  31. package/dist/types/resources/content/intel/reports.d.ts +108 -0
  32. package/dist/types/resources/content/intel/scripts.d.ts +152 -0
  33. package/dist/types/resources/content/intel/sources.d.ts +236 -0
  34. package/dist/types/resources/content/intel/stats.d.ts +105 -0
  35. package/dist/types/resources/content/intel/types.d.ts +86 -0
  36. package/dist/types/resources/content/jokes.d.ts +93 -0
  37. package/dist/types/resources/content/notifications.d.ts +147 -0
  38. package/dist/types/resources/content/serviceUsages.d.ts +73 -0
  39. package/dist/types/resources/content/servicesStatus.d.ts +194 -0
  40. package/dist/types/resources/content/siteConfig.d.ts +43 -0
  41. package/dist/types/resources/content/spaceInvaders.d.ts +154 -0
  42. package/dist/types/resources/content.d.ts +41 -236
  43. package/dist/types/resources/jobs.d.ts +7 -4
  44. package/dist/types/resources/library/annotations.d.ts +162 -0
  45. package/dist/types/resources/library/books.d.ts +534 -0
  46. package/dist/types/resources/library/chat.d.ts +259 -0
  47. package/dist/types/resources/library/index.d.ts +39 -0
  48. package/dist/types/resources/library/shelves.d.ts +237 -0
  49. package/dist/types/resources/library/types.d.ts +120 -0
  50. package/dist/types/resources/library.d.ts +20 -22
  51. package/dist/types/resources/movies/addons.d.ts +388 -0
  52. package/dist/types/resources/movies/collections.d.ts +352 -0
  53. package/dist/types/resources/movies/index.d.ts +29 -0
  54. package/dist/types/resources/movies/types.d.ts +50 -0
  55. package/dist/types/resources/movies/watchProgress.d.ts +277 -0
  56. package/dist/types/resources/movies.d.ts +27 -53
  57. package/dist/types/resources/music/artists.d.ts +3 -1
  58. package/dist/types/resources/music/imports.d.ts +9 -8
  59. package/dist/types/resources/music/playlists.d.ts +8 -7
  60. package/dist/types/resources/music/songs.d.ts +5 -21
  61. package/dist/types/resources/shortLinks.d.ts +5 -2
  62. package/dist/types/resources/social/groupChats.d.ts +458 -0
  63. package/dist/types/resources/social/index.d.ts +19 -0
  64. package/dist/types/resources/social/messages.d.ts +424 -0
  65. package/dist/types/resources/social/relationships.d.ts +322 -0
  66. package/dist/types/resources/social/types.d.ts +37 -0
  67. package/dist/types/resources/social.d.ts +21 -3
  68. package/dist/types/resources/storage.d.ts +24 -6
  69. package/dist/types/resources/tickets.d.ts +19 -10
  70. package/package.json +1 -1
@@ -0,0 +1,322 @@
1
+ /** Relationships: friendships and blocks, and `oms.social.relationships`. */
2
+ import { Resource } from "../../http";
3
+ import type { ListParams } from "../../listing";
4
+ import type { User } from "../account";
5
+ import type { Id, Paginated, RequestOptions, Timestamp } from "../../types";
6
+ /** Primary key of a relationship row. An integer, for the same reason. */
7
+ export type RelationshipId = number;
8
+ /** A relationship row: one friendship or one block, between two users. */
9
+ export interface Relationship {
10
+ /** Integer. */
11
+ readonly id: RelationshipId;
12
+ readonly created_at: Timestamp;
13
+ readonly updated_at: Timestamp;
14
+ readonly kind: RelationshipKind;
15
+ readonly status: RelationshipStatus;
16
+ /** Whoever created the row. Always the authenticated user at create time. */
17
+ readonly requester_id: Id;
18
+ readonly accepter_id: Id;
19
+ readonly requester: User;
20
+ readonly accepter: User;
21
+ }
22
+ /** What a relationship row means. */
23
+ export type RelationshipKind = "friend" | "block";
24
+ /** Where a relationship row is in its lifecycle. */
25
+ export type RelationshipStatus = "pending" | "accepted";
26
+ /** Filter columns of `GET /relationships`, on top of {@link BASE_FILTER_COLUMNS}. */
27
+ export declare const RELATIONSHIP_FILTER_COLUMNS: readonly ["requester_id", "accepter_id"];
28
+ /** `extra_options` keys of `GET /relationships`. */
29
+ export declare const RELATIONSHIP_EXTRA_OPTION_KEYS: readonly ["user_id"];
30
+ /** `extra_options` of `GET /relationships`. `user_id` matches rows where the user is either end. */
31
+ export interface RelationshipExtraOptions {
32
+ readonly user_id?: Id;
33
+ }
34
+ /** Filters accepted by {@link RelationshipsNamespace.list}. */
35
+ export interface ListRelationshipsParams extends ListParams<(typeof RELATIONSHIP_FILTER_COLUMNS)[number], RelationshipExtraOptions> {
36
+ /**
37
+ * `extra_options[user_id]`: rows where this user is either end.
38
+ *
39
+ * Worth passing your own id even though it narrows nothing. The filter is
40
+ * what makes the server preload both ends of every row. Without it the
41
+ * nested {@link User} for both ends of every row is rendered out of an
42
+ * unprepared query - two extra `SELECT`s per relationship.
43
+ */
44
+ readonly userId?: Id;
45
+ /** `exact_search[requester_id]`: rows this user created. */
46
+ readonly requesterId?: Id;
47
+ /** `exact_search[accepter_id]`: rows aimed at this user. */
48
+ readonly accepterId?: Id;
49
+ }
50
+ /** Body of {@link RelationshipsNamespace.create}. */
51
+ export interface CreateRelationshipInput {
52
+ /** The other user. */
53
+ readonly userId: Id;
54
+ /** `"friend"` for a request, `"block"` for a block. */
55
+ readonly kind: RelationshipKind;
56
+ }
57
+ /**
58
+ * Friendships and blocks, reachable as `oms.social.relationships`.
59
+ *
60
+ * ## The state machine is TWO columns, not one
61
+ *
62
+ * There is no single `status` enum with a `blocked` member, however the UIs
63
+ * present it. A row carries `kind` (`friend` | `block`) and `status`
64
+ * (`pending` | `accepted`), and only three of the four combinations exist:
65
+ *
66
+ * | kind | status | what it is |
67
+ * | -------- | ---------- | ---------------------------------------------- |
68
+ * | `friend` | `pending` | a friend request, awaiting the accepter |
69
+ * | `friend` | `accepted` | a friendship |
70
+ * | `block` | `accepted` | the requester has blocked the accepter |
71
+ *
72
+ * `block` + `pending` is unreachable: a block is forced to `accepted` at
73
+ * birth, which also means a block's status can never be edited afterwards
74
+ * (see the transition rules below). Blocking is asymmetric and direction
75
+ * matters - `requester_id` blocked `accepter_id`, never the reverse.
76
+ *
77
+ * ## Transitions the server will accept
78
+ *
79
+ * `PATCH` may write `status` and nothing else. Any change whose PREVIOUS value
80
+ * was `accepted` is aborted, so:
81
+ *
82
+ * - `pending -> accepted` is the one real transition, and it is what
83
+ * {@link accept} does;
84
+ * - `pending -> pending` is a no-op that answers `200`, because nothing
85
+ * changed and the guard only fires on a change;
86
+ * - `accepted -> pending` is refused, `400 "Status cannot be changed"`;
87
+ * - `accepted -> accepted` is a no-op `200`, same reason as above;
88
+ * - anything outside `pending` / `accepted` is refused by the inclusion
89
+ * validation, `400 "Status is not included in the list"`.
90
+ *
91
+ * There is no un-accept, no un-block and no "decline" verb. Ending ANY
92
+ * relationship - rejecting a request, unfriending, unblocking - is
93
+ * {@link delete} on the row. That is one method for three intentions, and the
94
+ * server cannot tell them apart either.
95
+ *
96
+ * ## EITHER PARTY CAN ACCEPT. INCLUDING THE ONE WHO ASKED.
97
+ *
98
+ * Either end of the row may `PATCH` it, and nothing narrows that for the
99
+ * `pending -> accepted` transition. So the sender of a friend request can
100
+ * `PATCH` their own request to `accepted` and become the recipient's friend
101
+ * without the recipient doing anything.
102
+ *
103
+ * That is a real hole, not a subtlety of this SDK, and it is load-bearing
104
+ * because friendship gates real things elsewhere in the API - a `friends`
105
+ * playlist becomes visible, the friends listening feed starts carrying that
106
+ * user's playback. Do not build a UI that offers the requester an accept
107
+ * button, and do not treat `status: "accepted"` as proof of consent from the
108
+ * accepter.
109
+ *
110
+ * ## A block you receive is INVISIBLE to you
111
+ *
112
+ * A block aimed at you is hidden from listings AND from lookups by id. You
113
+ * can see blocks you made; you cannot see, list, count or delete a block
114
+ * someone made against you. Its only observable effect is that
115
+ * {@link DirectMessagesNamespace.send} answers `401`.
116
+ *
117
+ * ## Realtime
118
+ *
119
+ * Both interesting events reach the other party as `NotificationsChannel`
120
+ * pushes rather than as anything on this namespace: `friendship_request`
121
+ * (`{ asker_id, asker_handle }`) when a `friend`/`pending` row is created, and
122
+ * `friendship_accepted` (`{ accepter_id, accepter_handle }`) when it flips.
123
+ * Neither carries the relationship row, so a client still has to
124
+ * {@link list} after the nudge. `block`, `delete` and every failed transition
125
+ * are silent.
126
+ */
127
+ export declare class RelationshipsNamespace extends Resource {
128
+ /**
129
+ * `GET /relationships` - every relationship the caller is part of, in either
130
+ * direction, minus the blocks aimed at them.
131
+ *
132
+ * ## `kind` AND `status` ARE NOT FILTERABLE
133
+ *
134
+ * The filter columns are `requester_id, accepter_id` plus `id, created_at,
135
+ * updated_at`. `kind` and `status` are absent, and an unknown filter key
136
+ * does not get dropped - it is `400 "Unknown search filter: kind"`. So "list
137
+ * my friends" is not a query the API can answer: fetch the rows and filter
138
+ * here. {@link friends}, {@link incomingRequests}, {@link outgoingRequests}
139
+ * and {@link blocked} do exactly that.
140
+ *
141
+ * This is the single most surprising thing about the endpoint.
142
+ *
143
+ * ## Paging
144
+ *
145
+ * The SDK sends an explicit `modifiers[page]` and an explicit
146
+ * `created_at:desc` order, for the usual reason: with no page the server
147
+ * silently forces `1:500`, and offset paging over an unordered query can
148
+ * repeat and skip rows. A client that sends neither truncates at 500 rows
149
+ * without saying so - a real ceiling for an account with a long history,
150
+ * since blocks and dead requests count towards it.
151
+ *
152
+ * Indexes carry an `ETag`, so a conditional GET can come back `304`; the SDK
153
+ * does not send `If-None-Match` of its own.
154
+ */
155
+ list(params?: ListRelationshipsParams, options?: RequestOptions): Promise<Paginated<Relationship>>;
156
+ /**
157
+ * Every relationship row, paged out in full and filtered in memory.
158
+ *
159
+ * The building block under {@link friends} and its siblings, exported
160
+ * because "fetch them all, then filter" is the only shape this endpoint
161
+ * supports and every client ends up writing it.
162
+ *
163
+ * `limit` caps how many rows are pulled, so a pathological account cannot
164
+ * turn one call into an unbounded walk. It defaults to 2000, which is four
165
+ * requests at the server's maximum page size.
166
+ */
167
+ all(params?: ListRelationshipsParams, limit?: number, options?: RequestOptions): Promise<Relationship[]>;
168
+ /**
169
+ * The caller's accepted friends, as {@link User} records rather than as
170
+ * relationship rows.
171
+ *
172
+ * `selfId` is required and is NOT fetched for you: knowing which end of the
173
+ * row is "the other person" needs the caller's own id, and this namespace
174
+ * refuses to spend a `GET /sessions/mine` on every call to find it. Take it
175
+ * from `oms.account.me()` once and keep it.
176
+ *
177
+ * A friend appears exactly once even though the row could be in either
178
+ * direction. The result is derived from the same nested `requester` /
179
+ * `accepter` objects the listing already carries, so this costs no extra
180
+ * request beyond the paging {@link all} does.
181
+ */
182
+ friends(selfId: Id, options?: RequestOptions): Promise<User[]>;
183
+ /**
184
+ * Friend requests waiting for the caller to answer: `friend` + `pending`
185
+ * rows where the caller is the ACCEPTER.
186
+ *
187
+ * These are the ones {@link accept} is meant for. Answer with {@link accept}
188
+ * or refuse with {@link delete}; there is no third verb.
189
+ *
190
+ * This walks the listing itself, as do {@link friends}, {@link blocked} and
191
+ * {@link outgoingRequests}, because the server cannot filter on `kind` or
192
+ * `status`. A screen that wants more than one of them should call
193
+ * {@link all} ONCE and sort the rows with {@link isFriendship},
194
+ * {@link isPendingRequest} and {@link isBlock} rather than paying for the
195
+ * same walk four times.
196
+ */
197
+ incomingRequests(selfId: Id, options?: RequestOptions): Promise<Relationship[]>;
198
+ /**
199
+ * Friend requests the caller sent and nobody has answered: `friend` +
200
+ * `pending` rows where the caller is the REQUESTER.
201
+ *
202
+ * {@link delete} on one of these is a cancel. {@link accept} on one of these
203
+ * works too, and should not - see the class docs.
204
+ */
205
+ outgoingRequests(selfId: Id, options?: RequestOptions): Promise<Relationship[]>;
206
+ /**
207
+ * Users the caller has blocked.
208
+ *
209
+ * Only blocks the caller MADE. A block made against the caller is hidden
210
+ * and cannot be enumerated by any means; see the class docs.
211
+ */
212
+ blocked(selfId: Id, options?: RequestOptions): Promise<User[]>;
213
+ /**
214
+ * `POST /relationships` - creates a row. `201` with the record.
215
+ *
216
+ * `requester_id` is forced to the authenticated user and `status` is not
217
+ * writable: a `friend` starts `pending`, a `block` is born `accepted`.
218
+ * Prefer {@link request} and {@link block}, which say which of the two you
219
+ * meant.
220
+ *
221
+ * @throws {OmsApiError} `400 "Cannot create relationship with yourself"`,
222
+ * or `400 "A relationship of this kind already exists between these
223
+ * users"` when a `friend` row already exists in either direction.
224
+ */
225
+ create(input: CreateRelationshipInput, options?: RequestOptions): Promise<Relationship>;
226
+ /**
227
+ * Sends a friend request: `create({ kind: "friend" })`.
228
+ *
229
+ * At most one `friend` row may exist between two users in either direction,
230
+ * and the uniqueness check runs UNSCOPED - it sees rows the default scope
231
+ * hides from you. So a second request answers `400 "A relationship of this
232
+ * kind already exists between these users"`, and so does requesting someone
233
+ * who has already requested you (accept theirs instead) and, less obviously,
234
+ * requesting someone who has blocked you: their block row counts as an
235
+ * existing relationship. That last case is the only signal the API gives that
236
+ * a block against you exists, and it is indistinguishable from a duplicate
237
+ * request.
238
+ *
239
+ * The accepter gets a `friendship_request` notification over the cable.
240
+ */
241
+ request(userId: Id, options?: RequestOptions): Promise<Relationship>;
242
+ /**
243
+ * Blocks a user: `create({ kind: "block" })`.
244
+ *
245
+ * Three things happen server-side that no other call does:
246
+ *
247
+ * 1. the row is born `accepted`, so its status is immediately frozen;
248
+ * 2. every existing relationship between the two of you is DELETED first -
249
+ * an accepted friendship is gone, not suspended, and unblocking later
250
+ * does not bring it back;
251
+ * 3. that deletion is skipped when a block already exists between you in
252
+ * EITHER direction, which also means **blocking is not idempotent**: a
253
+ * second call creates a SECOND block row rather than answering with the
254
+ * first, because the uniqueness validation deliberately exempts blocks.
255
+ * Check {@link blocked} before calling, and unblock all the rows you find.
256
+ *
257
+ * The effect on the other user is exactly one thing: their
258
+ * {@link DirectMessagesNamespace.send} to you starts answering `401`. It does
259
+ * not stop you messaging them, it does not hide either profile, and it does
260
+ * not remove either of you from the other's
261
+ * {@link DirectMessagesNamespace.conversedUsers}, which is built from message
262
+ * history rather than from relationships.
263
+ *
264
+ * The blocked user is not notified.
265
+ */
266
+ block(userId: Id, options?: RequestOptions): Promise<Relationship>;
267
+ /**
268
+ * `PATCH /relationships/:id` with `status: "accepted"` - accepts a pending
269
+ * friend request. `200` with the updated record.
270
+ *
271
+ * Only ever call this on a row from {@link incomingRequests}. The server will
272
+ * happily accept one of your OWN outgoing requests, which is a hole, not a
273
+ * feature; see the class docs.
274
+ *
275
+ * The requester gets a `friendship_accepted` notification.
276
+ *
277
+ * @throws {OmsApiError} `400 "Status cannot be changed"` when the row was
278
+ * already `accepted` and something is trying to move it back; `401` when
279
+ * the caller is neither end of the row; `404 "Resource not found"` when the
280
+ * id is not visible to the caller - which includes a block made against
281
+ * them.
282
+ */
283
+ accept(id: RelationshipId, options?: RequestOptions): Promise<Relationship>;
284
+ /**
285
+ * `DELETE /relationships/:id` - `204`, empty body.
286
+ *
287
+ * The one verb for every ending: rejecting an incoming request, cancelling an
288
+ * outgoing one, unfriending, and unblocking. Either party may call it, and
289
+ * the row is gone for both - there is no soft state and no history.
290
+ *
291
+ * Unblocking does NOT restore the friendship the block destroyed on its way
292
+ * in. That row was deleted, not archived.
293
+ *
294
+ * Nobody is notified, so the other side finds out by noticing the row is no
295
+ * longer in their listing.
296
+ *
297
+ * `GET /relationships/:id` does not exist. Read a single row out of
298
+ * {@link list} instead.
299
+ */
300
+ delete(id: RelationshipId, options?: RequestOptions): Promise<void>;
301
+ }
302
+ /**
303
+ * The user at the other end of a relationship row, given the caller's own id.
304
+ *
305
+ * A relationship is stored with a direction (`requester` asked, `accepter` was
306
+ * asked) that a friends list does not care about, so every client writes this
307
+ * function. It is here once instead.
308
+ *
309
+ * Returns `undefined` when `selfId` is neither end of the row, and when the
310
+ * nested user object is missing - which the API does not currently do, but is
311
+ * treated as possible rather than asserted away.
312
+ */
313
+ export declare function counterpart(relationship: Relationship, selfId: Id): User | undefined;
314
+ /** `kind === "friend" && status === "accepted"`. */
315
+ export declare function isFriendship(relationship: Relationship): boolean;
316
+ /** An unanswered friend request, in either direction. */
317
+ export declare function isPendingRequest(relationship: Relationship): boolean;
318
+ /**
319
+ * A block the CALLER made. There is no such thing as a visible block against
320
+ * the caller - see {@link RelationshipsNamespace}.
321
+ */
322
+ export declare function isBlock(relationship: Relationship): boolean;
@@ -0,0 +1,37 @@
1
+ /** What direct messages and group chats share: the attachment kind and the caps both message families obey. */
2
+ import type { Timestamp } from "../../types";
3
+ /**
4
+ * 25 MiB, for a direct message and a group chat message alike, checked before
5
+ * anything is attached.
6
+ *
7
+ * IMAGES HAVE A LOWER, WORSE-BEHAVED CEILING. See
8
+ * {@link MESSAGE_IMAGE_MAX_BYTES}.
9
+ */
10
+ export declare const MESSAGE_ATTACHMENT_MAX_BYTES: number;
11
+ /**
12
+ * Fifteen minutes from `created_at`, for a direct message and a group chat
13
+ * message alike, after which an edit is `401`.
14
+ *
15
+ * Measured against the SERVER's clock. {@link canEditMessage} compares against
16
+ * the caller's, which is close enough to grey out a button and not close
17
+ * enough to promise the edit will land.
18
+ */
19
+ export declare const MESSAGE_EDIT_WINDOW_MS: number;
20
+ /** How the server classified an attachment, from its `content_type`. */
21
+ export type AttachmentKind = "image" | "audio" | "video" | "file";
22
+ /**
23
+ * Whether a message is still inside its edit window, for greying out a button.
24
+ *
25
+ * Measured against the CALLER's clock, and the server measures against its own,
26
+ * so this is an approximation that gets less honest the further the two drift.
27
+ * Always handle the `401` as well; do not treat `true` here as a promise that
28
+ * the edit will land, and do not treat `false` as a reason to skip the call if
29
+ * the user insists.
30
+ *
31
+ * Takes `now` so the function stays pure and the module stays isolate-safe -
32
+ * no `Date.now()` at module scope, and a caller can pass a server-derived
33
+ * clock if it has one.
34
+ */
35
+ export declare function canEditMessage(message: {
36
+ created_at: Timestamp;
37
+ }, now?: number): boolean;
@@ -68,8 +68,9 @@
68
68
  * cost actually is.
69
69
  */
70
70
  import { Resource } from "../http";
71
+ import type { ListParams } from "../listing";
71
72
  import type { User } from "./account";
72
- import type { BaseRecord, FileInput, Id, NativeFile, PageParams, Paginated, RequestOptions, Timestamp } from "../types";
73
+ import type { BaseRecord, FileInput, Id, NativeFile, Paginated, RequestOptions, Timestamp } from "../types";
73
74
  /**
74
75
  * Primary key of a direct message. An INTEGER: `messages` is one of the tables
75
76
  * that kept an auto-increment key, so `id` and `quoted_message_id` are JSON
@@ -296,8 +297,17 @@ export declare class SocialNamespace extends Resource {
296
297
  readonly groupChats: GroupChatsNamespace;
297
298
  constructor(http: ConstructorParameters<typeof Resource>[0]);
298
299
  }
300
+ /** Filter columns of `GET /messages`. */
301
+ export declare const MESSAGE_FILTER_COLUMNS: readonly ["id", "created_at", "updated_at", "content", "sender_id", "receiver_id", "read_at"];
302
+ /** `extra_options` keys of `GET /messages`. */
303
+ export declare const MESSAGE_EXTRA_OPTION_KEYS: readonly ["user_id", "other_user_id"];
304
+ /** `extra_options` of `GET /messages`. Each matches rows where the user is either end. */
305
+ export interface MessageExtraOptions {
306
+ readonly user_id?: Id;
307
+ readonly other_user_id?: Id;
308
+ }
299
309
  /** Filters accepted by {@link DirectMessagesNamespace.list}. */
300
- export interface ListMessagesParams extends PageParams {
310
+ export interface ListMessagesParams extends ListParams<(typeof MESSAGE_FILTER_COLUMNS)[number], MessageExtraOptions> {
301
311
  /**
302
312
  * The other end of the conversation. Sent as
303
313
  * `extra_options[other_user_id]`, which the server expands to
@@ -621,8 +631,16 @@ export declare class DirectMessagesNamespace extends Resource {
621
631
  */
622
632
  attachmentUrl(id: MessageId): Promise<string>;
623
633
  }
634
+ /** Filter columns of `GET /relationships`, on top of {@link BASE_FILTER_COLUMNS}. */
635
+ export declare const RELATIONSHIP_FILTER_COLUMNS: readonly ["requester_id", "accepter_id"];
636
+ /** `extra_options` keys of `GET /relationships`. */
637
+ export declare const RELATIONSHIP_EXTRA_OPTION_KEYS: readonly ["user_id"];
638
+ /** `extra_options` of `GET /relationships`. `user_id` matches rows where the user is either end. */
639
+ export interface RelationshipExtraOptions {
640
+ readonly user_id?: Id;
641
+ }
624
642
  /** Filters accepted by {@link RelationshipsNamespace.list}. */
625
- export interface ListRelationshipsParams extends PageParams {
643
+ export interface ListRelationshipsParams extends ListParams<(typeof RELATIONSHIP_FILTER_COLUMNS)[number], RelationshipExtraOptions> {
626
644
  /**
627
645
  * `extra_options[user_id]`: rows where this user is either end.
628
646
  *
@@ -42,7 +42,8 @@
42
42
  * around that difference; do not collapse the two filters back together.
43
43
  */
44
44
  import { type ApiClient, Resource } from "../http";
45
- import type { BaseRecord, FileOutput, Id, OperationOptions, Paginated, PageParams, RequestOptions } from "../types";
45
+ import type { ListParams } from "../listing";
46
+ import type { BaseRecord, FileOutput, Id, OperationOptions, Paginated, RequestOptions } from "../types";
46
47
  import type { User } from "./account";
47
48
  import { StorageRateGate, UploadManager } from "./storage/upload";
48
49
  import type { UploadInput } from "./storage/upload";
@@ -125,12 +126,27 @@ export interface FsStream {
125
126
  readonly size: number | undefined;
126
127
  }
127
128
  /** Filters for {@link StorageNamespace.list}. */
128
- export interface ListFsNodesParams extends PageParams {
129
+ /** Filter columns of `GET /fs_nodes`. */
130
+ export declare const FS_NODE_FILTER_COLUMNS: readonly ["id", "created_at", "updated_at", "name", "parent_id"];
131
+ /** `extra_options` keys of `GET /fs_nodes`. */
132
+ export declare const FS_NODE_EXTRA_OPTION_KEYS: readonly ["parent_id", "include_pending"];
133
+ /**
134
+ * `extra_options` of `GET /fs_nodes`. `parent_id` here returns the folder's
135
+ * children AND the folder itself; the `parent_id` column in `exactSearch`
136
+ * returns the children only, and is the only one that can say `null`.
137
+ */
138
+ export interface FsNodeExtraOptions {
139
+ readonly parent_id?: Id;
140
+ readonly include_pending?: boolean;
141
+ }
142
+ /** Filters for {@link StorageNamespace.list}. */
143
+ export interface ListFsNodesParams extends ListParams<(typeof FS_NODE_FILTER_COLUMNS)[number], FsNodeExtraOptions> {
129
144
  /**
130
145
  * Directory to list. `null` lists the caller's ROOT nodes (home, trash,
131
- * vault), which the server selects through its `\b` null sentinel.
146
+ * vault). Omitted, no parent filter is applied and the listing spans the
147
+ * caller's whole tree, which is what a name search across folders wants.
132
148
  */
133
- readonly parentId: Id | null;
149
+ readonly parentId?: Id | null;
134
150
  /**
135
151
  * Include nodes whose bytes never landed. Off by default, because a
136
152
  * half-finished upload is not something a user wants to see - and because a
@@ -165,6 +181,8 @@ export interface CopyFsNodesInput {
165
181
  readonly ids: Id[];
166
182
  readonly newParentId: Id;
167
183
  }
184
+ /** `GET /fs_grants` filters on {@link BASE_FILTER_COLUMNS} only. */
185
+ export type ListFsGrantsParams = ListParams<never>;
168
186
  /**
169
187
  * A sharing grant on a node.
170
188
  *
@@ -229,7 +247,7 @@ export declare class FsGrantsNamespace extends Resource {
229
247
  *
230
248
  * @throws {OmsAuthError} 401 when anonymous.
231
249
  */
232
- list(params?: PageParams, options?: RequestOptions): Promise<Paginated<FsGrant>>;
250
+ list(params?: ListFsGrantsParams, options?: RequestOptions): Promise<Paginated<FsGrant>>;
233
251
  /** `GET /fs_grants/:id` - one grant, with its node, grantor and grantee expanded. */
234
252
  get(id: Id, options?: RequestOptions): Promise<FsGrant>;
235
253
  /**
@@ -327,7 +345,7 @@ export declare class StorageNamespace extends Resource {
327
345
  * revalidate on its own, because a 304 has no body and would surface here as
328
346
  * an error rather than as an empty page.
329
347
  */
330
- list(params: ListFsNodesParams, options?: RequestOptions): Promise<Paginated<FsNode>>;
348
+ list(params?: ListFsNodesParams, options?: RequestOptions): Promise<Paginated<FsNode>>;
331
349
  /**
332
350
  * `GET /fs_nodes/:id` - one node.
333
351
  *
@@ -11,7 +11,8 @@
11
11
  * in the same request.
12
12
  */
13
13
  import { type ApiClient, Resource } from "../http";
14
- import type { FileInput, Id, Paginated, PageParams, RequestOptions, Timestamp } from "../types";
14
+ import type { ListParams } from "../listing";
15
+ import type { FileInput, Id, Paginated, RequestOptions, Timestamp } from "../types";
15
16
  /** Lifecycle of a ticket. */
16
17
  export type TicketStatus = "open" | "closed";
17
18
  /**
@@ -99,29 +100,37 @@ export interface CreateTicketInput {
99
100
  readonly initialMessage?: string;
100
101
  readonly context?: TicketContext;
101
102
  /**
102
- * Files to attach. The SDK turns each one into the data URI the endpoint
103
- * expects, so every attachment is buffered in memory.
103
+ * Files to attach, as bytes or as an already-encoded data URL. Bytes are
104
+ * base64-encoded here, so every attachment is buffered in memory.
104
105
  *
105
- * Backend caps: {@link TICKET_MAX_ATTACHMENTS} files,
106
+ * Server caps: {@link TICKET_MAX_ATTACHMENTS} files,
106
107
  * {@link TICKET_MAX_ATTACHMENT_BYTES} in total, `image/*` and `video/*`
107
- * only - and an attachment that breaks any of them is dropped in SILENCE,
108
- * with the ticket still answering 201. The SDK therefore validates before
109
- * sending and raises rather than let a screenshot disappear.
108
+ * only. An attachment over a cap is dropped server-side with the ticket
109
+ * still answering 201, so the SDK validates first and throws instead.
110
110
  */
111
- readonly attachments?: FileInput[];
111
+ readonly attachments?: ReadonlyArray<FileInput | TicketAttachmentDataUrl>;
112
+ }
113
+ /** An attachment that is already a `data:<mime>;base64,...` URL. */
114
+ export interface TicketAttachmentDataUrl {
115
+ readonly dataUrl: string;
116
+ readonly filename: string;
112
117
  }
113
118
  /** Fields that can change after a ticket exists. */
114
119
  export interface UpdateTicketInput {
115
120
  readonly status?: TicketStatus;
116
121
  }
122
+ /** Filter columns of `GET /tickets`, on top of {@link BASE_FILTER_COLUMNS}. */
123
+ export declare const TICKET_FILTER_COLUMNS: readonly ["status", "user_id"];
117
124
  /** Filters for {@link TicketsNamespace.list}. */
118
- export interface ListTicketsParams extends PageParams {
125
+ export interface ListTicketsParams extends ListParams<(typeof TICKET_FILTER_COLUMNS)[number]> {
119
126
  readonly status?: TicketStatus;
120
127
  /** Administrators only: someone else's tickets. */
121
128
  readonly userId?: Id;
122
129
  }
130
+ /** Filter columns of `GET /ticket_messages`, on top of {@link BASE_FILTER_COLUMNS}. */
131
+ export declare const TICKET_MESSAGE_FILTER_COLUMNS: readonly ["ticket_id", "sender_id", "created_at"];
123
132
  /** Filters for {@link TicketMessagesNamespace.list}. */
124
- export interface ListTicketMessagesParams extends PageParams {
133
+ export interface ListTicketMessagesParams extends ListParams<(typeof TICKET_MESSAGE_FILTER_COLUMNS)[number]> {
125
134
  readonly ticketId: TicketId;
126
135
  }
127
136
  /** Arguments for replying to a ticket. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omelhorsite/sdk",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
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",