@omelhorsite/sdk 0.2.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 (96) hide show
  1. package/README.md +112 -130
  2. package/dist/index.js +4800 -610
  3. package/dist/types/client.d.ts +60 -3
  4. package/dist/types/http.d.ts +444 -19
  5. package/dist/types/index.d.ts +5 -1
  6. package/dist/types/internal/attachments.d.ts +17 -0
  7. package/dist/types/internal/helpers.d.ts +9 -0
  8. package/dist/types/listing.d.ts +90 -0
  9. package/dist/types/resources/account.d.ts +71 -5
  10. package/dist/types/resources/admin/authorizedApplications.d.ts +133 -0
  11. package/dist/types/resources/admin/chests.d.ts +51 -0
  12. package/dist/types/resources/admin/eventAlerts.d.ts +60 -0
  13. package/dist/types/resources/admin/identities.d.ts +99 -0
  14. package/dist/types/resources/admin/index.d.ts +77 -0
  15. package/dist/types/resources/admin/jobs.d.ts +97 -0
  16. package/dist/types/resources/admin/myOauthApplications.d.ts +282 -0
  17. package/dist/types/resources/admin/notepads.d.ts +49 -0
  18. package/dist/types/resources/admin/oauthApplications.d.ts +309 -0
  19. package/dist/types/resources/admin/quotas.d.ts +114 -0
  20. package/dist/types/resources/admin/shortLinks.d.ts +201 -0
  21. package/dist/types/resources/admin/types.d.ts +222 -0
  22. package/dist/types/resources/admin/vocalSeparations.d.ts +98 -0
  23. package/dist/types/resources/admin.d.ts +1841 -0
  24. package/dist/types/resources/auth/index.d.ts +39 -0
  25. package/dist/types/resources/auth/passkeys.d.ts +652 -0
  26. package/dist/types/resources/auth/sessions.d.ts +844 -0
  27. package/dist/types/resources/chests.d.ts +54 -3
  28. package/dist/types/resources/content/analysis.d.ts +62 -0
  29. package/dist/types/resources/content/blogs.d.ts +471 -0
  30. package/dist/types/resources/content/feedbacks.d.ts +263 -0
  31. package/dist/types/resources/content/index.d.ts +52 -0
  32. package/dist/types/resources/content/intel/articles.d.ts +230 -0
  33. package/dist/types/resources/content/intel/config.d.ts +135 -0
  34. package/dist/types/resources/content/intel/index.d.ts +53 -0
  35. package/dist/types/resources/content/intel/items.d.ts +91 -0
  36. package/dist/types/resources/content/intel/reports.d.ts +108 -0
  37. package/dist/types/resources/content/intel/scripts.d.ts +152 -0
  38. package/dist/types/resources/content/intel/sources.d.ts +236 -0
  39. package/dist/types/resources/content/intel/stats.d.ts +105 -0
  40. package/dist/types/resources/content/intel/types.d.ts +86 -0
  41. package/dist/types/resources/content/jokes.d.ts +93 -0
  42. package/dist/types/resources/content/notifications.d.ts +147 -0
  43. package/dist/types/resources/content/serviceUsages.d.ts +73 -0
  44. package/dist/types/resources/content/servicesStatus.d.ts +194 -0
  45. package/dist/types/resources/content/siteConfig.d.ts +43 -0
  46. package/dist/types/resources/content/spaceInvaders.d.ts +154 -0
  47. package/dist/types/resources/content.d.ts +2775 -0
  48. package/dist/types/resources/dynamicQrs.d.ts +39 -3
  49. package/dist/types/resources/forms.d.ts +176 -35
  50. package/dist/types/resources/index.d.ts +19 -8
  51. package/dist/types/resources/ipLookup.d.ts +20 -4
  52. package/dist/types/resources/jobs.d.ts +69 -25
  53. package/dist/types/resources/library/annotations.d.ts +162 -0
  54. package/dist/types/resources/library/books.d.ts +534 -0
  55. package/dist/types/resources/library/chat.d.ts +259 -0
  56. package/dist/types/resources/library/index.d.ts +39 -0
  57. package/dist/types/resources/library/shelves.d.ts +237 -0
  58. package/dist/types/resources/library/types.d.ts +120 -0
  59. package/dist/types/resources/library.d.ts +1433 -0
  60. package/dist/types/resources/linkTrees.d.ts +142 -30
  61. package/dist/types/resources/media.d.ts +351 -0
  62. package/dist/types/resources/movies/addons.d.ts +388 -0
  63. package/dist/types/resources/movies/collections.d.ts +352 -0
  64. package/dist/types/resources/movies/index.d.ts +29 -0
  65. package/dist/types/resources/movies/types.d.ts +50 -0
  66. package/dist/types/resources/movies/watchProgress.d.ts +277 -0
  67. package/dist/types/resources/movies.d.ts +1160 -0
  68. package/dist/types/resources/music/artists.d.ts +1068 -0
  69. package/dist/types/resources/music/imports.d.ts +941 -0
  70. package/dist/types/resources/music/index.d.ts +61 -0
  71. package/dist/types/resources/music/playlists.d.ts +1027 -0
  72. package/dist/types/resources/music/social.d.ts +1132 -0
  73. package/dist/types/resources/music/songs.d.ts +1167 -0
  74. package/dist/types/resources/notepads.d.ts +4 -1
  75. package/dist/types/resources/quotas.d.ts +7 -1
  76. package/dist/types/resources/realtime.d.ts +855 -0
  77. package/dist/types/resources/shortLinks.d.ts +49 -5
  78. package/dist/types/resources/social/groupChats.d.ts +458 -0
  79. package/dist/types/resources/social/index.d.ts +19 -0
  80. package/dist/types/resources/social/messages.d.ts +424 -0
  81. package/dist/types/resources/social/relationships.d.ts +322 -0
  82. package/dist/types/resources/social/types.d.ts +37 -0
  83. package/dist/types/resources/social.d.ts +1348 -0
  84. package/dist/types/resources/storage/upload.d.ts +158 -11
  85. package/dist/types/resources/storage.d.ts +111 -27
  86. package/dist/types/resources/tickets.d.ts +101 -13
  87. package/dist/types/resources/tools/backgroundRemoval.d.ts +18 -3
  88. package/dist/types/resources/tools/captions.d.ts +448 -21
  89. package/dist/types/resources/tools/downloader.d.ts +21 -0
  90. package/dist/types/resources/tools/index.d.ts +57 -15
  91. package/dist/types/resources/tools/jumpstyle.d.ts +50 -17
  92. package/dist/types/resources/tools/transcription.d.ts +35 -13
  93. package/dist/types/resources/tools/upscale.d.ts +23 -3
  94. package/dist/types/resources/tools/vocalSeparation.d.ts +30 -13
  95. package/dist/types/types.d.ts +249 -17
  96. package/package.json +2 -1
@@ -9,9 +9,17 @@
9
9
  * Creating a link works anonymously; listing, editing and statistics need a
10
10
  * credential. Creation is the most tightly throttled write in the whole API -
11
11
  * see {@link ShortLinksNamespace.create} before you spend one.
12
+ *
13
+ * There is deliberately no `get(id)` here, and its absence is the API's, not
14
+ * an omission: the route file declares `resources :short_links, only: [:create,
15
+ * :index, :update, :destroy]`, so `GET /short_links/:id` is not routed at all
16
+ * and answers 404 for every id, including your own links. To read one link,
17
+ * find it in {@link ShortLinksNamespace.list} - or by endpoint with
18
+ * {@link ShortLinksNamespace.resolve}, which explains what that costs.
12
19
  */
13
20
  import { Resource } from "../http";
14
- import { type BaseRecord, type Id, type JsonObject, type PageParams, type Paginated, type RequestOptions, type Timestamp } from "../types";
21
+ import type { ListParams } from "../listing";
22
+ import { type BaseRecord, type Id, type Json, type Paginated, type RequestOptions, type Timestamp } from "../types";
15
23
  /** Public host that fronts `short_links#follow`. See {@link ShortLinksNamespace.shortUrl}. */
16
24
  export declare const SHORT_LINK_BASE_URL = "https://omelhor.site";
17
25
  /**
@@ -33,11 +41,39 @@ export interface ShortLinkClick {
33
41
  /** Browser or app name parsed from the user agent, or `null`. */
34
42
  readonly device_name: string | null;
35
43
  }
44
+ /**
45
+ * The owner of a link, rendered inline by `UserBlueprint`'s default view.
46
+ *
47
+ * Only the keys that view declares unconditionally are named. `UserBlueprint`
48
+ * also renders `group`, `email`, `gender`, `last_seen_at`, `sessions_count`,
49
+ * `deactivated_at`, `allowed_to_use_spotify` and `share_listening` behind `if:`
50
+ * predicates that test who is ASKING, so whether they appear depends on the
51
+ * caller's own privileges rather than on the record. That is why they are
52
+ * reached through the index signature instead of being declared here as
53
+ * optionals: an optional would suggest the server decides, and it does not.
54
+ */
55
+ export interface ShortLinkOwner {
56
+ readonly id: Id;
57
+ readonly handle: string;
58
+ readonly name: string;
59
+ readonly bio: string | null;
60
+ readonly country_code: string;
61
+ readonly created_at: Timestamp;
62
+ readonly updated_at: Timestamp;
63
+ readonly [key: string]: Json | undefined;
64
+ }
36
65
  /**
37
66
  * A short link.
38
67
  *
39
68
  * `Omit<BaseRecord, "id">` rather than a plain `extends BaseRecord`: see
40
69
  * {@link ShortLinkId} for why the identifier is a number on this one table.
70
+ *
71
+ * Every key below is present on every response this namespace can produce.
72
+ * `ShortLinkBlueprint` does declare a second, narrower `:admin` view - it drops
73
+ * `updated_at`, both associations, and adds `owner`, `click_count` and
74
+ * `last_click_at` - but that view is only ever rendered by the admin
75
+ * shortlinks tool under `/admin/short_links`, which is not this resource. A
76
+ * record that arrived here has the full default shape.
41
77
  */
42
78
  export interface ShortLink extends Omit<BaseRecord, "id"> {
43
79
  /** Integer primary key. See {@link ShortLinkId}. */
@@ -52,6 +88,9 @@ export interface ShortLink extends Omit<BaseRecord, "id"> {
52
88
  * shares), `"qr"` (dynamic QR), `"f"` (forms) and `"t"` (link trees). That
53
89
  * is why {@link ShortLink} and `DynamicQr` are separate resources even
54
90
  * though both are rows in the same table.
91
+ *
92
+ * A link that reached you through {@link ShortLinksNamespace.list} always
93
+ * holds `null` or `""`, because the listing scope is `user_managed`.
55
94
  */
56
95
  readonly namespace: string | null;
57
96
  /** Owner, or `null` for a link created anonymously. */
@@ -61,10 +100,13 @@ export interface ShortLink extends Omit<BaseRecord, "id"> {
61
100
  * page. A link with 50 000 visits sends 50 000 objects here. Use
62
101
  * {@link ShortLinksNamespace.stats} for anything analytical and treat this
63
102
  * field as a payload hazard, not as a feature.
103
+ *
104
+ * Always present, and `[]` rather than `null` for a link nobody has clicked:
105
+ * a Blueprinter association over an empty `has_many` renders an empty array.
64
106
  */
65
- readonly short_link_clicks?: ShortLinkClick[];
66
- /** The owner rendered inline (the same shape `oms.account` returns), or `null`. */
67
- readonly user?: JsonObject | null;
107
+ readonly short_link_clicks: ShortLinkClick[];
108
+ /** The owner rendered inline, or `null` for a link created anonymously. */
109
+ readonly user: ShortLinkOwner | null;
68
110
  }
69
111
  /** One day of the click histogram. */
70
112
  export interface ShortLinkDailyClicks {
@@ -128,8 +170,10 @@ export interface UpdateShortLinkInput {
128
170
  readonly url?: string;
129
171
  readonly endpoint?: string;
130
172
  }
173
+ /** Filter columns of `GET /short_links`, on top of {@link BASE_FILTER_COLUMNS}. */
174
+ export declare const SHORT_LINK_FILTER_COLUMNS: readonly ["user_id"];
131
175
  /** Filters for {@link ShortLinksNamespace.list}. */
132
- export interface ListShortLinksParams extends PageParams {
176
+ export interface ListShortLinksParams extends ListParams<(typeof SHORT_LINK_FILTER_COLUMNS)[number]> {
133
177
  /**
134
178
  * Narrow to one owner, sent as `exact_search[user_id]`.
135
179
  *
@@ -0,0 +1,458 @@
1
+ /** Group chats: the chat, its roster and its messages, as `oms.social.groupChats`. */
2
+ import { Resource } from "../../http";
3
+ import type { BaseRecord, FileInput, Id, NativeFile, RequestOptions, Timestamp } from "../../types";
4
+ import type { AttachmentKind } from "./types";
5
+ /**
6
+ * Primary key of a group chat. A STRING - `group_chats` is an `id: :string`
7
+ * table, unlike `messages` and `relationships`.
8
+ */
9
+ export type GroupChatId = string;
10
+ /** Primary key of a membership row. A string. */
11
+ export type GroupChatMemberId = string;
12
+ /** Primary key of a group chat message. A string. */
13
+ export type GroupChatMessageId = string;
14
+ /** `GroupChatMessage` allows four thousand, not one thousand. */
15
+ export declare const GROUP_CHAT_MESSAGE_CONTENT_MAX_LENGTH = 4000;
16
+ /** Length cap of a group chat's name. */
17
+ export declare const GROUP_CHAT_NAME_MAX_LENGTH = 120;
18
+ /**
19
+ * Rows `GET /group_chats/:id/messages` returns per call.
20
+ *
21
+ * A hard constant, not a modifier: this endpoint does not speak the list DSL
22
+ * and `modifiers[page]` on it is ignored.
23
+ */
24
+ export declare const GROUP_CHAT_MESSAGE_PAGE_SIZE = 100;
25
+ /** Newest message in a chat, as the chat record summarises it. */
26
+ export interface GroupChatLastMessage {
27
+ readonly id: GroupChatMessageId;
28
+ readonly sender_id: Id | null;
29
+ readonly preview: string;
30
+ readonly attachment_kind: AttachmentKind | null;
31
+ readonly created_at: Timestamp;
32
+ }
33
+ /** One membership row, as the `:extended` chat view embeds it. */
34
+ export interface GroupChatMember {
35
+ readonly id: GroupChatMemberId;
36
+ readonly user_id: Id;
37
+ readonly user_handle: string | null;
38
+ readonly user_name: string | null;
39
+ readonly role: GroupChatRole;
40
+ readonly joined_at: Timestamp;
41
+ }
42
+ /**
43
+ * A group chat, as the index renders it.
44
+ *
45
+ * Extends {@link BaseRecord}, which the integer-keyed direct message and
46
+ * relationship records cannot: `group_chats` is an `id: :string` table, so its
47
+ * key is the same opaque string every other resource in the SDK uses.
48
+ */
49
+ export interface GroupChat extends BaseRecord {
50
+ readonly id: GroupChatId;
51
+ readonly name: string | null;
52
+ readonly kind: "ad_hoc";
53
+ readonly system_managed: boolean;
54
+ readonly context_type: string | null;
55
+ readonly context_id: string | null;
56
+ readonly last_message: GroupChatLastMessage | null;
57
+ }
58
+ /** The `:extended` view: {@link GroupChat} plus the roster. */
59
+ export interface GroupChatDetail extends GroupChat {
60
+ readonly members: GroupChatMember[];
61
+ }
62
+ /** A message inside a group chat. */
63
+ export interface GroupChatMessage extends BaseRecord {
64
+ readonly id: GroupChatMessageId;
65
+ readonly group_chat_id: GroupChatId;
66
+ /** Null on a system message. */
67
+ readonly sender_id: Id | null;
68
+ readonly sender_handle: string | null;
69
+ readonly sender_name: string | null;
70
+ readonly content: string | null;
71
+ readonly attachment_kind: AttachmentKind | null;
72
+ readonly has_attachment: boolean;
73
+ readonly system_kind: string | null;
74
+ readonly system_payload: Record<string, unknown>;
75
+ readonly edited_at: Timestamp | null;
76
+ readonly attachment_filename?: string;
77
+ readonly attachment_byte_size?: number;
78
+ readonly attachment_content_type?: string;
79
+ }
80
+ /** Membership role. */
81
+ export type GroupChatRole = "member" | "admin";
82
+ /** Body of {@link GroupChatsNamespace.create}. */
83
+ export interface CreateGroupChatInput {
84
+ /**
85
+ * Required, up to {@link GROUP_CHAT_NAME_MAX_LENGTH}. Blank, whitespace-only
86
+ * and the null sentinel are all rejected with `400 "Name is required"`.
87
+ */
88
+ readonly name: string;
89
+ /**
90
+ * Everyone else to put in the chat, by user id.
91
+ *
92
+ * De-duplicated, stripped of blanks, and the caller's own id is removed - the
93
+ * creator is added separately, as the chat's `admin`. Ids that do not name a
94
+ * real user are DROPPED IN SILENCE: the call still answers `201`, and the
95
+ * only way to know a member is missing is to count `members` on the answer.
96
+ *
97
+ * There is no friendship check and no invitation step. Anyone can be put into
98
+ * a chat by anyone, and finds out by seeing it in their listing.
99
+ */
100
+ readonly memberIds?: readonly Id[];
101
+ }
102
+ /** Body of {@link GroupChatMessagesNamespace.send}. */
103
+ export interface SendGroupChatMessageInput {
104
+ /**
105
+ * Up to {@link GROUP_CHAT_MESSAGE_CONTENT_MAX_LENGTH} - four thousand
106
+ * characters here, against one thousand for a direct message.
107
+ *
108
+ * Optional when `attachment` is present, and genuinely optional: unlike
109
+ * {@link SendMessageInput.content}, nothing substitutes a placeholder, so an
110
+ * attachment-only message comes back with `content: null`.
111
+ */
112
+ readonly content?: string;
113
+ /**
114
+ * One file, up to {@link MESSAGE_ATTACHMENT_MAX_BYTES}.
115
+ *
116
+ * Stored byte for byte. There is no webp recompression here and no
117
+ * pixel-bomb check either, which is the opposite of what
118
+ * {@link DirectMessagesNamespace.send} does with an image, so the 20 MiB
119
+ * image ceiling does NOT apply and `attachment_content_type` on the answer is
120
+ * whatever you uploaded.
121
+ */
122
+ readonly attachment?: FileInput | NativeFile;
123
+ }
124
+ /** Cursor for {@link GroupChatMessagesNamespace.list}. */
125
+ export interface ListGroupChatMessagesParams {
126
+ /**
127
+ * Return messages created strictly AFTER this one. Sent as `after_id`.
128
+ *
129
+ * Read {@link GroupChatMessagesNamespace.list} before using it: this cursor
130
+ * fails open, and the failure looks like a working request.
131
+ */
132
+ readonly afterId?: GroupChatMessageId;
133
+ }
134
+ /**
135
+ * Many-to-many chats, reachable as `oms.social.groupChats`.
136
+ *
137
+ * ## THERE IS NO REALTIME HERE AT ALL
138
+ *
139
+ * Direct messages at least push a `message_received` notification over the
140
+ * cable. Group chats push NOTHING: no channel streams them, no `Notification`
141
+ * row is written when a message lands, and the only thing a new group message
142
+ * triggers server-side is a Discord alert for the operators. A group chat UI
143
+ * has to poll {@link GroupChatMessagesNamespace.list} with an `after_id`
144
+ * cursor, and there is no endpoint that will tell it which chats changed
145
+ * without listing them.
146
+ *
147
+ * The cheapest honest loop is {@link GroupChatsNamespace.list} on a slow timer
148
+ * for the chat list (it carries `last_message` per chat, so one request covers
149
+ * every conversation) and
150
+ * {@link GroupChatMessagesNamespace.list} with `afterId` on a fast timer for
151
+ * the chat that is open. Both are on the general 600/min ceiling shared with
152
+ * the rest of the app.
153
+ *
154
+ * ## Every id in this family is a STRING
155
+ *
156
+ * Unlike {@link DirectMessage} and {@link Relationship}.
157
+ *
158
+ * ## Only one `kind` exists
159
+ *
160
+ * `kind` is always `"ad_hoc"`. `system_managed`, `context_type` and
161
+ * `context_id` are there for a future subsystem; nothing writes them today.
162
+ *
163
+ * ## Errors here have a different SHAPE from the rest of the API
164
+ *
165
+ * A `404` or a `401` from these routes carries the JSON body `null` rather
166
+ * than the bare error string the rest of the API sends. Branch on the status,
167
+ * not on the body.
168
+ */
169
+ export declare class GroupChatsNamespace extends Resource {
170
+ /** Messages inside a chat. */
171
+ readonly messages: GroupChatMessagesNamespace;
172
+ constructor(http: ConstructorParameters<typeof Resource>[0]);
173
+ /**
174
+ * `GET /group_chats` - every chat the caller is a member of, most recently
175
+ * touched first.
176
+ *
177
+ * Returns a bare array and not a {@link Paginated}, because the endpoint
178
+ * genuinely has no paging: `modifiers[page]`, `search[...]` and the `ETag`
179
+ * are all absent and the whole list comes back on every call. That is fine
180
+ * while a user has tens of chats and is a cliff if one ever has thousands.
181
+ *
182
+ * `updated_at` is the sort key and it is touched by a new message, by a
183
+ * rename, and by nothing else - a deleted message does not move a chat back
184
+ * down the list.
185
+ *
186
+ * Each chat carries a `last_message` summary, computed for the whole page in
187
+ * one window-function query. That summary is what makes this endpoint usable
188
+ * as a poll for "did anything change anywhere": compare `last_message.id`
189
+ * per chat instead of listing every conversation.
190
+ *
191
+ * Members are NOT included. Use {@link get} for the roster.
192
+ *
193
+ * A site administrator sees every chat on the instance here, not just their
194
+ * own.
195
+ */
196
+ list(options?: RequestOptions): Promise<GroupChat[]>;
197
+ /**
198
+ * `GET /group_chats/:id` - one chat with its member roster.
199
+ *
200
+ * The `:extended` view, which is everything {@link list} returns PLUS
201
+ * `members`. Each member row carries `user_handle` and `user_name`
202
+ * denormalised, so rendering a roster needs no further requests.
203
+ *
204
+ * Not a member? `404 "Resource not found"` - the id is not distinguishable
205
+ * from one that does not exist, which is the right answer.
206
+ *
207
+ * Note that this is one of the few places in this namespace whose 404 body
208
+ * is the usual string rather than `null`.
209
+ */
210
+ get(id: GroupChatId, options?: RequestOptions): Promise<GroupChatDetail>;
211
+ /**
212
+ * `POST /group_chats` - creates a chat and its roster in one transaction.
213
+ * `201` with the `:extended` view.
214
+ *
215
+ * The caller becomes the chat's `admin`; everyone in
216
+ * {@link CreateGroupChatInput.memberIds} becomes a `member`. There is no way
217
+ * to create a chat you are not in, and no way to hand out a second admin
218
+ * afterwards - `role` is not writable through any route in this namespace, so
219
+ * the creator is the only administrator the chat will ever have. If they
220
+ * leave, the chat keeps working for everybody but can never be renamed and
221
+ * can never take another member.
222
+ *
223
+ * Not retried: a replay after a lost response creates a second chat.
224
+ *
225
+ * @throws {OmsError} `invalid_request` when the name is blank here.
226
+ * @throws {OmsApiError} `400 "Name is required"` when the server judges it
227
+ * blank.
228
+ */
229
+ create(input: CreateGroupChatInput, options?: RequestOptions): Promise<GroupChatDetail>;
230
+ /**
231
+ * `PATCH /group_chats/:id` - renames the chat. `200` with the `:extended`
232
+ * view.
233
+ *
234
+ * The name is the ONLY writable field: `kind`, `system_managed` and the
235
+ * context pair are ignored if sent.
236
+ *
237
+ * Passing `null` clears the name, and so does passing `""` or any
238
+ * whitespace-only string - all three collapse to `null`, so there is no way
239
+ * to set a blank name and no error telling you it was dropped. A nameless
240
+ * chat is legal and every client has to fall back to listing the members.
241
+ *
242
+ * Restricted to the chat's admin (its creator) or a site administrator.
243
+ * Anyone else gets `401` with a `null` body.
244
+ */
245
+ rename(id: GroupChatId, name: string | null, options?: RequestOptions): Promise<GroupChatDetail>;
246
+ /**
247
+ * `POST /group_chats/:id/members` - adds one user. `200` (NOT `201`) with the
248
+ * `:extended` view.
249
+ *
250
+ * Idempotent by design: a user who is already a member is not re-added and
251
+ * the current chat comes back unchanged, so this is safe to retry and safe to
252
+ * call from a UI that is not sure of its own state.
253
+ *
254
+ * Admin-only, and the new member joins as a plain `member` - there is no way
255
+ * to promote anyone.
256
+ *
257
+ * A `user_id` that names nobody is `400 "user_id is required"`, which is the
258
+ * same message an absent `user_id` gets and is therefore not a useful
259
+ * diagnostic.
260
+ */
261
+ addMember(id: GroupChatId, userId: Id, options?: RequestOptions): Promise<GroupChatDetail>;
262
+ /**
263
+ * `DELETE /group_chats/:id/members/:user_id` - `204`, empty body.
264
+ *
265
+ * Two callers are allowed and they mean different things: the chat's admin
266
+ * removing somebody, and any member removing THEMSELVES, which is how you
267
+ * leave. {@link leave} is the same call under a name that says so.
268
+ *
269
+ * ## Removing the last member DESTROYS THE CHAT
270
+ *
271
+ * A chat whose roster is empty after the removal is destroyed on the spot,
272
+ * messages included. So the last person to leave takes the entire history
273
+ * with them, for everyone, with no confirmation and no way back. There is no
274
+ * `DELETE /group_chats/:id` - emptying the roster is the only way a chat is
275
+ * ever deleted, and it is easy to trigger by accident on a two-person chat.
276
+ *
277
+ * ## An admin can strand a chat
278
+ *
279
+ * The admin leaving is permitted and promotes nobody. The chat survives with
280
+ * members and no administrator: nobody can rename it and nobody can add
281
+ * anyone ever again. Warn before letting the creator leave a chat that still
282
+ * has people in it.
283
+ *
284
+ * Removing someone who is not a member is a `204` with no effect, not a 404.
285
+ */
286
+ removeMember(id: GroupChatId, userId: Id, options?: RequestOptions): Promise<void>;
287
+ /**
288
+ * Leaves a chat: {@link removeMember} with the caller's own id.
289
+ *
290
+ * `selfId` is passed rather than looked up, for the same reason
291
+ * {@link RelationshipsNamespace.friends} takes one - the SDK will not spend a
292
+ * session round trip on every call to learn who it is.
293
+ *
294
+ * If you are the last member this DESTROYS the chat and every message in it.
295
+ * If you are the admin it leaves the chat permanently unadministered. Both
296
+ * are described on {@link removeMember} and both are worth a confirmation
297
+ * dialog.
298
+ */
299
+ leave(id: GroupChatId, selfId: Id, options?: RequestOptions): Promise<void>;
300
+ }
301
+ /**
302
+ * Messages inside a group chat, reachable as
303
+ * `oms.social.groupChats.messages`.
304
+ *
305
+ * Every route is nested under the chat, and every one of them resolves the
306
+ * chat first: a caller who is not a member gets `404` on the CHAT before the
307
+ * message id is even looked at, so there is no way to probe for message ids.
308
+ */
309
+ export declare class GroupChatMessagesNamespace extends Resource {
310
+ /**
311
+ * `GET /group_chats/:id/messages` - up to
312
+ * {@link GROUP_CHAT_MESSAGE_PAGE_SIZE} messages, OLDEST FIRST.
313
+ *
314
+ * This endpoint does not speak the list DSL. No `search`, no `exact_search`,
315
+ * no `modifiers`, no `ETag`; the page size is a constant and
316
+ * `modifiers[page]` is ignored rather than rejected. The only knob is
317
+ * `after_id`, and it has two sharp edges.
318
+ *
319
+ * ## `afterId` FAILS OPEN
320
+ *
321
+ * The server looks the anchor up in the chat and applies the filter only
322
+ * when it finds one. An id it cannot find - a message that was deleted, an
323
+ * id from a different chat, a typo - does not produce an error. The cursor
324
+ * is silently DROPPED and you get the first 100 messages of the chat from
325
+ * the very beginning.
326
+ *
327
+ * A client that pages by remembering the last id it saw, and whose last id
328
+ * gets deleted, therefore restarts at the top and appends the same 100
329
+ * messages forever. Guard it: if the first row you get back is one you have
330
+ * already seen, your cursor is gone, not your data.
331
+ *
332
+ * ## `afterId` SKIPS TIES
333
+ *
334
+ * The filter is `created_at > anchor.created_at`, on the timestamp alone
335
+ * rather than on `(created_at, id)`. Two messages written in the same
336
+ * microsecond - which is how a burst of system messages arrives - and
337
+ * anchoring on the first one drops the second permanently from a forward
338
+ * walk.
339
+ *
340
+ * ## THERE IS NO BACKWARD CURSOR
341
+ *
342
+ * `before_id` does not exist. The only entry point into a chat's history is
343
+ * its beginning, and the only direction is forward. Opening a 5000-message
344
+ * chat at the newest message costs 50 sequential requests, and there is no
345
+ * way to fetch the tail directly. For the common "what is new" case, keep the
346
+ * newest id you have seen and poll with it; for a first open, either walk
347
+ * with {@link all} or accept that you are showing the top of the chat.
348
+ *
349
+ * System messages (`system_kind` set, `sender_id` null) are in the same
350
+ * stream and are meant to render as centred pills rather than as messages.
351
+ * {@link isSystemMessage} tests for them.
352
+ */
353
+ list(chatId: GroupChatId, params?: ListGroupChatMessagesParams, options?: RequestOptions): Promise<GroupChatMessage[]>;
354
+ /**
355
+ * Walks a chat's history forward from the beginning and returns it in one
356
+ * array, oldest first.
357
+ *
358
+ * One request per {@link GROUP_CHAT_MESSAGE_PAGE_SIZE} messages, which is the
359
+ * only shape the endpoint allows. `limit` caps the walk at 1000 messages (ten
360
+ * requests) by default so a long chat cannot quietly spend a large share of
361
+ * the 600/min ceiling; raise it deliberately.
362
+ *
363
+ * Stops early on a short page, and also stops if the server hands back a page
364
+ * whose first row it has already seen - that is the fail-open cursor
365
+ * described on {@link list}, and continuing would loop forever.
366
+ */
367
+ all(chatId: GroupChatId, limit?: number, options?: RequestOptions): Promise<GroupChatMessage[]>;
368
+ /**
369
+ * `POST /group_chats/:id/messages` - sends one message. `201` with the
370
+ * record.
371
+ *
372
+ * Content, an attachment, or both; a message with neither is `400 "Message
373
+ * must have content or an attachment"`. The sender is always the
374
+ * authenticated user, and non-members never get this far - the chat lookup
375
+ * answers `404` first.
376
+ *
377
+ * Sending TOUCHES the chat, which is what moves it to the top of
378
+ * {@link GroupChatsNamespace.list}. Nothing else in this namespace does, so a
379
+ * chat whose only recent activity was a rename or a deletion sorts by its own
380
+ * `updated_at` rather than by its newest message.
381
+ *
382
+ * Sent as JSON with no attachment and as `multipart/form-data` with one.
383
+ *
384
+ * Nobody is notified. See the {@link GroupChatsNamespace} docs: there is no
385
+ * cable channel, no notification row, and no push for group chat messages, so
386
+ * the only way anyone learns about this is by polling.
387
+ *
388
+ * Not retried: a replay after a lost response posts the message twice.
389
+ *
390
+ * @throws {OmsError} `invalid_request` when neither content nor attachment is
391
+ * given, or content is over the cap.
392
+ */
393
+ send(chatId: GroupChatId, input: SendGroupChatMessageInput, options?: RequestOptions): Promise<GroupChatMessage>;
394
+ /**
395
+ * `PATCH /group_chats/:id/messages/:id` - rewrites the content. `200`.
396
+ *
397
+ * Content only, and it must be non-blank: an empty edit is `400 "Content
398
+ * required"` rather than a way to clear the text. An attachment cannot be
399
+ * changed or removed.
400
+ *
401
+ * Allowed for the sender within {@link MESSAGE_EDIT_WINDOW_MS} of
402
+ * `created_at`, and for a site administrator with no window at all. A system
403
+ * message is never editable by anybody. Past the window: `401`.
404
+ *
405
+ * `edited_at` is stamped only when the content actually differs, so
406
+ * re-sending the same string is a genuine no-op rather than a way to mark a
407
+ * message edited.
408
+ *
409
+ * Does NOT touch the chat, so an edit does not reorder
410
+ * {@link GroupChatsNamespace.list}.
411
+ */
412
+ edit(chatId: GroupChatId, messageId: GroupChatMessageId, content: string, options?: RequestOptions): Promise<GroupChatMessage>;
413
+ /**
414
+ * `DELETE /group_chats/:id/messages/:id` - `204`, empty body.
415
+ *
416
+ * The sender may delete at ANY time - unlike editing, destroying has no
417
+ * fifteen-minute window - and so may a site administrator. A system message
418
+ * cannot be deleted by anyone. The row and its blob go for everybody.
419
+ *
420
+ * Deleting does not touch the chat, so {@link GroupChatsNamespace.list} keeps
421
+ * its old ordering, and it invalidates any `afterId` cursor pointing at the
422
+ * deleted message: the next {@link list} call with that cursor silently
423
+ * restarts at the top of the chat. See {@link list}.
424
+ */
425
+ delete(chatId: GroupChatId, messageId: GroupChatMessageId, options?: RequestOptions): Promise<void>;
426
+ /**
427
+ * `GET /group_chats/:id/messages/:id/attachment` - the bytes of the attached
428
+ * file.
429
+ *
430
+ * A `302` to a presigned object-store URL, which `fetch` follows on its own
431
+ * everywhere except a browser in cookie mode; see
432
+ * {@link DirectMessagesNamespace.attachment} for why, and use
433
+ * {@link attachmentUrl} there.
434
+ *
435
+ * Filename, byte size and content type are on the {@link GroupChatMessage}
436
+ * itself - but only when it HAS an attachment: those three fields are ABSENT
437
+ * rather than `null` on a message without one. Test `has_attachment`, not
438
+ * `attachment_filename !== null`.
439
+ *
440
+ * @throws {OmsError} `unsupported` when the redirect was blocked by CORS.
441
+ * @throws {OmsApiError} `404` with a `null` body when the chat is not the
442
+ * caller's or the message is not in it; `404 "No attachment"` when it
443
+ * carries none.
444
+ */
445
+ attachment(chatId: GroupChatId, messageId: GroupChatMessageId, options?: RequestOptions): Promise<Blob>;
446
+ /**
447
+ * Absolute URL for a group chat attachment, for an `<img>`, an
448
+ * `<a download>` or a new tab.
449
+ *
450
+ * Same rules as {@link DirectMessagesNamespace.attachmentUrl}: no credential
451
+ * in cookie mode, `?token=` in token mode, and THE TOKEN-MODE URL IS A LIVE
452
+ * CREDENTIAL - build it at the moment of use and never store, log or share
453
+ * it.
454
+ */
455
+ attachmentUrl(chatId: GroupChatId, messageId: GroupChatMessageId): Promise<string>;
456
+ }
457
+ /** A system message: rendered as a centred pill, never editable or deletable. */
458
+ export declare function isSystemMessage(message: GroupChatMessage): boolean;
@@ -0,0 +1,19 @@
1
+ /** The `social` namespace: direct messages, relationships and group chats, reachable as `oms.social`. */
2
+ import { Resource } from "../../http";
3
+ import { GroupChatsNamespace } from "./groupChats";
4
+ import { DirectMessagesNamespace } from "./messages";
5
+ import { RelationshipsNamespace } from "./relationships";
6
+ export * from "./groupChats";
7
+ export * from "./messages";
8
+ export * from "./relationships";
9
+ export * from "./types";
10
+ /** The `social` namespace, reachable as `oms.social`. */
11
+ export declare class SocialNamespace extends Resource {
12
+ /** One-to-one messages. */
13
+ readonly messages: DirectMessagesNamespace;
14
+ /** Friendships and blocks. */
15
+ readonly relationships: RelationshipsNamespace;
16
+ /** Many-to-many chats, their roster and their messages. */
17
+ readonly groupChats: GroupChatsNamespace;
18
+ constructor(http: ConstructorParameters<typeof Resource>[0]);
19
+ }