@openclaw/matrix 2026.3.13 → 2026.5.10-beta.1
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/account-config-D2W-V1eQ.js +96 -0
- package/dist/account-selection-BWwIruri.js +158 -0
- package/dist/accounts-Bm90Rzvp.js +130 -0
- package/dist/active-client-uhlxdhEy.js +20 -0
- package/dist/allowlist-sTzpCn5d.js +68 -0
- package/dist/api.js +12 -0
- package/dist/approval-handler.runtime-DWTQfd4m.js +370 -0
- package/dist/approval-ids-DoC2z7tR.js +7 -0
- package/dist/approval-reaction-auth-DbcA1gGd.js +27 -0
- package/dist/approval-reactions-o2_tuH8D.js +162 -0
- package/dist/async-lock-uQfhfQIY.js +19 -0
- package/dist/auth-presence.js +26 -0
- package/dist/backup-health-Cabu_WQC.js +60 -0
- package/dist/channel-H_6lMgwf.js +1116 -0
- package/dist/channel-plugin-api.js +2 -0
- package/dist/channel.runtime-BnO9f0pR.js +246 -0
- package/dist/cli-CYZ9yVcB.js +1340 -0
- package/dist/cli-metadata-DPIHnoa6.js +22 -0
- package/dist/cli-metadata.js +2 -0
- package/dist/client-DkcXnm0X.js +25 -0
- package/dist/client-_hckQNGW.js +31 -0
- package/dist/client-bootstrap-Rb8oHvhH.js +114 -0
- package/dist/config--5-S2Akv.js +452 -0
- package/dist/config-paths-nsVaysCu.js +19 -0
- package/dist/config-schema-nPLpEgHl.js +200 -0
- package/dist/config-secret-input.runtime-DiKFehsE.js +2 -0
- package/dist/config-update-wZX-HLMn.js +143 -0
- package/dist/contract-api.js +9 -0
- package/dist/create-client-DCnqDaqd.js +64 -0
- package/dist/credentials-DV6fWXhC.js +56 -0
- package/dist/credentials-read-cmHgousK.js +112 -0
- package/dist/credentials-write.runtime-zniTq-Gr.js +17 -0
- package/dist/crypto-node.runtime-pihzdpY7.js +12 -0
- package/dist/crypto-runtime-ZI0zAtn3.js +1214 -0
- package/dist/deps-C6WqKY7m.js +235 -0
- package/dist/device-health-UVYpbA_W.js +16 -0
- package/dist/direct-management-DMMMgtTB.js +249 -0
- package/dist/direct-room-XkutHjES.js +76 -0
- package/dist/directory-live-DmOtMhyr.js +150 -0
- package/dist/doctor-C4__7c-U.js +153 -0
- package/dist/doctor-contract-D4-64QuJ.js +246 -0
- package/dist/doctor-contract-api.js +2 -0
- package/dist/draft-stream-BE2QevQQ.js +144 -0
- package/dist/encryption-guidance-BPi3A_m3.js +15 -0
- package/dist/env-auth-BJqGI8M6.js +63 -0
- package/dist/env-vars-C7uQCTKn.js +63 -0
- package/dist/errors-CTcpEDq-.js +17 -0
- package/dist/exec-approval-resolver-Bza9Dhlm.js +15 -0
- package/dist/exec-approvals-Crnh543m.js +196 -0
- package/dist/helper-api.js +4 -0
- package/dist/http-client-C7AeVJay.js +319 -0
- package/dist/index.js +46 -0
- package/dist/legacy-crypto-inspector-poDWldgy.js +41 -0
- package/dist/legacy-crypto-restore-Biw-w2ng.js +85 -0
- package/dist/logger-CnZRVrux.js +78 -0
- package/dist/logging-DZHSPP5N.js +99 -0
- package/dist/matrix-migration.runtime-WY6ffcrf.js +525 -0
- package/dist/media-text-DU6nWZuj.js +146 -0
- package/dist/messages-BpihMh82.js +140 -0
- package/dist/migration-snapshot-backup-DaCHTp8C.js +69 -0
- package/dist/migration-snapshot.runtime-CKHE3xF9.js +2 -0
- package/dist/monitor-BaRCKyLd.js +4175 -0
- package/dist/plugin-entry.handlers.runtime.js +51 -0
- package/dist/probe.runtime-BvAzYAIe.js +3 -0
- package/dist/profile-BlHu0wDX.js +111 -0
- package/dist/profile-update-DjeBNgIV.js +69 -0
- package/dist/reaction-common-ejrL19w-.js +71 -0
- package/dist/reaction-events-CiARZfjk.js +121 -0
- package/dist/record-shared-CHWJCTWf.js +2 -0
- package/dist/recovery-key-store-BTJ6jz5v.js +294 -0
- package/dist/resolve-targets-YtJnw1Tb.js +140 -0
- package/dist/resolver.runtime-D9piiGEl.js +5 -0
- package/dist/rolldown-runtime-DUslC3ob.js +14 -0
- package/dist/route-D6rg-iXN.js +161 -0
- package/dist/runtime-C6X4h_SJ.js +6 -0
- package/dist/runtime-Dog86njy.js +8 -0
- package/dist/runtime-api-DTKcXOhp.js +24 -0
- package/dist/runtime-api.js +25 -0
- package/dist/runtime-heavy-api.js +3 -0
- package/dist/runtime-setter-api.js +2 -0
- package/dist/sdk-B2vZA27-.js +1416 -0
- package/dist/secret-contract-DcrJWCQI.js +120 -0
- package/dist/secret-contract-api.js +2 -0
- package/dist/send-Bo0DU1ca.js +1200 -0
- package/dist/session-store-metadata-DQXjgNLt.js +77 -0
- package/dist/setup-bootstrap-ImenBsMt.js +62 -0
- package/dist/setup-core-CfZy05oW.js +116 -0
- package/dist/setup-dm-policy-2-r1FrQh.js +194 -0
- package/dist/setup-entry.js +19 -0
- package/dist/setup-plugin-api.js +44 -0
- package/dist/setup-surface-CqT_o61M.js +540 -0
- package/dist/shared-CpMoYKm1.js +195 -0
- package/dist/startup-abort-56edvmbM.js +32 -0
- package/dist/startup-verification-Demyp0bP.js +132 -0
- package/dist/storage-paths-BJLdnCjV.js +52 -0
- package/dist/storage-tC3ujLiW.js +281 -0
- package/dist/subagent-hooks-DQbyqq9V.js +149 -0
- package/dist/subagent-hooks-api.js +23 -0
- package/dist/sync-state-C_beeevA.js +12 -0
- package/dist/target-ids-80nQ2gql.js +77 -0
- package/dist/test-api.js +4 -0
- package/dist/thread-binding-api-Cq_E-E1K.js +17 -0
- package/dist/thread-binding-api.js +2 -0
- package/dist/thread-bindings-B9mesxXk.js +352 -0
- package/dist/thread-bindings-runtime.js +2 -0
- package/dist/thread-bindings-shared-DK-d-oYX.js +97 -0
- package/dist/timeout-abort-signal-CtaIaP1v.js +2 -0
- package/dist/tool-actions.runtime-ThYhfHtZ.js +532 -0
- package/dist/url-validation-DiK9j7jz.js +36 -0
- package/dist/verification-CZ2rDeHL.js +345 -0
- package/openclaw.plugin.json +796 -1
- package/package.json +82 -16
- package/CHANGELOG.md +0 -104
- package/index.ts +0 -22
- package/src/actions.ts +0 -195
- package/src/channel.directory.test.ts +0 -135
- package/src/channel.ts +0 -461
- package/src/config-schema.test.ts +0 -26
- package/src/config-schema.ts +0 -62
- package/src/directory-live.test.ts +0 -85
- package/src/directory-live.ts +0 -209
- package/src/group-mentions.ts +0 -52
- package/src/matrix/accounts.test.ts +0 -131
- package/src/matrix/accounts.ts +0 -114
- package/src/matrix/actions/client.ts +0 -47
- package/src/matrix/actions/limits.test.ts +0 -15
- package/src/matrix/actions/limits.ts +0 -6
- package/src/matrix/actions/messages.ts +0 -126
- package/src/matrix/actions/pins.test.ts +0 -74
- package/src/matrix/actions/pins.ts +0 -84
- package/src/matrix/actions/reactions.test.ts +0 -109
- package/src/matrix/actions/reactions.ts +0 -102
- package/src/matrix/actions/room.ts +0 -85
- package/src/matrix/actions/summary.ts +0 -75
- package/src/matrix/actions/types.ts +0 -85
- package/src/matrix/actions.ts +0 -15
- package/src/matrix/active-client.ts +0 -32
- package/src/matrix/client/config.ts +0 -245
- package/src/matrix/client/create-client.ts +0 -125
- package/src/matrix/client/logging.ts +0 -46
- package/src/matrix/client/runtime.ts +0 -4
- package/src/matrix/client/shared.test.ts +0 -85
- package/src/matrix/client/shared.ts +0 -210
- package/src/matrix/client/startup.test.ts +0 -49
- package/src/matrix/client/startup.ts +0 -29
- package/src/matrix/client/storage.ts +0 -131
- package/src/matrix/client/types.ts +0 -34
- package/src/matrix/client-bootstrap.ts +0 -47
- package/src/matrix/client.test.ts +0 -56
- package/src/matrix/client.ts +0 -14
- package/src/matrix/credentials.ts +0 -125
- package/src/matrix/deps.test.ts +0 -74
- package/src/matrix/deps.ts +0 -126
- package/src/matrix/format.test.ts +0 -33
- package/src/matrix/format.ts +0 -22
- package/src/matrix/index.ts +0 -11
- package/src/matrix/monitor/access-policy.ts +0 -126
- package/src/matrix/monitor/allowlist.test.ts +0 -45
- package/src/matrix/monitor/allowlist.ts +0 -94
- package/src/matrix/monitor/auto-join.ts +0 -72
- package/src/matrix/monitor/direct.test.ts +0 -396
- package/src/matrix/monitor/direct.ts +0 -152
- package/src/matrix/monitor/events.test.ts +0 -186
- package/src/matrix/monitor/events.ts +0 -168
- package/src/matrix/monitor/handler.body-for-agent.test.ts +0 -196
- package/src/matrix/monitor/handler.ts +0 -768
- package/src/matrix/monitor/inbound-body.test.ts +0 -73
- package/src/matrix/monitor/inbound-body.ts +0 -28
- package/src/matrix/monitor/index.test.ts +0 -18
- package/src/matrix/monitor/index.ts +0 -414
- package/src/matrix/monitor/location.ts +0 -100
- package/src/matrix/monitor/media.test.ts +0 -86
- package/src/matrix/monitor/media.ts +0 -118
- package/src/matrix/monitor/mentions.test.ts +0 -154
- package/src/matrix/monitor/mentions.ts +0 -62
- package/src/matrix/monitor/replies.test.ts +0 -184
- package/src/matrix/monitor/replies.ts +0 -124
- package/src/matrix/monitor/room-info.ts +0 -55
- package/src/matrix/monitor/rooms.test.ts +0 -124
- package/src/matrix/monitor/rooms.ts +0 -47
- package/src/matrix/monitor/threads.ts +0 -68
- package/src/matrix/monitor/types.ts +0 -39
- package/src/matrix/poll-types.test.ts +0 -21
- package/src/matrix/poll-types.ts +0 -167
- package/src/matrix/probe.ts +0 -69
- package/src/matrix/sdk-runtime.ts +0 -18
- package/src/matrix/send/client.ts +0 -99
- package/src/matrix/send/formatting.ts +0 -93
- package/src/matrix/send/media.ts +0 -230
- package/src/matrix/send/targets.test.ts +0 -98
- package/src/matrix/send/targets.ts +0 -150
- package/src/matrix/send/types.ts +0 -110
- package/src/matrix/send-queue.test.ts +0 -145
- package/src/matrix/send-queue.ts +0 -28
- package/src/matrix/send.test.ts +0 -319
- package/src/matrix/send.ts +0 -267
- package/src/onboarding.ts +0 -462
- package/src/outbound.test.ts +0 -159
- package/src/outbound.ts +0 -58
- package/src/resolve-targets.test.ts +0 -68
- package/src/resolve-targets.ts +0 -125
- package/src/runtime.ts +0 -6
- package/src/secret-input.ts +0 -13
- package/src/test-mocks.ts +0 -53
- package/src/tool-actions.ts +0 -164
- package/src/types.ts +0 -118
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
import type { MatrixClient } from "@vector-im/matrix-bot-sdk";
|
|
2
|
-
import { EventType, type MatrixDirectAccountData } from "./types.js";
|
|
3
|
-
|
|
4
|
-
function normalizeTarget(raw: string): string {
|
|
5
|
-
const trimmed = raw.trim();
|
|
6
|
-
if (!trimmed) {
|
|
7
|
-
throw new Error("Matrix target is required (room:<id> or #alias)");
|
|
8
|
-
}
|
|
9
|
-
return trimmed;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function normalizeThreadId(raw?: string | number | null): string | null {
|
|
13
|
-
if (raw === undefined || raw === null) {
|
|
14
|
-
return null;
|
|
15
|
-
}
|
|
16
|
-
const trimmed = String(raw).trim();
|
|
17
|
-
return trimmed ? trimmed : null;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// Size-capped to prevent unbounded growth (#4948)
|
|
21
|
-
const MAX_DIRECT_ROOM_CACHE_SIZE = 1024;
|
|
22
|
-
const directRoomCache = new Map<string, string>();
|
|
23
|
-
function setDirectRoomCached(key: string, value: string): void {
|
|
24
|
-
directRoomCache.set(key, value);
|
|
25
|
-
if (directRoomCache.size > MAX_DIRECT_ROOM_CACHE_SIZE) {
|
|
26
|
-
const oldest = directRoomCache.keys().next().value;
|
|
27
|
-
if (oldest !== undefined) {
|
|
28
|
-
directRoomCache.delete(oldest);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
async function persistDirectRoom(
|
|
34
|
-
client: MatrixClient,
|
|
35
|
-
userId: string,
|
|
36
|
-
roomId: string,
|
|
37
|
-
): Promise<void> {
|
|
38
|
-
let directContent: MatrixDirectAccountData | null = null;
|
|
39
|
-
try {
|
|
40
|
-
directContent = await client.getAccountData(EventType.Direct);
|
|
41
|
-
} catch {
|
|
42
|
-
// Ignore fetch errors and fall back to an empty map.
|
|
43
|
-
}
|
|
44
|
-
const existing = directContent && !Array.isArray(directContent) ? directContent : {};
|
|
45
|
-
const current = Array.isArray(existing[userId]) ? existing[userId] : [];
|
|
46
|
-
if (current[0] === roomId) {
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
const next = [roomId, ...current.filter((id) => id !== roomId)];
|
|
50
|
-
try {
|
|
51
|
-
await client.setAccountData(EventType.Direct, {
|
|
52
|
-
...existing,
|
|
53
|
-
[userId]: next,
|
|
54
|
-
});
|
|
55
|
-
} catch {
|
|
56
|
-
// Ignore persistence errors.
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
async function resolveDirectRoomId(client: MatrixClient, userId: string): Promise<string> {
|
|
61
|
-
const trimmed = userId.trim();
|
|
62
|
-
if (!trimmed.startsWith("@")) {
|
|
63
|
-
throw new Error(`Matrix user IDs must be fully qualified (got "${trimmed}")`);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const cached = directRoomCache.get(trimmed);
|
|
67
|
-
if (cached) {
|
|
68
|
-
return cached;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// 1) Fast path: use account data (m.direct) for *this* logged-in user (the bot).
|
|
72
|
-
try {
|
|
73
|
-
const directContent = (await client.getAccountData(EventType.Direct)) as Record<
|
|
74
|
-
string,
|
|
75
|
-
string[] | undefined
|
|
76
|
-
>;
|
|
77
|
-
const list = Array.isArray(directContent?.[trimmed]) ? directContent[trimmed] : [];
|
|
78
|
-
if (list && list.length > 0) {
|
|
79
|
-
setDirectRoomCached(trimmed, list[0]);
|
|
80
|
-
return list[0];
|
|
81
|
-
}
|
|
82
|
-
} catch {
|
|
83
|
-
// Ignore and fall back.
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// 2) Fallback: look for an existing joined room that looks like a 1:1 with the user.
|
|
87
|
-
// Many clients only maintain m.direct for *their own* account data, so relying on it is brittle.
|
|
88
|
-
let fallbackRoom: string | null = null;
|
|
89
|
-
try {
|
|
90
|
-
const rooms = await client.getJoinedRooms();
|
|
91
|
-
for (const roomId of rooms) {
|
|
92
|
-
let members: string[];
|
|
93
|
-
try {
|
|
94
|
-
members = await client.getJoinedRoomMembers(roomId);
|
|
95
|
-
} catch {
|
|
96
|
-
continue;
|
|
97
|
-
}
|
|
98
|
-
if (!members.includes(trimmed)) {
|
|
99
|
-
continue;
|
|
100
|
-
}
|
|
101
|
-
// Prefer classic 1:1 rooms, but allow larger rooms if requested.
|
|
102
|
-
if (members.length === 2) {
|
|
103
|
-
setDirectRoomCached(trimmed, roomId);
|
|
104
|
-
await persistDirectRoom(client, trimmed, roomId);
|
|
105
|
-
return roomId;
|
|
106
|
-
}
|
|
107
|
-
if (!fallbackRoom) {
|
|
108
|
-
fallbackRoom = roomId;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
} catch {
|
|
112
|
-
// Ignore and fall back.
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (fallbackRoom) {
|
|
116
|
-
setDirectRoomCached(trimmed, fallbackRoom);
|
|
117
|
-
await persistDirectRoom(client, trimmed, fallbackRoom);
|
|
118
|
-
return fallbackRoom;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
throw new Error(`No direct room found for ${trimmed} (m.direct missing)`);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export async function resolveMatrixRoomId(client: MatrixClient, raw: string): Promise<string> {
|
|
125
|
-
const target = normalizeTarget(raw);
|
|
126
|
-
const lowered = target.toLowerCase();
|
|
127
|
-
if (lowered.startsWith("matrix:")) {
|
|
128
|
-
return await resolveMatrixRoomId(client, target.slice("matrix:".length));
|
|
129
|
-
}
|
|
130
|
-
if (lowered.startsWith("room:")) {
|
|
131
|
-
return await resolveMatrixRoomId(client, target.slice("room:".length));
|
|
132
|
-
}
|
|
133
|
-
if (lowered.startsWith("channel:")) {
|
|
134
|
-
return await resolveMatrixRoomId(client, target.slice("channel:".length));
|
|
135
|
-
}
|
|
136
|
-
if (lowered.startsWith("user:")) {
|
|
137
|
-
return await resolveDirectRoomId(client, target.slice("user:".length));
|
|
138
|
-
}
|
|
139
|
-
if (target.startsWith("@")) {
|
|
140
|
-
return await resolveDirectRoomId(client, target);
|
|
141
|
-
}
|
|
142
|
-
if (target.startsWith("#")) {
|
|
143
|
-
const resolved = await client.resolveRoom(target);
|
|
144
|
-
if (!resolved) {
|
|
145
|
-
throw new Error(`Matrix alias ${target} could not be resolved`);
|
|
146
|
-
}
|
|
147
|
-
return resolved;
|
|
148
|
-
}
|
|
149
|
-
return target;
|
|
150
|
-
}
|
package/src/matrix/send/types.ts
DELETED
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
DimensionalFileInfo,
|
|
3
|
-
EncryptedFile,
|
|
4
|
-
FileWithThumbnailInfo,
|
|
5
|
-
MessageEventContent,
|
|
6
|
-
TextualMessageEventContent,
|
|
7
|
-
TimedFileInfo,
|
|
8
|
-
VideoFileInfo,
|
|
9
|
-
} from "@vector-im/matrix-bot-sdk";
|
|
10
|
-
|
|
11
|
-
// Message types
|
|
12
|
-
export const MsgType = {
|
|
13
|
-
Text: "m.text",
|
|
14
|
-
Image: "m.image",
|
|
15
|
-
Audio: "m.audio",
|
|
16
|
-
Video: "m.video",
|
|
17
|
-
File: "m.file",
|
|
18
|
-
Notice: "m.notice",
|
|
19
|
-
} as const;
|
|
20
|
-
|
|
21
|
-
// Relation types
|
|
22
|
-
export const RelationType = {
|
|
23
|
-
Annotation: "m.annotation",
|
|
24
|
-
Replace: "m.replace",
|
|
25
|
-
Thread: "m.thread",
|
|
26
|
-
} as const;
|
|
27
|
-
|
|
28
|
-
// Event types
|
|
29
|
-
export const EventType = {
|
|
30
|
-
Direct: "m.direct",
|
|
31
|
-
Reaction: "m.reaction",
|
|
32
|
-
RoomMessage: "m.room.message",
|
|
33
|
-
} as const;
|
|
34
|
-
|
|
35
|
-
export type MatrixDirectAccountData = Record<string, string[]>;
|
|
36
|
-
|
|
37
|
-
export type MatrixReplyRelation = {
|
|
38
|
-
"m.in_reply_to": { event_id: string };
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export type MatrixThreadRelation = {
|
|
42
|
-
rel_type: typeof RelationType.Thread;
|
|
43
|
-
event_id: string;
|
|
44
|
-
is_falling_back?: boolean;
|
|
45
|
-
"m.in_reply_to"?: { event_id: string };
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
export type MatrixRelation = MatrixReplyRelation | MatrixThreadRelation;
|
|
49
|
-
|
|
50
|
-
export type MatrixReplyMeta = {
|
|
51
|
-
"m.relates_to"?: MatrixRelation;
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
export type MatrixMediaInfo =
|
|
55
|
-
| FileWithThumbnailInfo
|
|
56
|
-
| DimensionalFileInfo
|
|
57
|
-
| TimedFileInfo
|
|
58
|
-
| VideoFileInfo;
|
|
59
|
-
|
|
60
|
-
export type MatrixTextContent = TextualMessageEventContent & MatrixReplyMeta;
|
|
61
|
-
|
|
62
|
-
export type MatrixMediaContent = MessageEventContent &
|
|
63
|
-
MatrixReplyMeta & {
|
|
64
|
-
info?: MatrixMediaInfo;
|
|
65
|
-
url?: string;
|
|
66
|
-
file?: EncryptedFile;
|
|
67
|
-
filename?: string;
|
|
68
|
-
"org.matrix.msc3245.voice"?: Record<string, never>;
|
|
69
|
-
"org.matrix.msc1767.audio"?: { duration: number };
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
export type MatrixOutboundContent = MatrixTextContent | MatrixMediaContent;
|
|
73
|
-
|
|
74
|
-
export type ReactionEventContent = {
|
|
75
|
-
"m.relates_to": {
|
|
76
|
-
rel_type: typeof RelationType.Annotation;
|
|
77
|
-
event_id: string;
|
|
78
|
-
key: string;
|
|
79
|
-
};
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
export type MatrixSendResult = {
|
|
83
|
-
messageId: string;
|
|
84
|
-
roomId: string;
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
export type MatrixSendOpts = {
|
|
88
|
-
cfg?: import("../../types.js").CoreConfig;
|
|
89
|
-
client?: import("@vector-im/matrix-bot-sdk").MatrixClient;
|
|
90
|
-
mediaUrl?: string;
|
|
91
|
-
accountId?: string;
|
|
92
|
-
replyToId?: string;
|
|
93
|
-
threadId?: string | number | null;
|
|
94
|
-
timeoutMs?: number;
|
|
95
|
-
/** Send audio as voice message (voice bubble) instead of audio file. Defaults to false. */
|
|
96
|
-
audioAsVoice?: boolean;
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
export type MatrixMediaMsgType =
|
|
100
|
-
| typeof MsgType.Image
|
|
101
|
-
| typeof MsgType.Audio
|
|
102
|
-
| typeof MsgType.Video
|
|
103
|
-
| typeof MsgType.File;
|
|
104
|
-
|
|
105
|
-
export type MediaKind = "image" | "audio" | "video" | "document" | "unknown";
|
|
106
|
-
|
|
107
|
-
export type MatrixFormattedContent = MessageEventContent & {
|
|
108
|
-
format?: string;
|
|
109
|
-
formatted_body?: string;
|
|
110
|
-
};
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
import { createDeferred } from "../../../shared/deferred.js";
|
|
3
|
-
import { DEFAULT_SEND_GAP_MS, enqueueSend } from "./send-queue.js";
|
|
4
|
-
|
|
5
|
-
describe("enqueueSend", () => {
|
|
6
|
-
beforeEach(() => {
|
|
7
|
-
vi.useFakeTimers();
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
afterEach(() => {
|
|
11
|
-
vi.useRealTimers();
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
it("serializes sends per room", async () => {
|
|
15
|
-
const gate = createDeferred<void>();
|
|
16
|
-
const events: string[] = [];
|
|
17
|
-
|
|
18
|
-
const first = enqueueSend("!room:example.org", async () => {
|
|
19
|
-
events.push("start1");
|
|
20
|
-
await gate.promise;
|
|
21
|
-
events.push("end1");
|
|
22
|
-
return "one";
|
|
23
|
-
});
|
|
24
|
-
const second = enqueueSend("!room:example.org", async () => {
|
|
25
|
-
events.push("start2");
|
|
26
|
-
events.push("end2");
|
|
27
|
-
return "two";
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
await vi.advanceTimersByTimeAsync(DEFAULT_SEND_GAP_MS);
|
|
31
|
-
expect(events).toEqual(["start1"]);
|
|
32
|
-
|
|
33
|
-
await vi.advanceTimersByTimeAsync(DEFAULT_SEND_GAP_MS * 2);
|
|
34
|
-
expect(events).toEqual(["start1"]);
|
|
35
|
-
|
|
36
|
-
gate.resolve();
|
|
37
|
-
await first;
|
|
38
|
-
await vi.advanceTimersByTimeAsync(DEFAULT_SEND_GAP_MS - 1);
|
|
39
|
-
expect(events).toEqual(["start1", "end1"]);
|
|
40
|
-
await vi.advanceTimersByTimeAsync(1);
|
|
41
|
-
await second;
|
|
42
|
-
expect(events).toEqual(["start1", "end1", "start2", "end2"]);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it("does not serialize across different rooms", async () => {
|
|
46
|
-
const events: string[] = [];
|
|
47
|
-
|
|
48
|
-
const a = enqueueSend("!a:example.org", async () => {
|
|
49
|
-
events.push("a");
|
|
50
|
-
return "a";
|
|
51
|
-
});
|
|
52
|
-
const b = enqueueSend("!b:example.org", async () => {
|
|
53
|
-
events.push("b");
|
|
54
|
-
return "b";
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
await vi.advanceTimersByTimeAsync(DEFAULT_SEND_GAP_MS);
|
|
58
|
-
await Promise.all([a, b]);
|
|
59
|
-
expect(events.sort()).toEqual(["a", "b"]);
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it("continues queue after failures", async () => {
|
|
63
|
-
const first = enqueueSend("!room:example.org", async () => {
|
|
64
|
-
throw new Error("boom");
|
|
65
|
-
}).then(
|
|
66
|
-
() => ({ ok: true as const }),
|
|
67
|
-
(error) => ({ ok: false as const, error }),
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
await vi.advanceTimersByTimeAsync(DEFAULT_SEND_GAP_MS);
|
|
71
|
-
const firstResult = await first;
|
|
72
|
-
expect(firstResult.ok).toBe(false);
|
|
73
|
-
if (firstResult.ok) {
|
|
74
|
-
throw new Error("expected first queue item to fail");
|
|
75
|
-
}
|
|
76
|
-
expect(firstResult.error).toBeInstanceOf(Error);
|
|
77
|
-
expect(firstResult.error.message).toBe("boom");
|
|
78
|
-
|
|
79
|
-
const second = enqueueSend("!room:example.org", async () => "ok");
|
|
80
|
-
await vi.advanceTimersByTimeAsync(DEFAULT_SEND_GAP_MS);
|
|
81
|
-
await expect(second).resolves.toBe("ok");
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it("continues queued work when the head task fails", async () => {
|
|
85
|
-
const gate = createDeferred<void>();
|
|
86
|
-
const events: string[] = [];
|
|
87
|
-
|
|
88
|
-
const first = enqueueSend("!room:example.org", async () => {
|
|
89
|
-
events.push("start1");
|
|
90
|
-
await gate.promise;
|
|
91
|
-
throw new Error("boom");
|
|
92
|
-
}).then(
|
|
93
|
-
() => ({ ok: true as const }),
|
|
94
|
-
(error) => ({ ok: false as const, error }),
|
|
95
|
-
);
|
|
96
|
-
const second = enqueueSend("!room:example.org", async () => {
|
|
97
|
-
events.push("start2");
|
|
98
|
-
return "two";
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
await vi.advanceTimersByTimeAsync(DEFAULT_SEND_GAP_MS);
|
|
102
|
-
expect(events).toEqual(["start1"]);
|
|
103
|
-
|
|
104
|
-
gate.resolve();
|
|
105
|
-
const firstResult = await first;
|
|
106
|
-
expect(firstResult.ok).toBe(false);
|
|
107
|
-
if (firstResult.ok) {
|
|
108
|
-
throw new Error("expected head queue item to fail");
|
|
109
|
-
}
|
|
110
|
-
expect(firstResult.error).toBeInstanceOf(Error);
|
|
111
|
-
|
|
112
|
-
await vi.advanceTimersByTimeAsync(DEFAULT_SEND_GAP_MS);
|
|
113
|
-
await expect(second).resolves.toBe("two");
|
|
114
|
-
expect(events).toEqual(["start1", "start2"]);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it("supports custom gap and delay injection", async () => {
|
|
118
|
-
const events: string[] = [];
|
|
119
|
-
const delayFn = vi.fn(async (_ms: number) => {});
|
|
120
|
-
|
|
121
|
-
const first = enqueueSend(
|
|
122
|
-
"!room:example.org",
|
|
123
|
-
async () => {
|
|
124
|
-
events.push("first");
|
|
125
|
-
return "one";
|
|
126
|
-
},
|
|
127
|
-
{ gapMs: 7, delayFn },
|
|
128
|
-
);
|
|
129
|
-
const second = enqueueSend(
|
|
130
|
-
"!room:example.org",
|
|
131
|
-
async () => {
|
|
132
|
-
events.push("second");
|
|
133
|
-
return "two";
|
|
134
|
-
},
|
|
135
|
-
{ gapMs: 7, delayFn },
|
|
136
|
-
);
|
|
137
|
-
|
|
138
|
-
await expect(first).resolves.toBe("one");
|
|
139
|
-
await expect(second).resolves.toBe("two");
|
|
140
|
-
expect(events).toEqual(["first", "second"]);
|
|
141
|
-
expect(delayFn).toHaveBeenCalledTimes(2);
|
|
142
|
-
expect(delayFn).toHaveBeenNthCalledWith(1, 7);
|
|
143
|
-
expect(delayFn).toHaveBeenNthCalledWith(2, 7);
|
|
144
|
-
});
|
|
145
|
-
});
|
package/src/matrix/send-queue.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
|
|
2
|
-
|
|
3
|
-
export const DEFAULT_SEND_GAP_MS = 150;
|
|
4
|
-
|
|
5
|
-
type MatrixSendQueueOptions = {
|
|
6
|
-
gapMs?: number;
|
|
7
|
-
delayFn?: (ms: number) => Promise<void>;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
// Serialize sends per room to preserve Matrix delivery order.
|
|
11
|
-
const roomQueues = new KeyedAsyncQueue();
|
|
12
|
-
|
|
13
|
-
export function enqueueSend<T>(
|
|
14
|
-
roomId: string,
|
|
15
|
-
fn: () => Promise<T>,
|
|
16
|
-
options?: MatrixSendQueueOptions,
|
|
17
|
-
): Promise<T> {
|
|
18
|
-
const gapMs = options?.gapMs ?? DEFAULT_SEND_GAP_MS;
|
|
19
|
-
const delayFn = options?.delayFn ?? delay;
|
|
20
|
-
return roomQueues.enqueue(roomId, async () => {
|
|
21
|
-
await delayFn(gapMs);
|
|
22
|
-
return await fn();
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function delay(ms: number): Promise<void> {
|
|
27
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
28
|
-
}
|