@lingyao037/openclaw-lingyao-cli 0.9.5 → 0.9.6

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.
@@ -1,4 +1,4 @@
1
- import { L as LingyaoRuntime, g as LingyaoAccount, c as DeviceToken, D as DeviceInfo } from './types-Zbv12l39.js';
1
+ import { L as LingyaoRuntime, g as LingyaoAccount, c as DeviceToken, D as DeviceInfo } from './types-LFC6Wpqo.js';
2
2
 
3
3
  /**
4
4
  * Account storage and management
package/dist/cli.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { L as LingyaoRuntime, H as HealthStatus } from './types-Zbv12l39.js';
2
- import { A as AccountManager } from './accounts-CzjBLXMH.js';
1
+ import { L as LingyaoRuntime, H as HealthStatus } from './types-LFC6Wpqo.js';
2
+ import { A as AccountManager } from './accounts-BykE02r0.js';
3
3
 
4
4
  /**
5
5
  * Probe status levels
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { R as ResolvedAccount, L as LingyaoProbeResult } from './status-DdIuhIHE.js';
1
+ import { R as ResolvedAccount, L as LingyaoProbeResult } from './status-CVwSoPKi.js';
2
2
  import * as openclaw_plugin_sdk from 'openclaw/plugin-sdk';
3
3
  import { PluginRuntime, ChannelPlugin } from 'openclaw/plugin-sdk';
4
- import { L as LingyaoRuntime, S as SyncRequest, a as SyncResponse, b as LingyaoMessage, D as DeviceInfo, c as DeviceToken, d as LingyaoConfig, N as NotifyPayload, H as HealthStatus } from './types-Zbv12l39.js';
5
- export { A as AckRequest, e as DiarySyncPayload, F as FailedEntry, f as LINGYAO_SERVER_URL, g as LingyaoAccount, h as LingyaoAccountConfig, M as MemorySyncPayload, i as MessageType, j as NotifyAction, k as NotifyRequest, P as PairingCode, l as PairingConfirmRequest, m as PairingConfirmResponse, n as PollRequest, o as PollResponse, Q as QueuedMessage, T as TokenRefreshRequest, p as TokenRefreshResponse, W as WebSocketConnection } from './types-Zbv12l39.js';
6
- import { A as AccountManager } from './accounts-CzjBLXMH.js';
4
+ import { L as LingyaoRuntime, S as SyncRequest, a as SyncResponse, b as LingyaoMessage, D as DeviceInfo, c as DeviceToken, d as LingyaoConfig, N as NotifyPayload, H as HealthStatus } from './types-LFC6Wpqo.js';
5
+ export { A as AckRequest, e as DiarySyncPayload, F as FailedEntry, f as LINGYAO_SERVER_URL, g as LingyaoAccount, h as LingyaoAccountConfig, M as MemorySyncPayload, i as MessageType, j as NotifyAction, k as NotifyRequest, P as PairingCode, l as PairingConfirmRequest, m as PairingConfirmResponse, n as PollRequest, o as PollResponse, Q as QueuedMessage, T as TokenRefreshRequest, p as TokenRefreshResponse, W as WebSocketConnection, q as getLingyaoGatewayWsUrl } from './types-LFC6Wpqo.js';
6
+ import { A as AccountManager } from './accounts-BykE02r0.js';
7
7
 
8
8
  /**
9
9
  * 灵爻服务器 HTTP 客户端
@@ -134,6 +134,11 @@ declare class ServerHttpClient {
134
134
  * 检查是否已注册
135
135
  */
136
136
  isReady(): boolean;
137
+ /**
138
+ * Clear local gateway token/session (storage + in-memory). Used when WS handshake
139
+ * fails with 404 or when forcing re-registration with the same gatewayId.
140
+ */
141
+ clearLocalSession(): Promise<void>;
137
142
  /**
138
143
  * 从存储恢复会话
139
144
  */
@@ -218,6 +223,9 @@ type WSClientEvent = {
218
223
  } | {
219
224
  type: "error";
220
225
  error: Error;
226
+ } | {
227
+ type: "fatal_handshake";
228
+ reason: "http_404";
221
229
  } | {
222
230
  type: "message";
223
231
  message: WSMessage;
@@ -259,6 +267,8 @@ declare class LingyaoWSClient {
259
267
  private connectionId;
260
268
  private heartbeatTimer;
261
269
  private reconnectTimer;
270
+ /** When set, close handler will not schedule reconnect (e.g. HTTP 404 on upgrade). */
271
+ private suppressReconnect;
262
272
  private messageHandlers;
263
273
  private logger;
264
274
  constructor(runtime: LingyaoRuntime, config: WSClientConfig);
package/dist/index.js CHANGED
@@ -409,6 +409,9 @@ import { createHash as createHash2 } from "crypto";
409
409
 
410
410
  // src/types.ts
411
411
  var LINGYAO_SERVER_URL = "https://api.lingyao.live";
412
+ function getLingyaoGatewayWsUrl() {
413
+ return LINGYAO_SERVER_URL.replace(/^https:/i, "wss:") + "/lyoc/gateway/ws";
414
+ }
412
415
  var MessageType = /* @__PURE__ */ ((MessageType2) => {
413
416
  MessageType2["SYNC_DIARY"] = "sync_diary";
414
417
  MessageType2["SYNC_MEMORY"] = "sync_memory";
@@ -445,7 +448,8 @@ var ServerHttpClient = class {
445
448
  this.storagePrefix = storagePrefix;
446
449
  this.config = {
447
450
  baseURL: serverConfig.baseURL || "https://api.lingyao.live",
448
- apiBase: serverConfig.apiBase || "/v1",
451
+ // Public API (api.lingyao.live) serves gateway HTTP under /lyoc; local relay also accepts /lyoc (see server getApiPathSuffix).
452
+ apiBase: serverConfig.apiBase || "/lyoc",
449
453
  timeout: serverConfig.timeout || 3e4,
450
454
  connectionTimeout: serverConfig.connectionTimeout || 5e3
451
455
  };
@@ -525,6 +529,10 @@ var ServerHttpClient = class {
525
529
  throw new Error("Gateway already registered");
526
530
  } else if (status === 400) {
527
531
  throw new Error(`Invalid request: ${data?.details || "Unknown error"}`);
532
+ } else if (status === 404) {
533
+ throw new Error(
534
+ "Lingyao gateway register returned 404. Check server URL and /lyoc/gateway/register; the gatewayId may be invalid or the API may not be deployed on this host."
535
+ );
528
536
  }
529
537
  throw new Error(`Registration failed: ${axiosError.message}`);
530
538
  }
@@ -659,6 +667,26 @@ var ServerHttpClient = class {
659
667
  isReady() {
660
668
  return this.isRegistered && !!this.gatewayToken;
661
669
  }
670
+ /**
671
+ * Clear local gateway token/session (storage + in-memory). Used when WS handshake
672
+ * fails with 404 or when forcing re-registration with the same gatewayId.
673
+ */
674
+ async clearLocalSession() {
675
+ this.stopHeartbeat();
676
+ this.gatewayToken = null;
677
+ this.webhookSecret = null;
678
+ this.tokenExpiresAt = 0;
679
+ this.isRegistered = false;
680
+ const keys = ["gatewayToken", "webhookSecret", "tokenExpiresAt", "serverConfig"];
681
+ for (const k of keys) {
682
+ try {
683
+ await this.runtime.storage.delete(this.storageKey(k));
684
+ } catch (e) {
685
+ this.runtime.logger.warn(`Failed to delete storage key ${k}`, e);
686
+ }
687
+ }
688
+ this.runtime.logger.info("Cleared local Lingyao gateway session");
689
+ }
662
690
  /**
663
691
  * 从存储恢复会话
664
692
  */
@@ -705,6 +733,9 @@ var ServerHttpClient = class {
705
733
 
706
734
  // src/websocket-client.ts
707
735
  import WebSocket from "ws";
736
+ function isWebsocketUpgradeNotFoundError(message) {
737
+ return /Unexpected server response:\s*404/i.test(message) || /\b404\b/.test(message);
738
+ }
708
739
  var LingyaoWSClient = class {
709
740
  config;
710
741
  ws = null;
@@ -712,6 +743,8 @@ var LingyaoWSClient = class {
712
743
  connectionId = null;
713
744
  heartbeatTimer = null;
714
745
  reconnectTimer = null;
746
+ /** When set, close handler will not schedule reconnect (e.g. HTTP 404 on upgrade). */
747
+ suppressReconnect = false;
715
748
  messageHandlers = /* @__PURE__ */ new Map();
716
749
  logger;
717
750
  constructor(runtime, config) {
@@ -734,6 +767,7 @@ var LingyaoWSClient = class {
734
767
  return;
735
768
  }
736
769
  this.state = "connecting";
770
+ this.suppressReconnect = false;
737
771
  this.emitEvent({ type: "disconnected", code: 0, reason: "Reconnecting" });
738
772
  try {
739
773
  this.logger.info(`Connecting to Lingyao server: ${this.config.url}`);
@@ -810,7 +844,16 @@ var LingyaoWSClient = class {
810
844
  * 处理连接错误
811
845
  */
812
846
  handleErrorEvent(error) {
813
- this.logger.error("WebSocket error", error);
847
+ const msg = error?.message ?? String(error);
848
+ if (isWebsocketUpgradeNotFoundError(msg)) {
849
+ this.suppressReconnect = true;
850
+ this.logger.error(
851
+ "WebSocket handshake failed with HTTP 404 \u2014 stopping reconnect loop. If the gateway was removed server-side, remove `gatewayId` from channels.lingyao.accounts.* or use a new account id; if the path is wrong, verify wss://\u2026/lyoc/gateway/ws is deployed on api.lingyao.live.",
852
+ { gatewayId: this.config.gatewayId, message: msg }
853
+ );
854
+ } else {
855
+ this.logger.error("WebSocket error", error);
856
+ }
814
857
  this.state = "error";
815
858
  this.emitEvent({ type: "error", error });
816
859
  }
@@ -827,6 +870,11 @@ var LingyaoWSClient = class {
827
870
  this.logger.error("WebSocket closed with 1008 (Invalid Token). Stopping reconnect loop.");
828
871
  return;
829
872
  }
873
+ if (this.suppressReconnect) {
874
+ this.suppressReconnect = false;
875
+ this.emitEvent({ type: "fatal_handshake", reason: "http_404" });
876
+ return;
877
+ }
830
878
  if (code !== 1e3) {
831
879
  this.scheduleReconnect();
832
880
  }
@@ -2683,7 +2731,7 @@ var MultiAccountOrchestrator = class {
2683
2731
  }
2684
2732
  await this.registerToServer(state);
2685
2733
  const wsClient = new LingyaoWSClient(this.runtime, {
2686
- url: `${LINGYAO_SERVER_URL}/v1/gateway/ws`,
2734
+ url: getLingyaoGatewayWsUrl(),
2687
2735
  gatewayId,
2688
2736
  token: httpClient.getGatewayToken() ?? void 0,
2689
2737
  reconnectInterval: 5e3,
@@ -2905,6 +2953,11 @@ var MultiAccountOrchestrator = class {
2905
2953
  });
2906
2954
  state.errorHandler.handleError(event.error);
2907
2955
  break;
2956
+ case "fatal_handshake":
2957
+ if (event.reason === "http_404") {
2958
+ void this.handleWsHandshake404(state);
2959
+ }
2960
+ break;
2908
2961
  case "pairing_completed":
2909
2962
  this.handlePairingCompleted(state, event);
2910
2963
  break;
@@ -2928,6 +2981,45 @@ var MultiAccountOrchestrator = class {
2928
2981
  this.runtime.logger.error(`[${state.accountId}] Failed to auto-bind device: ${deviceId}`, error);
2929
2982
  }
2930
2983
  }
2984
+ /**
2985
+ * After HTTP 404 on WebSocket upgrade: clear local tokens, re-register once, reconnect.
2986
+ * Does not fix wrong server URL or permanently deleted gateway rows (user must fix config).
2987
+ */
2988
+ async handleWsHandshake404(state) {
2989
+ if (state.wsHandshake404RecoveryAttempted) {
2990
+ this.runtime.logger.error(
2991
+ `[${state.accountId}] Lingyao WebSocket still failing after one recovery attempt. Check that wss://\u2026/lyoc/gateway/ws is deployed; if the gateway was removed, delete \`channels.lingyao.accounts.${state.accountId}.gatewayId\` or use a new account id, then restart.`
2992
+ );
2993
+ return;
2994
+ }
2995
+ state.wsHandshake404RecoveryAttempted = true;
2996
+ const { httpClient, wsClient, accountId } = state;
2997
+ if (!httpClient || !wsClient) {
2998
+ return;
2999
+ }
3000
+ this.runtime.logger.info(`[${accountId}] WS HTTP 404 \u2014 clearing local session and re-registering...`);
3001
+ try {
3002
+ await httpClient.clearLocalSession();
3003
+ const response = await httpClient.register({
3004
+ websocket: true,
3005
+ compression: false,
3006
+ maxMessageSize: 1048576
3007
+ });
3008
+ wsClient.updateToken(response.gatewayToken);
3009
+ await wsClient.connect();
3010
+ this.runtime.logger.info(`[${accountId}] Re-register OK; WebSocket reconnect issued.`);
3011
+ } catch (error) {
3012
+ const msg = error instanceof Error ? error.message : String(error);
3013
+ if (msg.includes("already registered")) {
3014
+ this.runtime.logger.error(
3015
+ `[${accountId}] Re-register failed: gateway still registered on server but local session was cleared. Remove or change \`gatewayId\` under this account, or reset the gateway on lingyao.live, then restart OpenClaw.`,
3016
+ error
3017
+ );
3018
+ } else {
3019
+ this.runtime.logger.error(`[${accountId}] WS 404 recovery (clear + register) failed`, error);
3020
+ }
3021
+ }
3022
+ }
2931
3023
  /**
2932
3024
  * Handle invalid token by re-registering the gateway and reconnecting WS
2933
3025
  */
@@ -3164,7 +3256,7 @@ var LingyaoChannel = class {
3164
3256
  try {
3165
3257
  await this.registerToServer();
3166
3258
  this.wsClient = new LingyaoWSClient(this.runtime, {
3167
- url: `${LINGYAO_SERVER_URL}/v1/gateway/ws`,
3259
+ url: getLingyaoGatewayWsUrl(),
3168
3260
  gatewayId: this.gatewayId,
3169
3261
  token: this.serverClient?.getGatewayToken() ?? void 0,
3170
3262
  reconnectInterval: 5e3,
@@ -3313,6 +3405,11 @@ var LingyaoChannel = class {
3313
3405
  )
3314
3406
  );
3315
3407
  break;
3408
+ case "fatal_handshake":
3409
+ this.runtime.logger.error(
3410
+ "Lingyao WebSocket upgrade failed (HTTP 404). Use the OpenClaw plugin path for automatic recovery, or clear gateway session / gatewayId in config."
3411
+ );
3412
+ break;
3316
3413
  }
3317
3414
  }
3318
3415
  /**
@@ -3702,7 +3799,7 @@ async function createPlugin(runtime, config = {}) {
3702
3799
  }
3703
3800
  var pluginMetadata = {
3704
3801
  name: "lingyao",
3705
- version: "0.9.1",
3802
+ version: "0.9.6",
3706
3803
  description: "Lingyao Channel Plugin - bidirectional sync via lingyao.live server relay",
3707
3804
  type: "channel",
3708
3805
  capabilities: {
@@ -3738,6 +3835,7 @@ export {
3738
3835
  createPlugin,
3739
3836
  index_default as default,
3740
3837
  getDefaultConfig,
3838
+ getLingyaoGatewayWsUrl,
3741
3839
  initializeLingyaoRuntime,
3742
3840
  lingyaoPlugin,
3743
3841
  pluginMetadata,