@pmate/chat-sdk 0.7.2 → 0.7.4
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/lib/runtime/chatClient.d.ts +4 -0
- package/lib/runtime/chatClient.js +13 -1
- package/lib/runtime/index.d.ts +2 -0
- package/lib/runtime/index.js +2 -0
- package/lib/runtime/updater.d.ts +11 -0
- package/lib/runtime/updater.js +55 -0
- package/lib/runtime/updates.d.ts +14 -0
- package/lib/runtime/updates.js +12 -0
- package/package.json +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type ChatPresence } from "./presence.js";
|
|
2
|
+
import { type ChatUpdate } from "./updates.js";
|
|
2
3
|
import { ChatActivityPublisher, type ActivityTarget, type ChatActivity, type ChatActivityState, type ChatActivityUpdate } from "./activity.js";
|
|
3
4
|
import type { ChatMention } from "../mentions/model";
|
|
4
5
|
import { type BotLoginSession } from "./botAuth.js";
|
|
@@ -39,6 +40,8 @@ export declare class ChatClient {
|
|
|
39
40
|
private readonly publishers;
|
|
40
41
|
private readonly pendingAcks;
|
|
41
42
|
private readonly messageHandlers;
|
|
43
|
+
private readonly updateHandlers;
|
|
44
|
+
watchUpdates(handler: (update: ChatUpdate) => void): () => void;
|
|
42
45
|
constructor(options: ChatClientOptions);
|
|
43
46
|
connect(): Promise<this>;
|
|
44
47
|
private initialize;
|
|
@@ -93,6 +96,7 @@ export declare class ChatClient {
|
|
|
93
96
|
addMembers?: string[];
|
|
94
97
|
removeMembers?: string[];
|
|
95
98
|
title?: string;
|
|
99
|
+
avatar?: string;
|
|
96
100
|
}): Promise<ChatRuntimeMessage>;
|
|
97
101
|
sendGroup(input: {
|
|
98
102
|
groupId: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ChatPresenceClient } from "./presence.js";
|
|
2
|
+
import { parseChatUpdate } from "./updates.js";
|
|
2
3
|
import { ChatActivityStore, ChatActivityPublisher, createActivityMessage, parseChatActivity } from "./activity.js";
|
|
3
4
|
import { loginPmateBot } from "./botAuth.js";
|
|
4
5
|
import { parsePmateBotKeyJson } from "./botKey.js";
|
|
@@ -25,6 +26,11 @@ export class ChatClient {
|
|
|
25
26
|
publishers = new Set();
|
|
26
27
|
pendingAcks = new Map();
|
|
27
28
|
messageHandlers = new Set();
|
|
29
|
+
updateHandlers = new Set();
|
|
30
|
+
watchUpdates(handler) {
|
|
31
|
+
this.updateHandlers.add(handler);
|
|
32
|
+
return () => { this.updateHandlers.delete(handler); };
|
|
33
|
+
}
|
|
28
34
|
constructor(options) {
|
|
29
35
|
this.options = options;
|
|
30
36
|
if (options.botKey) {
|
|
@@ -221,7 +227,7 @@ export class ChatClient {
|
|
|
221
227
|
return this.sendChat(input.groupId, {
|
|
222
228
|
kind: "group", threadKind: "group", action: "groupUpdate",
|
|
223
229
|
payload: { appId: this.options.appId, groupId: input.groupId, expectedRevision: input.expectedRevision,
|
|
224
|
-
addMembers: input.addMembers ?? [], removeMembers: input.removeMembers ?? [], ...(input.title !== undefined ? { title: input.title } : {}) },
|
|
230
|
+
addMembers: input.addMembers ?? [], removeMembers: input.removeMembers ?? [], ...(input.title !== undefined ? { title: input.title } : {}), ...(input.avatar !== undefined ? { avatar: input.avatar } : {}) },
|
|
225
231
|
});
|
|
226
232
|
}
|
|
227
233
|
async sendGroup(input) {
|
|
@@ -288,6 +294,12 @@ export class ChatClient {
|
|
|
288
294
|
return ack;
|
|
289
295
|
}
|
|
290
296
|
handleIncoming(message) {
|
|
297
|
+
const update = parseChatUpdate(message, this.options.appId);
|
|
298
|
+
if (update) {
|
|
299
|
+
for (const handler of this.updateHandlers)
|
|
300
|
+
handler(update);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
291
303
|
if (message.opcode === ChatMsgOp.ACK) {
|
|
292
304
|
const ack = message.body;
|
|
293
305
|
const pending = this.pendingAcks.get(ack.ackOf);
|
package/lib/runtime/index.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ export * from "./chatClient.js";
|
|
|
4
4
|
export * from "./protocol.js";
|
|
5
5
|
export * from "./readerClient.js";
|
|
6
6
|
export * from "./thread.js";
|
|
7
|
+
export * from "./updater.js";
|
|
8
|
+
export * from "./updates.js";
|
|
7
9
|
export * from "./activity.js";
|
|
8
10
|
export * from "./call.js";
|
|
9
11
|
export * from "./presence.js";
|
package/lib/runtime/index.js
CHANGED
|
@@ -4,6 +4,8 @@ export * from "./chatClient.js";
|
|
|
4
4
|
export * from "./protocol.js";
|
|
5
5
|
export * from "./readerClient.js";
|
|
6
6
|
export * from "./thread.js";
|
|
7
|
+
export * from "./updater.js";
|
|
8
|
+
export * from "./updates.js";
|
|
7
9
|
export * from "./activity.js";
|
|
8
10
|
export * from "./call.js";
|
|
9
11
|
export * from "./presence.js";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** 按资源键合并刷新任务;聊天正文不经过此调度器。 */
|
|
2
|
+
export declare class RefreshUpdater {
|
|
3
|
+
private readonly windowMs;
|
|
4
|
+
private readonly onError;
|
|
5
|
+
private tasks;
|
|
6
|
+
private closed;
|
|
7
|
+
constructor(windowMs?: number, onError?: (error: unknown, key: string) => void);
|
|
8
|
+
invalidate(key: string, refresh: () => Promise<void>): void;
|
|
9
|
+
close(): void;
|
|
10
|
+
private run;
|
|
11
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** 按资源键合并刷新任务;聊天正文不经过此调度器。 */
|
|
2
|
+
export class RefreshUpdater {
|
|
3
|
+
windowMs;
|
|
4
|
+
onError;
|
|
5
|
+
tasks = new Map();
|
|
6
|
+
closed = false;
|
|
7
|
+
constructor(windowMs = 3_000, onError = () => { }) {
|
|
8
|
+
this.windowMs = windowMs;
|
|
9
|
+
this.onError = onError;
|
|
10
|
+
}
|
|
11
|
+
invalidate(key, refresh) {
|
|
12
|
+
if (this.closed)
|
|
13
|
+
return;
|
|
14
|
+
let task = this.tasks.get(key);
|
|
15
|
+
if (!task) {
|
|
16
|
+
task = { running: false, due: false, refresh };
|
|
17
|
+
this.tasks.set(key, task);
|
|
18
|
+
}
|
|
19
|
+
task.refresh = refresh;
|
|
20
|
+
if (task.timer || task.due)
|
|
21
|
+
return;
|
|
22
|
+
task.timer = setTimeout(() => {
|
|
23
|
+
task.timer = undefined;
|
|
24
|
+
task.due = true;
|
|
25
|
+
void this.run(key, task);
|
|
26
|
+
}, this.windowMs);
|
|
27
|
+
}
|
|
28
|
+
close() {
|
|
29
|
+
this.closed = true;
|
|
30
|
+
for (const task of this.tasks.values())
|
|
31
|
+
clearTimeout(task.timer);
|
|
32
|
+
this.tasks.clear();
|
|
33
|
+
}
|
|
34
|
+
async run(key, task) {
|
|
35
|
+
if (this.closed || task.running || !task.due)
|
|
36
|
+
return;
|
|
37
|
+
task.running = true;
|
|
38
|
+
task.due = false;
|
|
39
|
+
try {
|
|
40
|
+
await task.refresh();
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
this.onError(error, key);
|
|
44
|
+
if (!this.closed)
|
|
45
|
+
this.invalidate(key, task.refresh);
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
task.running = false;
|
|
49
|
+
if (!this.closed && task.due)
|
|
50
|
+
void this.run(key, task);
|
|
51
|
+
else if (!task.timer)
|
|
52
|
+
this.tasks.delete(key);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type ChatUpdateType = "org.members.changed" | "org.profiles.changed";
|
|
2
|
+
export type ChatUpdate = {
|
|
3
|
+
eventId: string;
|
|
4
|
+
appId: string;
|
|
5
|
+
orgId: string;
|
|
6
|
+
type: ChatUpdateType;
|
|
7
|
+
revision: string;
|
|
8
|
+
};
|
|
9
|
+
/** Accept only silent updater deliveries from the trusted Hub notification sender. */
|
|
10
|
+
export declare function parseChatUpdate(message: {
|
|
11
|
+
opcode: number;
|
|
12
|
+
from: string;
|
|
13
|
+
body: unknown;
|
|
14
|
+
}, appId: string): ChatUpdate | null;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Accept only silent updater deliveries from the trusted Hub notification sender. */
|
|
2
|
+
export function parseChatUpdate(message, appId) {
|
|
3
|
+
if (message.opcode !== 5 || message.from !== "@hub/notifications")
|
|
4
|
+
return null;
|
|
5
|
+
const body = message.body;
|
|
6
|
+
const data = body?.data;
|
|
7
|
+
if (body?.kind !== "delivery" || body.displayPolicy !== "silent" || !data || data.appId !== appId
|
|
8
|
+
|| !["org.members.changed", "org.profiles.changed"].includes(String(data.type))
|
|
9
|
+
|| typeof body.notificationId !== "string" || typeof data.orgId !== "string" || typeof data.revision !== "string")
|
|
10
|
+
return null;
|
|
11
|
+
return { eventId: body.notificationId, appId, orgId: data.orgId, type: data.type, revision: data.revision };
|
|
12
|
+
}
|