@archipelagolab/lobi 1.0.7 → 1.0.8
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/README.md +134 -0
- package/index.ts +47 -42
- package/package.json +2 -3
- package/src/directory-live.test.ts +2 -2
- package/src/directory-live.ts +4 -4
- package/src/matrix/actions/messages.ts +1 -1
- package/src/matrix/client/config.ts +2 -2
- package/src/matrix/client/file-sync-store.test.ts +1 -1
- package/src/matrix/client/file-sync-store.ts +1 -1
- package/src/matrix/client/logging.ts +1 -1
- package/src/matrix/client.test.ts +8 -8
- package/src/matrix/reaction-common.ts +1 -1
- package/src/matrix/sdk/crypto-bootstrap.ts +1 -1
- package/src/matrix/sdk/decrypt-bridge.ts +2 -2
- package/src/matrix/sdk/event-helpers.test.ts +1 -1
- package/src/matrix/sdk/event-helpers.ts +1 -1
- package/src/matrix/sdk/http-client.test.ts +5 -5
- package/src/matrix/sdk/recovery-key-store.test.ts +1 -1
- package/src/matrix/sdk/recovery-key-store.ts +1 -1
- package/src/matrix/sdk/transport.test.ts +4 -4
- package/src/matrix/sdk/verification-manager.test.ts +1 -1
- package/src/matrix/sdk/verification-manager.ts +2 -2
- package/src/matrix/sdk.test.ts +7 -7
- package/src/matrix/sdk.ts +9 -9
package/README.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# @archipelagolab/lobi
|
|
2
|
+
|
|
3
|
+
**Lobi - The official A2A (Agent-to-Agent) messaging platform by Lobisland.**
|
|
4
|
+
|
|
5
|
+
Built for AI, enabling seamless communication between intelligent agents.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
This plugin provides Lobi channel support for OpenClaw, allowing your AI agents to communicate through Lobisland's official A2A messaging platform. Lobi is designed from the ground up for AI-driven communication, enabling seamless interactions between intelligent agents.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
### From npm registry
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
openclaw plugins install @archipelagolab/lobi
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Specific version
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
openclaw plugins install @archipelagolab/lobi@1.0.7
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Configuration
|
|
32
|
+
|
|
33
|
+
### Using OpenClaw CLI
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Set homeserver
|
|
37
|
+
openclaw config set channels.lobi.homeserver "https://your-homeserver.com"
|
|
38
|
+
|
|
39
|
+
# Set user ID
|
|
40
|
+
openclaw config set channels.lobi.userId "@your-user:your-homeserver.com"
|
|
41
|
+
|
|
42
|
+
# Set access token
|
|
43
|
+
openclaw config set channels.lobi.accessToken "your-access-token"
|
|
44
|
+
|
|
45
|
+
# Set device ID (optional)
|
|
46
|
+
openclaw config set channels.lobi.deviceId "your-device-id"
|
|
47
|
+
|
|
48
|
+
# Set device name (optional)
|
|
49
|
+
openclaw config set channels.lobi.deviceName "OpenClaw Bot"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Using environment variables
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
export LOBI_HOMESERVER="https://your-homeserver.com"
|
|
56
|
+
export LOBI_USER_ID="@your-user:your-homeserver.com"
|
|
57
|
+
export LOBI_ACCESS_TOKEN="your-access-token"
|
|
58
|
+
export LOBI_DEVICE_ID="your-device-id"
|
|
59
|
+
export LOBI_DEVICE_NAME="OpenClaw Bot"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Using config file
|
|
63
|
+
|
|
64
|
+
Edit `~/.openclaw/config.json`:
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"channels": {
|
|
69
|
+
"lobi": {
|
|
70
|
+
"homeserver": "https://your-homeserver.com",
|
|
71
|
+
"userId": "@your-user:your-homeserver.com",
|
|
72
|
+
"accessToken": "your-access-token",
|
|
73
|
+
"deviceId": "your-device-id",
|
|
74
|
+
"deviceName": "OpenClaw Bot",
|
|
75
|
+
"dm": {
|
|
76
|
+
"policy": "pairing",
|
|
77
|
+
"allowFrom": ["@friend:example.com"]
|
|
78
|
+
},
|
|
79
|
+
"groups": {
|
|
80
|
+
"!roomid:example.com": {
|
|
81
|
+
"enabled": true,
|
|
82
|
+
"requireMention": true
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Features
|
|
93
|
+
|
|
94
|
+
- **Direct Messages**: Support for DM conversations with AI agents
|
|
95
|
+
- **Group/Room Support**: Multi-user room interactions
|
|
96
|
+
- **Thread Support**: Threaded conversations for organized discussions
|
|
97
|
+
- **Media Support**: Send and receive media files
|
|
98
|
+
- **Reactions**: Message reactions support
|
|
99
|
+
- **Polls**: Create and manage polls
|
|
100
|
+
- **Auto-join**: Automatically join invited rooms
|
|
101
|
+
- **Allowlist**: Control who can interact with your agent
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## CLI Commands
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
# Check lobi plugin status
|
|
109
|
+
openclaw channels status lobi
|
|
110
|
+
|
|
111
|
+
# Send a message
|
|
112
|
+
openclaw message send "Hello from Lobi!" --to "room:!roomid:example.com" --channel lobi
|
|
113
|
+
|
|
114
|
+
# Use lobi CLI
|
|
115
|
+
openclaw lobi --help
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Requirements
|
|
121
|
+
|
|
122
|
+
- OpenClaw >= 2026.4.3
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## License
|
|
127
|
+
|
|
128
|
+
MIT
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Support
|
|
133
|
+
|
|
134
|
+
For support, please visit [Lobisland](https://lobisland.com) or open an issue on GitHub.
|
package/index.ts
CHANGED
|
@@ -1,51 +1,56 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
|
2
2
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
3
|
+
import type { ChannelPlugin, OpenClawPluginApi } from "openclaw/plugin-sdk/channel-entry-contract";
|
|
3
4
|
import { registerLobiCliMetadata } from "./cli-metadata.js";
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
description: "Lobi - The official A2A (Agent-to-Agent) messaging platform by Lobisland.",
|
|
9
|
-
importMetaUrl: import.meta.url,
|
|
10
|
-
plugin: {
|
|
11
|
-
specifier: "./channel-plugin-api.js",
|
|
12
|
-
exportName: "matrixPlugin",
|
|
13
|
-
},
|
|
14
|
-
secrets: {
|
|
15
|
-
specifier: "./secret-contract-api.js",
|
|
16
|
-
exportName: "channelSecrets",
|
|
17
|
-
},
|
|
18
|
-
runtime: {
|
|
19
|
-
specifier: "./runtime-api.js",
|
|
20
|
-
exportName: "setMatrixRuntime",
|
|
21
|
-
},
|
|
22
|
-
registerCliMetadata: registerLobiCliMetadata,
|
|
23
|
-
registerFull(api) {
|
|
24
|
-
void import("./plugin-entry.handlers.runtime.js")
|
|
25
|
-
.then(({ ensureMatrixCryptoRuntime }) =>
|
|
26
|
-
ensureMatrixCryptoRuntime({ log: api.logger.info }).catch((err: unknown) => {
|
|
27
|
-
const message = formatErrorMessage(err);
|
|
28
|
-
api.logger.warn?.(`lobi: crypto runtime bootstrap failed: ${message}`);
|
|
29
|
-
}),
|
|
30
|
-
)
|
|
31
|
-
.catch((err: unknown) => {
|
|
32
|
-
const message = formatErrorMessage(err);
|
|
33
|
-
api.logger.warn?.(`lobi: failed loading crypto bootstrap runtime: ${message}`);
|
|
34
|
-
});
|
|
6
|
+
async function registerLobiChannel(api: OpenClawPluginApi) {
|
|
7
|
+
// Load the channel plugin
|
|
8
|
+
const { matrixPlugin } = await import("./src/channel.js");
|
|
35
9
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
await handleVerifyRecoveryKey(ctx);
|
|
39
|
-
});
|
|
10
|
+
// Register the channel
|
|
11
|
+
api.registerChannel({ plugin: matrixPlugin as ChannelPlugin });
|
|
40
12
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
});
|
|
13
|
+
// Load runtime
|
|
14
|
+
const { setMatrixRuntime } = await import("./src/runtime.js");
|
|
15
|
+
setMatrixRuntime(api.runtime);
|
|
45
16
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
17
|
+
// Register CLI metadata
|
|
18
|
+
registerLobiCliMetadata(api);
|
|
19
|
+
|
|
20
|
+
// Register gateway methods
|
|
21
|
+
void import("./plugin-entry.handlers.runtime.js")
|
|
22
|
+
.then(({ ensureMatrixCryptoRuntime }) =>
|
|
23
|
+
ensureMatrixCryptoRuntime({ log: api.logger.info }).catch((err: unknown) => {
|
|
24
|
+
const message = formatErrorMessage(err);
|
|
25
|
+
api.logger.warn?.(`lobi: crypto runtime bootstrap failed: ${message}`);
|
|
26
|
+
}),
|
|
27
|
+
)
|
|
28
|
+
.catch((err: unknown) => {
|
|
29
|
+
const message = formatErrorMessage(err);
|
|
30
|
+
api.logger.warn?.(`lobi: failed loading crypto bootstrap runtime: ${message}`);
|
|
49
31
|
});
|
|
32
|
+
|
|
33
|
+
api.registerGatewayMethod("lobi.verify.recoveryKey", async (ctx) => {
|
|
34
|
+
const { handleVerifyRecoveryKey } = await import("./plugin-entry.handlers.runtime.js");
|
|
35
|
+
await handleVerifyRecoveryKey(ctx);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
api.registerGatewayMethod("lobi.verify.bootstrap", async (ctx) => {
|
|
39
|
+
const { handleVerificationBootstrap } = await import("./plugin-entry.handlers.runtime.js");
|
|
40
|
+
await handleVerificationBootstrap(ctx);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
api.registerGatewayMethod("lobi.verify.status", async (ctx) => {
|
|
44
|
+
const { handleVerificationStatus } = await import("./plugin-entry.handlers.runtime.js");
|
|
45
|
+
await handleVerificationStatus(ctx);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export default definePluginEntry({
|
|
50
|
+
id: "lobi",
|
|
51
|
+
name: "Lobi",
|
|
52
|
+
description: "Lobi - The official A2A (Agent-to-Agent) messaging platform by Lobisland.",
|
|
53
|
+
async register(api) {
|
|
54
|
+
await registerLobiChannel(api);
|
|
50
55
|
},
|
|
51
56
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@archipelagolab/lobi",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "Lobi - The official A2A (Agent-to-Agent) messaging platform by Lobisland. Built for AI, enabling seamless communication between intelligent agents.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"dependencies": {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"@matrix-org/matrix-sdk-crypto-wasm": "18.0.0",
|
|
9
9
|
"fake-indexeddb": "^6.2.5",
|
|
10
10
|
"markdown-it": "14.1.1",
|
|
11
|
-
"
|
|
11
|
+
"@archipelagolab/lobi-js-sdk": "1.0.2",
|
|
12
12
|
"music-metadata": "^11.12.3"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
"extensions": [
|
|
28
28
|
"./index.ts"
|
|
29
29
|
],
|
|
30
|
-
"setupEntry": "./setup-entry.ts",
|
|
31
30
|
"channel": {
|
|
32
31
|
"id": "lobi",
|
|
33
32
|
"label": "Lobi",
|
|
@@ -130,7 +130,7 @@ describe("matrix directory live", () => {
|
|
|
130
130
|
expect(requestJsonMock).toHaveBeenCalledWith(
|
|
131
131
|
expect.objectContaining({
|
|
132
132
|
method: "POST",
|
|
133
|
-
endpoint: "/
|
|
133
|
+
endpoint: "/_lobi/client/v3/user_directory/search",
|
|
134
134
|
timeoutMs: 10_000,
|
|
135
135
|
body: {
|
|
136
136
|
search_term: "Alice",
|
|
@@ -176,7 +176,7 @@ describe("matrix directory live", () => {
|
|
|
176
176
|
expect(requestJsonMock).toHaveBeenCalledWith(
|
|
177
177
|
expect.objectContaining({
|
|
178
178
|
method: "GET",
|
|
179
|
-
endpoint: "/
|
|
179
|
+
endpoint: "/_lobi/client/v3/directory/room/%23Team%3AExample.org",
|
|
180
180
|
timeoutMs: 10_000,
|
|
181
181
|
}),
|
|
182
182
|
);
|
package/src/directory-live.ts
CHANGED
|
@@ -123,7 +123,7 @@ export async function listMatrixDirectoryPeersLive(
|
|
|
123
123
|
|
|
124
124
|
const res = await requestMatrixJson<MatrixUserDirectoryResponse>(context.client, {
|
|
125
125
|
method: "POST",
|
|
126
|
-
endpoint: "/
|
|
126
|
+
endpoint: "/_lobi/client/v3/user_directory/search",
|
|
127
127
|
body: {
|
|
128
128
|
search_term: context.query,
|
|
129
129
|
limit: resolveMatrixDirectoryLimit(params.limit),
|
|
@@ -155,7 +155,7 @@ async function resolveMatrixRoomAlias(
|
|
|
155
155
|
try {
|
|
156
156
|
const res = await requestMatrixJson<MatrixAliasLookup>(client, {
|
|
157
157
|
method: "GET",
|
|
158
|
-
endpoint: `/
|
|
158
|
+
endpoint: `/_lobi/client/v3/directory/room/${encodeURIComponent(alias)}`,
|
|
159
159
|
});
|
|
160
160
|
return normalizeOptionalString(res.room_id) ?? null;
|
|
161
161
|
} catch {
|
|
@@ -170,7 +170,7 @@ async function fetchMatrixRoomName(
|
|
|
170
170
|
try {
|
|
171
171
|
const res = await requestMatrixJson<MatrixRoomNameState>(client, {
|
|
172
172
|
method: "GET",
|
|
173
|
-
endpoint: `/
|
|
173
|
+
endpoint: `/_lobi/client/v3/rooms/${encodeURIComponent(roomId)}/state/m.room.name`,
|
|
174
174
|
});
|
|
175
175
|
return normalizeOptionalString(res.name) ?? null;
|
|
176
176
|
} catch {
|
|
@@ -211,7 +211,7 @@ export async function listMatrixDirectoryGroupsLive(
|
|
|
211
211
|
|
|
212
212
|
const joined = await requestMatrixJson<MatrixJoinedRoomsResponse>(client, {
|
|
213
213
|
method: "GET",
|
|
214
|
-
endpoint: "/
|
|
214
|
+
endpoint: "/_lobi/client/v3/joined_rooms",
|
|
215
215
|
});
|
|
216
216
|
const rooms = (joined.joined_rooms ?? [])
|
|
217
217
|
.map((roomId) => normalizeOptionalString(roomId))
|
|
@@ -83,7 +83,7 @@ export async function readMatrixMessages(
|
|
|
83
83
|
// Room history is queried via the low-level endpoint for compatibility.
|
|
84
84
|
const res = (await client.doRequest(
|
|
85
85
|
"GET",
|
|
86
|
-
`/
|
|
86
|
+
`/_lobi/client/v3/rooms/${encodeURIComponent(resolvedRoom)}/messages`,
|
|
87
87
|
{
|
|
88
88
|
dir,
|
|
89
89
|
limit,
|
|
@@ -140,7 +140,7 @@ async function fetchMatrixWhoamiIdentity(params: {
|
|
|
140
140
|
dispatcherPolicy: params.dispatcherPolicy,
|
|
141
141
|
});
|
|
142
142
|
return (await retryMatrixAuthRequest("matrix auth whoami", async () => {
|
|
143
|
-
return (await tempClient.doRequest("GET", "/
|
|
143
|
+
return (await tempClient.doRequest("GET", "/_lobi/client/v3/account/whoami")) as {
|
|
144
144
|
user_id?: string;
|
|
145
145
|
device_id?: string;
|
|
146
146
|
};
|
|
@@ -857,7 +857,7 @@ export async function resolveMatrixAuth(params?: {
|
|
|
857
857
|
dispatcherPolicy: resolved.dispatcherPolicy,
|
|
858
858
|
});
|
|
859
859
|
const login = (await retryMatrixAuthRequest("matrix auth login", async () => {
|
|
860
|
-
return (await loginClient.doRequest("POST", "/
|
|
860
|
+
return (await loginClient.doRequest("POST", "/_lobi/client/v3/login", undefined, {
|
|
861
861
|
type: "m.login.password",
|
|
862
862
|
identifier: { type: "m.id.user", user: resolved.userId },
|
|
863
863
|
password,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import os from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import type { ISyncResponse } from "
|
|
4
|
+
import type { ISyncResponse } from "@archipelagolab/lobi-js-sdk";
|
|
5
5
|
import * as jsonStore from "openclaw/plugin-sdk/json-store";
|
|
6
6
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
7
7
|
import { FileBackedMatrixSyncStore } from "./file-sync-store.js";
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
type IRooms,
|
|
10
10
|
type ISyncResponse,
|
|
11
11
|
type IStoredClientOpts,
|
|
12
|
-
} from "
|
|
12
|
+
} from "@archipelagolab/lobi-js-sdk/lib/matrix.js";
|
|
13
13
|
import { writeJsonFileAtomically } from "openclaw/plugin-sdk/json-store";
|
|
14
14
|
import { isRecord } from "../../record-shared.js";
|
|
15
15
|
import { createAsyncLock } from "../async-lock.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { logger as matrixJsSdkRootLogger } from "
|
|
1
|
+
import { logger as matrixJsSdkRootLogger } from "@archipelagolab/lobi-js-sdk/lib/logger.js";
|
|
2
2
|
import { ConsoleLogger, LogService, setMatrixConsoleLogging } from "../sdk/logger.js";
|
|
3
3
|
|
|
4
4
|
let matrixSdkLoggingConfigured = false;
|
|
@@ -793,7 +793,7 @@ describe("resolveMatrixAuth", () => {
|
|
|
793
793
|
|
|
794
794
|
expect(matrixDoRequestMock).toHaveBeenCalledWith(
|
|
795
795
|
"POST",
|
|
796
|
-
"/
|
|
796
|
+
"/_lobi/client/v3/login",
|
|
797
797
|
undefined,
|
|
798
798
|
expect.objectContaining({
|
|
799
799
|
type: "m.login.password",
|
|
@@ -841,7 +841,7 @@ describe("resolveMatrixAuth", () => {
|
|
|
841
841
|
|
|
842
842
|
expect(matrixDoRequestMock).toHaveBeenCalledWith(
|
|
843
843
|
"POST",
|
|
844
|
-
"/
|
|
844
|
+
"/_lobi/client/v3/login",
|
|
845
845
|
undefined,
|
|
846
846
|
expect.objectContaining({
|
|
847
847
|
type: "m.login.password",
|
|
@@ -1023,7 +1023,7 @@ describe("resolveMatrixAuth", () => {
|
|
|
1023
1023
|
accountId: "ops",
|
|
1024
1024
|
});
|
|
1025
1025
|
|
|
1026
|
-
expect(matrixDoRequestMock).toHaveBeenCalledWith("GET", "/
|
|
1026
|
+
expect(matrixDoRequestMock).toHaveBeenCalledWith("GET", "/_lobi/client/v3/account/whoami");
|
|
1027
1027
|
expect(auth.userId).toBe("@ops:example.org");
|
|
1028
1028
|
expect(auth.deviceId).toBe("OPSDEVICE");
|
|
1029
1029
|
});
|
|
@@ -1061,7 +1061,7 @@ describe("resolveMatrixAuth", () => {
|
|
|
1061
1061
|
|
|
1062
1062
|
expect(matrixDoRequestMock).toHaveBeenCalledWith(
|
|
1063
1063
|
"POST",
|
|
1064
|
-
"/
|
|
1064
|
+
"/_lobi/client/v3/login",
|
|
1065
1065
|
undefined,
|
|
1066
1066
|
expect.objectContaining({
|
|
1067
1067
|
type: "m.login.password",
|
|
@@ -1099,7 +1099,7 @@ describe("resolveMatrixAuth", () => {
|
|
|
1099
1099
|
env: {} as NodeJS.ProcessEnv,
|
|
1100
1100
|
});
|
|
1101
1101
|
|
|
1102
|
-
expect(matrixDoRequestMock).toHaveBeenCalledWith("GET", "/
|
|
1102
|
+
expect(matrixDoRequestMock).toHaveBeenCalledWith("GET", "/_lobi/client/v3/account/whoami");
|
|
1103
1103
|
expect(auth).toMatchObject({
|
|
1104
1104
|
accountId: "default",
|
|
1105
1105
|
homeserver: "https://matrix.example.org",
|
|
@@ -1228,7 +1228,7 @@ describe("resolveMatrixAuth", () => {
|
|
|
1228
1228
|
env: {} as NodeJS.ProcessEnv,
|
|
1229
1229
|
});
|
|
1230
1230
|
|
|
1231
|
-
expect(matrixDoRequestMock).toHaveBeenCalledWith("GET", "/
|
|
1231
|
+
expect(matrixDoRequestMock).toHaveBeenCalledWith("GET", "/_lobi/client/v3/account/whoami");
|
|
1232
1232
|
expect(saveBackfilledMatrixDeviceIdMock).toHaveBeenCalledWith(
|
|
1233
1233
|
{
|
|
1234
1234
|
homeserver: "https://matrix.example.org",
|
|
@@ -1390,7 +1390,7 @@ describe("resolveMatrixAuth", () => {
|
|
|
1390
1390
|
env: {} as NodeJS.ProcessEnv,
|
|
1391
1391
|
});
|
|
1392
1392
|
|
|
1393
|
-
expect(matrixDoRequestMock).toHaveBeenCalledWith("GET", "/
|
|
1393
|
+
expect(matrixDoRequestMock).toHaveBeenCalledWith("GET", "/_lobi/client/v3/account/whoami");
|
|
1394
1394
|
expect(auth).toMatchObject({
|
|
1395
1395
|
accountId: "default",
|
|
1396
1396
|
homeserver: "https://matrix.example.org",
|
|
@@ -1437,7 +1437,7 @@ describe("resolveMatrixAuth", () => {
|
|
|
1437
1437
|
accountId: "ops",
|
|
1438
1438
|
});
|
|
1439
1439
|
|
|
1440
|
-
expect(matrixDoRequestMock).toHaveBeenCalledWith("GET", "/
|
|
1440
|
+
expect(matrixDoRequestMock).toHaveBeenCalledWith("GET", "/_lobi/client/v3/account/whoami");
|
|
1441
1441
|
expect(auth).toMatchObject({
|
|
1442
1442
|
accountId: "ops",
|
|
1443
1443
|
homeserver: "https://matrix.example.org",
|
|
@@ -58,7 +58,7 @@ export function buildMatrixReactionContent(
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
export function buildMatrixReactionRelationsPath(roomId: string, messageId: string): string {
|
|
61
|
-
return `/
|
|
61
|
+
return `/_lobi/client/v1/rooms/${encodeURIComponent(roomId)}/relations/${encodeURIComponent(normalizeMatrixReactionMessageId(messageId))}/${MATRIX_ANNOTATION_RELATION_TYPE}/${MATRIX_REACTION_EVENT_TYPE}`;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
export function extractMatrixReactionAnnotation(
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CryptoEvent } from "
|
|
1
|
+
import { CryptoEvent } from "@archipelagolab/lobi-js-sdk/lib/crypto-api/CryptoEvent.js";
|
|
2
2
|
import type { MatrixDecryptBridge } from "./decrypt-bridge.js";
|
|
3
3
|
import { LogService } from "./logger.js";
|
|
4
4
|
import type { MatrixRecoveryKeyStore } from "./recovery-key-store.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { CryptoEvent } from "
|
|
2
|
-
import { MatrixEventEvent, type MatrixEvent } from "
|
|
1
|
+
import { CryptoEvent } from "@archipelagolab/lobi-js-sdk/lib/crypto-api/CryptoEvent.js";
|
|
2
|
+
import { MatrixEventEvent, type MatrixEvent } from "@archipelagolab/lobi-js-sdk/lib/matrix.js";
|
|
3
3
|
import { LogService, noop } from "./logger.js";
|
|
4
4
|
|
|
5
5
|
type MatrixDecryptIfNeededClient = {
|
|
@@ -42,7 +42,7 @@ describe("MatrixAuthedHttpClient", () => {
|
|
|
42
42
|
});
|
|
43
43
|
const result = await client.requestJson({
|
|
44
44
|
method: "GET",
|
|
45
|
-
endpoint: "https://matrix.example.org/
|
|
45
|
+
endpoint: "https://matrix.example.org/_lobi/client/v3/account/whoami",
|
|
46
46
|
timeoutMs: 5000,
|
|
47
47
|
allowAbsoluteEndpoint: true,
|
|
48
48
|
});
|
|
@@ -51,7 +51,7 @@ describe("MatrixAuthedHttpClient", () => {
|
|
|
51
51
|
expect(performMatrixRequestMock).toHaveBeenCalledWith(
|
|
52
52
|
expect.objectContaining({
|
|
53
53
|
method: "GET",
|
|
54
|
-
endpoint: "https://matrix.example.org/
|
|
54
|
+
endpoint: "https://matrix.example.org/_lobi/client/v3/account/whoami",
|
|
55
55
|
allowAbsoluteEndpoint: true,
|
|
56
56
|
ssrfPolicy: { allowPrivateNetwork: true },
|
|
57
57
|
dispatcherPolicy: {
|
|
@@ -78,7 +78,7 @@ describe("MatrixAuthedHttpClient", () => {
|
|
|
78
78
|
});
|
|
79
79
|
const result = await client.requestJson({
|
|
80
80
|
method: "GET",
|
|
81
|
-
endpoint: "/
|
|
81
|
+
endpoint: "/_lobi/client/v3/ping",
|
|
82
82
|
timeoutMs: 5000,
|
|
83
83
|
});
|
|
84
84
|
|
|
@@ -99,7 +99,7 @@ describe("MatrixAuthedHttpClient", () => {
|
|
|
99
99
|
});
|
|
100
100
|
const result = await client.requestRaw({
|
|
101
101
|
method: "GET",
|
|
102
|
-
endpoint: "/
|
|
102
|
+
endpoint: "/_lobi/media/v3/download/example/id",
|
|
103
103
|
timeoutMs: 5000,
|
|
104
104
|
});
|
|
105
105
|
|
|
@@ -123,7 +123,7 @@ describe("MatrixAuthedHttpClient", () => {
|
|
|
123
123
|
await expect(
|
|
124
124
|
client.requestJson({
|
|
125
125
|
method: "GET",
|
|
126
|
-
endpoint: "/
|
|
126
|
+
endpoint: "/_lobi/client/v3/rooms",
|
|
127
127
|
timeoutMs: 5000,
|
|
128
128
|
}),
|
|
129
129
|
).rejects.toMatchObject({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import os from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import { encodeRecoveryKey } from "
|
|
4
|
+
import { encodeRecoveryKey } from "@archipelagolab/lobi-js-sdk/lib/crypto-api/recovery-key.js";
|
|
5
5
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
6
6
|
import { MatrixRecoveryKeyStore } from "./recovery-key-store.js";
|
|
7
7
|
import type { MatrixCryptoBootstrapApi, MatrixSecretStorageStatus } from "./types.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { decodeRecoveryKey } from "
|
|
3
|
+
import { decodeRecoveryKey } from "@archipelagolab/lobi-js-sdk/lib/crypto-api/recovery-key.js";
|
|
4
4
|
import { formatMatrixErrorMessage, formatMatrixErrorReason } from "../errors.js";
|
|
5
5
|
import { LogService } from "./logger.js";
|
|
6
6
|
import type {
|
|
@@ -37,7 +37,7 @@ describe("performMatrixRequest", () => {
|
|
|
37
37
|
homeserver: "http://127.0.0.1:8008",
|
|
38
38
|
accessToken: "token",
|
|
39
39
|
method: "GET",
|
|
40
|
-
endpoint: "/
|
|
40
|
+
endpoint: "/_lobi/media/v3/download/example/id",
|
|
41
41
|
timeoutMs: 5000,
|
|
42
42
|
raw: true,
|
|
43
43
|
maxBytes: 1024,
|
|
@@ -70,7 +70,7 @@ describe("performMatrixRequest", () => {
|
|
|
70
70
|
homeserver: "http://127.0.0.1:8008",
|
|
71
71
|
accessToken: "token",
|
|
72
72
|
method: "GET",
|
|
73
|
-
endpoint: "/
|
|
73
|
+
endpoint: "/_lobi/media/v3/download/example/id",
|
|
74
74
|
timeoutMs: 5000,
|
|
75
75
|
raw: true,
|
|
76
76
|
maxBytes: 1024,
|
|
@@ -101,7 +101,7 @@ describe("performMatrixRequest", () => {
|
|
|
101
101
|
homeserver: "http://127.0.0.1:8008",
|
|
102
102
|
accessToken: "token",
|
|
103
103
|
method: "GET",
|
|
104
|
-
endpoint: "/
|
|
104
|
+
endpoint: "/_lobi/media/v3/download/example/id",
|
|
105
105
|
timeoutMs: 5000,
|
|
106
106
|
raw: true,
|
|
107
107
|
maxBytes: 1024,
|
|
@@ -146,7 +146,7 @@ describe("performMatrixRequest", () => {
|
|
|
146
146
|
homeserver: "http://127.0.0.1:8008",
|
|
147
147
|
accessToken: "token",
|
|
148
148
|
method: "GET",
|
|
149
|
-
endpoint: "/
|
|
149
|
+
endpoint: "/_lobi/client/v3/account/whoami",
|
|
150
150
|
timeoutMs: 5000,
|
|
151
151
|
ssrfPolicy: { allowPrivateNetwork: true },
|
|
152
152
|
});
|
|
@@ -2,7 +2,7 @@ import { EventEmitter } from "node:events";
|
|
|
2
2
|
import {
|
|
3
3
|
VerificationPhase,
|
|
4
4
|
VerificationRequestEvent,
|
|
5
|
-
} from "
|
|
5
|
+
} from "@archipelagolab/lobi-js-sdk/lib/crypto-api/verification.js";
|
|
6
6
|
import { describe, expect, it, vi } from "vitest";
|
|
7
7
|
import {
|
|
8
8
|
MatrixVerificationManager,
|
|
@@ -2,8 +2,8 @@ import {
|
|
|
2
2
|
VerificationPhase,
|
|
3
3
|
VerificationRequestEvent,
|
|
4
4
|
VerifierEvent,
|
|
5
|
-
} from "
|
|
6
|
-
import { VerificationMethod } from "
|
|
5
|
+
} from "@archipelagolab/lobi-js-sdk/lib/crypto-api/verification.js";
|
|
6
|
+
import { VerificationMethod } from "@archipelagolab/lobi-js-sdk/lib/types.js";
|
|
7
7
|
import { formatMatrixErrorMessage } from "../errors.js";
|
|
8
8
|
|
|
9
9
|
export type MatrixVerificationMethod = "sas" | "show-qr" | "scan-qr";
|
package/src/matrix/sdk.test.ts
CHANGED
|
@@ -196,7 +196,7 @@ let matrixJsClient = createMatrixJsClientStub();
|
|
|
196
196
|
let lastCreateClientOpts: Record<string, unknown> | null = null;
|
|
197
197
|
|
|
198
198
|
vi.mock("matrix-js-sdk/lib/matrix.js", async () => {
|
|
199
|
-
const actual = await vi.importActual<typeof import("
|
|
199
|
+
const actual = await vi.importActual<typeof import("@archipelagolab/lobi-js-sdk/lib/matrix.js")>(
|
|
200
200
|
"matrix-js-sdk/lib/matrix.js",
|
|
201
201
|
);
|
|
202
202
|
return {
|
|
@@ -215,7 +215,7 @@ vi.mock("matrix-js-sdk/lib/matrix.js", async () => {
|
|
|
215
215
|
};
|
|
216
216
|
});
|
|
217
217
|
|
|
218
|
-
const { encodeRecoveryKey } = await import("
|
|
218
|
+
const { encodeRecoveryKey } = await import("@archipelagolab/lobi-js-sdk/lib/crypto-api/recovery-key.js");
|
|
219
219
|
const { MatrixClient } = await import("./sdk.js");
|
|
220
220
|
|
|
221
221
|
describe("MatrixClient request hardening", () => {
|
|
@@ -275,14 +275,14 @@ describe("MatrixClient request hardening", () => {
|
|
|
275
275
|
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
276
276
|
const firstInput = (fetchMock.mock.calls as Array<[RequestInfo | URL]>)[0]?.[0];
|
|
277
277
|
const firstUrl = requestUrl(firstInput);
|
|
278
|
-
expect(firstUrl).toContain("/
|
|
278
|
+
expect(firstUrl).toContain("/_lobi/client/v1/media/download/example.org/media");
|
|
279
279
|
});
|
|
280
280
|
|
|
281
281
|
it("falls back to legacy media downloads for older homeservers", async () => {
|
|
282
282
|
const payload = Buffer.from([5, 6, 7, 8]);
|
|
283
283
|
const fetchMock = vi.fn(async (input: RequestInfo | URL) => {
|
|
284
284
|
const url = requestUrl(input);
|
|
285
|
-
if (url.includes("/
|
|
285
|
+
if (url.includes("/_lobi/client/v1/media/download/")) {
|
|
286
286
|
return new Response(
|
|
287
287
|
JSON.stringify({
|
|
288
288
|
errcode: "M_UNRECOGNIZED",
|
|
@@ -309,8 +309,8 @@ describe("MatrixClient request hardening", () => {
|
|
|
309
309
|
const secondInput = secondCall?.[0];
|
|
310
310
|
const firstUrl = requestUrl(firstInput);
|
|
311
311
|
const secondUrl = requestUrl(secondInput);
|
|
312
|
-
expect(firstUrl).toContain("/
|
|
313
|
-
expect(secondUrl).toContain("/
|
|
312
|
+
expect(firstUrl).toContain("/_lobi/client/v1/media/download/example.org/media");
|
|
313
|
+
expect(secondUrl).toContain("/_lobi/media/v3/download/example.org/media");
|
|
314
314
|
});
|
|
315
315
|
|
|
316
316
|
it("decrypts encrypted room events returned by getEvent", async () => {
|
|
@@ -538,7 +538,7 @@ describe("MatrixClient request hardening", () => {
|
|
|
538
538
|
ssrfPolicy: { allowPrivateNetwork: true },
|
|
539
539
|
});
|
|
540
540
|
|
|
541
|
-
const pending = client.doRequest("GET", "/
|
|
541
|
+
const pending = client.doRequest("GET", "/_lobi/client/v3/account/whoami");
|
|
542
542
|
const assertion = expect(pending).rejects.toThrow("aborted");
|
|
543
543
|
await vi.advanceTimersByTimeAsync(30);
|
|
544
544
|
|
package/src/matrix/sdk.ts
CHANGED
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
createClient as createMatrixJsClient,
|
|
7
7
|
type MatrixClient as MatrixJsClient,
|
|
8
8
|
type MatrixEvent,
|
|
9
|
-
} from "
|
|
10
|
-
import { VerificationMethod } from "
|
|
9
|
+
} from "@archipelagolab/lobi-js-sdk/lib/matrix.js";
|
|
10
|
+
import { VerificationMethod } from "@archipelagolab/lobi-js-sdk/lib/types.js";
|
|
11
11
|
import type { PinnedDispatcherPolicy } from "openclaw/plugin-sdk/infra-runtime";
|
|
12
12
|
import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
|
|
13
13
|
import { normalizeNullableString } from "openclaw/plugin-sdk/text-runtime";
|
|
@@ -686,7 +686,7 @@ export class MatrixClient {
|
|
|
686
686
|
if (this.selfUserId) {
|
|
687
687
|
return this.selfUserId;
|
|
688
688
|
}
|
|
689
|
-
const whoami = (await this.doRequest("GET", "/
|
|
689
|
+
const whoami = (await this.doRequest("GET", "/_lobi/client/v3/account/whoami")) as {
|
|
690
690
|
user_id?: string;
|
|
691
691
|
};
|
|
692
692
|
const resolved = whoami.user_id?.trim();
|
|
@@ -879,7 +879,7 @@ export class MatrixClient {
|
|
|
879
879
|
readIdleTimeoutMs: opts.readIdleTimeoutMs,
|
|
880
880
|
});
|
|
881
881
|
|
|
882
|
-
const authenticatedEndpoint = `/
|
|
882
|
+
const authenticatedEndpoint = `/_lobi/client/v1/media/download/${encodedServer}/${encodedMediaId}`;
|
|
883
883
|
try {
|
|
884
884
|
return await request(authenticatedEndpoint);
|
|
885
885
|
} catch (err) {
|
|
@@ -888,7 +888,7 @@ export class MatrixClient {
|
|
|
888
888
|
}
|
|
889
889
|
}
|
|
890
890
|
|
|
891
|
-
const legacyEndpoint = `/
|
|
891
|
+
const legacyEndpoint = `/_lobi/media/v3/download/${encodedServer}/${encodedMediaId}`;
|
|
892
892
|
return await request(legacyEndpoint);
|
|
893
893
|
}
|
|
894
894
|
|
|
@@ -966,7 +966,7 @@ export class MatrixClient {
|
|
|
966
966
|
async sendReadReceipt(roomId: string, eventId: string): Promise<void> {
|
|
967
967
|
await this.httpClient.requestJson({
|
|
968
968
|
method: "POST",
|
|
969
|
-
endpoint: `/
|
|
969
|
+
endpoint: `/_lobi/client/v3/rooms/${encodeURIComponent(roomId)}/receipt/m.read/${encodeURIComponent(
|
|
970
970
|
eventId,
|
|
971
971
|
)}`,
|
|
972
972
|
body: {},
|
|
@@ -1285,7 +1285,7 @@ export class MatrixClient {
|
|
|
1285
1285
|
try {
|
|
1286
1286
|
await this.doRequest(
|
|
1287
1287
|
"DELETE",
|
|
1288
|
-
`/
|
|
1288
|
+
`/_lobi/client/v3/room_keys/version/${encodeURIComponent(previousVersion)}`,
|
|
1289
1289
|
);
|
|
1290
1290
|
} catch (err) {
|
|
1291
1291
|
if (!isMatrixNotFoundError(err)) {
|
|
@@ -1358,7 +1358,7 @@ export class MatrixClient {
|
|
|
1358
1358
|
}
|
|
1359
1359
|
|
|
1360
1360
|
try {
|
|
1361
|
-
const response = (await this.doRequest("POST", "/
|
|
1361
|
+
const response = (await this.doRequest("POST", "/_lobi/client/v3/keys/query", undefined, {
|
|
1362
1362
|
device_keys: { [userId]: [] as string[] },
|
|
1363
1363
|
})) as {
|
|
1364
1364
|
master_keys?: Record<string, unknown>;
|
|
@@ -1621,7 +1621,7 @@ export class MatrixClient {
|
|
|
1621
1621
|
|
|
1622
1622
|
private async resolveRoomKeyBackupVersion(): Promise<string | null> {
|
|
1623
1623
|
try {
|
|
1624
|
-
const response = (await this.doRequest("GET", "/
|
|
1624
|
+
const response = (await this.doRequest("GET", "/_lobi/client/v3/room_keys/version")) as {
|
|
1625
1625
|
version?: string;
|
|
1626
1626
|
};
|
|
1627
1627
|
return normalizeOptionalString(response.version);
|