@openmarket/rooms-client 0.8.0 → 0.9.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 +23 -0
- package/dist/shared/rooms-protocol.js +2 -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 +27 -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];
|
|
@@ -975,6 +977,19 @@ export interface RoomTopicUpdatedPayload {
|
|
|
975
977
|
room: string;
|
|
976
978
|
topic: RoomTopic;
|
|
977
979
|
}
|
|
980
|
+
/** Poke: a space's doc-library change head moved (create/edit/archive/restore).
|
|
981
|
+
* Deliberately content-free: clients refetch deltas over REST. */
|
|
982
|
+
export interface RoomDocChangedPayload {
|
|
983
|
+
spaceId: string;
|
|
984
|
+
/** The space's change head after the mutation, when the server knows it
|
|
985
|
+
* cheaply; absent still means "something changed, refetch". */
|
|
986
|
+
latestSeq?: number | undefined;
|
|
987
|
+
}
|
|
988
|
+
/** Poke: the recipient's friendship graph changed. Clients refetch over REST. */
|
|
989
|
+
export interface RoomFriendUpdatedPayload {
|
|
990
|
+
kind: "request" | "accepted" | "rejected" | "removed";
|
|
991
|
+
friendshipId?: string | undefined;
|
|
992
|
+
}
|
|
978
993
|
export type RoomClientMessage = {
|
|
979
994
|
type: typeof RoomClientMessageType.AUTHENTICATE;
|
|
980
995
|
payload: {
|
|
@@ -1504,6 +1519,14 @@ export type RoomServerMessage = {
|
|
|
1504
1519
|
type: typeof RoomServerMessageType.TOPIC_UPDATED;
|
|
1505
1520
|
payload: RoomTopicUpdatedPayload;
|
|
1506
1521
|
timestamp: number;
|
|
1522
|
+
} | {
|
|
1523
|
+
type: typeof RoomServerMessageType.DOC_CHANGED;
|
|
1524
|
+
payload: RoomDocChangedPayload;
|
|
1525
|
+
timestamp: number;
|
|
1526
|
+
} | {
|
|
1527
|
+
type: typeof RoomServerMessageType.FRIEND_UPDATED;
|
|
1528
|
+
payload: RoomFriendUpdatedPayload;
|
|
1529
|
+
timestamp: number;
|
|
1507
1530
|
};
|
|
1508
1531
|
export type RoomServerMessageOf<T extends RoomServerMessageType> = Extract<RoomServerMessage, {
|
|
1509
1532
|
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/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.0";
|
|
2
|
+
export declare const RUNNER_VERSION = "0.9.0";
|
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.0";
|
|
2
|
+
export const RUNNER_VERSION = "0.9.0";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openmarket/rooms-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.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 {
|
|
@@ -1118,6 +1120,21 @@ export interface RoomTopicUpdatedPayload {
|
|
|
1118
1120
|
topic: RoomTopic;
|
|
1119
1121
|
}
|
|
1120
1122
|
|
|
1123
|
+
/** Poke: a space's doc-library change head moved (create/edit/archive/restore).
|
|
1124
|
+
* Deliberately content-free: clients refetch deltas over REST. */
|
|
1125
|
+
export interface RoomDocChangedPayload {
|
|
1126
|
+
spaceId: string;
|
|
1127
|
+
/** The space's change head after the mutation, when the server knows it
|
|
1128
|
+
* cheaply; absent still means "something changed, refetch". */
|
|
1129
|
+
latestSeq?: number | undefined;
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
/** Poke: the recipient's friendship graph changed. Clients refetch over REST. */
|
|
1133
|
+
export interface RoomFriendUpdatedPayload {
|
|
1134
|
+
kind: "request" | "accepted" | "rejected" | "removed";
|
|
1135
|
+
friendshipId?: string | undefined;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1121
1138
|
export type RoomClientMessage =
|
|
1122
1139
|
| {
|
|
1123
1140
|
type: typeof RoomClientMessageType.AUTHENTICATE;
|
|
@@ -1696,6 +1713,16 @@ export type RoomServerMessage =
|
|
|
1696
1713
|
type: typeof RoomServerMessageType.TOPIC_UPDATED;
|
|
1697
1714
|
payload: RoomTopicUpdatedPayload;
|
|
1698
1715
|
timestamp: number;
|
|
1716
|
+
}
|
|
1717
|
+
| {
|
|
1718
|
+
type: typeof RoomServerMessageType.DOC_CHANGED;
|
|
1719
|
+
payload: RoomDocChangedPayload;
|
|
1720
|
+
timestamp: number;
|
|
1721
|
+
}
|
|
1722
|
+
| {
|
|
1723
|
+
type: typeof RoomServerMessageType.FRIEND_UPDATED;
|
|
1724
|
+
payload: RoomFriendUpdatedPayload;
|
|
1725
|
+
timestamp: number;
|
|
1699
1726
|
};
|
|
1700
1727
|
|
|
1701
1728
|
export type RoomServerMessageOf<T extends RoomServerMessageType> = Extract<
|
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.0";
|
|
2
|
+
export const RUNNER_VERSION = "0.9.0";
|