@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.
@@ -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);
@@ -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;
@@ -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.7.0";
2
- export declare const RUNNER_VERSION = "0.7.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.7.0";
2
- export const RUNNER_VERSION = "0.7.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.8.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<
@@ -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.7.0";
2
- export const RUNNER_VERSION = "0.7.0";
1
+ export const VERSION = "0.9.1";
2
+ export const RUNNER_VERSION = "0.9.1";