@omelhorsite/sdk 0.3.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 +113 -131
- package/dist/index.js +1049 -1246
- 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 +2 -2
- package/dist/types/internal/attachments.d.ts +17 -0
- package/dist/types/internal/helpers.d.ts +9 -0
- package/dist/types/listing.d.ts +90 -0
- 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 +19 -19
- package/dist/types/resources/admin/authorizedApplications.d.ts +133 -0
- package/dist/types/resources/admin/chests.d.ts +51 -0
- package/dist/types/resources/admin/eventAlerts.d.ts +60 -0
- package/dist/types/resources/admin/identities.d.ts +99 -0
- package/dist/types/resources/admin/index.d.ts +77 -0
- package/dist/types/resources/admin/jobs.d.ts +97 -0
- package/dist/types/resources/admin/myOauthApplications.d.ts +282 -0
- package/dist/types/resources/admin/notepads.d.ts +49 -0
- package/dist/types/resources/admin/oauthApplications.d.ts +309 -0
- package/dist/types/resources/admin/quotas.d.ts +114 -0
- package/dist/types/resources/admin/shortLinks.d.ts +201 -0
- package/dist/types/resources/admin/types.d.ts +222 -0
- package/dist/types/resources/admin/vocalSeparations.d.ts +98 -0
- package/dist/types/resources/admin.d.ts +17 -13
- 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 +116 -161
- package/dist/types/resources/chests.d.ts +27 -31
- package/dist/types/resources/content/analysis.d.ts +62 -0
- package/dist/types/resources/content/blogs.d.ts +471 -0
- package/dist/types/resources/content/feedbacks.d.ts +263 -0
- package/dist/types/resources/content/index.d.ts +52 -0
- package/dist/types/resources/content/intel/articles.d.ts +230 -0
- package/dist/types/resources/content/intel/config.d.ts +135 -0
- package/dist/types/resources/content/intel/index.d.ts +53 -0
- package/dist/types/resources/content/intel/items.d.ts +91 -0
- package/dist/types/resources/content/intel/reports.d.ts +108 -0
- package/dist/types/resources/content/intel/scripts.d.ts +152 -0
- package/dist/types/resources/content/intel/sources.d.ts +236 -0
- package/dist/types/resources/content/intel/stats.d.ts +105 -0
- package/dist/types/resources/content/intel/types.d.ts +86 -0
- package/dist/types/resources/content/jokes.d.ts +93 -0
- package/dist/types/resources/content/notifications.d.ts +147 -0
- package/dist/types/resources/content/serviceUsages.d.ts +73 -0
- package/dist/types/resources/content/servicesStatus.d.ts +194 -0
- package/dist/types/resources/content/siteConfig.d.ts +43 -0
- package/dist/types/resources/content/spaceInvaders.d.ts +154 -0
- package/dist/types/resources/content.d.ts +41 -236
- 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 +35 -44
- package/dist/types/resources/library/annotations.d.ts +162 -0
- package/dist/types/resources/library/books.d.ts +534 -0
- package/dist/types/resources/library/chat.d.ts +259 -0
- package/dist/types/resources/library/index.d.ts +39 -0
- package/dist/types/resources/library/shelves.d.ts +237 -0
- package/dist/types/resources/library/types.d.ts +120 -0
- package/dist/types/resources/library.d.ts +20 -22
- package/dist/types/resources/media.d.ts +48 -61
- package/dist/types/resources/movies/addons.d.ts +388 -0
- package/dist/types/resources/movies/collections.d.ts +352 -0
- package/dist/types/resources/movies/index.d.ts +29 -0
- package/dist/types/resources/movies/types.d.ts +50 -0
- package/dist/types/resources/movies/watchProgress.d.ts +277 -0
- package/dist/types/resources/movies.d.ts +27 -53
- package/dist/types/resources/music/artists.d.ts +182 -246
- package/dist/types/resources/music/imports.d.ts +190 -218
- package/dist/types/resources/music/index.d.ts +8 -7
- package/dist/types/resources/music/playlists.d.ts +85 -117
- package/dist/types/resources/music/social.d.ts +153 -228
- package/dist/types/resources/music/songs.d.ts +165 -227
- package/dist/types/resources/realtime.d.ts +75 -88
- package/dist/types/resources/shortLinks.d.ts +38 -47
- package/dist/types/resources/social/groupChats.d.ts +458 -0
- package/dist/types/resources/social/index.d.ts +19 -0
- package/dist/types/resources/social/messages.d.ts +424 -0
- package/dist/types/resources/social/relationships.d.ts +322 -0
- package/dist/types/resources/social/types.d.ts +37 -0
- package/dist/types/resources/social.d.ts +21 -3
- package/dist/types/resources/storage/upload.d.ts +42 -56
- package/dist/types/resources/storage.d.ts +94 -109
- package/dist/types/resources/tickets.d.ts +19 -10
- 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
|
@@ -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,
|
|
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
|
|
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
|
|
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
|
*
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The direct-upload driver.
|
|
3
3
|
*
|
|
4
|
-
* Bytes never pass through
|
|
5
|
-
* this module follows exactly:
|
|
4
|
+
* Bytes never pass through the API. The flow:
|
|
6
5
|
*
|
|
7
6
|
* 1. `POST /fs_nodes/batch_upload_urls` with a manifest of up to 100 files
|
|
8
7
|
* (`client_id`, `name`, `size`, and optionally `relative_path`,
|
|
9
8
|
* `content_type`, `checksum`). ONE request does directory resolution, one
|
|
10
|
-
* quota reservation
|
|
9
|
+
* quota reservation, node creation and plan minting.
|
|
11
10
|
* 2. Per file the server answers a {@link UploadPlan}:
|
|
12
11
|
* - `strategy: "direct"` below 32 MiB: PUT the whole body to a presigned URL
|
|
13
12
|
* with the exact headers returned, then remember `blob_signed_id`;
|
|
@@ -25,27 +24,21 @@
|
|
|
25
24
|
* self-contained implementation - see the note there.
|
|
26
25
|
* - The presigned PUTs go to the object store, NOT to the API. They must be
|
|
27
26
|
* sent with the injected fetch but WITHOUT the `Authorization` header, or
|
|
28
|
-
*
|
|
27
|
+
* the store rejects the request for having two authentication schemes.
|
|
29
28
|
*
|
|
30
29
|
* A node whose bytes never landed is adopted on the next attempt rather than
|
|
31
30
|
* failing, so a torn batch is simply retried with the same manifest.
|
|
32
31
|
*
|
|
33
|
-
* Multipart is not an optimisation.
|
|
34
|
-
*
|
|
35
|
-
* other way in.
|
|
32
|
+
* Multipart is not an optimisation. A single request to the object store is
|
|
33
|
+
* capped at roughly 100 MB, so anything larger has no other way in.
|
|
36
34
|
*
|
|
37
35
|
* ## Progress, and why it ticks per transfer rather than per byte
|
|
38
36
|
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* problem, and the SDK solves it as far as `fetch` allows and no further.
|
|
37
|
+
* `fetch` has no upload-progress event, and the two ways around it were both
|
|
38
|
+
* rejected for the core:
|
|
42
39
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* - **XHR**, which is what the web frontend's axios uses today, is the only API
|
|
47
|
-
* that reports request bytes as they leave. It does not exist in a
|
|
48
|
-
* Cloudflare-Worker-class isolate, and this package must load there.
|
|
40
|
+
* - **XHR** is the only API that reports request bytes as they leave. It does
|
|
41
|
+
* not exist in a Worker-class isolate, and this package must load there.
|
|
49
42
|
* - **A counting `ReadableStream` request body** would run in an isolate, and
|
|
50
43
|
* still does not work HERE. A stream body forces chunked transfer encoding,
|
|
51
44
|
* while a presigned PUT is signed over a fixed `Content-Length` (and, on the
|
|
@@ -82,35 +75,28 @@ import type { FsNode } from "../storage";
|
|
|
82
75
|
* import { MULTIPART_THRESHOLD } from "@omelhorsite/sdk";
|
|
83
76
|
* ```
|
|
84
77
|
*
|
|
85
|
-
* The
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
* -
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
* - here.
|
|
93
|
-
*
|
|
94
|
-
* The client-side copies exist because the CHECKSUM has to be in the manifest
|
|
95
|
-
* before the server has decided anything: below the threshold the digest is
|
|
96
|
-
* mandatory (it is Content-MD5-bound into the presigned signature), at or above
|
|
97
|
-
* it is pointless (multipart verifies per-part ETags). So the comparison is
|
|
98
|
-
* made twice, and {@link manifestEntryFor} uses `<` against exactly the
|
|
99
|
-
* server's `>=`.
|
|
78
|
+
* The server decides the strategy per file with `size >= 32 MiB` and puts it
|
|
79
|
+
* in the plan. The client-side copy exists because the CHECKSUM has to be in
|
|
80
|
+
* the manifest before the server has decided anything: below the threshold
|
|
81
|
+
* the digest is mandatory (it is Content-MD5-bound into the presigned
|
|
82
|
+
* signature), at or above it is pointless (multipart verifies per-part ETags).
|
|
83
|
+
* So the comparison is made twice, and {@link manifestEntryFor} uses `<`
|
|
84
|
+
* against exactly the server's `>=`.
|
|
100
85
|
*
|
|
101
86
|
* Drift is expensive and silent in one direction: a client that thinks the
|
|
102
87
|
* threshold is HIGHER than the server's omits the checksum on a file the server
|
|
103
|
-
* still plans as direct, and the upload dies at
|
|
104
|
-
* that never mentions checksums. That is the whole reason this
|
|
88
|
+
* still plans as direct, and the upload dies at the object store with a
|
|
89
|
+
* signature error that never mentions checksums. That is the whole reason this
|
|
90
|
+
* is exported.
|
|
105
91
|
*/
|
|
106
92
|
export declare const MULTIPART_THRESHOLD: number;
|
|
107
93
|
/**
|
|
108
|
-
* Part size for the multipart path.
|
|
94
|
+
* Part size for the multipart path. The server's default, but only a
|
|
109
95
|
* fallback: the real part size is whatever `multipart/start` answered, and that
|
|
110
96
|
* is the number the driver slices with.
|
|
111
97
|
*/
|
|
112
98
|
export declare const MULTIPART_PART_SIZE: number;
|
|
113
|
-
/** Maximum files in one `batch_upload_urls` call.
|
|
99
|
+
/** Maximum files in one `batch_upload_urls` call. Server limit. */
|
|
114
100
|
export declare const MAX_BATCH = 100;
|
|
115
101
|
/**
|
|
116
102
|
* Files sent in one `batch_upload_urls` call by default.
|
|
@@ -120,25 +106,25 @@ export declare const MAX_BATCH = 100;
|
|
|
120
106
|
* run leaves reserved-but-unused bytes behind.
|
|
121
107
|
*/
|
|
122
108
|
export declare const DEFAULT_BATCH_SIZE = 50;
|
|
123
|
-
/** Maximum part URLs requested in one call.
|
|
109
|
+
/** Maximum part URLs requested in one call. Server limit. */
|
|
124
110
|
export declare const MAX_PART_URLS = 100;
|
|
125
|
-
/** Parts one multipart upload may have.
|
|
111
|
+
/** Parts one multipart upload may have. Server limit. */
|
|
126
112
|
export declare const MAX_PARTS = 10000;
|
|
127
113
|
/** Part URLs asked for in one round trip. Below {@link MAX_PART_URLS} on purpose. */
|
|
128
114
|
export declare const PART_URL_WINDOW = 32;
|
|
129
|
-
/** Parallel presigned PUTs in flight by default.
|
|
115
|
+
/** Parallel presigned PUTs in flight by default. Keep it modest. */
|
|
130
116
|
export declare const DEFAULT_UPLOAD_CONCURRENCY = 4;
|
|
131
117
|
/**
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
118
|
+
* `batch_upload_urls`, `batch_attach_blobs` and every `multipart/*` call
|
|
119
|
+
* share 300 requests a minute, keyed by session. {@link UploadManager} paces
|
|
120
|
+
* itself against this so a large run degrades into waiting rather than into a
|
|
121
|
+
* wall of 429s.
|
|
136
122
|
*/
|
|
137
123
|
export declare const FS_UPLOAD_RATE_LIMIT = 300;
|
|
138
124
|
/**
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
125
|
+
* `copy`, `create_directories`, `empty_trash` and `move_to_trash` share
|
|
126
|
+
* TWELVE requests a minute. It is the tightest limit in the API and the
|
|
127
|
+
* easiest one to trip by looping.
|
|
142
128
|
*/
|
|
143
129
|
export declare const FS_BULK_JOB_RATE_LIMIT = 12;
|
|
144
130
|
/** One entry of the manifest sent to `batch_upload_urls`. */
|
|
@@ -247,7 +233,7 @@ export interface UploadInput {
|
|
|
247
233
|
* folder upload costs no extra round trips. A `..` segment is a 400.
|
|
248
234
|
*/
|
|
249
235
|
readonly relativePaths?: string[];
|
|
250
|
-
/** Parallel PUTs in flight. Keep it modest
|
|
236
|
+
/** Parallel PUTs in flight. Keep it modest. */
|
|
251
237
|
readonly concurrency?: number;
|
|
252
238
|
/** Files per `batch_upload_urls` call. Clamped to {@link MAX_BATCH}. */
|
|
253
239
|
readonly batchSize?: number;
|
|
@@ -338,7 +324,7 @@ export interface UploadManagerOptions {
|
|
|
338
324
|
*
|
|
339
325
|
* Two things the wrapper MUST get right, both of which the SDK's own
|
|
340
326
|
* transport already does. It must not add an `Authorization` header or a
|
|
341
|
-
* cookie: the presigned signature is the credential and
|
|
327
|
+
* cookie: the presigned signature is the credential and the store rejects a
|
|
342
328
|
* request carrying two authentication schemes. And it must expose `ETag` on
|
|
343
329
|
* the `Response` it builds, or the multipart tier has nothing to complete
|
|
344
330
|
* with - in a browser that additionally needs `ETag` in the bucket's
|
|
@@ -356,7 +342,7 @@ export interface UploadManagerOptions {
|
|
|
356
342
|
* steps, for instance to resume a torn multipart.
|
|
357
343
|
*/
|
|
358
344
|
export declare class UploadManager extends Resource {
|
|
359
|
-
/** Paces every control-plane call against the
|
|
345
|
+
/** Paces every control-plane call against the 300-a-minute upload limit. */
|
|
360
346
|
readonly gate: StorageRateGate;
|
|
361
347
|
private readonly transport;
|
|
362
348
|
private readonly md5;
|
|
@@ -402,9 +388,9 @@ export declare class UploadManager extends Resource {
|
|
|
402
388
|
* progress accounting drives `createBatch` -> {@link putDirect} /
|
|
403
389
|
* {@link uploadMultipart} -> {@link attachBlobs} itself, and this is where it
|
|
404
390
|
* learns the per-file strategy and the byte counts it will be reporting
|
|
405
|
-
* against. Whatever it does, it must pace itself against
|
|
406
|
-
*
|
|
407
|
-
*
|
|
391
|
+
* against. Whatever it does, it must pace itself against the 300 requests a
|
|
392
|
+
* minute shared by every call in this class - {@link gate} is exposed for
|
|
393
|
+
* exactly that.
|
|
408
394
|
*
|
|
409
395
|
* @throws {OmsApiError} 400 on a structural problem, 404 when the parent is
|
|
410
396
|
* not a directory the caller may write to.
|
|
@@ -417,8 +403,8 @@ export declare class UploadManager extends Resource {
|
|
|
417
403
|
* PUTs one whole body to a presigned URL.
|
|
418
404
|
*
|
|
419
405
|
* Sends the plan's headers verbatim and NO `Authorization`: this request goes
|
|
420
|
-
* to the object store, not to the API
|
|
421
|
-
* both a presigned signature and a bearer header.
|
|
406
|
+
* to the object store, not to the API, and the store refuses a request that
|
|
407
|
+
* carries both a presigned signature and a bearer header.
|
|
422
408
|
*
|
|
423
409
|
* Retries a network fault or a 5xx from the store. A 4xx is never retried: an
|
|
424
410
|
* expired signature or a checksum mismatch is deterministic and a retry only
|
|
@@ -450,7 +436,7 @@ export declare class UploadManager extends Resource {
|
|
|
450
436
|
* with per-item results even when every item failed: read `attached` on each
|
|
451
437
|
* one, and never infer success from the status. A caller driving the flow by
|
|
452
438
|
* hand must not skip this - a node with no blob is invisible in listings and
|
|
453
|
-
* is eventually swept by
|
|
439
|
+
* is eventually swept by the server.
|
|
454
440
|
*/
|
|
455
441
|
attachBlobs(attachments: Array<{
|
|
456
442
|
fs_node_id: Id;
|
|
@@ -504,7 +490,7 @@ export declare class UploadManager extends Resource {
|
|
|
504
490
|
* parts, PUT them in parallel, complete.
|
|
505
491
|
*
|
|
506
492
|
* Parts are sliced with the size the SERVER reported, never with
|
|
507
|
-
* {@link MULTIPART_PART_SIZE}, so a change
|
|
493
|
+
* {@link MULTIPART_PART_SIZE}, so a server-side change does not silently
|
|
508
494
|
* corrupt an upload here.
|
|
509
495
|
*
|
|
510
496
|
* Phases 2 and 3 at once for a file at or above {@link MULTIPART_THRESHOLD}:
|
|
@@ -562,7 +548,7 @@ export declare class UploadManager extends Resource {
|
|
|
562
548
|
/**
|
|
563
549
|
* Base64 MD5 of a blob, in the exact form `Content-MD5` wants.
|
|
564
550
|
*
|
|
565
|
-
* The algorithm is not negotiable: the
|
|
551
|
+
* The algorithm is not negotiable: the server binds this digest into the
|
|
566
552
|
* presigned PUT signature as `Content-MD5`, so anything else makes the object
|
|
567
553
|
* store reject the upload with a signature error that never mentions checksums.
|
|
568
554
|
*
|