botschat 0.1.6 → 0.1.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 +62 -22
- package/migrations/0011_e2e_encryption.sql +35 -0
- package/package.json +4 -2
- package/packages/api/src/do/connection-do.ts +37 -9
- package/packages/api/src/index.ts +29 -7
- package/packages/api/src/routes/auth.ts +4 -1
- package/packages/api/src/routes/setup.ts +2 -0
- package/packages/plugin/dist/src/accounts.d.ts.map +1 -1
- package/packages/plugin/dist/src/accounts.js +1 -0
- package/packages/plugin/dist/src/accounts.js.map +1 -1
- package/packages/plugin/dist/src/channel.d.ts +1 -0
- package/packages/plugin/dist/src/channel.d.ts.map +1 -1
- package/packages/plugin/dist/src/channel.js +180 -13
- package/packages/plugin/dist/src/channel.js.map +1 -1
- package/packages/plugin/dist/src/types.d.ts +16 -0
- package/packages/plugin/dist/src/types.d.ts.map +1 -1
- package/packages/plugin/dist/src/ws-client.d.ts +2 -0
- package/packages/plugin/dist/src/ws-client.d.ts.map +1 -1
- package/packages/plugin/dist/src/ws-client.js +18 -3
- package/packages/plugin/dist/src/ws-client.js.map +1 -1
- package/packages/plugin/package.json +3 -2
- package/packages/web/dist/architecture.png +0 -0
- package/packages/web/dist/assets/__vite-browser-external-BIHI7g3E.js +1 -0
- package/packages/web/dist/assets/{index-BST9bfvT.css → index-B1sFqYiM.css} +1 -1
- package/packages/web/dist/assets/index-C-FpELeN.js +1497 -0
- package/packages/web/dist/index.html +2 -2
- package/packages/web/package.json +1 -0
- package/packages/web/src/App.tsx +53 -9
- package/packages/web/src/analytics.ts +57 -0
- package/packages/web/src/api.ts +4 -0
- package/packages/web/src/components/ConnectionSettings.tsx +3 -1
- package/packages/web/src/components/E2ESettings.tsx +146 -0
- package/packages/web/src/components/IconRail.tsx +1 -12
- package/packages/web/src/components/LoginPage.tsx +19 -3
- package/packages/web/src/components/OnboardingPage.tsx +199 -5
- package/packages/web/src/e2e.ts +146 -0
- package/packages/web/src/main.tsx +3 -0
- package/packages/web/src/store.ts +4 -3
- package/packages/web/src/ws.ts +79 -4
- package/scripts/dev.sh +5 -5
- package/scripts/test-e2e-chat.ts +97 -0
- package/scripts/test-e2e-live.ts +194 -0
- package/scripts/verify-e2e-db.ts +48 -0
- package/scripts/verify-e2e.ts +56 -0
- package/packages/web/dist/assets/index-Da18EnTa.js +0 -851
package/README.md
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
[](https://www.npmjs.com/package/@botschat/botschat)
|
|
5
5
|
[](LICENSE)
|
|
6
6
|
|
|
7
|
-
A self-hosted chat interface for [OpenClaw](https://github.com/openclaw/openclaw) AI agents.
|
|
7
|
+
A self-hosted, **end-to-end encrypted** chat interface for [OpenClaw](https://github.com/openclaw/openclaw) AI agents.
|
|
8
8
|
|
|
9
|
-
BotsChat gives you a modern, Slack-like web UI to interact with your OpenClaw agents — organize conversations into **Channels**, schedule **Background Tasks**, and monitor **Job** executions.
|
|
9
|
+
BotsChat gives you a modern, Slack-like web UI to interact with your OpenClaw agents — organize conversations into **Channels**, schedule **Background Tasks**, and monitor **Job** executions. With **E2E encryption**, your chat messages, cron prompts, and job summaries are encrypted on your device before they ever leave — the server only sees ciphertext it cannot decrypt. Your API keys and data never leave your machine.
|
|
10
10
|
|
|
11
11
|
## Key Features
|
|
12
12
|
|
|
@@ -34,6 +34,15 @@ Schedule **cron-style background tasks** that run your agents on autopilot. Each
|
|
|
34
34
|
|
|
35
35
|

|
|
36
36
|
|
|
37
|
+
### End-to-End Encryption
|
|
38
|
+
|
|
39
|
+
BotsChat supports **optional E2E encryption** so the server never sees your content in plaintext:
|
|
40
|
+
|
|
41
|
+
- **What's encrypted**: Chat messages, cron task prompts, and job execution summaries — all encrypted with AES-256-CTR before leaving your browser or plugin.
|
|
42
|
+
- **Zero-knowledge server**: The BotsChat cloud/server stores only ciphertext and cannot decrypt your data. No keys, no salts stored server-side.
|
|
43
|
+
- **How it works**: You set an E2E password in both the web UI and the OpenClaw plugin. Both sides derive the same encryption key using `PBKDF2(password, userId)`. Messages are encrypted/decrypted locally — the server just relays and stores opaque bytes.
|
|
44
|
+
- **Zero overhead**: AES-CTR produces ciphertext the same size as plaintext — no bloat, no padding.
|
|
45
|
+
|
|
37
46
|
### Built-in Debug Log
|
|
38
47
|
|
|
39
48
|
A collapsible **Debug Log** panel at the bottom of the UI gives you real-time visibility into what's happening under the hood — WebSocket events, cron task loading, agent scan results, and more. Filter by log level (ALL, WS, WST, API, INF, WRN, ERR) to quickly diagnose issues without leaving the chat interface.
|
|
@@ -46,7 +55,9 @@ A collapsible **Debug Log** panel at the bottom of the UI gives you real-time vi
|
|
|
46
55
|
|
|
47
56
|

|
|
48
57
|
|
|
49
|
-
OpenClaw runs your agents locally (with your API keys, data, and configs). The BotsChat plugin establishes an **outbound WebSocket** to the BotsChat server — no port forwarding, no tunnels. Your API keys and data never leave your machine
|
|
58
|
+
OpenClaw runs your agents locally (with your API keys, data, and configs). The BotsChat plugin establishes an **outbound WebSocket** to the BotsChat server — no port forwarding, no tunnels. Your API keys and data never leave your machine.
|
|
59
|
+
|
|
60
|
+
When **E2E encryption** is enabled, messages are encrypted on the sender's device (browser or plugin) before transmission. The BotsChat server (ConnectionDO) only relays and stores opaque ciphertext — it has no access to keys and cannot read your content. Encryption keys are derived locally from your password and never sent over the network.
|
|
50
61
|
|
|
51
62
|
You can run BotsChat locally on the same machine, or deploy it to Cloudflare for remote access (e.g. from your phone).
|
|
52
63
|
|
|
@@ -71,36 +82,42 @@ BotsChat introduces a few UI-level concepts that map to OpenClaw primitives:
|
|
|
71
82
|
|
|
72
83
|
### Prerequisites
|
|
73
84
|
|
|
74
|
-
- [Node.js](https://nodejs.org/) 22+
|
|
75
|
-
- [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/install-and-update/)
|
|
76
85
|
- An [OpenClaw](https://github.com/openclaw/openclaw) instance
|
|
86
|
+
- For self-hosting (Option B or C): [Node.js](https://nodejs.org/) 22+, [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/install-and-update/)
|
|
77
87
|
|
|
78
|
-
###
|
|
88
|
+
### Choose Your Deployment
|
|
79
89
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
90
|
+
BotsChat is **100% open source** — the [same code](https://github.com/botschat-app/botsChat) runs whether you use our hosted console, run it locally, or deploy to your own Cloudflare. The only difference is *where* the server runs; your API keys and data always stay on your machine.
|
|
91
|
+
|
|
92
|
+
| Mode | Best for | Clone repo? |
|
|
93
|
+
|------|----------|-------------|
|
|
94
|
+
| **A. Hosted Console** | Zero setup, start in minutes | No |
|
|
95
|
+
| **B. Run Locally** | Development, no cloud account | Yes |
|
|
96
|
+
| **C. Deploy to Cloudflare** | Remote access (e.g. from phone) | Yes |
|
|
85
97
|
|
|
86
|
-
|
|
98
|
+
Pick one below and follow its steps, then continue to [Install the OpenClaw Plugin](#install-the-openclaw-plugin).
|
|
99
|
+
|
|
100
|
+
---
|
|
87
101
|
|
|
88
|
-
|
|
102
|
+
#### Option A: Hosted Console (Recommended)
|
|
89
103
|
|
|
90
|
-
|
|
104
|
+
We run the same open-source stack at **[console.botschat.app](https://console.botschat.app)**. No clone, no deploy: open the link → sign up → create a pairing token → connect OpenClaw.
|
|
91
105
|
|
|
92
|
-
|
|
106
|
+
Your API keys and data still stay on your machine; the hosted console only relays chat messages via WebSocket. Enable **E2E encryption** for complete privacy — the hosted console cannot decrypt your content.
|
|
93
107
|
|
|
94
|
-
|
|
108
|
+
→ Then go to [Install the OpenClaw Plugin](#install-the-openclaw-plugin).
|
|
95
109
|
|
|
96
|
-
|
|
110
|
+
---
|
|
97
111
|
|
|
98
112
|
#### Option B: Run Locally
|
|
99
113
|
|
|
100
|
-
Wrangler uses [Miniflare](https://miniflare.dev)
|
|
114
|
+
Clone, install, and run the server on your machine. Wrangler uses [Miniflare](https://miniflare.dev), so D1, R2, and Durable Objects all run locally — **no Cloudflare account needed**.
|
|
101
115
|
|
|
102
116
|
```bash
|
|
103
|
-
|
|
117
|
+
git clone https://github.com/botschat-app/botsChat.git
|
|
118
|
+
cd botsChat
|
|
119
|
+
npm install
|
|
120
|
+
# One-command startup: build web → migrate D1 → start on 0.0.0.0:8787
|
|
104
121
|
./scripts/dev.sh
|
|
105
122
|
```
|
|
106
123
|
|
|
@@ -124,11 +141,19 @@ Other dev commands:
|
|
|
124
141
|
./scripts/dev.sh logs # Tail remote gateway logs
|
|
125
142
|
```
|
|
126
143
|
|
|
144
|
+
→ Then go to [Install the OpenClaw Plugin](#install-the-openclaw-plugin).
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
127
148
|
#### Option C: Deploy to Cloudflare
|
|
128
149
|
|
|
129
|
-
For remote access (e.g. chatting
|
|
150
|
+
For remote access (e.g. chatting from your phone), deploy the same code to Cloudflare Workers. The free tier is enough for personal use.
|
|
130
151
|
|
|
131
152
|
```bash
|
|
153
|
+
git clone https://github.com/botschat-app/botsChat.git
|
|
154
|
+
cd botsChat
|
|
155
|
+
npm install
|
|
156
|
+
|
|
132
157
|
# Create Cloudflare resources
|
|
133
158
|
wrangler d1 create botschat-db # Copy the database_id into wrangler.toml
|
|
134
159
|
wrangler r2 bucket create botschat-media
|
|
@@ -147,7 +172,11 @@ wrangler secret put JWT_SECRET # Set a production JWT secret
|
|
|
147
172
|
| D1 | Database (users, channels, tasks) | 5M reads/day, 100K writes/day |
|
|
148
173
|
| R2 | Media storage | 10GB, no egress fees |
|
|
149
174
|
|
|
150
|
-
|
|
175
|
+
→ Then go to [Install the OpenClaw Plugin](#install-the-openclaw-plugin).
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
### Install the OpenClaw Plugin
|
|
151
180
|
|
|
152
181
|
After the BotsChat server is running, connect your OpenClaw instance to it.
|
|
153
182
|
|
|
@@ -172,6 +201,14 @@ openclaw config set channels.botschat.pairingToken <YOUR_PAIRING_TOKEN>
|
|
|
172
201
|
openclaw config set channels.botschat.enabled true
|
|
173
202
|
```
|
|
174
203
|
|
|
204
|
+
**3b. (Optional) Enable E2E encryption**
|
|
205
|
+
|
|
206
|
+
Set the same password you'll use in the BotsChat web UI:
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
openclaw config set channels.botschat.e2ePassword "your-secret-e2e-password"
|
|
210
|
+
```
|
|
211
|
+
|
|
175
212
|
This writes the following to your `~/.openclaw/openclaw.json`:
|
|
176
213
|
|
|
177
214
|
```json
|
|
@@ -180,7 +217,8 @@ This writes the following to your `~/.openclaw/openclaw.json`:
|
|
|
180
217
|
"botschat": {
|
|
181
218
|
"enabled": true,
|
|
182
219
|
"cloudUrl": "http://localhost:8787",
|
|
183
|
-
"pairingToken": "bc_pat_xxxxxxxxxxxxxxxx"
|
|
220
|
+
"pairingToken": "bc_pat_xxxxxxxxxxxxxxxx",
|
|
221
|
+
"e2ePassword": "your-secret-e2e-password"
|
|
184
222
|
}
|
|
185
223
|
}
|
|
186
224
|
}
|
|
@@ -207,6 +245,7 @@ Open the BotsChat web UI in your browser, sign in, and start chatting with your
|
|
|
207
245
|
2. This WebSocket stays connected (with automatic reconnection if it drops).
|
|
208
246
|
3. When you type a message in the web UI, it travels: **Browser → ConnectionDO → WebSocket → OpenClaw → Agent → response back through the same path**.
|
|
209
247
|
4. Your API keys, agent configs, and data never leave your machine — only chat messages travel through the relay.
|
|
248
|
+
5. With **E2E encryption** enabled, messages are encrypted **before** step 3 and decrypted **after** — the ConnectionDO and database only ever see ciphertext.
|
|
210
249
|
|
|
211
250
|
## Plugin Reference
|
|
212
251
|
|
|
@@ -219,6 +258,7 @@ All config lives under `channels.botschat` in your `openclaw.json`:
|
|
|
219
258
|
| `enabled` | boolean | no | Enable/disable the channel (default: true) |
|
|
220
259
|
| `cloudUrl` | string | yes | BotsChat server URL (e.g. `http://localhost:8787`) |
|
|
221
260
|
| `pairingToken` | string | yes | Your pairing token from the BotsChat dashboard |
|
|
261
|
+
| `e2ePassword` | string | no | E2E encryption password (must match the web UI) |
|
|
222
262
|
| `name` | string | no | Display name for this connection |
|
|
223
263
|
|
|
224
264
|
### Message Protocol
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
-- E2E Encryption: rebuild messages and jobs tables with BLOB columns + encrypted flag.
|
|
2
|
+
-- WARNING: This migration drops all existing data in messages and jobs tables.
|
|
3
|
+
|
|
4
|
+
DROP TABLE IF EXISTS messages;
|
|
5
|
+
CREATE TABLE messages (
|
|
6
|
+
id TEXT PRIMARY KEY,
|
|
7
|
+
user_id TEXT NOT NULL,
|
|
8
|
+
session_key TEXT NOT NULL,
|
|
9
|
+
thread_id TEXT,
|
|
10
|
+
sender TEXT NOT NULL CHECK (sender IN ('user', 'agent')),
|
|
11
|
+
text BLOB,
|
|
12
|
+
media_url TEXT,
|
|
13
|
+
a2ui BLOB,
|
|
14
|
+
encrypted INTEGER NOT NULL DEFAULT 0,
|
|
15
|
+
created_at INTEGER NOT NULL DEFAULT (unixepoch())
|
|
16
|
+
);
|
|
17
|
+
CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_key, created_at);
|
|
18
|
+
CREATE INDEX IF NOT EXISTS idx_messages_thread ON messages(thread_id, created_at);
|
|
19
|
+
|
|
20
|
+
DROP TABLE IF EXISTS jobs;
|
|
21
|
+
CREATE TABLE jobs (
|
|
22
|
+
id TEXT PRIMARY KEY,
|
|
23
|
+
task_id TEXT NOT NULL,
|
|
24
|
+
user_id TEXT NOT NULL,
|
|
25
|
+
session_key TEXT NOT NULL,
|
|
26
|
+
status TEXT NOT NULL CHECK (status IN ('running', 'ok', 'error', 'skipped')),
|
|
27
|
+
started_at INTEGER NOT NULL DEFAULT (unixepoch()),
|
|
28
|
+
finished_at INTEGER,
|
|
29
|
+
duration_ms INTEGER,
|
|
30
|
+
summary BLOB,
|
|
31
|
+
encrypted INTEGER NOT NULL DEFAULT 0,
|
|
32
|
+
created_at INTEGER NOT NULL DEFAULT (unixepoch())
|
|
33
|
+
);
|
|
34
|
+
CREATE INDEX IF NOT EXISTS idx_jobs_task ON jobs(task_id, started_at DESC);
|
|
35
|
+
CREATE INDEX IF NOT EXISTS idx_jobs_session ON jobs(session_key);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "botschat",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "A self-hosted chat interface for OpenClaw AI agents",
|
|
5
5
|
"workspaces": [
|
|
6
6
|
"packages/*"
|
|
@@ -15,7 +15,9 @@
|
|
|
15
15
|
"db:migrate": "wrangler d1 migrations apply botschat-db --local",
|
|
16
16
|
"db:migrate:remote": "wrangler d1 migrations apply botschat-db --remote",
|
|
17
17
|
"typecheck": "tsc --noEmit",
|
|
18
|
-
"build:plugin": "npm run build -w packages/plugin"
|
|
18
|
+
"build:plugin": "npm run build -w packages/plugin",
|
|
19
|
+
"test:e2e": "npx tsx scripts/verify-e2e.ts && npx tsx packages/e2e-crypto/e2e-crypto.test.ts",
|
|
20
|
+
"test:e2e-db": "npx tsx scripts/verify-e2e-db.ts"
|
|
19
21
|
},
|
|
20
22
|
"files": [
|
|
21
23
|
"packages/api/src/",
|
|
@@ -179,7 +179,10 @@ export class ConnectionDO implements DurableObject {
|
|
|
179
179
|
|
|
180
180
|
if (isValid) {
|
|
181
181
|
ws.serializeAttachment({ ...attachment, authenticated: true });
|
|
182
|
-
|
|
182
|
+
// Include userId so the plugin can derive the E2E key
|
|
183
|
+
const userId = await this.state.storage.get<string>("userId");
|
|
184
|
+
console.log(`[DO] auth.ok → userId=${userId}`);
|
|
185
|
+
ws.send(JSON.stringify({ type: "auth.ok", userId }));
|
|
183
186
|
// Store gateway default model from plugin auth
|
|
184
187
|
if (msg.model) {
|
|
185
188
|
this.defaultModel = msg.model as string;
|
|
@@ -228,12 +231,14 @@ export class ConnectionDO implements DurableObject {
|
|
|
228
231
|
}
|
|
229
232
|
|
|
230
233
|
await this.persistMessage({
|
|
234
|
+
id: msg.messageId as string | undefined,
|
|
231
235
|
sender: "agent",
|
|
232
236
|
sessionKey: msg.sessionKey as string,
|
|
233
237
|
threadId: (msg.threadId ?? msg.replyToId) as string | undefined,
|
|
234
238
|
text: (msg.text ?? msg.caption ?? "") as string,
|
|
235
239
|
mediaUrl: persistedMediaUrl,
|
|
236
240
|
a2ui: msg.jsonl as string | undefined,
|
|
241
|
+
encrypted: msg.encrypted ? 1 : 0,
|
|
237
242
|
});
|
|
238
243
|
}
|
|
239
244
|
|
|
@@ -270,12 +275,24 @@ export class ConnectionDO implements DurableObject {
|
|
|
270
275
|
);
|
|
271
276
|
}
|
|
272
277
|
|
|
278
|
+
// Plugin applied BotsChat default model to OpenClaw config — update and broadcast
|
|
279
|
+
if (msg.type === "defaultModel.updated" && typeof msg.model === "string") {
|
|
280
|
+
this.defaultModel = msg.model;
|
|
281
|
+
await this.state.storage.put("defaultModel", this.defaultModel);
|
|
282
|
+
this.broadcastToBrowsers(
|
|
283
|
+
JSON.stringify({ type: "connection.status", openclawConnected: true, defaultModel: this.defaultModel, models: this.cachedModels }),
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
|
|
273
287
|
// Handle job updates from plugin — persist and forward to browsers
|
|
274
288
|
if (msg.type === "job.update") {
|
|
275
289
|
await this.handleJobUpdate(msg);
|
|
276
290
|
}
|
|
277
291
|
|
|
278
292
|
// Forward all messages to browser clients
|
|
293
|
+
if (msg.type === "agent.text") {
|
|
294
|
+
console.log(`[DO] Forwarding agent.text to browsers: encrypted=${msg.encrypted}, messageId=${msg.messageId}, textLen=${typeof msg.text === "string" ? msg.text.length : "?"}`);
|
|
295
|
+
}
|
|
279
296
|
this.broadcastToBrowsers(JSON.stringify(msg));
|
|
280
297
|
}
|
|
281
298
|
|
|
@@ -311,7 +328,9 @@ export class ConnectionDO implements DurableObject {
|
|
|
311
328
|
}
|
|
312
329
|
|
|
313
330
|
ws.serializeAttachment({ ...attachment, authenticated: true });
|
|
314
|
-
|
|
331
|
+
// Include userId so the browser can derive the E2E key
|
|
332
|
+
const doUserId2 = doUserId ?? payload.sub;
|
|
333
|
+
ws.send(JSON.stringify({ type: "auth.ok", userId: doUserId2 }));
|
|
315
334
|
|
|
316
335
|
// Send current OpenClaw connection status + cached models
|
|
317
336
|
await this.ensureCachedModels();
|
|
@@ -346,6 +365,7 @@ export class ConnectionDO implements DurableObject {
|
|
|
346
365
|
sessionKey: msg.sessionKey as string,
|
|
347
366
|
text: (msg.text ?? "") as string,
|
|
348
367
|
mediaUrl: msg.mediaUrl as string | undefined,
|
|
368
|
+
encrypted: msg.encrypted ? 1 : 0,
|
|
349
369
|
});
|
|
350
370
|
}
|
|
351
371
|
|
|
@@ -400,6 +420,8 @@ export class ConnectionDO implements DurableObject {
|
|
|
400
420
|
instructions: (t.instructions as string) ?? "",
|
|
401
421
|
model: (t.model as string) ?? "",
|
|
402
422
|
enabled: t.enabled as boolean,
|
|
423
|
+
encrypted: (t.encrypted as boolean) ?? false,
|
|
424
|
+
iv: (t.iv as string) ?? undefined,
|
|
403
425
|
}));
|
|
404
426
|
return Response.json({ tasks: result });
|
|
405
427
|
} catch (err) {
|
|
@@ -633,10 +655,12 @@ export class ConnectionDO implements DurableObject {
|
|
|
633
655
|
text: string;
|
|
634
656
|
mediaUrl?: string;
|
|
635
657
|
a2ui?: string;
|
|
658
|
+
encrypted?: number;
|
|
636
659
|
}): Promise<void> {
|
|
637
660
|
try {
|
|
638
661
|
const userId = (await this.state.storage.get<string>("userId")) ?? "unknown";
|
|
639
662
|
const id = opts.id ?? crypto.randomUUID();
|
|
663
|
+
const encrypted = opts.encrypted ?? 0;
|
|
640
664
|
|
|
641
665
|
// Extract threadId from sessionKey pattern: ....:thread:{threadId}
|
|
642
666
|
let threadId = opts.threadId;
|
|
@@ -646,10 +670,10 @@ export class ConnectionDO implements DurableObject {
|
|
|
646
670
|
}
|
|
647
671
|
|
|
648
672
|
await this.env.DB.prepare(
|
|
649
|
-
`INSERT INTO messages (id, user_id, session_key, thread_id, sender, text, media_url, a2ui)
|
|
650
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
673
|
+
`INSERT INTO messages (id, user_id, session_key, thread_id, sender, text, media_url, a2ui, encrypted)
|
|
674
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
651
675
|
)
|
|
652
|
-
.bind(id, userId, opts.sessionKey, threadId ?? null, opts.sender, opts.text, opts.mediaUrl ?? null, opts.a2ui ?? null)
|
|
676
|
+
.bind(id, userId, opts.sessionKey, threadId ?? null, opts.sender, opts.text, opts.mediaUrl ?? null, opts.a2ui ?? null, encrypted)
|
|
653
677
|
.run();
|
|
654
678
|
} catch (err) {
|
|
655
679
|
console.error("Failed to persist message:", err);
|
|
@@ -671,7 +695,7 @@ export class ConnectionDO implements DurableObject {
|
|
|
671
695
|
if (threadId) {
|
|
672
696
|
// Load thread messages
|
|
673
697
|
result = await this.env.DB.prepare(
|
|
674
|
-
`SELECT id, session_key, thread_id, sender, text, media_url, a2ui, created_at
|
|
698
|
+
`SELECT id, session_key, thread_id, sender, text, media_url, a2ui, encrypted, created_at
|
|
675
699
|
FROM messages
|
|
676
700
|
WHERE session_key = ? AND thread_id = ?
|
|
677
701
|
ORDER BY created_at ASC
|
|
@@ -682,7 +706,7 @@ export class ConnectionDO implements DurableObject {
|
|
|
682
706
|
} else {
|
|
683
707
|
// Load main session messages (exclude thread messages from the main list)
|
|
684
708
|
result = await this.env.DB.prepare(
|
|
685
|
-
`SELECT id, session_key, thread_id, sender, text, media_url, a2ui, created_at
|
|
709
|
+
`SELECT id, session_key, thread_id, sender, text, media_url, a2ui, encrypted, created_at
|
|
686
710
|
FROM messages
|
|
687
711
|
WHERE session_key = ? AND thread_id IS NULL
|
|
688
712
|
ORDER BY created_at ASC
|
|
@@ -720,6 +744,7 @@ export class ConnectionDO implements DurableObject {
|
|
|
720
744
|
mediaUrl: row.media_url ?? undefined,
|
|
721
745
|
a2ui: row.a2ui ?? undefined,
|
|
722
746
|
threadId: row.thread_id ?? undefined,
|
|
747
|
+
encrypted: row.encrypted ?? 0,
|
|
723
748
|
}));
|
|
724
749
|
|
|
725
750
|
return Response.json({ messages, replyCounts });
|
|
@@ -967,9 +992,11 @@ export class ConnectionDO implements DurableObject {
|
|
|
967
992
|
return;
|
|
968
993
|
}
|
|
969
994
|
|
|
995
|
+
const encrypted = msg.encrypted ? 1 : 0;
|
|
996
|
+
|
|
970
997
|
await this.env.DB.prepare(
|
|
971
|
-
`INSERT OR REPLACE INTO jobs (id, task_id, user_id, session_key, status, started_at, finished_at, duration_ms, summary)
|
|
972
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
998
|
+
`INSERT OR REPLACE INTO jobs (id, task_id, user_id, session_key, status, started_at, finished_at, duration_ms, summary, encrypted)
|
|
999
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
973
1000
|
)
|
|
974
1001
|
.bind(
|
|
975
1002
|
jobId,
|
|
@@ -981,6 +1008,7 @@ export class ConnectionDO implements DurableObject {
|
|
|
981
1008
|
finishedAt ?? null,
|
|
982
1009
|
durationMs ?? null,
|
|
983
1010
|
summary,
|
|
1011
|
+
encrypted,
|
|
984
1012
|
)
|
|
985
1013
|
.run();
|
|
986
1014
|
} catch (err) {
|
|
@@ -104,11 +104,14 @@ protectedApp.get("/me", async (c) => {
|
|
|
104
104
|
created_at: number;
|
|
105
105
|
}>();
|
|
106
106
|
if (!row) return c.json({ error: "User not found" }, 404);
|
|
107
|
+
const settings = JSON.parse(row.settings_json || "{}");
|
|
108
|
+
// defaultModel is not stored in D1 — it comes from the plugin (connection.status).
|
|
109
|
+
delete settings.defaultModel;
|
|
107
110
|
return c.json({
|
|
108
111
|
id: row.id,
|
|
109
112
|
email: row.email,
|
|
110
113
|
displayName: row.display_name,
|
|
111
|
-
settings
|
|
114
|
+
settings,
|
|
112
115
|
createdAt: row.created_at,
|
|
113
116
|
});
|
|
114
117
|
});
|
|
@@ -117,6 +120,7 @@ protectedApp.patch("/me", async (c) => {
|
|
|
117
120
|
const userId = c.get("userId");
|
|
118
121
|
const body = await c.req.json<{ defaultModel?: string }>();
|
|
119
122
|
|
|
123
|
+
// defaultModel is not stored in D1 — get/set only via plugin (connection.status / push).
|
|
120
124
|
const existing = await c.env.DB.prepare(
|
|
121
125
|
"SELECT settings_json FROM users WHERE id = ?",
|
|
122
126
|
)
|
|
@@ -124,18 +128,36 @@ protectedApp.patch("/me", async (c) => {
|
|
|
124
128
|
.first<{ settings_json: string }>();
|
|
125
129
|
|
|
126
130
|
const settings = JSON.parse(existing?.settings_json || "{}");
|
|
127
|
-
|
|
128
|
-
if
|
|
129
|
-
settings.defaultModel = body.defaultModel;
|
|
130
|
-
}
|
|
131
|
-
|
|
131
|
+
delete settings.defaultModel;
|
|
132
|
+
// Persist other settings (if any) to D1; defaultModel is never written.
|
|
132
133
|
await c.env.DB.prepare(
|
|
133
134
|
"UPDATE users SET settings_json = ? WHERE id = ?",
|
|
134
135
|
)
|
|
135
136
|
.bind(JSON.stringify(settings), userId)
|
|
136
137
|
.run();
|
|
137
138
|
|
|
138
|
-
|
|
139
|
+
if (body.defaultModel !== undefined) {
|
|
140
|
+
try {
|
|
141
|
+
const doId = c.env.CONNECTION_DO.idFromName(userId);
|
|
142
|
+
const stub = c.env.CONNECTION_DO.get(doId);
|
|
143
|
+
await stub.fetch(
|
|
144
|
+
new Request("https://internal/send", {
|
|
145
|
+
method: "POST",
|
|
146
|
+
headers: { "Content-Type": "application/json" },
|
|
147
|
+
body: JSON.stringify({
|
|
148
|
+
type: "settings.defaultModel",
|
|
149
|
+
defaultModel: body.defaultModel ?? "",
|
|
150
|
+
}),
|
|
151
|
+
}),
|
|
152
|
+
);
|
|
153
|
+
} catch (err) {
|
|
154
|
+
console.error("Failed to push default model to OpenClaw:", err);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const outSettings = { ...settings };
|
|
159
|
+
delete outSettings.defaultModel;
|
|
160
|
+
return c.json({ ok: true, settings: outSettings });
|
|
139
161
|
});
|
|
140
162
|
|
|
141
163
|
// OpenClaw scan data — schedule/instructions/model cached in the ConnectionDO.
|
|
@@ -287,11 +287,14 @@ auth.get("/me", async (c) => {
|
|
|
287
287
|
|
|
288
288
|
if (!row) return c.json({ error: "User not found" }, 404);
|
|
289
289
|
|
|
290
|
+
const settings = JSON.parse(row.settings_json || "{}");
|
|
291
|
+
delete settings.defaultModel; // not in D1 — comes from plugin (connection.status)
|
|
292
|
+
|
|
290
293
|
return c.json({
|
|
291
294
|
id: row.id,
|
|
292
295
|
email: row.email,
|
|
293
296
|
displayName: row.display_name,
|
|
294
|
-
settings
|
|
297
|
+
settings,
|
|
295
298
|
createdAt: row.created_at,
|
|
296
299
|
});
|
|
297
300
|
});
|
|
@@ -22,6 +22,7 @@ setup.post("/init", async (c) => {
|
|
|
22
22
|
email?: string;
|
|
23
23
|
password?: string;
|
|
24
24
|
idToken?: string;
|
|
25
|
+
e2ePassword?: string;
|
|
25
26
|
}>();
|
|
26
27
|
|
|
27
28
|
let userId: string;
|
|
@@ -187,6 +188,7 @@ setup.post("/init", async (c) => {
|
|
|
187
188
|
"openclaw plugins install @botschat/botschat",
|
|
188
189
|
`openclaw config set channels.botschat.cloudUrl ${cloudUrl}`,
|
|
189
190
|
`openclaw config set channels.botschat.pairingToken ${pairingToken}`,
|
|
191
|
+
...(body.e2ePassword ? [`openclaw config set channels.botschat.e2ePassword "${body.e2ePassword}"`] : []),
|
|
190
192
|
"openclaw config set channels.botschat.enabled true",
|
|
191
193
|
"openclaw gateway restart",
|
|
192
194
|
],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"accounts.d.ts","sourceRoot":"","sources":["../../src/accounts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,uBAAuB,EACxB,MAAM,YAAY,CAAC;AAUpB,uCAAuC;AACvC,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,EAAE,CAgB7D;AAED,kCAAkC;AAClC,wBAAgB,+BAA+B,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAGpE;AAED,sCAAsC;AACtC,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,OAAO,EACZ,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GACxB,uBAAuB,
|
|
1
|
+
{"version":3,"file":"accounts.d.ts","sourceRoot":"","sources":["../../src/accounts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,uBAAuB,EACxB,MAAM,YAAY,CAAC;AAUpB,uCAAuC;AACvC,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,EAAE,CAgB7D;AAED,kCAAkC;AAClC,wBAAgB,+BAA+B,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAGpE;AAED,sCAAsC;AACtC,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,OAAO,EACZ,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GACxB,uBAAuB,CA8BzB;AAED,mEAAmE;AACnE,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,OAAO,EACZ,SAAS,EAAE,MAAM,GAChB,OAAO,CAsBT;AAED,8DAA8D;AAC9D,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,OAAO,EACZ,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,GACf,OAAO,CAoBT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"accounts.js","sourceRoot":"","sources":["../../src/accounts.ts"],"names":[],"mappings":"AAMA,MAAM,kBAAkB,GAAG,SAAS,CAAC;AAErC,yDAAyD;AACzD,SAAS,OAAO,CAAC,GAAY;IAC3B,MAAM,CAAC,GAAG,GAA4B,CAAC;IACvC,OAAO,CAAC,EAAE,QAAQ,EAAE,QAAQ,IAAI,EAAE,CAAC;AACrC,CAAC;AAED,uCAAuC;AACvC,MAAM,UAAU,sBAAsB,CAAC,GAAY;IACjD,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IACvB,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,mDAAmD;IACnD,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;QACf,GAAG,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAC/B,CAAC;IACD,iBAAiB;IACjB,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;QACf,KAAK,MAAM,EAAE,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzC,IAAI,EAAE,KAAK,kBAAkB,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;gBAC7C,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACf,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC;AACrD,CAAC;AAED,kCAAkC;AAClC,MAAM,UAAU,+BAA+B,CAAC,GAAY;IAC1D,MAAM,GAAG,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC;IACxC,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,kBAAkB,CAAC;AACtC,CAAC;AAED,sCAAsC;AACtC,MAAM,UAAU,sBAAsB,CACpC,GAAY,EACZ,SAAyB;IAEzB,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IACvB,MAAM,EAAE,GAAG,SAAS,IAAI,+BAA+B,CAAC,GAAG,CAAC,CAAC;IAC7D,IAAI,IAA2B,CAAC;IAEhC,IAAI,EAAE,KAAK,kBAAkB,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QACnD,uBAAuB;QACvB,IAAI,GAAG;YACL,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,YAAY,EAAE,CAAC,CAAC,YAAY;
|
|
1
|
+
{"version":3,"file":"accounts.js","sourceRoot":"","sources":["../../src/accounts.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../../src/channel.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAuC,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAC/F,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../../src/channel.ts"],"names":[],"mappings":"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"}
|