@pmate/chat-sdk 0.12.0-next.1 → 0.12.0-next.2
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.
|
@@ -33,6 +33,7 @@ export declare class MessageClient<T extends StoredMessage> {
|
|
|
33
33
|
private watches;
|
|
34
34
|
private reads;
|
|
35
35
|
private syncing;
|
|
36
|
+
private paging;
|
|
36
37
|
private writes;
|
|
37
38
|
private activeWrites;
|
|
38
39
|
private writeTasks;
|
|
@@ -63,6 +64,7 @@ export declare class MessageClient<T extends StoredMessage> {
|
|
|
63
64
|
messages: T[];
|
|
64
65
|
hasEarlier: boolean;
|
|
65
66
|
}>;
|
|
67
|
+
private fillWindow;
|
|
66
68
|
revoke(thread: string): Promise<void>;
|
|
67
69
|
close(): Promise<void>;
|
|
68
70
|
}
|
|
@@ -7,6 +7,7 @@ export class MessageClient {
|
|
|
7
7
|
watches = new Map();
|
|
8
8
|
reads = new Map();
|
|
9
9
|
syncing = new Map();
|
|
10
|
+
paging = new Map();
|
|
10
11
|
writes = new Map();
|
|
11
12
|
activeWrites = new Set();
|
|
12
13
|
writeTasks;
|
|
@@ -55,6 +56,7 @@ export class MessageClient {
|
|
|
55
56
|
await this.synchronize(thread);
|
|
56
57
|
if (this.closed)
|
|
57
58
|
throw new Error("MESSAGE_CLIENT_CLOSED");
|
|
59
|
+
await this.fillWindow(thread, limit);
|
|
58
60
|
return this.reload(thread, limit);
|
|
59
61
|
})().finally(() => { if (this.reads.get(key) === task)
|
|
60
62
|
this.reads.delete(key); });
|
|
@@ -183,19 +185,33 @@ export class MessageClient {
|
|
|
183
185
|
throw new Error("MESSAGE_ACCESS_REVOKED");
|
|
184
186
|
if (!(await this.storage.read(thread, 1)).coverage?.complete)
|
|
185
187
|
await this.synchronize(thread);
|
|
188
|
+
return this.fillWindow(thread, limit, before);
|
|
189
|
+
}
|
|
190
|
+
async fillWindow(thread, limit, before) {
|
|
186
191
|
let page = await this.storage.read(thread, limit, before);
|
|
187
192
|
while (page.messages.length < limit && page.coverage?.nextBefore && this.options.transport.older) {
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
await this.storage.removeThread(thread);
|
|
194
|
-
throw new Error("MESSAGE_SYNC_RESET_REQUIRED");
|
|
193
|
+
const pending = this.paging.get(thread);
|
|
194
|
+
if (pending) {
|
|
195
|
+
await pending;
|
|
196
|
+
page = await this.storage.read(thread, limit, before);
|
|
197
|
+
continue;
|
|
195
198
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
+
const token = page.coverage.nextBefore;
|
|
200
|
+
const task = (async () => {
|
|
201
|
+
const remote = await this.options.transport.older(thread, token, this.abort.signal);
|
|
202
|
+
if (this.closed || this.revoked.has(thread))
|
|
203
|
+
throw new Error("MESSAGE_CLIENT_UNAVAILABLE");
|
|
204
|
+
if (remote.resetRequired) {
|
|
205
|
+
await this.storage.removeThread(thread);
|
|
206
|
+
throw new Error("MESSAGE_SYNC_RESET_REQUIRED");
|
|
207
|
+
}
|
|
208
|
+
if (remote.nextBefore === token)
|
|
209
|
+
throw new Error("MESSAGE_SYNC_NO_PROGRESS");
|
|
210
|
+
await this.persist(thread, remote.messages, undefined, true, remote.nextBefore ?? null);
|
|
211
|
+
})().finally(() => { if (this.paging.get(thread) === task)
|
|
212
|
+
this.paging.delete(thread); });
|
|
213
|
+
this.paging.set(thread, task);
|
|
214
|
+
await task;
|
|
199
215
|
page = await this.storage.read(thread, limit, before);
|
|
200
216
|
}
|
|
201
217
|
return { messages: page.messages, hasEarlier: page.hasEarlier || Boolean(page.coverage?.nextBefore) };
|
|
@@ -39,21 +39,33 @@ export class MessageReadersClient {
|
|
|
39
39
|
}
|
|
40
40
|
async request(input) {
|
|
41
41
|
const { token, fetch: fetcher, hubHttpUrl, appId, profileId } = this.options;
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
42
|
+
const controller = new AbortController();
|
|
43
|
+
const cancel = () => controller.abort(this.lifetime.signal.reason);
|
|
44
|
+
this.lifetime.signal.addEventListener("abort", cancel, { once: true });
|
|
45
|
+
const timeout = setTimeout(() => controller.abort(), 8000);
|
|
46
|
+
try {
|
|
47
|
+
const response = await (fetcher ?? fetch)(`${hubHttpUrl.replace(/^ws/, "http").replace(/\/+$/, "")}/api/social/reading/readers`, {
|
|
48
|
+
method: "POST", headers: { authorization: `Bearer ${token}`, "content-type": "application/json" }, body: JSON.stringify({ ...input, appId, profileId }),
|
|
49
|
+
signal: controller.signal, redirect: "error", cache: "no-store",
|
|
50
|
+
});
|
|
51
|
+
if (!response.ok)
|
|
52
|
+
throw new MessageReadersError(response.status, `MESSAGE_READERS_HTTP_${response.status}`);
|
|
53
|
+
const envelope = await response.json(), data = envelope.data;
|
|
54
|
+
if (envelope.success !== true || data?.appId !== appId || data.threadId !== input.threadId || data.messageId !== input.messageId
|
|
55
|
+
|| !Number.isSafeInteger(data.revision) || data.revision < 0 || !Number.isSafeInteger(data.total) || data.total < 0
|
|
56
|
+
|| !Array.isArray(data.profileIds) || data.profileIds.length > input.limit || data.profileIds.length > data.total
|
|
57
|
+
|| data.profileIds.some((id, i, ids) => typeof id !== "string" || !id || id.length > 512 || id === profileId || (i > 0 && id <= ids[i - 1]) || (input.afterProfileId && !data.resetRequired && id <= input.afterProfileId))
|
|
58
|
+
|| typeof data.resetRequired !== "boolean" || (data.nextAfter !== null && (typeof data.nextAfter !== "string" || data.nextAfter !== data.profileIds.at(-1)))
|
|
59
|
+
|| (!data.resetRequired && input.revision !== undefined && data.revision !== input.revision))
|
|
60
|
+
throw new Error("INVALID_MESSAGE_READERS_RESPONSE");
|
|
61
|
+
if (this.lifetime.signal.aborted)
|
|
62
|
+
throw new Error("MESSAGE_READERS_CLOSED");
|
|
63
|
+
return data;
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
clearTimeout(timeout);
|
|
67
|
+
this.lifetime.signal.removeEventListener("abort", cancel);
|
|
68
|
+
}
|
|
57
69
|
}
|
|
58
70
|
close() { this.lifetime.abort(); this.pending.clear(); }
|
|
59
71
|
}
|
package/package.json
CHANGED