@openmarket/rooms-client 0.6.0 → 0.7.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/dist/agent/armed-mode.js +7 -3
- package/dist/agent/clients/common.d.ts +5 -0
- package/dist/agent/topic-inbox.d.ts +6 -0
- package/dist/agent/topic-inbox.js +20 -5
- package/dist/shared/rooms-protocol.d.ts +82 -0
- package/dist/social-client.d.ts +188 -5
- package/dist/social-client.js +346 -5
- package/dist/social-types.d.ts +164 -1
- package/dist/types.d.ts +1 -1
- package/package.json +1 -1
- package/src/agent/armed-mode.ts +7 -3
- package/src/agent/clients/common.ts +5 -0
- package/src/agent/topic-inbox.ts +23 -5
- package/src/shared/rooms-protocol.ts +85 -0
- package/src/social-client.ts +587 -6
- package/src/social-types.ts +175 -1
- package/src/types.ts +3 -0
package/dist/agent/armed-mode.js
CHANGED
|
@@ -132,7 +132,9 @@ export function isTriggeringEntry(entry, ownHandle, ownUserId, ownSeqs) {
|
|
|
132
132
|
return false;
|
|
133
133
|
if (isWebhookEntry(entry))
|
|
134
134
|
return false;
|
|
135
|
-
|
|
135
|
+
// A poll is substantive content even with no caption, and a captionless
|
|
136
|
+
// poll REPLY is addressed at us like any other reply.
|
|
137
|
+
if (!entry.text?.trim() && entry.poll == null)
|
|
136
138
|
return false;
|
|
137
139
|
// Never trigger on our own message (we post as this handle/userId).
|
|
138
140
|
const fromHandle = normalizeHandle(entry.handle).toLowerCase();
|
|
@@ -149,7 +151,9 @@ export function isTriggeringEntry(entry, ownHandle, ownUserId, ownSeqs) {
|
|
|
149
151
|
// old mentionsAgent) fired on ordinary words for short handles like "may" /
|
|
150
152
|
// "btc"; armed posting has no human review, so it triggers ONLY on an `@handle`
|
|
151
153
|
// token. Empty handle never matches (mentionsAgentExplicit guards it).
|
|
152
|
-
|
|
154
|
+
// Mentions can live in the poll question too (member-authored content).
|
|
155
|
+
const mentionSource = [entry.text ?? "", entry.poll?.question ?? ""].filter(Boolean).join(" ");
|
|
156
|
+
return mentionsAgentExplicit(mentionSource, ownHandle);
|
|
153
157
|
}
|
|
154
158
|
/**
|
|
155
159
|
* The newest qualifying trigger among entries strictly newer than
|
|
@@ -330,7 +334,7 @@ export function isHumanResetEntry(entry, ownHandle, ownUserId) {
|
|
|
330
334
|
const me = normalizeHandle(ownHandle).toLowerCase();
|
|
331
335
|
if (me.length > 0 && fromHandle === me)
|
|
332
336
|
return false;
|
|
333
|
-
return Boolean(entry.text?.trim());
|
|
337
|
+
return Boolean(entry.text?.trim()) || entry.poll != null;
|
|
334
338
|
}
|
|
335
339
|
/** Note a turn/post error against the kill switch; returns true once the room
|
|
336
340
|
* should auto-disarm (>= maxConsecutiveErrors in a row). Mutates `state`. */
|
|
@@ -28,6 +28,11 @@ export type AgentMessage = {
|
|
|
28
28
|
export interface ToolDispatchResult {
|
|
29
29
|
isError?: true;
|
|
30
30
|
content: string;
|
|
31
|
+
/** Full-fidelity render payload for in-process SURFACES (e.g. the TUI's
|
|
32
|
+
* backtest card). Present only on the streamed copy channels consume —
|
|
33
|
+
* the agent runtime strips it before the result reaches the model's
|
|
34
|
+
* messages or the conversation store, so it never costs context. */
|
|
35
|
+
artifact?: unknown;
|
|
31
36
|
}
|
|
32
37
|
export interface LlmTool {
|
|
33
38
|
name: string;
|
|
@@ -18,6 +18,12 @@
|
|
|
18
18
|
import type { RoomTopic, RoomTopicAttention, RoomTopicBucketState, RoomTopicsResultPayload } from "../shared/rooms-protocol.js";
|
|
19
19
|
/** The reserved bucket key for untopicked (linear) messages. */
|
|
20
20
|
export declare const UNTOPICKED_BUCKET = "";
|
|
21
|
+
/** Effective attention for a bucket: an elapsed timed mute reads as the
|
|
22
|
+
* base attention ('default'). The store expires timed mutes lazily (no
|
|
23
|
+
* deadline-triggered frame), so a hydrated inbox would otherwise stay
|
|
24
|
+
* muted past the deadline until the next hydration. A null or absent
|
|
25
|
+
* deadline keeps the stored attention (permanent mute). */
|
|
26
|
+
export declare function resolveTopicAttention(state: Pick<RoomTopicBucketState, "attention" | "muteUntil">, nowMs?: number): RoomTopicAttention;
|
|
21
27
|
export interface TopicInboxItem {
|
|
22
28
|
/** Bucket key: a topicId, or UNTOPICKED_BUCKET for the linear lane. */
|
|
23
29
|
key: string;
|
|
@@ -17,6 +17,17 @@
|
|
|
17
17
|
*/
|
|
18
18
|
/** The reserved bucket key for untopicked (linear) messages. */
|
|
19
19
|
export const UNTOPICKED_BUCKET = "";
|
|
20
|
+
/** Effective attention for a bucket: an elapsed timed mute reads as the
|
|
21
|
+
* base attention ('default'). The store expires timed mutes lazily (no
|
|
22
|
+
* deadline-triggered frame), so a hydrated inbox would otherwise stay
|
|
23
|
+
* muted past the deadline until the next hydration. A null or absent
|
|
24
|
+
* deadline keeps the stored attention (permanent mute). */
|
|
25
|
+
export function resolveTopicAttention(state, nowMs = Date.now()) {
|
|
26
|
+
if (state.attention !== "mute" || state.muteUntil == null)
|
|
27
|
+
return state.attention;
|
|
28
|
+
const deadline = Date.parse(state.muteUntil);
|
|
29
|
+
return Number.isFinite(deadline) && deadline <= nowMs ? "default" : "mute";
|
|
30
|
+
}
|
|
20
31
|
function emptyBucket() {
|
|
21
32
|
return { lastSeq: 0, unreadCount: 0, cursor: 0, attention: "default" };
|
|
22
33
|
}
|
|
@@ -111,7 +122,7 @@ export class RoomTopicInbox {
|
|
|
111
122
|
return rows;
|
|
112
123
|
}
|
|
113
124
|
attentionFor(topicId) {
|
|
114
|
-
return this.bucketFor(topicId)
|
|
125
|
+
return resolveTopicAttention(this.bucketFor(topicId));
|
|
115
126
|
}
|
|
116
127
|
/** A registry mutation arrived (TOPIC_UPDATED, or a verb result echo). */
|
|
117
128
|
applyTopicUpdated(topic) {
|
|
@@ -160,6 +171,10 @@ export class RoomTopicInbox {
|
|
|
160
171
|
this.buckets.set(topicId, bucket);
|
|
161
172
|
}
|
|
162
173
|
bucket.attention = attention;
|
|
174
|
+
// The mirror knows only the new attention: a stale deadline from a
|
|
175
|
+
// previous timed mute must not expire it. The next hydration restores
|
|
176
|
+
// any server-side deadline.
|
|
177
|
+
delete bucket.muteUntil;
|
|
163
178
|
}
|
|
164
179
|
/**
|
|
165
180
|
* The viewer saw a bucket up to seq (the view batcher owns the durable
|
|
@@ -188,7 +203,7 @@ export class RoomTopicInbox {
|
|
|
188
203
|
channelUnread() {
|
|
189
204
|
let total = 0;
|
|
190
205
|
for (const bucket of this.buckets.values()) {
|
|
191
|
-
if (bucket
|
|
206
|
+
if (resolveTopicAttention(bucket) === "mute")
|
|
192
207
|
continue;
|
|
193
208
|
total += bucket.unreadCount;
|
|
194
209
|
}
|
|
@@ -205,7 +220,7 @@ export class RoomTopicInbox {
|
|
|
205
220
|
inboxItems() {
|
|
206
221
|
const items = [];
|
|
207
222
|
const untopicked = this.bucketFor(UNTOPICKED_BUCKET);
|
|
208
|
-
if (untopicked.unreadCount > 0 && untopicked
|
|
223
|
+
if (untopicked.unreadCount > 0 && resolveTopicAttention(untopicked) !== "mute") {
|
|
209
224
|
items.push({
|
|
210
225
|
key: UNTOPICKED_BUCKET,
|
|
211
226
|
topic: undefined,
|
|
@@ -218,12 +233,12 @@ export class RoomTopicInbox {
|
|
|
218
233
|
if (topic.mergedInto)
|
|
219
234
|
continue;
|
|
220
235
|
const state = this.bucketFor(topic.topicId);
|
|
221
|
-
if (state
|
|
236
|
+
if (resolveTopicAttention(state) === "mute")
|
|
222
237
|
continue;
|
|
223
238
|
let aliasUnread = 0;
|
|
224
239
|
for (const alias of this.aliasesOf(topic.topicId)) {
|
|
225
240
|
const aliasState = this.bucketFor(alias);
|
|
226
|
-
if (aliasState
|
|
241
|
+
if (resolveTopicAttention(aliasState) === "mute")
|
|
227
242
|
continue;
|
|
228
243
|
aliasUnread += aliasState.unreadCount;
|
|
229
244
|
}
|
|
@@ -222,6 +222,19 @@ export interface RoomLedgerEntry {
|
|
|
222
222
|
count: number;
|
|
223
223
|
}> | undefined;
|
|
224
224
|
editedAt?: string | number | Date | undefined;
|
|
225
|
+
/** Database-serialized edit counter: positive integer, strictly
|
|
226
|
+
* increasing per event row, incremented on every successful text or
|
|
227
|
+
* caption edit; absent means never edited. Orders caption edits where
|
|
228
|
+
* wall-clock editedAt stamps can tie or skew across store replicas.
|
|
229
|
+
* Missing on stores older than edit revisions. */
|
|
230
|
+
editRevision?: number | undefined;
|
|
231
|
+
/** Database-serialized card-mutation counter: positive integer,
|
|
232
|
+
* strictly increasing per event row, bumped on every unfurl card
|
|
233
|
+
* mutation (attach, edit-drop, purge); absent means cards were never
|
|
234
|
+
* mutated. Consumers apply card patches only at or above their known
|
|
235
|
+
* revision, making stale post-removal unfurl frames inert. Missing on
|
|
236
|
+
* stores older than unfurl revisions. */
|
|
237
|
+
unfurlsRevision?: number | undefined;
|
|
225
238
|
deletedAt?: string | number | Date | undefined;
|
|
226
239
|
deletedBy?: string | undefined;
|
|
227
240
|
replyCount?: number | undefined;
|
|
@@ -230,6 +243,12 @@ export interface RoomLedgerEntry {
|
|
|
230
243
|
pinnedBy?: string | null | undefined;
|
|
231
244
|
pinnedAt?: string | number | Date | null | undefined;
|
|
232
245
|
attachments?: RoomAttachment[] | undefined;
|
|
246
|
+
/** Counts-only poll summary when this message carries a poll. Additive:
|
|
247
|
+
* non-poll entries omit it, and live updates ride ENTRY_UPDATED. */
|
|
248
|
+
poll?: RoomPollSummary | null | undefined;
|
|
249
|
+
/** Server-rendered link unfurl cards. Additive: entries without links
|
|
250
|
+
* (and servers older than the unfurl worker) omit it. */
|
|
251
|
+
unfurls?: RoomUnfurl[] | undefined;
|
|
233
252
|
roomRole?: RoomRole | null | undefined;
|
|
234
253
|
metadata?: (Record<string, unknown> & Partial<RoomForwardMetadata> & Partial<RoomWebhookMetadata>) | undefined;
|
|
235
254
|
}
|
|
@@ -279,6 +298,46 @@ export interface RoomAttachment {
|
|
|
279
298
|
export type RoomAttachmentInput = RoomAttachment & {
|
|
280
299
|
key: string;
|
|
281
300
|
};
|
|
301
|
+
export interface RoomPollOption {
|
|
302
|
+
id: string;
|
|
303
|
+
text: string;
|
|
304
|
+
/** Vote count for this option. Counts only, never voter identities
|
|
305
|
+
* (voters are fetched on demand, exactly like reactors). */
|
|
306
|
+
count: number;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Counts-only poll summary denormalized onto the carrying message (a poll
|
|
310
|
+
* IS a message). Vote/close/edit updates ride the existing ENTRY_UPDATED
|
|
311
|
+
* frame with the refreshed summary; the server's side collections stay the
|
|
312
|
+
* authoritative copy.
|
|
313
|
+
*/
|
|
314
|
+
export interface RoomPollSummary {
|
|
315
|
+
question: string;
|
|
316
|
+
options: RoomPollOption[];
|
|
317
|
+
multi: boolean;
|
|
318
|
+
/** ISO date when the poll auto-closes; null or absent means open-ended. */
|
|
319
|
+
closesAt?: string | null | undefined;
|
|
320
|
+
closed: boolean;
|
|
321
|
+
/** Store-serialized poll ordering revision, strictly increasing per
|
|
322
|
+
* poll: consumers reject frames below their known revision so
|
|
323
|
+
* bus-reordered vote/close updates cannot regress tallies. Present
|
|
324
|
+
* where the relay forwards it; missing on older relays. */
|
|
325
|
+
revision?: number | undefined;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Server-rendered link unfurl card on an entry. `url` is the canonical
|
|
329
|
+
* URL; `thumbnailKey` is the re-hosted copy in the attachments bucket,
|
|
330
|
+
* signed through the member-scoped attachment path. The origin's image URL
|
|
331
|
+
* never crosses the wire. Cards appear via ENTRY_UPDATED when the unfurl
|
|
332
|
+
* worker lands.
|
|
333
|
+
*/
|
|
334
|
+
export interface RoomUnfurl {
|
|
335
|
+
url: string;
|
|
336
|
+
title?: string | undefined;
|
|
337
|
+
description?: string | undefined;
|
|
338
|
+
siteName?: string | undefined;
|
|
339
|
+
thumbnailKey?: string | undefined;
|
|
340
|
+
}
|
|
282
341
|
/**
|
|
283
342
|
* A registry-backed topic inside a channel. The id is permanent: rename
|
|
284
343
|
* changes `name` only, and links (`om://topic/<topicId>`) keep resolving.
|
|
@@ -342,6 +401,21 @@ export interface RoomReadStatePayload {
|
|
|
342
401
|
* Present when the store surfaces it and on ROOM_SET_ATTENTION acks
|
|
343
402
|
* (which reply READ_STATE scoped to the one room, readState empty). */
|
|
344
403
|
attention?: Record<string, RoomTopicAttention> | undefined;
|
|
404
|
+
/** Per-room timed-mute expiry (ISO date), keyed like attention. Rides
|
|
405
|
+
* beside a 'mute' attention entry when the mute carries an expiry; null
|
|
406
|
+
* marks an explicitly cleared or permanent mute. A lapsed expiry never
|
|
407
|
+
* appears: the server resolves it at read time and the attention value
|
|
408
|
+
* reads as its base ('default'). Missing on servers older than
|
|
409
|
+
* mute-with-duration. */
|
|
410
|
+
muteUntil?: Record<string, string | null> | undefined;
|
|
411
|
+
/** Per-room attention commit revision, keyed like attention: a
|
|
412
|
+
* database-serialized, strictly increasing counter per (user, room),
|
|
413
|
+
* present only for rooms whose attention has ever been committed.
|
|
414
|
+
* ORDERING CONTRACT: a consumer that has synced revision R for a room
|
|
415
|
+
* must ignore snapshot attention entries whose revision is <= R (a
|
|
416
|
+
* snapshot read before a newer commit can arrive after that commit's
|
|
417
|
+
* sync frame). Missing on stores older than attention revisions. */
|
|
418
|
+
attentionRevision?: Record<string, number> | undefined;
|
|
345
419
|
/** Unread mention counts by room, server-computed from the notify
|
|
346
420
|
* worker's ROOM_MENTION rows so badges survive reload and clear through
|
|
347
421
|
* the ack path. Unlike readState/attention the map is SPARSE AND
|
|
@@ -864,6 +938,14 @@ export interface RoomTopicBucketState {
|
|
|
864
938
|
unreadCount: number;
|
|
865
939
|
cursor: number;
|
|
866
940
|
attention: RoomTopicAttention;
|
|
941
|
+
/** Standing timed-mute deadline (ISO date; null = permanent mute).
|
|
942
|
+
* Present only on the room-wide '' bucket and only while its attention
|
|
943
|
+
* is an active 'mute'; never on topic buckets. Same semantics as the
|
|
944
|
+
* read-state muteUntil: the store expires timed mutes lazily, so
|
|
945
|
+
* consumers resolve an elapsed deadline back to the base attention
|
|
946
|
+
* ('default') at read time (see resolveTopicAttention). Missing on
|
|
947
|
+
* servers older than mute-with-duration. */
|
|
948
|
+
muteUntil?: string | null | undefined;
|
|
867
949
|
}
|
|
868
950
|
export interface RoomTopicResultPayload {
|
|
869
951
|
room: string;
|
package/dist/social-client.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type { RoomTopicAttention } from "./shared/rooms-protocol.js";
|
|
2
|
+
import type { RoomBookmarkSaved, RoomBookmarksResult, RoomDmConversation, RoomDmHistory, RoomDmSendResult, RoomDmUnreadConversation, RoomDoc, RoomDocAttribution, RoomDocChanges, RoomDocConflictHead, RoomDocEditingLease, RoomDocProvenance, RoomDocRevision, RoomDocRunRevertResult, RoomDocWriteResult, RoomFollow, RoomFollowResult, RoomFriend, RoomFriendRequests, RoomNotificationInboxResult, RoomPollVotersResult, RoomPublicProfile, RoomRepliesReadResult, RoomRepliesResult, RoomRestEvent, RoomSocialConfig, RoomSpaceRestorePlan, RoomSpaceRestoreReceipt, RoomSuggestion, RoomSuggestionRequest, RoomUserBlock, RoomUserBlocksResult } from "./social-types.js";
|
|
3
|
+
export type { RoomAttachment, RoomBookmark, RoomBookmarkSaved, RoomBookmarksResult, RoomDmConversation, RoomDmHistory, RoomDmMessage, RoomDmParticipant, RoomDmSendResult, RoomDmUnreadConversation, RoomDocAttribution, RoomDocEditingLease, RoomDocMergeRegion, RoomDocRevisionSource, RoomDocRunRevertResult, RoomFollow, RoomFollowResult, RoomFriend, RoomFriendRequest, RoomFriendRequests, RoomNotificationInboxItem, RoomNotificationInboxResult, RoomNotificationKind, RoomNotificationMessageData, RoomNotifyQuietHours, RoomPollOptionVoters, RoomPollVotersResult, RoomPublicProfile, RoomRepliesReadResult, RoomRepliesResult, RoomReplyInboxItem, RoomRestEvent, RoomSocialConfig, RoomSpaceNotificationOverride, RoomSpaceRestoreAction, RoomSpaceRestoreActionKind, RoomSpaceRestorePlan, RoomSpaceRestoreReceipt, RoomSpaceRestoreSummary, RoomSuggestion, RoomSuggestionIntent, RoomSuggestionRequest, RoomSuggestionSource, RoomsNotificationSettings, RoomUserBlock, RoomUserBlocksResult, } from "./social-types.js";
|
|
3
4
|
/** Largest per-file size any tier accepts (plus tier). The server enforces
|
|
4
5
|
* the per-tier caps (free 10MB/file, plus 25MB/file) and daily quotas; this
|
|
5
6
|
* constant only pre-flights uploads no tier could ever accept. */
|
|
@@ -254,12 +255,20 @@ export interface RoomSpaceInvite {
|
|
|
254
255
|
invitedBy?: string;
|
|
255
256
|
role: "admin" | "member";
|
|
256
257
|
createdAt?: string;
|
|
258
|
+
/** Expiry deadline (ISO date); null or absent means the invite stands
|
|
259
|
+
* until accepted or declined. Additive (0.6.0 servers). */
|
|
260
|
+
expiresAt?: string | null;
|
|
257
261
|
}
|
|
258
|
-
/** Create (or refresh) a pending invitation. Membership needs their accept.
|
|
262
|
+
/** Create (or refresh) a pending invitation. Membership needs their accept.
|
|
263
|
+
* `expiresAt` (ISO date, future, at most 30 days out) puts a deadline on
|
|
264
|
+
* it; re-inviting without one clears any previous deadline. Fail-closed on
|
|
265
|
+
* servers older than 0.6.0: they persist the invite but drop the deadline,
|
|
266
|
+
* so a deadline the echo omits revokes the invite and throws. */
|
|
259
267
|
export declare function createSpaceInvite(config: RoomSocialConfig, spaceId: string, input: {
|
|
260
268
|
targetUserId?: string;
|
|
261
269
|
targetUsername?: string;
|
|
262
270
|
role?: "admin" | "member";
|
|
271
|
+
expiresAt?: string;
|
|
263
272
|
}): Promise<RoomSpaceInvite>;
|
|
264
273
|
/** The caller's own pending invitations. */
|
|
265
274
|
export declare function listMySpaceInvites(config: RoomSocialConfig): Promise<RoomSpaceInvite[]>;
|
|
@@ -274,10 +283,22 @@ export declare function acceptSpaceInvite(config: RoomSocialConfig, inviteId: st
|
|
|
274
283
|
export declare function declineSpaceInvite(config: RoomSocialConfig, inviteId: string): Promise<{
|
|
275
284
|
declined?: boolean;
|
|
276
285
|
}>;
|
|
277
|
-
/** Mint (or rotate) the shareable join code; plaintext comes back once.
|
|
278
|
-
|
|
286
|
+
/** Mint (or rotate) the shareable join code; plaintext comes back once.
|
|
287
|
+
* Optional caps: `expiresAt` (ISO date, future, at most 30 days out) and
|
|
288
|
+
* `maxUses` (1..10000). Rotation is a fresh grant: the new code starts at
|
|
289
|
+
* zero uses and takes exactly the caps given here (omitted caps clear the
|
|
290
|
+
* previous ones). Servers older than 0.6.0 echo neither cap field; they
|
|
291
|
+
* mint the code but drop the caps, so a requested cap the echo omits
|
|
292
|
+
* fail-closes: the fresh code is revoked and the call throws rather than
|
|
293
|
+
* hand back a live UNLIMITED code the caller believes capped. */
|
|
294
|
+
export declare function setSpaceJoinCode(config: RoomSocialConfig, spaceId: string, options?: {
|
|
295
|
+
expiresAt?: string | undefined;
|
|
296
|
+
maxUses?: number | undefined;
|
|
297
|
+
}): Promise<{
|
|
279
298
|
spaceId: string;
|
|
280
299
|
code: string;
|
|
300
|
+
expiresAt?: string | null;
|
|
301
|
+
maxUses?: number | null;
|
|
281
302
|
}>;
|
|
282
303
|
export declare function clearSpaceJoinCode(config: RoomSocialConfig, spaceId: string): Promise<{
|
|
283
304
|
cleared?: boolean;
|
|
@@ -411,6 +432,168 @@ export declare function listRoomNotifications(config: RoomSocialConfig, options?
|
|
|
411
432
|
unread?: boolean | undefined;
|
|
412
433
|
signal?: AbortSignal | undefined;
|
|
413
434
|
}): Promise<RoomNotificationInboxResult>;
|
|
435
|
+
/**
|
|
436
|
+
* Mark a room unread from `seq` (Discord-style): the room-wide read cursor
|
|
437
|
+
* drops to seq - 1 (server-clamped at 0) so the unread divider and pill
|
|
438
|
+
* return. The one sanctioned cursor-regression path; mention rows an
|
|
439
|
+
* earlier ack swept stay swept, and nothing is re-notified.
|
|
440
|
+
*/
|
|
441
|
+
export declare function markRoomUnread(config: RoomSocialConfig, room: string, seq: number): Promise<{
|
|
442
|
+
success: boolean;
|
|
443
|
+
}>;
|
|
444
|
+
/**
|
|
445
|
+
* Set the caller's room-level attention over REST, the path that carries
|
|
446
|
+
* mute-with-duration: `untilMs` (epoch ms, valid only with 'mute') stamps
|
|
447
|
+
* the expiry that read state later surfaces as `muteUntil`; the mute lapses
|
|
448
|
+
* server-side and reads as 'default' afterwards. Every write settles the
|
|
449
|
+
* expiry, so follow/default (and a plain permanent mute) clear a previous
|
|
450
|
+
* one. The pinned ROOM_SET_ATTENTION frame (setRoomAttentionOnClient)
|
|
451
|
+
* predates `untilMs` and stays the live-session path for permanent
|
|
452
|
+
* postures; servers older than mute-with-duration strip the field and land
|
|
453
|
+
* the mute permanent, so a requested `untilMs` the echo omits is a DROPPED
|
|
454
|
+
* DEADLINE. By default that fail-closes here: the attention is reset and
|
|
455
|
+
* the call throws rather than leave an unbounded mute the caller believes
|
|
456
|
+
* timed. Callers with a richer fail-closed seam of their own opt out via
|
|
457
|
+
* `onDroppedDeadline: "resolve"` and own the handling (see the option).
|
|
458
|
+
* Echoes the persisted attention; `muteUntil` is the ISO expiry, null when
|
|
459
|
+
* none stands (which, under "resolve", is how a dropped deadline reads).
|
|
460
|
+
*/
|
|
461
|
+
export declare function setRoomAttentionRest(config: RoomSocialConfig, room: string, attention: RoomTopicAttention, options?: {
|
|
462
|
+
untilMs?: number | undefined;
|
|
463
|
+
/** What to do when a requested `untilMs` comes back without an echoed
|
|
464
|
+
* `muteUntil` (the server predates timed mutes and landed the mute
|
|
465
|
+
* PERMANENT). Default "undo-and-throw": reset attention to 'default'
|
|
466
|
+
* and throw RoomSocialError 502, so no unbounded mute stands. Pass
|
|
467
|
+
* "resolve" ONLY when the caller implements its own dropped-deadline
|
|
468
|
+
* handling: the call then performs no undo write and no throw, and
|
|
469
|
+
* resolves with `muteUntil: null` for the caller to act on. Canonical
|
|
470
|
+
* example: the GUI session seam, which undoes to the last
|
|
471
|
+
* WS-confirmed attention, richer than this library's
|
|
472
|
+
* undo-to-default. */
|
|
473
|
+
onDroppedDeadline?: "undo-and-throw" | "resolve" | undefined;
|
|
474
|
+
}): Promise<{
|
|
475
|
+
attention: RoomTopicAttention;
|
|
476
|
+
muteUntil: string | null;
|
|
477
|
+
}>;
|
|
478
|
+
/**
|
|
479
|
+
* Save a message for later (personal, per-user; nothing broadcasts).
|
|
480
|
+
* Idempotent: re-saving an already bookmarked event echoes the standing
|
|
481
|
+
* row with its original createdAt.
|
|
482
|
+
*/
|
|
483
|
+
export declare function addRoomBookmark(config: RoomSocialConfig, room: string, seq: number): Promise<RoomBookmarkSaved>;
|
|
484
|
+
export declare function removeRoomBookmark(config: RoomSocialConfig, room: string, seq: number): Promise<{
|
|
485
|
+
removed: boolean;
|
|
486
|
+
}>;
|
|
487
|
+
/**
|
|
488
|
+
* The caller's bookmarks across every room (GET /users/bookmarks), newest
|
|
489
|
+
* first with the notification inbox's composite cursor: pass a page's
|
|
490
|
+
* lastCursor and lastCursorId back TOGETHER for the next page. Rows in
|
|
491
|
+
* rooms the caller can no longer read are subtracted server-side.
|
|
492
|
+
*/
|
|
493
|
+
export declare function listUserBookmarks(config: RoomSocialConfig, options?: {
|
|
494
|
+
limit?: number | undefined;
|
|
495
|
+
/** Feed a page's lastCursor back here (explicit undefined reads as
|
|
496
|
+
* "first page", so `page.lastCursor ?? undefined` composes under
|
|
497
|
+
* exactOptionalPropertyTypes). */
|
|
498
|
+
cursor?: string | undefined;
|
|
499
|
+
cursorId?: string | undefined;
|
|
500
|
+
signal?: AbortSignal | undefined;
|
|
501
|
+
}): Promise<RoomBookmarksResult>;
|
|
502
|
+
/**
|
|
503
|
+
* The caller's user-block list (GET /users/blocks), newest first with the
|
|
504
|
+
* same composite-cursor paging as the notification inbox. Blocks are
|
|
505
|
+
* directional and the blocker is always the verified caller.
|
|
506
|
+
*/
|
|
507
|
+
export declare function getUserBlocks(config: RoomSocialConfig, options?: {
|
|
508
|
+
limit?: number | undefined;
|
|
509
|
+
cursor?: string | undefined;
|
|
510
|
+
cursorId?: string | undefined;
|
|
511
|
+
signal?: AbortSignal | undefined;
|
|
512
|
+
}): Promise<RoomUserBlocksResult>;
|
|
513
|
+
/** Block a user by userId (PUT, idempotent: re-blocking echoes the standing
|
|
514
|
+
* row with its original createdAt). Server-enforced effects: DM doors shut
|
|
515
|
+
* both directions, friend requests refuse, and the blocked sender produces
|
|
516
|
+
* no notifications for the caller. Room visibility is unchanged. */
|
|
517
|
+
export declare function blockUser(config: RoomSocialConfig, userId: string): Promise<RoomUserBlock>;
|
|
518
|
+
/** Unblock a user (idempotent: unblocking a non-blocked user is a no-op). */
|
|
519
|
+
export declare function unblockUser(config: RoomSocialConfig, userId: string): Promise<{
|
|
520
|
+
success: boolean;
|
|
521
|
+
}>;
|
|
522
|
+
/**
|
|
523
|
+
* Post a poll message. There is no separate create route and no WS input
|
|
524
|
+
* path (the relay's post frame carries text only): a poll rides the normal
|
|
525
|
+
* REST append as the strict body's `poll` block. `options` are option TEXT
|
|
526
|
+
* (2..10 entries; ids are minted server-side) and `closesAt` is an ISO
|
|
527
|
+
* deadline that must sit in the future. `text` is the optional caption;
|
|
528
|
+
* absent is fine, the poll IS the content. Echoes the created store event
|
|
529
|
+
* row with its counts-only summary; the room hears the same message
|
|
530
|
+
* through the ordinary live echo. Additive (0.6.0 servers): older stores
|
|
531
|
+
* reject the unknown block.
|
|
532
|
+
*/
|
|
533
|
+
export declare function createRoomPoll(config: RoomSocialConfig, room: string, input: {
|
|
534
|
+
question: string;
|
|
535
|
+
options: string[];
|
|
536
|
+
multi?: boolean | undefined;
|
|
537
|
+
closesAt?: string | undefined;
|
|
538
|
+
text?: string | undefined;
|
|
539
|
+
/** Exact-case workspace id: lets a COLD relay replica materialize a
|
|
540
|
+
* virtual workspace room without guessing the id's casing from the
|
|
541
|
+
* lowercased room name (owners resolve server-side; non-owner first
|
|
542
|
+
* writers need this). */
|
|
543
|
+
workspaceId?: string | undefined;
|
|
544
|
+
/** Route into a topic lane like any other append. */
|
|
545
|
+
topicId?: string | undefined;
|
|
546
|
+
/** Post the poll as a threaded reply. */
|
|
547
|
+
replyToSeq?: number | undefined;
|
|
548
|
+
/** Server-side idempotency: retries after an ambiguous failure reuse
|
|
549
|
+
* the key instead of minting a duplicate poll. */
|
|
550
|
+
clientMsgId?: string | undefined;
|
|
551
|
+
}): Promise<RoomRestEvent>;
|
|
552
|
+
/**
|
|
553
|
+
* Vote on a poll (the poll is keyed by its carrying message's seq). Echoes
|
|
554
|
+
* the store's public event row (RoomRestEvent, not the relay's mapped
|
|
555
|
+
* ledger entry) with the refreshed counts-only summary; the room hears the
|
|
556
|
+
* same update over ENTRY_UPDATED. Single-choice polls replace the caller's
|
|
557
|
+
* previous ballot; multi-choice polls union into it.
|
|
558
|
+
*/
|
|
559
|
+
export declare function voteRoomPoll(config: RoomSocialConfig, room: string, seq: number, optionIds: string[]): Promise<RoomRestEvent>;
|
|
560
|
+
/** Clear the caller's vote. Echoes the refreshed store event row. */
|
|
561
|
+
export declare function unvoteRoomPoll(config: RoomSocialConfig, room: string, seq: number): Promise<RoomRestEvent>;
|
|
562
|
+
/** Close a poll (idempotent on an already-closed poll). Echoes the store
|
|
563
|
+
* event row with `poll.closed` set. */
|
|
564
|
+
export declare function closeRoomPoll(config: RoomSocialConfig, room: string, seq: number): Promise<RoomRestEvent>;
|
|
565
|
+
/** Edit a poll's question/options (author-only, and locked once any vote
|
|
566
|
+
* exists or the poll closes; at least one field required). Options are
|
|
567
|
+
* full replacement TEXT, like creation. */
|
|
568
|
+
/** Purge an event's frozen unfurl cards without editing or deleting the
|
|
569
|
+
* message. Author or a delete-any moderation power; the store unsets the
|
|
570
|
+
* cards, schedules thumbnail cleanup, and returns the mutated event for
|
|
571
|
+
* ENTRY_UPDATED fan-out. An edit that removes a card's URL from the text
|
|
572
|
+
* drops that card automatically; this route is the explicit purge for
|
|
573
|
+
* everything else (a capability URL that must go without rewording the
|
|
574
|
+
* message, a moderator acting on someone else's post). */
|
|
575
|
+
export declare function unsetRoomEventUnfurls(config: RoomSocialConfig, room: string, seq: number): Promise<void>;
|
|
576
|
+
/** Edit an event's text over REST: the cold-replica-safe mirror of the WS
|
|
577
|
+
* EDIT frame, and the ONE shape the WS path cannot express: an empty text
|
|
578
|
+
* on a poll-bearing message legally clears the optional caption (the poll
|
|
579
|
+
* stays the content; the store rejects empty edits on plain messages).
|
|
580
|
+
* Viewers reconcile through the store's ENTRY_UPDATED fan-out exactly
|
|
581
|
+
* like the REST poll verbs. */
|
|
582
|
+
export declare function editRoomEventRest(config: RoomSocialConfig, room: string, seq: number, text: string): Promise<void>;
|
|
583
|
+
export declare function editRoomPoll(config: RoomSocialConfig, room: string, seq: number, patch: {
|
|
584
|
+
question?: string | undefined;
|
|
585
|
+
options?: string[] | undefined;
|
|
586
|
+
}): Promise<RoomRestEvent>;
|
|
587
|
+
/**
|
|
588
|
+
* Voter identities, on demand (the entry's summary carries counts only).
|
|
589
|
+
* Grouped per option; `optionId` narrows to one option and `limit` caps the
|
|
590
|
+
* identities per option (counts stay exact).
|
|
591
|
+
*/
|
|
592
|
+
export declare function listRoomPollVoters(config: RoomSocialConfig, room: string, seq: number, options?: {
|
|
593
|
+
optionId?: string | undefined;
|
|
594
|
+
limit?: number | undefined;
|
|
595
|
+
signal?: AbortSignal | undefined;
|
|
596
|
+
}): Promise<RoomPollVotersResult>;
|
|
414
597
|
export declare function suggestRooms(config: RoomSocialConfig, request: RoomSuggestionRequest, options?: {
|
|
415
598
|
signal?: AbortSignal;
|
|
416
599
|
}): Promise<RoomSuggestion[]>;
|