@openclaw/matrix 2026.3.11 → 2026.3.13
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/CHANGELOG.md +13 -0
- package/package.json +3 -3
- package/src/channel.directory.test.ts +6 -25
- package/src/channel.ts +2 -2
- package/src/matrix/monitor/allowlist.ts +2 -8
- package/src/matrix/monitor/direct.test.ts +21 -25
- package/src/matrix/monitor/events.test.ts +41 -27
- package/src/matrix/monitor/handler.ts +2 -1
- package/src/matrix/send-queue.test.ts +3 -12
- package/src/matrix/send.test.ts +8 -15
- package/src/resolve-targets.test.ts +11 -10
- package/src/test-mocks.ts +53 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2026.3.13
|
|
4
|
+
|
|
5
|
+
### Changes
|
|
6
|
+
|
|
7
|
+
- Version alignment with core OpenClaw release numbers.
|
|
8
|
+
|
|
9
|
+
## 2026.3.12
|
|
10
|
+
|
|
11
|
+
### Changes
|
|
12
|
+
|
|
13
|
+
- Version alignment with core OpenClaw release numbers.
|
|
14
|
+
|
|
3
15
|
## 2026.3.11
|
|
4
16
|
|
|
5
17
|
### Changes
|
|
18
|
+
|
|
6
19
|
- Version alignment with core OpenClaw release numbers.
|
|
7
20
|
|
|
8
21
|
## 2026.3.10
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/matrix",
|
|
3
|
-
"version": "2026.3.
|
|
3
|
+
"version": "2026.3.13",
|
|
4
4
|
"description": "OpenClaw Matrix channel plugin",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@mariozechner/pi-agent-core": "0.
|
|
7
|
+
"@mariozechner/pi-agent-core": "0.58.0",
|
|
8
8
|
"@matrix-org/matrix-sdk-crypto-nodejs": "^0.4.0",
|
|
9
9
|
"@vector-im/matrix-bot-sdk": "0.8.0-element.3",
|
|
10
10
|
"markdown-it": "14.1.1",
|
|
11
|
-
"music-metadata": "^11.12.
|
|
11
|
+
"music-metadata": "^11.12.3",
|
|
12
12
|
"zod": "^4.3.6"
|
|
13
13
|
},
|
|
14
14
|
"openclaw": {
|
|
@@ -1,36 +1,17 @@
|
|
|
1
1
|
import type { PluginRuntime, RuntimeEnv } from "openclaw/plugin-sdk/matrix";
|
|
2
2
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
|
+
import { createRuntimeEnv } from "../../test-utils/runtime-env.js";
|
|
3
4
|
import { matrixPlugin } from "./channel.js";
|
|
4
5
|
import { setMatrixRuntime } from "./runtime.js";
|
|
6
|
+
import { createMatrixBotSdkMock } from "./test-mocks.js";
|
|
5
7
|
import type { CoreConfig } from "./types.js";
|
|
6
8
|
|
|
7
|
-
vi.mock("@vector-im/matrix-bot-sdk", () =>
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
debug = vi.fn();
|
|
11
|
-
info = vi.fn();
|
|
12
|
-
warn = vi.fn();
|
|
13
|
-
error = vi.fn();
|
|
14
|
-
},
|
|
15
|
-
MatrixClient: class {},
|
|
16
|
-
LogService: {
|
|
17
|
-
setLogger: vi.fn(),
|
|
18
|
-
warn: vi.fn(),
|
|
19
|
-
info: vi.fn(),
|
|
20
|
-
debug: vi.fn(),
|
|
21
|
-
},
|
|
22
|
-
SimpleFsStorageProvider: class {},
|
|
23
|
-
RustSdkCryptoStorageProvider: class {},
|
|
24
|
-
}));
|
|
9
|
+
vi.mock("@vector-im/matrix-bot-sdk", () =>
|
|
10
|
+
createMatrixBotSdkMock({ includeVerboseLogService: true }),
|
|
11
|
+
);
|
|
25
12
|
|
|
26
13
|
describe("matrix directory", () => {
|
|
27
|
-
const runtimeEnv: RuntimeEnv =
|
|
28
|
-
log: vi.fn(),
|
|
29
|
-
error: vi.fn(),
|
|
30
|
-
exit: vi.fn((code: number): never => {
|
|
31
|
-
throw new Error(`exit ${code}`);
|
|
32
|
-
}),
|
|
33
|
-
};
|
|
14
|
+
const runtimeEnv: RuntimeEnv = createRuntimeEnv();
|
|
34
15
|
|
|
35
16
|
beforeEach(() => {
|
|
36
17
|
setMatrixRuntime({
|
package/src/channel.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
PAIRING_APPROVED_MESSAGE,
|
|
16
16
|
type ChannelPlugin,
|
|
17
17
|
} from "openclaw/plugin-sdk/matrix";
|
|
18
|
+
import { buildTrafficStatusSummary } from "../../shared/channel-status-summary.js";
|
|
18
19
|
import { matrixMessageActions } from "./actions.js";
|
|
19
20
|
import { MatrixConfigSchema } from "./config-schema.js";
|
|
20
21
|
import { listMatrixDirectoryGroupsLive, listMatrixDirectoryPeersLive } from "./directory-live.js";
|
|
@@ -410,8 +411,7 @@ export const matrixPlugin: ChannelPlugin<ResolvedMatrixAccount> = {
|
|
|
410
411
|
lastError: runtime?.lastError ?? null,
|
|
411
412
|
probe,
|
|
412
413
|
lastProbeAt: runtime?.lastProbeAt ?? null,
|
|
413
|
-
|
|
414
|
-
lastOutboundAt: runtime?.lastOutboundAt ?? null,
|
|
414
|
+
...buildTrafficStatusSummary(runtime),
|
|
415
415
|
}),
|
|
416
416
|
},
|
|
417
417
|
gateway: {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
compileAllowlist,
|
|
3
3
|
normalizeStringEntries,
|
|
4
|
-
|
|
4
|
+
resolveCompiledAllowlistMatch,
|
|
5
5
|
type AllowlistMatch,
|
|
6
6
|
} from "openclaw/plugin-sdk/matrix";
|
|
7
7
|
|
|
@@ -77,19 +77,13 @@ export function resolveMatrixAllowListMatch(params: {
|
|
|
77
77
|
userId?: string;
|
|
78
78
|
}): MatrixAllowListMatch {
|
|
79
79
|
const compiledAllowList = compileAllowlist(params.allowList);
|
|
80
|
-
if (compiledAllowList.set.size === 0) {
|
|
81
|
-
return { allowed: false };
|
|
82
|
-
}
|
|
83
|
-
if (compiledAllowList.wildcard) {
|
|
84
|
-
return { allowed: true, matchKey: "*", matchSource: "wildcard" };
|
|
85
|
-
}
|
|
86
80
|
const userId = normalizeMatrixUser(params.userId);
|
|
87
81
|
const candidates: Array<{ value?: string; source: MatrixAllowListSource }> = [
|
|
88
82
|
{ value: userId, source: "id" },
|
|
89
83
|
{ value: userId ? `matrix:${userId}` : "", source: "prefixed-id" },
|
|
90
84
|
{ value: userId ? `user:${userId}` : "", source: "prefixed-user" },
|
|
91
85
|
];
|
|
92
|
-
return
|
|
86
|
+
return resolveCompiledAllowlistMatch({
|
|
93
87
|
compiledAllowlist: compiledAllowList,
|
|
94
88
|
candidates,
|
|
95
89
|
});
|
|
@@ -7,6 +7,8 @@ import { createDirectRoomTracker } from "./direct.js";
|
|
|
7
7
|
|
|
8
8
|
type StateEvent = Record<string, unknown>;
|
|
9
9
|
type DmMap = Record<string, boolean>;
|
|
10
|
+
const brokenDmRoomId = "!broken-dm:example.org";
|
|
11
|
+
const defaultBrokenDmMembers = ["@alice:example.org", "@bot:example.org"];
|
|
10
12
|
|
|
11
13
|
function createMockClient(opts: {
|
|
12
14
|
dmRooms?: DmMap;
|
|
@@ -50,6 +52,21 @@ function createMockClient(opts: {
|
|
|
50
52
|
};
|
|
51
53
|
}
|
|
52
54
|
|
|
55
|
+
function createBrokenDmClient(roomNameEvent?: StateEvent) {
|
|
56
|
+
return createMockClient({
|
|
57
|
+
dmRooms: {},
|
|
58
|
+
membersByRoom: {
|
|
59
|
+
[brokenDmRoomId]: defaultBrokenDmMembers,
|
|
60
|
+
},
|
|
61
|
+
stateEvents: {
|
|
62
|
+
// is_direct not set on either member (e.g. Continuwuity bug)
|
|
63
|
+
[`${brokenDmRoomId}|m.room.member|@alice:example.org`]: {},
|
|
64
|
+
[`${brokenDmRoomId}|m.room.member|@bot:example.org`]: {},
|
|
65
|
+
...(roomNameEvent ? { [`${brokenDmRoomId}|m.room.name|`]: roomNameEvent } : {}),
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
53
70
|
// ---------------------------------------------------------------------------
|
|
54
71
|
// Tests -- isDirectMessage
|
|
55
72
|
// ---------------------------------------------------------------------------
|
|
@@ -131,22 +148,11 @@ describe("createDirectRoomTracker", () => {
|
|
|
131
148
|
|
|
132
149
|
describe("conservative fallback (memberCount + room name)", () => {
|
|
133
150
|
it("returns true for 2-member room WITHOUT a room name (broken flags)", async () => {
|
|
134
|
-
const client =
|
|
135
|
-
dmRooms: {},
|
|
136
|
-
membersByRoom: {
|
|
137
|
-
"!broken-dm:example.org": ["@alice:example.org", "@bot:example.org"],
|
|
138
|
-
},
|
|
139
|
-
stateEvents: {
|
|
140
|
-
// is_direct not set on either member (e.g. Continuwuity bug)
|
|
141
|
-
"!broken-dm:example.org|m.room.member|@alice:example.org": {},
|
|
142
|
-
"!broken-dm:example.org|m.room.member|@bot:example.org": {},
|
|
143
|
-
// No m.room.name -> getRoomStateEvent will throw (event not found)
|
|
144
|
-
},
|
|
145
|
-
});
|
|
151
|
+
const client = createBrokenDmClient();
|
|
146
152
|
const tracker = createDirectRoomTracker(client as never);
|
|
147
153
|
|
|
148
154
|
const result = await tracker.isDirectMessage({
|
|
149
|
-
roomId:
|
|
155
|
+
roomId: brokenDmRoomId,
|
|
150
156
|
senderId: "@alice:example.org",
|
|
151
157
|
});
|
|
152
158
|
|
|
@@ -154,21 +160,11 @@ describe("createDirectRoomTracker", () => {
|
|
|
154
160
|
});
|
|
155
161
|
|
|
156
162
|
it("returns true for 2-member room with empty room name", async () => {
|
|
157
|
-
const client =
|
|
158
|
-
dmRooms: {},
|
|
159
|
-
membersByRoom: {
|
|
160
|
-
"!broken-dm:example.org": ["@alice:example.org", "@bot:example.org"],
|
|
161
|
-
},
|
|
162
|
-
stateEvents: {
|
|
163
|
-
"!broken-dm:example.org|m.room.member|@alice:example.org": {},
|
|
164
|
-
"!broken-dm:example.org|m.room.member|@bot:example.org": {},
|
|
165
|
-
"!broken-dm:example.org|m.room.name|": { name: "" },
|
|
166
|
-
},
|
|
167
|
-
});
|
|
163
|
+
const client = createBrokenDmClient({ name: "" });
|
|
168
164
|
const tracker = createDirectRoomTracker(client as never);
|
|
169
165
|
|
|
170
166
|
const result = await tracker.isDirectMessage({
|
|
171
|
-
roomId:
|
|
167
|
+
roomId: brokenDmRoomId,
|
|
172
168
|
senderId: "@alice:example.org",
|
|
173
169
|
});
|
|
174
170
|
|
|
@@ -12,6 +12,19 @@ vi.mock("../send.js", () => ({
|
|
|
12
12
|
}));
|
|
13
13
|
|
|
14
14
|
describe("registerMatrixMonitorEvents", () => {
|
|
15
|
+
const roomId = "!room:example.org";
|
|
16
|
+
|
|
17
|
+
function makeEvent(overrides: Partial<MatrixRawEvent>): MatrixRawEvent {
|
|
18
|
+
return {
|
|
19
|
+
event_id: "$event",
|
|
20
|
+
sender: "@alice:example.org",
|
|
21
|
+
type: "m.room.message",
|
|
22
|
+
origin_server_ts: 0,
|
|
23
|
+
content: {},
|
|
24
|
+
...overrides,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
15
28
|
beforeEach(() => {
|
|
16
29
|
sendReadReceiptMatrixMock.mockClear();
|
|
17
30
|
});
|
|
@@ -53,12 +66,22 @@ describe("registerMatrixMonitorEvents", () => {
|
|
|
53
66
|
return { client, getUserId, onRoomMessage, roomMessageHandler, logVerboseMessage };
|
|
54
67
|
}
|
|
55
68
|
|
|
69
|
+
async function expectForwardedWithoutReadReceipt(event: MatrixRawEvent) {
|
|
70
|
+
const { onRoomMessage, roomMessageHandler } = createHarness();
|
|
71
|
+
|
|
72
|
+
roomMessageHandler(roomId, event);
|
|
73
|
+
await vi.waitFor(() => {
|
|
74
|
+
expect(onRoomMessage).toHaveBeenCalledWith(roomId, event);
|
|
75
|
+
});
|
|
76
|
+
expect(sendReadReceiptMatrixMock).not.toHaveBeenCalled();
|
|
77
|
+
}
|
|
78
|
+
|
|
56
79
|
it("sends read receipt immediately for non-self messages", async () => {
|
|
57
80
|
const { client, onRoomMessage, roomMessageHandler } = createHarness();
|
|
58
|
-
const event = {
|
|
81
|
+
const event = makeEvent({
|
|
59
82
|
event_id: "$e1",
|
|
60
83
|
sender: "@alice:example.org",
|
|
61
|
-
}
|
|
84
|
+
});
|
|
62
85
|
|
|
63
86
|
roomMessageHandler("!room:example.org", event);
|
|
64
87
|
|
|
@@ -69,36 +92,27 @@ describe("registerMatrixMonitorEvents", () => {
|
|
|
69
92
|
});
|
|
70
93
|
|
|
71
94
|
it("does not send read receipts for self messages", async () => {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
roomMessageHandler("!room:example.org", event);
|
|
79
|
-
await vi.waitFor(() => {
|
|
80
|
-
expect(onRoomMessage).toHaveBeenCalledWith("!room:example.org", event);
|
|
81
|
-
});
|
|
82
|
-
expect(sendReadReceiptMatrixMock).not.toHaveBeenCalled();
|
|
95
|
+
await expectForwardedWithoutReadReceipt(
|
|
96
|
+
makeEvent({
|
|
97
|
+
event_id: "$e2",
|
|
98
|
+
sender: "@bot:example.org",
|
|
99
|
+
}),
|
|
100
|
+
);
|
|
83
101
|
});
|
|
84
102
|
|
|
85
103
|
it("skips receipt when message lacks sender or event id", async () => {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
await vi.waitFor(() => {
|
|
93
|
-
expect(onRoomMessage).toHaveBeenCalledWith("!room:example.org", event);
|
|
94
|
-
});
|
|
95
|
-
expect(sendReadReceiptMatrixMock).not.toHaveBeenCalled();
|
|
104
|
+
await expectForwardedWithoutReadReceipt(
|
|
105
|
+
makeEvent({
|
|
106
|
+
sender: "@alice:example.org",
|
|
107
|
+
event_id: "",
|
|
108
|
+
}),
|
|
109
|
+
);
|
|
96
110
|
});
|
|
97
111
|
|
|
98
112
|
it("caches self user id across messages", async () => {
|
|
99
113
|
const { getUserId, roomMessageHandler } = createHarness();
|
|
100
|
-
const first = { event_id: "$e3", sender: "@alice:example.org" }
|
|
101
|
-
const second = { event_id: "$e4", sender: "@bob:example.org" }
|
|
114
|
+
const first = makeEvent({ event_id: "$e3", sender: "@alice:example.org" });
|
|
115
|
+
const second = makeEvent({ event_id: "$e4", sender: "@bob:example.org" });
|
|
102
116
|
|
|
103
117
|
roomMessageHandler("!room:example.org", first);
|
|
104
118
|
roomMessageHandler("!room:example.org", second);
|
|
@@ -112,7 +126,7 @@ describe("registerMatrixMonitorEvents", () => {
|
|
|
112
126
|
it("logs and continues when sending read receipt fails", async () => {
|
|
113
127
|
sendReadReceiptMatrixMock.mockRejectedValueOnce(new Error("network boom"));
|
|
114
128
|
const { roomMessageHandler, onRoomMessage, logVerboseMessage } = createHarness();
|
|
115
|
-
const event = { event_id: "$e5", sender: "@alice:example.org" }
|
|
129
|
+
const event = makeEvent({ event_id: "$e5", sender: "@alice:example.org" });
|
|
116
130
|
|
|
117
131
|
roomMessageHandler("!room:example.org", event);
|
|
118
132
|
|
|
@@ -128,7 +142,7 @@ describe("registerMatrixMonitorEvents", () => {
|
|
|
128
142
|
const { roomMessageHandler, onRoomMessage, getUserId } = createHarness({
|
|
129
143
|
getUserId: vi.fn().mockRejectedValue(new Error("cannot resolve self")),
|
|
130
144
|
});
|
|
131
|
-
const event = { event_id: "$e6", sender: "@alice:example.org" }
|
|
145
|
+
const event = makeEvent({ event_id: "$e6", sender: "@alice:example.org" });
|
|
132
146
|
|
|
133
147
|
roomMessageHandler("!room:example.org", event);
|
|
134
148
|
|
|
@@ -686,6 +686,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
|
|
686
686
|
channel: "matrix",
|
|
687
687
|
accountId: route.accountId,
|
|
688
688
|
});
|
|
689
|
+
const humanDelay = core.channel.reply.resolveHumanDelayConfig(cfg, route.agentId);
|
|
689
690
|
const typingCallbacks = createTypingCallbacks({
|
|
690
691
|
start: () => sendTypingMatrix(roomId, true, undefined, client),
|
|
691
692
|
stop: () => sendTypingMatrix(roomId, false, undefined, client),
|
|
@@ -711,7 +712,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
|
|
711
712
|
const { dispatcher, replyOptions, markDispatchIdle } =
|
|
712
713
|
core.channel.reply.createReplyDispatcherWithTyping({
|
|
713
714
|
...prefixOptions,
|
|
714
|
-
humanDelay
|
|
715
|
+
humanDelay,
|
|
715
716
|
typingCallbacks,
|
|
716
717
|
deliver: async (payload) => {
|
|
717
718
|
await deliverMatrixReplies({
|
|
@@ -1,16 +1,7 @@
|
|
|
1
1
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { createDeferred } from "../../../shared/deferred.js";
|
|
2
3
|
import { DEFAULT_SEND_GAP_MS, enqueueSend } from "./send-queue.js";
|
|
3
4
|
|
|
4
|
-
function deferred<T>() {
|
|
5
|
-
let resolve!: (value: T | PromiseLike<T>) => void;
|
|
6
|
-
let reject!: (reason?: unknown) => void;
|
|
7
|
-
const promise = new Promise<T>((res, rej) => {
|
|
8
|
-
resolve = res;
|
|
9
|
-
reject = rej;
|
|
10
|
-
});
|
|
11
|
-
return { promise, resolve, reject };
|
|
12
|
-
}
|
|
13
|
-
|
|
14
5
|
describe("enqueueSend", () => {
|
|
15
6
|
beforeEach(() => {
|
|
16
7
|
vi.useFakeTimers();
|
|
@@ -21,7 +12,7 @@ describe("enqueueSend", () => {
|
|
|
21
12
|
});
|
|
22
13
|
|
|
23
14
|
it("serializes sends per room", async () => {
|
|
24
|
-
const gate =
|
|
15
|
+
const gate = createDeferred<void>();
|
|
25
16
|
const events: string[] = [];
|
|
26
17
|
|
|
27
18
|
const first = enqueueSend("!room:example.org", async () => {
|
|
@@ -91,7 +82,7 @@ describe("enqueueSend", () => {
|
|
|
91
82
|
});
|
|
92
83
|
|
|
93
84
|
it("continues queued work when the head task fails", async () => {
|
|
94
|
-
const gate =
|
|
85
|
+
const gate = createDeferred<void>();
|
|
95
86
|
const events: string[] = [];
|
|
96
87
|
|
|
97
88
|
const first = enqueueSend("!room:example.org", async () => {
|
package/src/matrix/send.test.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { PluginRuntime } from "openclaw/plugin-sdk/matrix";
|
|
2
2
|
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
3
|
import { setMatrixRuntime } from "../runtime.js";
|
|
4
|
+
import { createMatrixBotSdkMock } from "../test-mocks.js";
|
|
4
5
|
|
|
5
6
|
vi.mock("music-metadata", () => ({
|
|
6
7
|
// `resolveMediaDurationMs` lazily imports `music-metadata`; in tests we don't
|
|
@@ -8,21 +9,13 @@ vi.mock("music-metadata", () => ({
|
|
|
8
9
|
parseBuffer: vi.fn().mockResolvedValue({ format: {} }),
|
|
9
10
|
}));
|
|
10
11
|
|
|
11
|
-
vi.mock("@vector-im/matrix-bot-sdk", () =>
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
},
|
|
19
|
-
LogService: {
|
|
20
|
-
setLogger: vi.fn(),
|
|
21
|
-
},
|
|
22
|
-
MatrixClient: vi.fn(),
|
|
23
|
-
SimpleFsStorageProvider: vi.fn(),
|
|
24
|
-
RustSdkCryptoStorageProvider: vi.fn(),
|
|
25
|
-
}));
|
|
12
|
+
vi.mock("@vector-im/matrix-bot-sdk", () =>
|
|
13
|
+
createMatrixBotSdkMock({
|
|
14
|
+
matrixClient: vi.fn(),
|
|
15
|
+
simpleFsStorageProvider: vi.fn(),
|
|
16
|
+
rustSdkCryptoStorageProvider: vi.fn(),
|
|
17
|
+
}),
|
|
18
|
+
);
|
|
26
19
|
|
|
27
20
|
vi.mock("./send-queue.js", () => ({
|
|
28
21
|
enqueueSend: async <T>(_roomId: string, fn: () => Promise<T>) => await fn(),
|
|
@@ -8,6 +8,15 @@ vi.mock("./directory-live.js", () => ({
|
|
|
8
8
|
listMatrixDirectoryGroupsLive: vi.fn(),
|
|
9
9
|
}));
|
|
10
10
|
|
|
11
|
+
async function resolveUserTarget(input = "Alice") {
|
|
12
|
+
const [result] = await resolveMatrixTargets({
|
|
13
|
+
cfg: {},
|
|
14
|
+
inputs: [input],
|
|
15
|
+
kind: "user",
|
|
16
|
+
});
|
|
17
|
+
return result;
|
|
18
|
+
}
|
|
19
|
+
|
|
11
20
|
describe("resolveMatrixTargets (users)", () => {
|
|
12
21
|
beforeEach(() => {
|
|
13
22
|
vi.mocked(listMatrixDirectoryPeersLive).mockReset();
|
|
@@ -20,11 +29,7 @@ describe("resolveMatrixTargets (users)", () => {
|
|
|
20
29
|
];
|
|
21
30
|
vi.mocked(listMatrixDirectoryPeersLive).mockResolvedValue(matches);
|
|
22
31
|
|
|
23
|
-
const
|
|
24
|
-
cfg: {},
|
|
25
|
-
inputs: ["Alice"],
|
|
26
|
-
kind: "user",
|
|
27
|
-
});
|
|
32
|
+
const result = await resolveUserTarget();
|
|
28
33
|
|
|
29
34
|
expect(result?.resolved).toBe(true);
|
|
30
35
|
expect(result?.id).toBe("@alice:example.org");
|
|
@@ -37,11 +42,7 @@ describe("resolveMatrixTargets (users)", () => {
|
|
|
37
42
|
];
|
|
38
43
|
vi.mocked(listMatrixDirectoryPeersLive).mockResolvedValue(matches);
|
|
39
44
|
|
|
40
|
-
const
|
|
41
|
-
cfg: {},
|
|
42
|
-
inputs: ["Alice"],
|
|
43
|
-
kind: "user",
|
|
44
|
-
});
|
|
45
|
+
const result = await resolveUserTarget();
|
|
45
46
|
|
|
46
47
|
expect(result?.resolved).toBe(false);
|
|
47
48
|
expect(result?.note).toMatch(/use full Matrix ID/i);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { Mock } from "vitest";
|
|
2
|
+
import { vi } from "vitest";
|
|
3
|
+
|
|
4
|
+
type MatrixBotSdkMockParams = {
|
|
5
|
+
matrixClient?: unknown;
|
|
6
|
+
simpleFsStorageProvider?: unknown;
|
|
7
|
+
rustSdkCryptoStorageProvider?: unknown;
|
|
8
|
+
includeVerboseLogService?: boolean;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
type MatrixBotSdkMock = {
|
|
12
|
+
ConsoleLogger: new () => {
|
|
13
|
+
trace: Mock<() => void>;
|
|
14
|
+
debug: Mock<() => void>;
|
|
15
|
+
info: Mock<() => void>;
|
|
16
|
+
warn: Mock<() => void>;
|
|
17
|
+
error: Mock<() => void>;
|
|
18
|
+
};
|
|
19
|
+
MatrixClient: unknown;
|
|
20
|
+
LogService: {
|
|
21
|
+
setLogger: Mock<() => void>;
|
|
22
|
+
warn?: Mock<() => void>;
|
|
23
|
+
info?: Mock<() => void>;
|
|
24
|
+
debug?: Mock<() => void>;
|
|
25
|
+
};
|
|
26
|
+
SimpleFsStorageProvider: unknown;
|
|
27
|
+
RustSdkCryptoStorageProvider: unknown;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export function createMatrixBotSdkMock(params: MatrixBotSdkMockParams = {}): MatrixBotSdkMock {
|
|
31
|
+
return {
|
|
32
|
+
ConsoleLogger: class {
|
|
33
|
+
trace = vi.fn();
|
|
34
|
+
debug = vi.fn();
|
|
35
|
+
info = vi.fn();
|
|
36
|
+
warn = vi.fn();
|
|
37
|
+
error = vi.fn();
|
|
38
|
+
},
|
|
39
|
+
MatrixClient: params.matrixClient ?? class {},
|
|
40
|
+
LogService: {
|
|
41
|
+
setLogger: vi.fn(),
|
|
42
|
+
...(params.includeVerboseLogService
|
|
43
|
+
? {
|
|
44
|
+
warn: vi.fn(),
|
|
45
|
+
info: vi.fn(),
|
|
46
|
+
debug: vi.fn(),
|
|
47
|
+
}
|
|
48
|
+
: {}),
|
|
49
|
+
},
|
|
50
|
+
SimpleFsStorageProvider: params.simpleFsStorageProvider ?? class {},
|
|
51
|
+
RustSdkCryptoStorageProvider: params.rustSdkCryptoStorageProvider ?? class {},
|
|
52
|
+
};
|
|
53
|
+
}
|