@openmarket/rooms-client 0.8.0 → 0.10.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.
- package/dist/agent/library-model.d.ts +14 -1
- package/dist/agent/library-model.js +26 -5
- package/dist/shared/rooms-protocol.d.ts +34 -0
- package/dist/shared/rooms-protocol.js +2 -0
- package/dist/social-client.d.ts +34 -0
- package/dist/social-client.js +28 -0
- package/dist/version.d.ts +2 -2
- package/dist/version.js +2 -2
- package/package.json +1 -1
- package/src/agent/library-model.ts +25 -5
- package/src/shared/rooms-protocol.ts +38 -0
- package/src/social-client.ts +53 -0
- package/src/version.ts +2 -2
|
@@ -24,7 +24,9 @@ export declare class LibraryModel {
|
|
|
24
24
|
refresh(): Promise<boolean>;
|
|
25
25
|
private refreshSpace;
|
|
26
26
|
private applyChanges;
|
|
27
|
-
/** Upsert after our own write so the UI reflects it without waiting a poll.
|
|
27
|
+
/** Upsert after our own write so the UI reflects it without waiting a poll.
|
|
28
|
+
* Every local write (archive included) advances the receipt: our write IS
|
|
29
|
+
* the head we would otherwise refetch. */
|
|
28
30
|
applyLocalWrite(doc: RoomDoc): void;
|
|
29
31
|
docsFor(spaceId: string): RoomDoc[];
|
|
30
32
|
recentFor(spaceId: string, limit?: number): RoomDoc[];
|
|
@@ -34,6 +36,17 @@ export declare class LibraryModel {
|
|
|
34
36
|
freshCount(spaceId: string): number;
|
|
35
37
|
isFresh(spaceId: string, docId: string): boolean;
|
|
36
38
|
markSeen(spaceId: string): void;
|
|
39
|
+
/**
|
|
40
|
+
* Record a server poke (DOC_CHANGED) that the space's change head moved.
|
|
41
|
+
* Bookkeeping only: latestSeq ratchets up (never down) so atHead() reports
|
|
42
|
+
* stale until a refresh catches up. Returns whether a refresh would fetch
|
|
43
|
+
* anything: false for untracked spaces, true for a seqless poke (an
|
|
44
|
+
* unconditional "something changed"), otherwise whether the poked head is
|
|
45
|
+
* ahead of the cursor. Callers own debounce/refresh scheduling, and must
|
|
46
|
+
* re-check atHead() after a refresh completes: the refresh() single-flight
|
|
47
|
+
* guard drops a poke that lands mid-refresh.
|
|
48
|
+
*/
|
|
49
|
+
noteRemoteHead(spaceId: string, latestSeq?: number): boolean;
|
|
37
50
|
/** True when the cache has provably caught up to the space's change head. */
|
|
38
51
|
atHead(spaceId: string): boolean;
|
|
39
52
|
syncedOnce(spaceId: string): boolean;
|
|
@@ -95,21 +95,23 @@ export class LibraryModel {
|
|
|
95
95
|
}
|
|
96
96
|
return changed;
|
|
97
97
|
}
|
|
98
|
-
/** Upsert after our own write so the UI reflects it without waiting a poll.
|
|
98
|
+
/** Upsert after our own write so the UI reflects it without waiting a poll.
|
|
99
|
+
* Every local write (archive included) advances the receipt: our write IS
|
|
100
|
+
* the head we would otherwise refetch. */
|
|
99
101
|
applyLocalWrite(doc) {
|
|
100
102
|
const state = this.spaces.get(doc.spaceId);
|
|
101
103
|
if (!state)
|
|
102
104
|
return;
|
|
105
|
+
if (doc.spaceDocSeq > state.cursor) {
|
|
106
|
+
state.cursor = doc.spaceDocSeq;
|
|
107
|
+
state.latestSeq = Math.max(state.latestSeq, doc.spaceDocSeq);
|
|
108
|
+
}
|
|
103
109
|
if (doc.status === "archived") {
|
|
104
110
|
state.docs.delete(doc.docId);
|
|
105
111
|
state.freshDocIds.delete(doc.docId);
|
|
106
112
|
return;
|
|
107
113
|
}
|
|
108
114
|
state.docs.set(doc.docId, doc);
|
|
109
|
-
if (doc.spaceDocSeq > state.cursor) {
|
|
110
|
-
state.cursor = doc.spaceDocSeq;
|
|
111
|
-
state.latestSeq = Math.max(state.latestSeq, doc.spaceDocSeq);
|
|
112
|
-
}
|
|
113
115
|
}
|
|
114
116
|
docsFor(spaceId) {
|
|
115
117
|
const state = this.spaces.get(spaceId);
|
|
@@ -157,6 +159,25 @@ export class LibraryModel {
|
|
|
157
159
|
markSeen(spaceId) {
|
|
158
160
|
this.spaces.get(spaceId)?.freshDocIds.clear();
|
|
159
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* Record a server poke (DOC_CHANGED) that the space's change head moved.
|
|
164
|
+
* Bookkeeping only: latestSeq ratchets up (never down) so atHead() reports
|
|
165
|
+
* stale until a refresh catches up. Returns whether a refresh would fetch
|
|
166
|
+
* anything: false for untracked spaces, true for a seqless poke (an
|
|
167
|
+
* unconditional "something changed"), otherwise whether the poked head is
|
|
168
|
+
* ahead of the cursor. Callers own debounce/refresh scheduling, and must
|
|
169
|
+
* re-check atHead() after a refresh completes: the refresh() single-flight
|
|
170
|
+
* guard drops a poke that lands mid-refresh.
|
|
171
|
+
*/
|
|
172
|
+
noteRemoteHead(spaceId, latestSeq) {
|
|
173
|
+
const state = this.spaces.get(spaceId);
|
|
174
|
+
if (!state)
|
|
175
|
+
return false;
|
|
176
|
+
if (latestSeq === undefined)
|
|
177
|
+
return true;
|
|
178
|
+
state.latestSeq = Math.max(state.latestSeq, latestSeq);
|
|
179
|
+
return latestSeq > state.cursor;
|
|
180
|
+
}
|
|
160
181
|
/** True when the cache has provably caught up to the space's change head. */
|
|
161
182
|
atHead(spaceId) {
|
|
162
183
|
const state = this.spaces.get(spaceId);
|
|
@@ -104,6 +104,8 @@ export declare const RoomServerMessageType: {
|
|
|
104
104
|
readonly TOPIC: "TOPIC";
|
|
105
105
|
readonly TOPICS: "TOPICS";
|
|
106
106
|
readonly TOPIC_UPDATED: "TOPIC_UPDATED";
|
|
107
|
+
readonly DOC_CHANGED: "DOC_CHANGED";
|
|
108
|
+
readonly FRIEND_UPDATED: "FRIEND_UPDATED";
|
|
107
109
|
};
|
|
108
110
|
export declare function addBounded<T>(set: Set<T>, value: T, max: number): void;
|
|
109
111
|
export type RoomServerMessageType = (typeof RoomServerMessageType)[keyof typeof RoomServerMessageType];
|
|
@@ -834,6 +836,12 @@ export interface RoomSpace {
|
|
|
834
836
|
createdAt: string | number | Date;
|
|
835
837
|
joined?: boolean | undefined;
|
|
836
838
|
iconUrl?: string | null | undefined;
|
|
839
|
+
/** Archived channels in this server (sidebar Archive row; absent on
|
|
840
|
+
* stores that predate the count). */
|
|
841
|
+
archivedRoomCount?: number | undefined;
|
|
842
|
+
/** Archived docs twin: keeps the Archive row reachable when only docs
|
|
843
|
+
* are archived. */
|
|
844
|
+
archivedDocCount?: number | undefined;
|
|
837
845
|
}
|
|
838
846
|
export interface RoomSpacesPayload {
|
|
839
847
|
requestId?: string;
|
|
@@ -874,6 +882,9 @@ export interface RoomUpdatedPayload {
|
|
|
874
882
|
room: string;
|
|
875
883
|
meta?: RoomMeta | undefined;
|
|
876
884
|
archived?: boolean | undefined;
|
|
885
|
+
/** Rides WITH archived on hard deletion: old clients evict on archived,
|
|
886
|
+
* new clients word the eviction honestly. */
|
|
887
|
+
deleted?: boolean | undefined;
|
|
877
888
|
}
|
|
878
889
|
/** Server settings changed (rename / icon / archive). */
|
|
879
890
|
export interface SpaceUpdatedPayload {
|
|
@@ -881,6 +892,8 @@ export interface SpaceUpdatedPayload {
|
|
|
881
892
|
name?: string | undefined;
|
|
882
893
|
iconUrl?: string | null | undefined;
|
|
883
894
|
archived?: boolean | undefined;
|
|
895
|
+
/** Rides WITH archived on hard deletion (see RoomUpdatedPayload). */
|
|
896
|
+
deleted?: boolean | undefined;
|
|
884
897
|
}
|
|
885
898
|
export interface RoomSpaceJoinedPayload {
|
|
886
899
|
requestId?: string;
|
|
@@ -975,6 +988,19 @@ export interface RoomTopicUpdatedPayload {
|
|
|
975
988
|
room: string;
|
|
976
989
|
topic: RoomTopic;
|
|
977
990
|
}
|
|
991
|
+
/** Poke: a space's doc-library change head moved (create/edit/archive/restore).
|
|
992
|
+
* Deliberately content-free: clients refetch deltas over REST. */
|
|
993
|
+
export interface RoomDocChangedPayload {
|
|
994
|
+
spaceId: string;
|
|
995
|
+
/** The space's change head after the mutation, when the server knows it
|
|
996
|
+
* cheaply; absent still means "something changed, refetch". */
|
|
997
|
+
latestSeq?: number | undefined;
|
|
998
|
+
}
|
|
999
|
+
/** Poke: the recipient's friendship graph changed. Clients refetch over REST. */
|
|
1000
|
+
export interface RoomFriendUpdatedPayload {
|
|
1001
|
+
kind: "request" | "accepted" | "rejected" | "removed";
|
|
1002
|
+
friendshipId?: string | undefined;
|
|
1003
|
+
}
|
|
978
1004
|
export type RoomClientMessage = {
|
|
979
1005
|
type: typeof RoomClientMessageType.AUTHENTICATE;
|
|
980
1006
|
payload: {
|
|
@@ -1504,6 +1530,14 @@ export type RoomServerMessage = {
|
|
|
1504
1530
|
type: typeof RoomServerMessageType.TOPIC_UPDATED;
|
|
1505
1531
|
payload: RoomTopicUpdatedPayload;
|
|
1506
1532
|
timestamp: number;
|
|
1533
|
+
} | {
|
|
1534
|
+
type: typeof RoomServerMessageType.DOC_CHANGED;
|
|
1535
|
+
payload: RoomDocChangedPayload;
|
|
1536
|
+
timestamp: number;
|
|
1537
|
+
} | {
|
|
1538
|
+
type: typeof RoomServerMessageType.FRIEND_UPDATED;
|
|
1539
|
+
payload: RoomFriendUpdatedPayload;
|
|
1540
|
+
timestamp: number;
|
|
1507
1541
|
};
|
|
1508
1542
|
export type RoomServerMessageOf<T extends RoomServerMessageType> = Extract<RoomServerMessage, {
|
|
1509
1543
|
type: T;
|
|
@@ -103,6 +103,8 @@ export const RoomServerMessageType = {
|
|
|
103
103
|
TOPIC: "TOPIC",
|
|
104
104
|
TOPICS: "TOPICS",
|
|
105
105
|
TOPIC_UPDATED: "TOPIC_UPDATED",
|
|
106
|
+
DOC_CHANGED: "DOC_CHANGED",
|
|
107
|
+
FRIEND_UPDATED: "FRIEND_UPDATED",
|
|
106
108
|
};
|
|
107
109
|
export function addBounded(set, value, max) {
|
|
108
110
|
set.add(value);
|
package/dist/social-client.d.ts
CHANGED
|
@@ -171,6 +171,13 @@ export interface RoomSpaceSummary {
|
|
|
171
171
|
iconUrl?: string | null;
|
|
172
172
|
/** Creation time — the stable server-rail sort key. */
|
|
173
173
|
createdAt?: string | number | null;
|
|
174
|
+
/** Archived channels in this server; with archivedDocCount it drives
|
|
175
|
+
* the sidebar's Archive row (rendered only when the sum > 0). Absent
|
|
176
|
+
* on stores that predate the counts. */
|
|
177
|
+
archivedRoomCount?: number | undefined;
|
|
178
|
+
/** Archived docs in this server: the row must stay reachable when only
|
|
179
|
+
* docs are archived, since they have no other retrieval surface. */
|
|
180
|
+
archivedDocCount?: number | undefined;
|
|
174
181
|
}
|
|
175
182
|
export declare function listRoomSpacesViaChat(config: RoomSocialConfig): Promise<RoomSpaceSummary[]>;
|
|
176
183
|
export interface RoomSpaceMember {
|
|
@@ -355,6 +362,33 @@ export declare function updateRoomSpace(config: RoomSocialConfig, spaceId: strin
|
|
|
355
362
|
export declare function archiveRoomSpace(config: RoomSocialConfig, spaceId: string): Promise<{
|
|
356
363
|
archived?: boolean;
|
|
357
364
|
}>;
|
|
365
|
+
/** Un-archive a channel back onto the active sidebar (manage-room). The
|
|
366
|
+
* wire verb is /restore, the store-wide grammar shared with docs; the
|
|
367
|
+
* receipt carries `restored`, not the archive shape's `archived`. */
|
|
368
|
+
export declare function unarchiveRoomChannel(config: RoomSocialConfig, room: string): Promise<{
|
|
369
|
+
roomId?: string;
|
|
370
|
+
restored?: boolean;
|
|
371
|
+
}>;
|
|
372
|
+
/** PERMANENTLY delete a channel and every row keyed to it (manage-room).
|
|
373
|
+
* The bare DELETE verb on /rooms/:id is the legacy ARCHIVE shape; purge is
|
|
374
|
+
* the explicit destruction verb and there is no undo. */
|
|
375
|
+
export declare function purgeRoomChannel(config: RoomSocialConfig, room: string): Promise<{
|
|
376
|
+
roomId?: string;
|
|
377
|
+
deleted?: boolean;
|
|
378
|
+
}>;
|
|
379
|
+
/** PERMANENTLY delete a server: every channel, message, member, role,
|
|
380
|
+
* invite, and the entire docs family (owner only; no undo). */
|
|
381
|
+
export declare function purgeRoomSpace(config: RoomSocialConfig, spaceId: string): Promise<{
|
|
382
|
+
spaceId?: string;
|
|
383
|
+
deleted?: boolean;
|
|
384
|
+
}>;
|
|
385
|
+
/** A server's archived channels, for the Archive panel. */
|
|
386
|
+
export declare function listArchivedRoomChannels(config: RoomSocialConfig, spaceId: string): Promise<Array<{
|
|
387
|
+
roomId: string;
|
|
388
|
+
name?: string;
|
|
389
|
+
title?: string;
|
|
390
|
+
archivedAt?: string;
|
|
391
|
+
}>>;
|
|
358
392
|
/** Full channel roster (paged): role + lastSeen for every membership row. */
|
|
359
393
|
export declare function listRoomChannelMembers(config: RoomSocialConfig, roomId: string, options?: {
|
|
360
394
|
offset?: number;
|
package/dist/social-client.js
CHANGED
|
@@ -567,6 +567,34 @@ export async function updateRoomSpace(config, spaceId, input) {
|
|
|
567
567
|
export async function archiveRoomSpace(config, spaceId) {
|
|
568
568
|
return socialRequest(config, `/spaces/${encodeURIComponent(spaceId)}`, { method: "DELETE" });
|
|
569
569
|
}
|
|
570
|
+
/** Un-archive a channel back onto the active sidebar (manage-room). The
|
|
571
|
+
* wire verb is /restore, the store-wide grammar shared with docs; the
|
|
572
|
+
* receipt carries `restored`, not the archive shape's `archived`. */
|
|
573
|
+
export async function unarchiveRoomChannel(config, room) {
|
|
574
|
+
return socialRequest(config, `/rooms/${encodeURIComponent(cleanRoomId(room))}/restore`, {
|
|
575
|
+
method: "POST",
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
/** PERMANENTLY delete a channel and every row keyed to it (manage-room).
|
|
579
|
+
* The bare DELETE verb on /rooms/:id is the legacy ARCHIVE shape; purge is
|
|
580
|
+
* the explicit destruction verb and there is no undo. */
|
|
581
|
+
export async function purgeRoomChannel(config, room) {
|
|
582
|
+
return socialRequest(config, `/rooms/${encodeURIComponent(cleanRoomId(room))}/purge`, {
|
|
583
|
+
method: "POST",
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
/** PERMANENTLY delete a server: every channel, message, member, role,
|
|
587
|
+
* invite, and the entire docs family (owner only; no undo). */
|
|
588
|
+
export async function purgeRoomSpace(config, spaceId) {
|
|
589
|
+
return socialRequest(config, `/spaces/${encodeURIComponent(spaceId)}/purge`, {
|
|
590
|
+
method: "POST",
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
/** A server's archived channels, for the Archive panel. */
|
|
594
|
+
export async function listArchivedRoomChannels(config, spaceId) {
|
|
595
|
+
const result = await socialRequest(config, `/spaces/${encodeURIComponent(spaceId)}/rooms/archived`, { method: "GET" });
|
|
596
|
+
return result.rooms ?? [];
|
|
597
|
+
}
|
|
570
598
|
/** Full channel roster (paged): role + lastSeen for every membership row. */
|
|
571
599
|
export async function listRoomChannelMembers(config, roomId, options = {}) {
|
|
572
600
|
const params = new URLSearchParams();
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "0.
|
|
2
|
-
export declare const RUNNER_VERSION = "0.
|
|
1
|
+
export declare const VERSION = "0.9.1";
|
|
2
|
+
export declare const RUNNER_VERSION = "0.9.1";
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const VERSION = "0.
|
|
2
|
-
export const RUNNER_VERSION = "0.
|
|
1
|
+
export const VERSION = "0.9.1";
|
|
2
|
+
export const RUNNER_VERSION = "0.9.1";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openmarket/rooms-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "OM Rooms protocol client: wire types, WebSocket + REST clients, and chat view-models. Browser-safe (no node:/bun: imports).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -129,20 +129,22 @@ export class LibraryModel {
|
|
|
129
129
|
return changed;
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
/** Upsert after our own write so the UI reflects it without waiting a poll.
|
|
132
|
+
/** Upsert after our own write so the UI reflects it without waiting a poll.
|
|
133
|
+
* Every local write (archive included) advances the receipt: our write IS
|
|
134
|
+
* the head we would otherwise refetch. */
|
|
133
135
|
applyLocalWrite(doc: RoomDoc): void {
|
|
134
136
|
const state = this.spaces.get(doc.spaceId);
|
|
135
137
|
if (!state) return;
|
|
138
|
+
if (doc.spaceDocSeq > state.cursor) {
|
|
139
|
+
state.cursor = doc.spaceDocSeq;
|
|
140
|
+
state.latestSeq = Math.max(state.latestSeq, doc.spaceDocSeq);
|
|
141
|
+
}
|
|
136
142
|
if (doc.status === "archived") {
|
|
137
143
|
state.docs.delete(doc.docId);
|
|
138
144
|
state.freshDocIds.delete(doc.docId);
|
|
139
145
|
return;
|
|
140
146
|
}
|
|
141
147
|
state.docs.set(doc.docId, doc);
|
|
142
|
-
if (doc.spaceDocSeq > state.cursor) {
|
|
143
|
-
state.cursor = doc.spaceDocSeq;
|
|
144
|
-
state.latestSeq = Math.max(state.latestSeq, doc.spaceDocSeq);
|
|
145
|
-
}
|
|
146
148
|
}
|
|
147
149
|
|
|
148
150
|
docsFor(spaceId: string): RoomDoc[] {
|
|
@@ -193,6 +195,24 @@ export class LibraryModel {
|
|
|
193
195
|
this.spaces.get(spaceId)?.freshDocIds.clear();
|
|
194
196
|
}
|
|
195
197
|
|
|
198
|
+
/**
|
|
199
|
+
* Record a server poke (DOC_CHANGED) that the space's change head moved.
|
|
200
|
+
* Bookkeeping only: latestSeq ratchets up (never down) so atHead() reports
|
|
201
|
+
* stale until a refresh catches up. Returns whether a refresh would fetch
|
|
202
|
+
* anything: false for untracked spaces, true for a seqless poke (an
|
|
203
|
+
* unconditional "something changed"), otherwise whether the poked head is
|
|
204
|
+
* ahead of the cursor. Callers own debounce/refresh scheduling, and must
|
|
205
|
+
* re-check atHead() after a refresh completes: the refresh() single-flight
|
|
206
|
+
* guard drops a poke that lands mid-refresh.
|
|
207
|
+
*/
|
|
208
|
+
noteRemoteHead(spaceId: string, latestSeq?: number): boolean {
|
|
209
|
+
const state = this.spaces.get(spaceId);
|
|
210
|
+
if (!state) return false;
|
|
211
|
+
if (latestSeq === undefined) return true;
|
|
212
|
+
state.latestSeq = Math.max(state.latestSeq, latestSeq);
|
|
213
|
+
return latestSeq > state.cursor;
|
|
214
|
+
}
|
|
215
|
+
|
|
196
216
|
/** True when the cache has provably caught up to the space's change head. */
|
|
197
217
|
atHead(spaceId: string): boolean {
|
|
198
218
|
const state = this.spaces.get(spaceId);
|
|
@@ -107,6 +107,8 @@ export const RoomServerMessageType = {
|
|
|
107
107
|
TOPIC: "TOPIC",
|
|
108
108
|
TOPICS: "TOPICS",
|
|
109
109
|
TOPIC_UPDATED: "TOPIC_UPDATED",
|
|
110
|
+
DOC_CHANGED: "DOC_CHANGED",
|
|
111
|
+
FRIEND_UPDATED: "FRIEND_UPDATED",
|
|
110
112
|
} as const;
|
|
111
113
|
|
|
112
114
|
export function addBounded<T>(set: Set<T>, value: T, max: number): void {
|
|
@@ -959,6 +961,12 @@ export interface RoomSpace {
|
|
|
959
961
|
createdAt: string | number | Date;
|
|
960
962
|
joined?: boolean | undefined;
|
|
961
963
|
iconUrl?: string | null | undefined;
|
|
964
|
+
/** Archived channels in this server (sidebar Archive row; absent on
|
|
965
|
+
* stores that predate the count). */
|
|
966
|
+
archivedRoomCount?: number | undefined;
|
|
967
|
+
/** Archived docs twin: keeps the Archive row reachable when only docs
|
|
968
|
+
* are archived. */
|
|
969
|
+
archivedDocCount?: number | undefined;
|
|
962
970
|
}
|
|
963
971
|
|
|
964
972
|
export interface RoomSpacesPayload {
|
|
@@ -1002,6 +1010,9 @@ export interface RoomUpdatedPayload {
|
|
|
1002
1010
|
room: string;
|
|
1003
1011
|
meta?: RoomMeta | undefined;
|
|
1004
1012
|
archived?: boolean | undefined;
|
|
1013
|
+
/** Rides WITH archived on hard deletion: old clients evict on archived,
|
|
1014
|
+
* new clients word the eviction honestly. */
|
|
1015
|
+
deleted?: boolean | undefined;
|
|
1005
1016
|
}
|
|
1006
1017
|
|
|
1007
1018
|
/** Server settings changed (rename / icon / archive). */
|
|
@@ -1010,6 +1021,8 @@ export interface SpaceUpdatedPayload {
|
|
|
1010
1021
|
name?: string | undefined;
|
|
1011
1022
|
iconUrl?: string | null | undefined;
|
|
1012
1023
|
archived?: boolean | undefined;
|
|
1024
|
+
/** Rides WITH archived on hard deletion (see RoomUpdatedPayload). */
|
|
1025
|
+
deleted?: boolean | undefined;
|
|
1013
1026
|
}
|
|
1014
1027
|
|
|
1015
1028
|
export interface RoomSpaceJoinedPayload {
|
|
@@ -1118,6 +1131,21 @@ export interface RoomTopicUpdatedPayload {
|
|
|
1118
1131
|
topic: RoomTopic;
|
|
1119
1132
|
}
|
|
1120
1133
|
|
|
1134
|
+
/** Poke: a space's doc-library change head moved (create/edit/archive/restore).
|
|
1135
|
+
* Deliberately content-free: clients refetch deltas over REST. */
|
|
1136
|
+
export interface RoomDocChangedPayload {
|
|
1137
|
+
spaceId: string;
|
|
1138
|
+
/** The space's change head after the mutation, when the server knows it
|
|
1139
|
+
* cheaply; absent still means "something changed, refetch". */
|
|
1140
|
+
latestSeq?: number | undefined;
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
/** Poke: the recipient's friendship graph changed. Clients refetch over REST. */
|
|
1144
|
+
export interface RoomFriendUpdatedPayload {
|
|
1145
|
+
kind: "request" | "accepted" | "rejected" | "removed";
|
|
1146
|
+
friendshipId?: string | undefined;
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1121
1149
|
export type RoomClientMessage =
|
|
1122
1150
|
| {
|
|
1123
1151
|
type: typeof RoomClientMessageType.AUTHENTICATE;
|
|
@@ -1696,6 +1724,16 @@ export type RoomServerMessage =
|
|
|
1696
1724
|
type: typeof RoomServerMessageType.TOPIC_UPDATED;
|
|
1697
1725
|
payload: RoomTopicUpdatedPayload;
|
|
1698
1726
|
timestamp: number;
|
|
1727
|
+
}
|
|
1728
|
+
| {
|
|
1729
|
+
type: typeof RoomServerMessageType.DOC_CHANGED;
|
|
1730
|
+
payload: RoomDocChangedPayload;
|
|
1731
|
+
timestamp: number;
|
|
1732
|
+
}
|
|
1733
|
+
| {
|
|
1734
|
+
type: typeof RoomServerMessageType.FRIEND_UPDATED;
|
|
1735
|
+
payload: RoomFriendUpdatedPayload;
|
|
1736
|
+
timestamp: number;
|
|
1699
1737
|
};
|
|
1700
1738
|
|
|
1701
1739
|
export type RoomServerMessageOf<T extends RoomServerMessageType> = Extract<
|
package/src/social-client.ts
CHANGED
|
@@ -671,6 +671,13 @@ export interface RoomSpaceSummary {
|
|
|
671
671
|
iconUrl?: string | null;
|
|
672
672
|
/** Creation time — the stable server-rail sort key. */
|
|
673
673
|
createdAt?: string | number | null;
|
|
674
|
+
/** Archived channels in this server; with archivedDocCount it drives
|
|
675
|
+
* the sidebar's Archive row (rendered only when the sum > 0). Absent
|
|
676
|
+
* on stores that predate the counts. */
|
|
677
|
+
archivedRoomCount?: number | undefined;
|
|
678
|
+
/** Archived docs in this server: the row must stay reachable when only
|
|
679
|
+
* docs are archived, since they have no other retrieval surface. */
|
|
680
|
+
archivedDocCount?: number | undefined;
|
|
674
681
|
}
|
|
675
682
|
|
|
676
683
|
export async function listRoomSpacesViaChat(config: RoomSocialConfig): Promise<RoomSpaceSummary[]> {
|
|
@@ -1179,6 +1186,52 @@ export async function archiveRoomSpace(
|
|
|
1179
1186
|
return socialRequest(config, `/spaces/${encodeURIComponent(spaceId)}`, { method: "DELETE" });
|
|
1180
1187
|
}
|
|
1181
1188
|
|
|
1189
|
+
/** Un-archive a channel back onto the active sidebar (manage-room). The
|
|
1190
|
+
* wire verb is /restore, the store-wide grammar shared with docs; the
|
|
1191
|
+
* receipt carries `restored`, not the archive shape's `archived`. */
|
|
1192
|
+
export async function unarchiveRoomChannel(
|
|
1193
|
+
config: RoomSocialConfig,
|
|
1194
|
+
room: string,
|
|
1195
|
+
): Promise<{ roomId?: string; restored?: boolean }> {
|
|
1196
|
+
return socialRequest(config, `/rooms/${encodeURIComponent(cleanRoomId(room))}/restore`, {
|
|
1197
|
+
method: "POST",
|
|
1198
|
+
});
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
/** PERMANENTLY delete a channel and every row keyed to it (manage-room).
|
|
1202
|
+
* The bare DELETE verb on /rooms/:id is the legacy ARCHIVE shape; purge is
|
|
1203
|
+
* the explicit destruction verb and there is no undo. */
|
|
1204
|
+
export async function purgeRoomChannel(
|
|
1205
|
+
config: RoomSocialConfig,
|
|
1206
|
+
room: string,
|
|
1207
|
+
): Promise<{ roomId?: string; deleted?: boolean }> {
|
|
1208
|
+
return socialRequest(config, `/rooms/${encodeURIComponent(cleanRoomId(room))}/purge`, {
|
|
1209
|
+
method: "POST",
|
|
1210
|
+
});
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
/** PERMANENTLY delete a server: every channel, message, member, role,
|
|
1214
|
+
* invite, and the entire docs family (owner only; no undo). */
|
|
1215
|
+
export async function purgeRoomSpace(
|
|
1216
|
+
config: RoomSocialConfig,
|
|
1217
|
+
spaceId: string,
|
|
1218
|
+
): Promise<{ spaceId?: string; deleted?: boolean }> {
|
|
1219
|
+
return socialRequest(config, `/spaces/${encodeURIComponent(spaceId)}/purge`, {
|
|
1220
|
+
method: "POST",
|
|
1221
|
+
});
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
/** A server's archived channels, for the Archive panel. */
|
|
1225
|
+
export async function listArchivedRoomChannels(
|
|
1226
|
+
config: RoomSocialConfig,
|
|
1227
|
+
spaceId: string,
|
|
1228
|
+
): Promise<Array<{ roomId: string; name?: string; title?: string; archivedAt?: string }>> {
|
|
1229
|
+
const result = await socialRequest<{
|
|
1230
|
+
rooms?: Array<{ roomId: string; name?: string; title?: string; archivedAt?: string }>;
|
|
1231
|
+
}>(config, `/spaces/${encodeURIComponent(spaceId)}/rooms/archived`, { method: "GET" });
|
|
1232
|
+
return result.rooms ?? [];
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1182
1235
|
/** Full channel roster (paged): role + lastSeen for every membership row. */
|
|
1183
1236
|
export async function listRoomChannelMembers(
|
|
1184
1237
|
config: RoomSocialConfig,
|
package/src/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const VERSION = "0.
|
|
2
|
-
export const RUNNER_VERSION = "0.
|
|
1
|
+
export const VERSION = "0.9.1";
|
|
2
|
+
export const RUNNER_VERSION = "0.9.1";
|