botschat 0.1.14 → 0.1.15

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.
Files changed (25) hide show
  1. package/package.json +1 -1
  2. package/packages/api/src/do/connection-do.ts +95 -41
  3. package/packages/api/src/index.ts +42 -13
  4. package/packages/plugin/dist/src/ws-client.d.ts +1 -0
  5. package/packages/plugin/dist/src/ws-client.d.ts.map +1 -1
  6. package/packages/plugin/dist/src/ws-client.js +41 -4
  7. package/packages/plugin/dist/src/ws-client.js.map +1 -1
  8. package/packages/plugin/package.json +1 -1
  9. package/packages/web/dist/assets/index-CbCpFrA9.js +2 -0
  10. package/packages/web/dist/assets/index-Ct0m11C8.js +2 -0
  11. package/packages/web/dist/assets/{index-BJye3VHV.js → index-CvbTpaza.js} +122 -122
  12. package/packages/web/dist/assets/{index-CkIgZfHf.js → index-DsWBWQD6.js} +1 -1
  13. package/packages/web/dist/assets/index-GwprVhDP.js +1 -0
  14. package/packages/web/dist/assets/{index-CNSCbd7_.css → index-cm_3YFsA.css} +1 -1
  15. package/packages/web/dist/assets/{index-CQPXprFz.js → index-dMn_npR3.js} +1 -1
  16. package/packages/web/dist/assets/{index.esm-DgcFARs7.js → index.esm-DdTIpXjl.js} +1 -1
  17. package/packages/web/dist/assets/{web-CnOlwlZw.js → web-DIeOUVhn.js} +1 -1
  18. package/packages/web/dist/assets/{web-Bfku9Io_.js → web-Dft_LGIH.js} +1 -1
  19. package/packages/web/dist/index.html +2 -2
  20. package/packages/web/src/components/ChatWindow.tsx +7 -2
  21. package/packages/web/src/components/ThreadPanel.tsx +13 -4
  22. package/packages/web/src/utils/time.ts +23 -0
  23. package/packages/web/dist/assets/index-CPOiRHa4.js +0 -2
  24. package/packages/web/dist/assets/index-DbUyNI4d.js +0 -1
  25. package/packages/web/dist/assets/index-Dpvhc_dU.js +0 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "botschat",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
4
4
  "description": "A self-hosted chat interface for OpenClaw AI agents",
5
5
  "workspaces": [
6
6
  "packages/*"
@@ -32,6 +32,9 @@ export class ConnectionDO implements DurableObject {
32
32
  /** Browser sessions that report themselves in foreground (push notifications are suppressed). */
33
33
  private foregroundSessions = new Set<string>();
34
34
 
35
+ /** Timestamp of last accepted OpenClaw WebSocket (in-memory, no storage write). */
36
+ private lastOpenClawAcceptedAt = 0;
37
+
35
38
  constructor(state: DurableObjectState, env: Env) {
36
39
  this.state = state;
37
40
  this.env = env;
@@ -39,16 +42,33 @@ export class ConnectionDO implements DurableObject {
39
42
 
40
43
  /** Handle incoming HTTP requests (WebSocket upgrades). */
41
44
  async fetch(request: Request): Promise<Response> {
45
+ try {
46
+ return await this._fetch(request);
47
+ } catch (err) {
48
+ const msg = String(err);
49
+ if (msg.includes("Exceeded")) {
50
+ console.error("[DO] Storage limit exceeded:", msg);
51
+ return new Response("Storage limit exceeded, retry later", {
52
+ status: 503,
53
+ headers: { "Retry-After": "300" },
54
+ });
55
+ }
56
+ throw err;
57
+ }
58
+ }
59
+
60
+ private async _fetch(request: Request): Promise<Response> {
42
61
  const url = new URL(request.url);
43
62
 
44
63
  // Route: /gateway/:accountId — OpenClaw plugin connects here
45
64
  if (url.pathname.startsWith("/gateway/")) {
46
- // Extract and store userId from the gateway path
47
65
  const userId = url.pathname.split("/gateway/")[1]?.split("?")[0];
48
66
  if (userId) {
49
- await this.state.storage.put("userId", userId);
67
+ const stored = await this.state.storage.get<string>("userId");
68
+ if (stored !== userId) {
69
+ await this.state.storage.put("userId", userId);
70
+ }
50
71
  }
51
- // Check if the API worker already verified the token against D1
52
72
  const preVerified = url.searchParams.get("verified") === "1";
53
73
  return this.handleOpenClawConnect(request, preVerified);
54
74
  }
@@ -92,22 +112,32 @@ export class ConnectionDO implements DurableObject {
92
112
 
93
113
  /** Called when a WebSocket receives a message (wakes from hibernation). */
94
114
  async webSocketMessage(ws: WebSocket, message: string | ArrayBuffer): Promise<void> {
95
- const tag = this.getTag(ws);
96
- const data = typeof message === "string" ? message : new TextDecoder().decode(message);
97
-
98
- let parsed: Record<string, unknown>;
99
115
  try {
100
- parsed = JSON.parse(data);
101
- } catch {
102
- return; // Ignore malformed JSON
103
- }
116
+ const tag = this.getTag(ws);
117
+ const data = typeof message === "string" ? message : new TextDecoder().decode(message);
104
118
 
105
- if (tag === "openclaw") {
106
- // Message from OpenClaw → handle auth or forward to browsers
107
- await this.handleOpenClawMessage(ws, parsed);
108
- } else if (tag?.startsWith("browser:")) {
109
- // Message from browser → forward to OpenClaw
110
- await this.handleBrowserMessage(ws, parsed);
119
+ let parsed: Record<string, unknown>;
120
+ try {
121
+ parsed = JSON.parse(data);
122
+ } catch {
123
+ return;
124
+ }
125
+
126
+ if (tag === "openclaw") {
127
+ await this.handleOpenClawMessage(ws, parsed);
128
+ } else if (tag?.startsWith("browser:")) {
129
+ await this.handleBrowserMessage(ws, parsed);
130
+ }
131
+ } catch (err) {
132
+ const msg = String(err);
133
+ if (msg.includes("Exceeded")) {
134
+ console.error("[DO] Storage limit exceeded in webSocketMessage:", msg);
135
+ try {
136
+ ws.send(JSON.stringify({ type: "error", message: "Storage limit exceeded, retry later" }));
137
+ } catch { /* socket may already be dead */ }
138
+ return;
139
+ }
140
+ throw err;
111
141
  }
112
142
  }
113
143
 
@@ -139,10 +169,31 @@ export class ConnectionDO implements DurableObject {
139
169
  return new Response("Expected WebSocket upgrade", { status: 426 });
140
170
  }
141
171
 
172
+ const now = Date.now();
173
+ const cooldownMs = 30_000;
174
+ if (now - this.lastOpenClawAcceptedAt < cooldownMs) {
175
+ const retryAfter = Math.ceil((cooldownMs - (now - this.lastOpenClawAcceptedAt)) / 1000);
176
+ return new Response("Too many connections, retry later", {
177
+ status: 429,
178
+ headers: { "Retry-After": String(retryAfter) },
179
+ });
180
+ }
181
+ this.lastOpenClawAcceptedAt = now;
182
+
183
+ // Safety valve: if stale openclaw sockets accumulated (e.g. from
184
+ // rapid reconnects that authenticated but then lost their edge
185
+ // connection), close them all before accepting a new one.
186
+ const existing = this.state.getWebSockets("openclaw");
187
+ if (existing.length > 3) {
188
+ console.warn(`[DO] Safety valve: ${existing.length} openclaw sockets, closing all`);
189
+ for (const s of existing) {
190
+ try { s.close(4009, "replaced"); } catch { /* dead */ }
191
+ }
192
+ }
193
+
142
194
  const pair = new WebSocketPair();
143
195
  const [client, server] = [pair[0], pair[1]];
144
196
 
145
- // Accept with Hibernation API, tag as "openclaw"
146
197
  this.state.acceptWebSocket(server, ["openclaw"]);
147
198
 
148
199
  // If the API worker already verified the token against D1, mark as
@@ -187,31 +238,26 @@ export class ConnectionDO implements DurableObject {
187
238
  const isValid = attachment?.preVerified || await this.validatePairingToken(token);
188
239
 
189
240
  if (isValid) {
190
- // Close any existing (potentially stale) openclaw sockets before
191
- // marking the new one as authenticated. Cloudflare's edge infra
192
- // terminates WebSocket connections every ~60 min (code 1006). The
193
- // plugin reconnects immediately, but the DO may not have detected
194
- // the old socket's death yet (no close frame → no webSocketClose
195
- // callback yet). Without this cleanup, getOpenClawSocket() could
196
- // return a stale/dead socket, silently dropping all messages.
241
+ // Close ALL other openclaw sockets. Use custom code 4009 so
242
+ // well-behaved plugins know they were replaced (not a crash)
243
+ // and should NOT reconnect. The Worker-level rate limit (10s)
244
+ // prevents the resulting close event from flooding the DO.
197
245
  const existingSockets = this.state.getWebSockets("openclaw");
246
+ let closedCount = 0;
198
247
  for (const oldWs of existingSockets) {
199
248
  if (oldWs !== ws) {
200
249
  try {
201
- oldWs.close(1000, "replaced by new connection");
202
- } catch {
203
- // Socket may already be dead ignore
204
- }
250
+ oldWs.close(4009, "replaced");
251
+ closedCount++;
252
+ } catch { /* already dead */ }
205
253
  }
206
254
  }
207
255
 
208
256
  ws.serializeAttachment({ ...attachment, authenticated: true });
209
- // Include userId so the plugin can derive the E2E key
210
257
  const userId = await this.state.storage.get<string>("userId");
211
- console.log(`[DO] auth.ok → userId=${userId}, closedStale=${existingSockets.length - 1}`);
258
+ console.log(`[DO] auth.ok → userId=${userId}, closed=${closedCount}, total=${existingSockets.length}`);
212
259
  ws.send(JSON.stringify({ type: "auth.ok", userId }));
213
- // Store gateway default model from plugin auth
214
- if (msg.model) {
260
+ if (msg.model && msg.model !== this.defaultModel) {
215
261
  this.defaultModel = msg.model as string;
216
262
  await this.state.storage.put("defaultModel", this.defaultModel);
217
263
  }
@@ -295,20 +341,24 @@ export class ConnectionDO implements DurableObject {
295
341
  await this.handleTaskScanResult(msg);
296
342
  }
297
343
 
298
- // Handle models list from plugin — persist to storage and broadcast to browsers
299
344
  if (msg.type === "models.list") {
300
- this.cachedModels = (msg.models as Array<{ id: string; name: string; provider: string }>) ?? [];
301
- await this.state.storage.put("cachedModels", this.cachedModels);
302
- console.log(`[DO] Persisted ${this.cachedModels.length} models to storage, broadcasting connection.status`);
345
+ const newModels = (msg.models as Array<{ id: string; name: string; provider: string }>) ?? [];
346
+ const changed = JSON.stringify(newModels) !== JSON.stringify(this.cachedModels);
347
+ this.cachedModels = newModels;
348
+ if (changed) {
349
+ await this.state.storage.put("cachedModels", this.cachedModels);
350
+ console.log(`[DO] Persisted ${this.cachedModels.length} models to storage`);
351
+ }
303
352
  this.broadcastToBrowsers(
304
353
  JSON.stringify({ type: "connection.status", openclawConnected: true, defaultModel: this.defaultModel, models: this.cachedModels }),
305
354
  );
306
355
  }
307
356
 
308
- // Plugin applied BotsChat default model to OpenClaw config — update and broadcast
309
357
  if (msg.type === "defaultModel.updated" && typeof msg.model === "string") {
310
- this.defaultModel = msg.model;
311
- await this.state.storage.put("defaultModel", this.defaultModel);
358
+ if (msg.model !== this.defaultModel) {
359
+ this.defaultModel = msg.model;
360
+ await this.state.storage.put("defaultModel", this.defaultModel);
361
+ }
312
362
  this.broadcastToBrowsers(
313
363
  JSON.stringify({ type: "connection.status", openclawConnected: true, defaultModel: this.defaultModel, models: this.cachedModels }),
314
364
  );
@@ -1299,7 +1349,11 @@ export class ConnectionDO implements DurableObject {
1299
1349
  .first<{ user_id: string }>();
1300
1350
 
1301
1351
  const isValid = !!row;
1302
- await this.state.storage.put(cacheKey, { valid: isValid, cachedAt: Date.now() });
1352
+ try {
1353
+ await this.state.storage.put(cacheKey, { valid: isValid, cachedAt: Date.now() });
1354
+ } catch {
1355
+ // Non-critical — skip caching if storage is full
1356
+ }
1303
1357
  return isValid;
1304
1358
  } catch (err) {
1305
1359
  console.error("[DO] Failed to validate pairing token against D1:", err);
@@ -365,7 +365,6 @@ async function verifyUserAccess(c: { req: { header: (n: string) => string | unde
365
365
  app.all("/api/gateway/:connId", async (c) => {
366
366
  let userId = c.req.param("connId");
367
367
 
368
- // If connId is not a real user ID (e.g. "default"), resolve via token
369
368
  if (!userId.startsWith("u_")) {
370
369
  const token =
371
370
  c.req.query("token") ??
@@ -376,7 +375,6 @@ app.all("/api/gateway/:connId", async (c) => {
376
375
  return c.json({ error: "Token required for gateway connection" }, 401);
377
376
  }
378
377
 
379
- // Look up user by pairing token (exclude revoked tokens)
380
378
  const row = await c.env.DB.prepare(
381
379
  "SELECT user_id FROM pairing_tokens WHERE token = ? AND revoked_at IS NULL",
382
380
  )
@@ -387,26 +385,57 @@ app.all("/api/gateway/:connId", async (c) => {
387
385
  return c.json({ error: "Invalid pairing token" }, 401);
388
386
  }
389
387
  userId = row.user_id;
388
+ }
389
+
390
+ // --- Worker-level rate limit (Cache API) ---
391
+ // Protects the DO from being woken up during reconnection storms.
392
+ // The Cache API persists across Worker isolates within the same colo.
393
+ const GATEWAY_COOLDOWN_S = 10;
394
+ const cache = caches.default;
395
+ const rateCacheUrl = `https://rate.internal/gateway/${userId}`;
396
+ const rateCacheReq = new Request(rateCacheUrl);
397
+ const rateCached = await cache.match(rateCacheReq);
398
+ if (rateCached) {
399
+ return c.text("Too many connections, retry later", 429, {
400
+ "Retry-After": String(GATEWAY_COOLDOWN_S),
401
+ });
402
+ }
390
403
 
391
- // Update audit fields: last_connected_at, last_ip, connection_count
404
+ // Audit: update pairing token stats (only when not rate-limited)
405
+ const token = c.req.query("token") ?? c.req.header("X-Pairing-Token");
406
+ if (token) {
392
407
  const clientIp = c.req.header("CF-Connecting-IP") ?? c.req.header("X-Forwarded-For") ?? "unknown";
393
- await c.env.DB.prepare(
394
- `UPDATE pairing_tokens
395
- SET last_connected_at = unixepoch(), last_ip = ?, connection_count = connection_count + 1
396
- WHERE token = ?`,
397
- )
398
- .bind(clientIp, token)
399
- .run();
408
+ c.executionCtx.waitUntil(
409
+ c.env.DB.prepare(
410
+ `UPDATE pairing_tokens
411
+ SET last_connected_at = unixepoch(), last_ip = ?, connection_count = connection_count + 1
412
+ WHERE token = ?`,
413
+ ).bind(clientIp, token).run(),
414
+ );
400
415
  }
401
416
 
402
417
  const doId = c.env.CONNECTION_DO.idFromName(userId);
403
418
  const stub = c.env.CONNECTION_DO.get(doId);
404
419
  const url = new URL(c.req.url);
405
- // Pass verified userId to DO — the API worker already validated the token
406
- // against D1 above, so DO can trust this.
407
420
  url.pathname = `/gateway/${userId}`;
408
421
  url.searchParams.set("verified", "1");
409
- return stub.fetch(new Request(url.toString(), c.req.raw));
422
+ const doResp = await stub.fetch(new Request(url.toString(), c.req.raw));
423
+
424
+ // Cache the rate limit after the DO responds (success or rate-limited).
425
+ // 101 = WebSocket accepted; 429 = DO's own rate limit.
426
+ // Either way, prevent further DO wake-ups for GATEWAY_COOLDOWN_S.
427
+ if (doResp.status === 101 || doResp.status === 429) {
428
+ c.executionCtx.waitUntil(
429
+ cache.put(
430
+ rateCacheReq,
431
+ new Response(null, {
432
+ headers: { "Cache-Control": `public, max-age=${GATEWAY_COOLDOWN_S}` },
433
+ }),
434
+ ),
435
+ );
436
+ }
437
+
438
+ return doResp;
410
439
  });
411
440
 
412
441
  // Browser client connects to: /api/ws/:userId/:sessionId
@@ -30,6 +30,7 @@ export declare class BotsChatCloudClient {
30
30
  private ws;
31
31
  private reconnectTimer;
32
32
  private pingTimer;
33
+ private backoffResetTimer;
33
34
  private backoffMs;
34
35
  private intentionalClose;
35
36
  private _connected;
@@ -1 +1 @@
1
- {"version":3,"file":"ws-client.d.ts","sourceRoot":"","sources":["../../src/ws-client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE9D,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,0FAA0F;IAC1F,QAAQ,CAAC,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACpC,SAAS,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,IAAI,CAAC;IACvC,cAAc,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C,GAAG,CAAC,EAAE;QACJ,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAC5B,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAC5B,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;KAC9B,CAAC;CACH,CAAC;AAKF;;;;;;;;;GASG;AACH,qBAAa,mBAAmB;IAUlB,OAAO,CAAC,IAAI;IATxB,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,SAAS,CAA+C;IAChE,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,UAAU,CAAS;IACpB,MAAM,EAAE,UAAU,GAAG,IAAI,CAAQ;IACjC,aAAa,UAAS;gBAET,IAAI,EAAE,0BAA0B;IAEpD,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,6CAA6C;IAC7C,OAAO,IAAI,IAAI;IAyDf,4CAA4C;IAC5C,IAAI,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI;IAQ9B,6BAA6B;IAC7B,UAAU,IAAI,IAAI;YAgBJ,aAAa;IAmC3B,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,SAAS;IAejB,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,GAAG;CAMZ"}
1
+ {"version":3,"file":"ws-client.d.ts","sourceRoot":"","sources":["../../src/ws-client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE9D,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,0FAA0F;IAC1F,QAAQ,CAAC,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACpC,SAAS,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,IAAI,CAAC;IACvC,cAAc,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C,GAAG,CAAC,EAAE;QACJ,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAC5B,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAC5B,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;KAC9B,CAAC;CACH,CAAC;AAOF;;;;;;;;;GASG;AACH,qBAAa,mBAAmB;IAWlB,OAAO,CAAC,IAAI;IAVxB,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,SAAS,CAA+C;IAChE,OAAO,CAAC,iBAAiB,CAA8C;IACvE,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,UAAU,CAAS;IACpB,MAAM,EAAE,UAAU,GAAG,IAAI,CAAQ;IACjC,aAAa,UAAS;gBAET,IAAI,EAAE,0BAA0B;IAEpD,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,6CAA6C;IAC7C,OAAO,IAAI,IAAI;IAgFf,4CAA4C;IAC5C,IAAI,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI;IAQ9B,6BAA6B;IAC7B,UAAU,IAAI,IAAI;YAoBJ,aAAa;IAyC3B,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,SAAS;IAejB,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,GAAG;CAMZ"}
@@ -2,6 +2,8 @@ import WebSocket from "ws";
2
2
  import { deriveKey } from "./e2e-crypto.js";
3
3
  const MIN_BACKOFF_MS = 1_000;
4
4
  const MAX_BACKOFF_MS = 30_000;
5
+ /** Custom close code: server replaced this connection with a newer one. */
6
+ const CLOSE_REPLACED = 4009;
5
7
  /**
6
8
  * Manages a persistent outbound WebSocket connection from the OpenClaw
7
9
  * plugin to the BotsChat cloud (ConnectionDO on Cloudflare).
@@ -17,6 +19,7 @@ export class BotsChatCloudClient {
17
19
  ws = null;
18
20
  reconnectTimer = null;
19
21
  pingTimer = null;
22
+ backoffResetTimer = null;
20
23
  backoffMs = MIN_BACKOFF_MS;
21
24
  intentionalClose = false;
22
25
  _connected = false;
@@ -70,13 +73,36 @@ export class BotsChatCloudClient {
70
73
  this.log("warn", `WebSocket closed: code=${code} reason=${reason?.toString() ?? ""}`);
71
74
  this.setConnected(false);
72
75
  this.stopPing();
76
+ if (this.backoffResetTimer) {
77
+ clearTimeout(this.backoffResetTimer);
78
+ this.backoffResetTimer = null;
79
+ }
80
+ if (code === CLOSE_REPLACED) {
81
+ this.log("info", "Connection replaced by server — not reconnecting");
82
+ this.intentionalClose = true;
83
+ }
73
84
  if (!this.intentionalClose) {
74
85
  this.scheduleReconnect();
75
86
  }
76
87
  });
88
+ // Detect HTTP-level rejections before the WebSocket is established.
89
+ // Node ws emits 'unexpected-response' when the server returns non-101.
90
+ this.ws.on("unexpected-response", (_req, res) => {
91
+ const status = res?.statusCode ?? 0;
92
+ const retryAfter = parseInt(res?.headers?.["retry-after"] ?? "0", 10);
93
+ if (status === 429 && retryAfter > 0) {
94
+ this.log("warn", `Rate-limited (429), backing off ${retryAfter}s`);
95
+ this.backoffMs = retryAfter * 1000;
96
+ }
97
+ else if (status === 503) {
98
+ const secs = retryAfter || 300;
99
+ this.log("warn", `Service unavailable (503), backing off ${secs}s`);
100
+ this.backoffMs = secs * 1000;
101
+ }
102
+ // ws will emit 'close' after this, triggering scheduleReconnect
103
+ });
77
104
  this.ws.on("error", (err) => {
78
105
  this.log("error", `WebSocket error: ${err.message}`);
79
- // The "close" event will fire after this, triggering reconnect
80
106
  });
81
107
  }
82
108
  /** Send a message to the BotsChat cloud. */
@@ -95,6 +121,10 @@ export class BotsChatCloudClient {
95
121
  clearTimeout(this.reconnectTimer);
96
122
  this.reconnectTimer = null;
97
123
  }
124
+ if (this.backoffResetTimer) {
125
+ clearTimeout(this.backoffResetTimer);
126
+ this.backoffResetTimer = null;
127
+ }
98
128
  if (this.ws) {
99
129
  this.ws.close(1000, "shutdown");
100
130
  this.ws = null;
@@ -106,9 +136,16 @@ export class BotsChatCloudClient {
106
136
  switch (msg.type) {
107
137
  case "auth.ok":
108
138
  this.log("info", `Authenticated with BotsChat cloud (userId=${msg.userId}, hasE2ePwd=${!!this.opts.e2ePassword})`);
109
- // Mark connected FIRST so that subsequent messages (task.scan.request,
110
- // models.request) arriving while deriveKey is running can be processed.
111
- this.backoffMs = MIN_BACKOFF_MS;
139
+ // Delay backoff reset: only reset to MIN after the connection has
140
+ // been stable for 10s. If the connection drops immediately (e.g.
141
+ // server-side replacement), we keep the current backoff to avoid
142
+ // a fast reconnect loop.
143
+ if (this.backoffResetTimer)
144
+ clearTimeout(this.backoffResetTimer);
145
+ this.backoffResetTimer = setTimeout(() => {
146
+ this.backoffMs = MIN_BACKOFF_MS;
147
+ this.backoffResetTimer = null;
148
+ }, 10_000);
112
149
  this.setConnected(true);
113
150
  this.startPing();
114
151
  // Derive E2E key AFTER marking connected (PBKDF2 is slow ~1-2s).
@@ -1 +1 @@
1
- {"version":3,"file":"ws-client.js","sourceRoot":"","sources":["../../src/ws-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ws-client.js","sourceRoot":"","sources":["../../src/ws-client.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botschat/botschat",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
4
4
  "description": "BotsChat channel plugin for OpenClaw — connects your OpenClaw agent to the BotsChat cloud platform",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -0,0 +1,2 @@
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/web-DIeOUVhn.js","assets/index-CvbTpaza.js","assets/index-cm_3YFsA.css"])))=>i.map(i=>d[i]);
2
+ import{r as o,f as t}from"./index-CvbTpaza.js";const n=o("SocialLogin",{web:()=>t(()=>import("./web-DIeOUVhn.js"),__vite__mapDeps([0,1,2])).then(e=>new e.SocialLoginWeb)});export{n as SocialLogin};
@@ -0,0 +1,2 @@
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/web-Dft_LGIH.js","assets/index-CvbTpaza.js","assets/index-cm_3YFsA.css"])))=>i.map(i=>d[i]);
2
+ import{r as p,f as r}from"./index-CvbTpaza.js";const o=p("App",{web:()=>r(()=>import("./web-Dft_LGIH.js"),__vite__mapDeps([0,1,2])).then(e=>new e.AppWeb)});export{o as App};