@pmate/chat-sdk 0.12.0-next.32 → 0.12.0-next.33
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.
|
@@ -203,7 +203,16 @@ export class ChatSession {
|
|
|
203
203
|
}
|
|
204
204
|
synchronizeReading(cursor, profileId) { return this.readingOperation(() => this.reading.synchronize(cursor, profileId), false); }
|
|
205
205
|
/** Explicit text-history acknowledgement; unheard audio stays unread. */
|
|
206
|
-
markRead(threadId, messages
|
|
206
|
+
async markRead(threadId, messages) {
|
|
207
|
+
this.assertOpen();
|
|
208
|
+
const cached = messages ?? this.getSnapshot(threadId).timeline.flatMap(item => {
|
|
209
|
+
if (item.recalled || !item.message)
|
|
210
|
+
return [];
|
|
211
|
+
const candidate = this.options.readingCandidate?.(item.message);
|
|
212
|
+
return candidate ? [{ id: item.id, threadId, from: item.from, mine: item.mine, recalled: item.recalled, readPolicy: candidate.readPolicy }] : [];
|
|
213
|
+
});
|
|
214
|
+
return this.readingOperation(() => this.reading.markRead(threadId, cached));
|
|
215
|
+
}
|
|
207
216
|
updateReading(transform) { return this.readingOperation(() => this.reading.update(transform)); }
|
|
208
217
|
assertOpen() { if (this.withdrawn)
|
|
209
218
|
throw new Error("CHAT_ACCESS_REVOKED"); if (this.closed)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isReadingControl } from "./readingContent.js";
|
|
1
|
+
import { isReadingControl, messageRequiresPlayback, messageMentionsProfile } from "./readingContent.js";
|
|
2
2
|
import { ChatSession } from "./chatSession.js";
|
|
3
3
|
import { SocialReadClient } from "./socialReadClient.js";
|
|
4
4
|
import { chatTeamId } from "./teamScope.js";
|
|
@@ -29,7 +29,7 @@ export function createChat(options) {
|
|
|
29
29
|
if (!body || !["message", "quote"].includes(String(body.kind)) && !(body.kind === "contact" && ["friendRequest", "requestFriend"].includes(String(body.action))))
|
|
30
30
|
return undefined;
|
|
31
31
|
return { id: message.id, threadId: message.threadId, from: message.from, mine: message.from === profileId, recalled: message.recalled, unread: message.from !== profileId,
|
|
32
|
-
readPolicy:
|
|
32
|
+
readPolicy: message.readPolicy === "explicit" || message.legacyDisplay?.kind === "voice" || messageRequiresPlayback(body) ? "explicit" : "visible", attentionEligible: messageMentionsProfile(body, profileId) };
|
|
33
33
|
},
|
|
34
34
|
decode: message => decodeIncoming(message, { appId, profileId, teamId }), onError,
|
|
35
35
|
});
|
|
@@ -3,6 +3,11 @@ function content(message, appId) {
|
|
|
3
3
|
const body = message.body;
|
|
4
4
|
return body?.kind === "message" && body.content?.appId === appId ? body : undefined;
|
|
5
5
|
}
|
|
6
|
+
function nativeRecall(message, appId) {
|
|
7
|
+
const body = message.body;
|
|
8
|
+
return message.appId === appId && body?.kind === "recall" && typeof body.targetMessageId === "string" && body.targetMessageId.length > 0 && body.targetMessageId.length <= 256 ? body.targetMessageId : undefined;
|
|
9
|
+
}
|
|
10
|
+
function isControl(message, appId) { return isReadingControl(message.body, appId) || nativeRecall(message, appId) !== undefined; }
|
|
6
11
|
function validReaction(value) {
|
|
7
12
|
if (!value || typeof value !== "object")
|
|
8
13
|
return false;
|
|
@@ -42,9 +47,9 @@ export function projectMessageTimeline(input) {
|
|
|
42
47
|
reactions.set(key, event);
|
|
43
48
|
};
|
|
44
49
|
for (const { message, status } of records.values()) {
|
|
45
|
-
if (status === "failed" &&
|
|
50
|
+
if (status === "failed" && isControl(message, input.appId))
|
|
46
51
|
continue;
|
|
47
|
-
const envelope = message, body = content(envelope, input.appId), target = body?.content?.recall?.messageId;
|
|
52
|
+
const envelope = message, body = content(envelope, input.appId), target = nativeRecall(envelope, input.appId) ?? body?.content?.recall?.messageId;
|
|
48
53
|
if (typeof target === "string" && target.length > 0 && target.length <= 256 && envelope.from) {
|
|
49
54
|
if (!recalled.has(target))
|
|
50
55
|
recalled.set(target, new Set());
|
|
@@ -97,7 +102,7 @@ export function projectMessageTimeline(input) {
|
|
|
97
102
|
const result = [];
|
|
98
103
|
for (const { message, status } of records.values()) {
|
|
99
104
|
const envelope = message;
|
|
100
|
-
if (
|
|
105
|
+
if (isControl(envelope, input.appId))
|
|
101
106
|
continue;
|
|
102
107
|
const mine = envelope.from === input.profileId, reading = input.reading[message.id];
|
|
103
108
|
const withdrawn = Boolean(tombstones.has(message.id) || message.recalled || envelope.legacyDisplay?.recalled || envelope.from && recalled.get(message.id)?.has(envelope.from));
|
|
@@ -1,2 +1,5 @@
|
|
|
1
1
|
/** Social control envelopes do not contribute to message unread counts. */
|
|
2
2
|
export declare function isReadingControl(payload: unknown, appId: string): boolean;
|
|
3
|
+
/** Mirrors the server's voice policy for ordinary and quoted wire envelopes. */
|
|
4
|
+
export declare function messageRequiresPlayback(body: unknown): boolean;
|
|
5
|
+
export declare function messageMentionsProfile(body: unknown, profileId: string): boolean;
|
|
@@ -7,3 +7,17 @@ export function isReadingControl(payload, appId) {
|
|
|
7
7
|
return isReadingControl(value.body, appId);
|
|
8
8
|
return value.kind === "message" && value.content?.appId === appId && (value.content.reaction !== undefined || value.content.recall !== undefined);
|
|
9
9
|
}
|
|
10
|
+
/** Mirrors the server's voice policy for ordinary and quoted wire envelopes. */
|
|
11
|
+
export function messageRequiresPlayback(body) {
|
|
12
|
+
if (!body || typeof body !== "object")
|
|
13
|
+
return false;
|
|
14
|
+
const value = body;
|
|
15
|
+
return value.contentKind === "voice" || value.content?.contentKind === "voice" || [value.content?.voice?.url, value.content?.content?.voice?.url].some(url => typeof url === "string" && url.length > 0);
|
|
16
|
+
}
|
|
17
|
+
export function messageMentionsProfile(body, profileId) {
|
|
18
|
+
if (!body || typeof body !== "object")
|
|
19
|
+
return false;
|
|
20
|
+
const content = body.content;
|
|
21
|
+
const mentions = content?.mentions !== undefined ? content.mentions : content?.content?.mentions;
|
|
22
|
+
return Array.isArray(mentions) && mentions.some(mention => mention?.id === profileId);
|
|
23
|
+
}
|
package/package.json
CHANGED