ai_co_discuss 0.3.57 → 0.3.58

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai_co_discuss",
3
- "version": "0.3.57",
3
+ "version": "0.3.58",
4
4
  "bin": {
5
5
  "codiscuss": "runner/codiscuss.mjs"
6
6
  },
package/web/app.js CHANGED
@@ -48,6 +48,10 @@ const RELAY_COMMAND_POLL_MS = 250;
48
48
  const RELAY_SETTINGS_WAIT_MS = 20000;
49
49
  // The computer allows each operation 60 seconds, as the local website does.
50
50
  const RELAY_COMMAND_WAIT_MS = 75000;
51
+ // The website answers a relayed request within its wait (9 seconds unless asked for more); a request still unanswered
52
+ // this much later is stuck in the network and is given up, so a hung connection cannot hold back reconnecting.
53
+ const RELAY_DEFAULT_WAIT_MS = 9000;
54
+ const MACHINE_REQUEST_MARGIN_MS = 15000;
51
55
  const RELAY_CIPHER_INFO = "codiscuss-relay-v1";
52
56
  // The rooms kept on the paired computer are read and written through its relay connection; only room routes go there.
53
57
  const RELAY_PROTOCOL = "codiscuss-relay";
@@ -231,6 +235,7 @@ async function request_json(path, payload, access_token) {
231
235
  options.headers["Content-Type"] = "application/json";
232
236
  options.body = JSON.stringify(payload);
233
237
  }
238
+ if (path.startsWith("/api/machines")) options.signal = AbortSignal.timeout((Number.isInteger(payload?.wait) ? payload.wait : RELAY_DEFAULT_WAIT_MS) + MACHINE_REQUEST_MARGIN_MS);
234
239
  const response = await fetch(path, options);
235
240
  const result = await response.json();
236
241
  if (!response.ok) throw Object.assign(new Error(result.error || "请求失败,请重试"), { preflight: response.status >= 400 && response.status < 500, status: response.status });
@@ -2435,7 +2440,12 @@ async function relay_exchange(action, payload, wait) {
2435
2440
  const target = computer_rooms_only() ? { target: "computer" } : {};
2436
2441
  const { key, envelope } = await seal_relay_request(machine, id, { action, payload, ...target });
2437
2442
  const result = await request_json(`/api/machines/${encodeURIComponent(machine.id)}/relay`, { id, envelope, ...(wait ? { wait } : {}) })
2438
- .catch(error => { throw error.status === 401 ? Object.assign(error, { need: "pairing" }) : error; });
2443
+ .catch(error => {
2444
+ // A request given up in the network may still have reached the computer, so its outcome is unconfirmed.
2445
+ if (error.name === "TimeoutError") throw Object.assign(new Error(`结果待确认:电脑「${machine.name}」未在限时内答复,请稍后查看房间,确认是否已生效后再重试`),
2446
+ { unconfirmed: true, launch: { stage: "unconfirmed" } });
2447
+ throw error.status === 401 ? Object.assign(error, { need: "pairing" }) : error;
2448
+ });
2439
2449
  if (result.status === "done") return open_relay_response(key, id, result.response);
2440
2450
  if (result.status === "offline") throw Object.assign(new Error(`电脑「${machine.name}」不在线,请确认它开机并运行 codiscuss`), { offline: true });
2441
2451
  throw Object.assign(new Error(`结果待确认:电脑「${machine.name}」未在限时内答复,请稍后查看房间,确认是否已生效后再重试`),
@@ -2815,7 +2825,8 @@ async function load_launch_settings() {
2815
2825
  load_room_models();
2816
2826
  } catch (error) {
2817
2827
  // An unpaired or expired device keeps its way to the computer: pairing and renewal go through it.
2818
- relay_machine = error.need === "pairing" || error.need === "renew" ? relay_machine : null;
2828
+ // A website without rooms of its own reaches the computer only through the relay, so one failed request keeps it.
2829
+ relay_machine = computer_rooms_only() || error.need === "pairing" || error.need === "renew" ? relay_machine : null;
2819
2830
  state.launch.remote = Boolean(local_connection);
2820
2831
  Object.assign(state.launch, { available: false, room_models: null, error: error.message });
2821
2832
  // Without a reachable local service, launches can still go through the paired computer.
@@ -2841,7 +2852,10 @@ async function load_relay_machine() {
2841
2852
  return null;
2842
2853
  }
2843
2854
  return machine;
2844
- } catch { return null; }
2855
+ } catch {
2856
+ // A failed read says nothing about the pairing, so the computer known so far stays in use.
2857
+ return state.launch.relay ?? null;
2858
+ }
2845
2859
  }
2846
2860
 
2847
2861
  /** Hand a room creation to the paired computer through the website and wait for it to finish. */
@@ -4466,7 +4480,9 @@ async function initialize() {
4466
4480
  });
4467
4481
  if (computer_rooms_only()) {
4468
4482
  await launch_settings;
4469
- state.remote_rooms = Boolean(relay_machine) && await load_remote_site().then(() => true, () => false);
4483
+ // A reconnect that ran meanwhile may already show the computer's rooms; a slower failure here must not hide them.
4484
+ const reachable = Boolean(relay_machine) && await load_remote_site().then(() => true, () => false);
4485
+ state.remote_rooms ||= reachable;
4470
4486
  }
4471
4487
  try {
4472
4488
  const result = computer_rooms_only() && !state.remote_rooms ? { rooms: [] } : await request_json("/api/rooms");