@honor-claw/yoyo 1.1.2 → 1.1.4-beta.1

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 (66) hide show
  1. package/index.ts +25 -25
  2. package/package.json +5 -5
  3. package/src/apis/claw-cloud.ts +124 -124
  4. package/src/apis/helpers.ts +10 -10
  5. package/src/apis/honor-auth.ts +158 -158
  6. package/src/apis/http-client.ts +239 -239
  7. package/src/apis/index.ts +8 -8
  8. package/src/apis/types.ts +77 -73
  9. package/src/cloud-channel/channel.ts +117 -117
  10. package/src/cloud-channel/client.ts +3 -3
  11. package/src/cloud-channel/index.ts +4 -4
  12. package/src/cloud-channel/message-handler.ts +50 -42
  13. package/src/cloud-channel/session-manager.ts +14 -9
  14. package/src/cloud-channel/types.ts +115 -115
  15. package/src/commands/env/impl.ts +58 -58
  16. package/src/commands/env/index.ts +1 -1
  17. package/src/commands/index.ts +30 -30
  18. package/src/commands/login/impl.ts +30 -30
  19. package/src/commands/login/index.ts +1 -1
  20. package/src/commands/logout/index.ts +1 -1
  21. package/src/commands/status/index.ts +194 -194
  22. package/src/gateway-client/client.ts +90 -90
  23. package/src/gateway-client/device/auth.ts +57 -57
  24. package/src/gateway-client/device/builder.ts +105 -105
  25. package/src/gateway-client/device/helpers.ts +40 -40
  26. package/src/gateway-client/device/identity.ts +251 -251
  27. package/src/gateway-client/device/index.ts +40 -40
  28. package/src/gateway-client/device/types.ts +57 -57
  29. package/src/gateway-client/index.ts +5 -5
  30. package/src/gateway-client/protocol-client.ts +49 -34
  31. package/src/honor-auth/browser.ts +2 -2
  32. package/src/honor-auth/callback-server.ts +109 -109
  33. package/src/honor-auth/cloud.ts +57 -57
  34. package/src/honor-auth/config.ts +43 -43
  35. package/src/honor-auth/index.ts +3 -3
  36. package/src/honor-auth/token-manager.ts +90 -90
  37. package/src/honor-auth/types.ts +50 -50
  38. package/src/index.ts +10 -10
  39. package/src/modules/claw-configs/config-manager.ts +409 -409
  40. package/src/modules/claw-configs/hosts.ts +48 -48
  41. package/src/modules/claw-configs/index.ts +8 -8
  42. package/src/modules/claw-configs/provider.ts +394 -394
  43. package/src/modules/claw-configs/types.ts +34 -34
  44. package/src/modules/device/device-info.ts +1 -1
  45. package/src/modules/device/index.ts +3 -3
  46. package/src/modules/device/providers/base.ts +32 -32
  47. package/src/modules/device/providers/pad.ts +107 -107
  48. package/src/modules/device/providers/windows.ts +130 -130
  49. package/src/modules/device/registry.ts +48 -43
  50. package/src/modules/login/impl.ts +31 -26
  51. package/src/modules/login/index.ts +6 -6
  52. package/src/schemas.ts +23 -23
  53. package/src/services/connection/impl.ts +339 -339
  54. package/src/services/connection/status-tracker/events.ts +127 -127
  55. package/src/services/connection/status-tracker/index.ts +31 -31
  56. package/src/services/connection/status-tracker/storage.ts +133 -133
  57. package/src/services/connection/status-tracker/tracker.ts +370 -370
  58. package/src/services/connection/status-tracker/types.ts +131 -131
  59. package/src/services/connection/types.ts +20 -20
  60. package/src/types.ts +64 -64
  61. package/src/utils/id.ts +8 -8
  62. package/src/utils/jwt.ts +37 -37
  63. package/src/utils/logger.ts +20 -20
  64. package/src/utils/proxy.ts +58 -58
  65. package/src/utils/version.ts +29 -29
  66. package/src/utils/ws.ts +21 -21
@@ -1,57 +1,57 @@
1
- /**
2
- * Device identity information
3
- */
4
- export type DeviceIdentity = {
5
- deviceId: string;
6
- publicKeyPem: string;
7
- privateKeyPem: string;
8
- };
9
-
10
- /**
11
- * Device authentication payload parameters
12
- */
13
- export type DeviceAuthPayloadParams = {
14
- deviceId: string;
15
- clientId: string;
16
- clientMode: string;
17
- role: string;
18
- scopes: string[];
19
- signedAtMs: number;
20
- token?: string | null;
21
- nonce: string;
22
- };
23
-
24
- /**
25
- * Device authentication payload V3 parameters (with platform/device family)
26
- */
27
- export type DeviceAuthPayloadV3Params = DeviceAuthPayloadParams & {
28
- platform?: string | null;
29
- deviceFamily?: string | null;
30
- };
31
-
32
- /**
33
- * Device information for gateway connection
34
- */
35
- export type DeviceInfo = {
36
- id: string;
37
- publicKey: string;
38
- signature: string;
39
- signedAt: number;
40
- nonce: string;
41
- };
42
-
43
- /**
44
- * Device builder options
45
- */
46
- export type DeviceBuilderOptions = {
47
- deviceIdentity?: DeviceIdentity;
48
- clientName?: string;
49
- clientMode?: string;
50
- role?: string;
51
- scopes?: string[];
52
- platform?: string;
53
- deviceFamily?: string;
54
- authToken?: string | null;
55
- nonce: string;
56
- signedAtMs?: number;
57
- };
1
+ /**
2
+ * Device identity information
3
+ */
4
+ export type DeviceIdentity = {
5
+ deviceId: string;
6
+ publicKeyPem: string;
7
+ privateKeyPem: string;
8
+ };
9
+
10
+ /**
11
+ * Device authentication payload parameters
12
+ */
13
+ export type DeviceAuthPayloadParams = {
14
+ deviceId: string;
15
+ clientId: string;
16
+ clientMode: string;
17
+ role: string;
18
+ scopes: string[];
19
+ signedAtMs: number;
20
+ token?: string | null;
21
+ nonce: string;
22
+ };
23
+
24
+ /**
25
+ * Device authentication payload V3 parameters (with platform/device family)
26
+ */
27
+ export type DeviceAuthPayloadV3Params = DeviceAuthPayloadParams & {
28
+ platform?: string | null;
29
+ deviceFamily?: string | null;
30
+ };
31
+
32
+ /**
33
+ * Device information for gateway connection
34
+ */
35
+ export type DeviceInfo = {
36
+ id: string;
37
+ publicKey: string;
38
+ signature: string;
39
+ signedAt: number;
40
+ nonce: string;
41
+ };
42
+
43
+ /**
44
+ * Device builder options
45
+ */
46
+ export type DeviceBuilderOptions = {
47
+ deviceIdentity?: DeviceIdentity;
48
+ clientName?: string;
49
+ clientMode?: string;
50
+ role?: string;
51
+ scopes?: string[];
52
+ platform?: string;
53
+ deviceFamily?: string;
54
+ authToken?: string | null;
55
+ nonce: string;
56
+ signedAtMs?: number;
57
+ };
@@ -1,5 +1,5 @@
1
- export * from "./client.js";
2
- export * from "./protocol-client.js";
3
- export * from "./protocol/index.js";
4
- export * from "./node-gateway-client.js";
5
- export * from './admin-gateway-client.js'
1
+ export * from "./client.js";
2
+ export * from "./protocol-client.js";
3
+ export * from "./protocol/index.js";
4
+ export * from "./node-gateway-client.js";
5
+ export * from './admin-gateway-client.js'
@@ -1,4 +1,12 @@
1
1
  import { randomUUID } from "node:crypto";
2
+ import { useClawLogger } from "../utils/logger.js";
3
+ import { GatewayClient } from "./client.js";
4
+ import {
5
+ loadOrCreateDeviceIdentity,
6
+ signDevicePayload,
7
+ publicKeyRawBase64UrlFromPem,
8
+ buildDeviceAuthPayloadV3,
9
+ } from "./device/index.js";
2
10
  import {
3
11
  type ConnectParams,
4
12
  type EventFrame,
@@ -9,11 +17,13 @@ import {
9
17
  ErrorCodes,
10
18
  PROTOCOL_VERSION,
11
19
  } from "./protocol/index.js";
12
- import { GatewayClient } from "./client.js";
13
20
  import { type ProtocolClientOptions } from "./protocol/index.js";
14
- import { type GatewayClientId, type GatewayClientMode, GATEWAY_CLIENT_IDS, GATEWAY_CLIENT_MODES } from "./protocol/index.js";
15
- import { useClawLogger } from "../utils/logger.js";
16
- import { loadOrCreateDeviceIdentity, signDevicePayload, publicKeyRawBase64UrlFromPem, buildDeviceAuthPayloadV3 } from "./device/index.js";
21
+ import {
22
+ type GatewayClientId,
23
+ type GatewayClientMode,
24
+ GATEWAY_CLIENT_IDS,
25
+ GATEWAY_CLIENT_MODES,
26
+ } from "./protocol/index.js";
17
27
 
18
28
  type PendingRequest = {
19
29
  resolve: (value: unknown) => void;
@@ -134,12 +144,14 @@ export class ProtocolGatewayClient extends GatewayClient {
134
144
  pending.resolve(response.payload);
135
145
  } else {
136
146
  const error = response.error || { code: ErrorCodes.UNKNOWN, message: "Unknown error" };
137
- pending.reject(new WebSocketClientError(
138
- this.toErrorCode(error.code),
139
- error.message,
140
- error.details,
141
- error.retryable
142
- ));
147
+ pending.reject(
148
+ new WebSocketClientError(
149
+ this.toErrorCode(error.code),
150
+ error.message,
151
+ error.details,
152
+ error.retryable,
153
+ ),
154
+ );
143
155
  }
144
156
  }
145
157
 
@@ -194,19 +206,21 @@ export class ProtocolGatewayClient extends GatewayClient {
194
206
  device,
195
207
  };
196
208
 
197
- this.sendRequest("connect", params).then((payload) => {
198
- this.helloOk = payload as HelloOk;
199
- this.connected = true;
200
- this.authenticated = true;
201
- this.protocolOpts.onAuthenticated?.();
202
- }).catch((error) => {
203
- this.authenticated = false;
204
- if (error instanceof WebSocketClientError) {
205
- this.protocolOpts.onClose?.(`auth failed: [${error.code}] ${error.message}`);
206
- } else {
207
- this.protocolOpts.onClose?.(`auth failed: ${error.message}`);
208
- }
209
- });
209
+ this.sendRequest("connect", params)
210
+ .then((payload) => {
211
+ this.helloOk = payload as HelloOk;
212
+ this.connected = true;
213
+ this.authenticated = true;
214
+ this.protocolOpts.onAuthenticated?.();
215
+ })
216
+ .catch((error) => {
217
+ this.authenticated = false;
218
+ if (error instanceof WebSocketClientError) {
219
+ this.protocolOpts.onClose?.(`auth failed: [${error.code}] ${error.message}`);
220
+ } else {
221
+ this.protocolOpts.onClose?.(`auth failed: ${error.message}`);
222
+ }
223
+ });
210
224
  }
211
225
 
212
226
  protected async sendRequest(method: string, params?: unknown): Promise<unknown> {
@@ -221,10 +235,12 @@ export class ProtocolGatewayClient extends GatewayClient {
221
235
  this.send(JSON.stringify(frame));
222
236
  } catch (error) {
223
237
  this.pendingRequests.delete(id);
224
- reject(new WebSocketClientError(
225
- ErrorCodes.CONNECTION_FAILED,
226
- `WebSocket is not connected, ${JSON.stringify(error)}`
227
- ));
238
+ reject(
239
+ new WebSocketClientError(
240
+ ErrorCodes.CONNECTION_FAILED,
241
+ `WebSocket is not connected, ${JSON.stringify(error)}`,
242
+ ),
243
+ );
228
244
  return;
229
245
  }
230
246
 
@@ -232,12 +248,11 @@ export class ProtocolGatewayClient extends GatewayClient {
232
248
  if (this.pendingRequests.has(id)) {
233
249
  this.pendingRequests.delete(id);
234
250
  const t = this.pendingTimers.get(id);
235
- if (t) clearTimeout(t);
251
+ if (t) {
252
+ clearTimeout(t);
253
+ }
236
254
  this.pendingTimers.delete(id);
237
- reject(new WebSocketClientError(
238
- ErrorCodes.TIMEOUT,
239
- `Request timeout: ${method}`
240
- ));
255
+ reject(new WebSocketClientError(ErrorCodes.TIMEOUT, `Request timeout: ${method}`));
241
256
  }
242
257
  }, DEFAULT_REQUEST_TIMEOUT_MS);
243
258
  this.pendingTimers.set(id, timer);
@@ -306,7 +321,7 @@ export class ProtocolGatewayClient extends GatewayClient {
306
321
 
307
322
  if (this.reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
308
323
  useClawLogger().error(
309
- `[protocol-gateway] max reconnect attempts (${MAX_RECONNECT_ATTEMPTS}) reached, giving up`
324
+ `[protocol-gateway] max reconnect attempts (${MAX_RECONNECT_ATTEMPTS}) reached, giving up`,
310
325
  );
311
326
  this.protocolOpts.onReconnectFailed?.();
312
327
  return;
@@ -315,7 +330,7 @@ export class ProtocolGatewayClient extends GatewayClient {
315
330
  this.reconnectAttempts++;
316
331
  this.isReconnecting = true;
317
332
  useClawLogger().info(
318
- `[protocol-gateway] attempting to reconnect (attempt ${this.reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})`
333
+ `[protocol-gateway] attempting to reconnect (attempt ${this.reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})`,
319
334
  );
320
335
 
321
336
  this.reconnectTimer = setTimeout(() => {
@@ -14,7 +14,7 @@ export async function performOAuth2AuthWithBrowser(_: DeviceInfo, configOverride
14
14
  const config = getConfig(configOverrides);
15
15
  const logger = useClawLogger();
16
16
 
17
- logger.debug('Starting Honor login flow...');
17
+ logger.debug?.('Starting Honor login flow...');
18
18
 
19
19
  // 创建认证客户端
20
20
  const authClient = createHonorAuthClient(config);
@@ -61,7 +61,7 @@ export async function performOAuth2AuthWithBrowser(_: DeviceInfo, configOverride
61
61
  try {
62
62
  const tokenInfo = await authClient.exchangeToken(receivedCode);
63
63
 
64
- if (!tokenInfo.token || !tokenInfo.userInfo?.userId) {
64
+ if (!tokenInfo?.token || !tokenInfo.userInfo?.userId) {
65
65
  throw new Error('failed to get user info');
66
66
  }
67
67
 
@@ -1,109 +1,109 @@
1
- /**
2
- * 本地HTTP回调服务器 - 接收OAuth2授权回调
3
- */
4
-
5
- import { createServer, type IncomingMessage, type ServerResponse } from 'http';
6
- import { URL } from 'url';
7
-
8
- /**
9
- * 回调服务器选项
10
- */
11
- export interface CallbackServerOptions {
12
- /** 监听端口 */
13
- port: number;
14
- /** 超时时间(毫秒) */
15
- timeout?: number;
16
- /** 授权码回调处理 */
17
- onCodeReceived: (code: string) => void;
18
- /** 错误回调 */
19
- onError?: (error: Error) => void;
20
- }
21
-
22
- /**
23
- * 启动本地回调服务器
24
- */
25
- export function startCallbackServer(options: CallbackServerOptions): Promise<void> {
26
- return new Promise((resolve, reject) => {
27
- const { port, timeout = 600000, onCodeReceived, onError } = options;
28
- let timeoutId: NodeJS.Timeout | null = null;
29
- let serverClosed = false;
30
- let hasReceivedCode = false;
31
- let promiseResolved = false;
32
-
33
- const server = createServer((req: IncomingMessage, res: ServerResponse) => {
34
- try {
35
- const url = new URL(req.url || '', `http://localhost:${port}`);
36
- const code = url.searchParams.get('code') || '';
37
-
38
- if (code && !hasReceivedCode) {
39
- hasReceivedCode = true;
40
-
41
- // 返回成功响应
42
- res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
43
- res.end('<h1>授权成功!可以关闭此窗口</h1>');
44
-
45
- // 延迟关闭服务器,确保响应已发送
46
- setTimeout(() => {
47
- if (!serverClosed) {
48
- serverClosed = true;
49
- if (timeoutId) clearTimeout(timeoutId);
50
- server.close();
51
- }
52
- }, 100);
53
-
54
- // 调用回调
55
- onCodeReceived(code);
56
- } else if (!hasReceivedCode) {
57
- // 返回错误响应
58
- res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
59
- res.end('<h1>授权失败:未获取到授权码</h1>');
60
- } else {
61
- // 重复请求,返回成功响应但不处理
62
- res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
63
- res.end('<h1>授权成功!可以关闭此窗口</h1>');
64
- }
65
- } catch (error) {
66
- console.error('authorize callback error:', error);
67
- res.writeHead(500, { 'Content-Type': 'text/html; charset=utf-8' });
68
- res.end('<h1>服务器错误</h1>');
69
- }
70
- });
71
-
72
- server.on('error', (error) => {
73
- if (!serverClosed) {
74
- serverClosed = true;
75
- if (timeoutId) clearTimeout(timeoutId);
76
- onError?.(error);
77
- if (!promiseResolved) {
78
- promiseResolved = true;
79
- reject(error);
80
- }
81
- }
82
- });
83
-
84
- server.listen(port, () => {
85
- // 设置超时
86
- timeoutId = setTimeout(() => {
87
- if (!serverClosed) {
88
- serverClosed = true;
89
- server.close();
90
- const error = new Error('authorize timeout');
91
- onError?.(error);
92
- if (!promiseResolved) {
93
- promiseResolved = true;
94
- reject(error);
95
- }
96
- }
97
- }, timeout);
98
- });
99
-
100
- // 服务器关闭时解析Promise
101
- server.on('close', () => {
102
- if (timeoutId) clearTimeout(timeoutId);
103
- if (!promiseResolved) {
104
- promiseResolved = true;
105
- resolve();
106
- }
107
- });
108
- });
109
- }
1
+ /**
2
+ * 本地HTTP回调服务器 - 接收OAuth2授权回调
3
+ */
4
+
5
+ import { createServer, type IncomingMessage, type ServerResponse } from 'http';
6
+ import { URL } from 'url';
7
+
8
+ /**
9
+ * 回调服务器选项
10
+ */
11
+ export interface CallbackServerOptions {
12
+ /** 监听端口 */
13
+ port: number;
14
+ /** 超时时间(毫秒) */
15
+ timeout?: number;
16
+ /** 授权码回调处理 */
17
+ onCodeReceived: (code: string) => void;
18
+ /** 错误回调 */
19
+ onError?: (error: Error) => void;
20
+ }
21
+
22
+ /**
23
+ * 启动本地回调服务器
24
+ */
25
+ export function startCallbackServer(options: CallbackServerOptions): Promise<void> {
26
+ return new Promise((resolve, reject) => {
27
+ const { port, timeout = 600000, onCodeReceived, onError } = options;
28
+ let timeoutId: NodeJS.Timeout | null = null;
29
+ let serverClosed = false;
30
+ let hasReceivedCode = false;
31
+ let promiseResolved = false;
32
+
33
+ const server = createServer((req: IncomingMessage, res: ServerResponse) => {
34
+ try {
35
+ const url = new URL(req.url || '', `http://localhost:${port}`);
36
+ const code = url.searchParams.get('code') || '';
37
+
38
+ if (code && !hasReceivedCode) {
39
+ hasReceivedCode = true;
40
+
41
+ // 返回成功响应
42
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
43
+ res.end('<h1>授权成功!可以关闭此窗口</h1>');
44
+
45
+ // 延迟关闭服务器,确保响应已发送
46
+ setTimeout(() => {
47
+ if (!serverClosed) {
48
+ serverClosed = true;
49
+ if (timeoutId) clearTimeout(timeoutId);
50
+ server.close();
51
+ }
52
+ }, 100);
53
+
54
+ // 调用回调
55
+ onCodeReceived(code);
56
+ } else if (!hasReceivedCode) {
57
+ // 返回错误响应
58
+ res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
59
+ res.end('<h1>授权失败:未获取到授权码</h1>');
60
+ } else {
61
+ // 重复请求,返回成功响应但不处理
62
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
63
+ res.end('<h1>授权成功!可以关闭此窗口</h1>');
64
+ }
65
+ } catch (error) {
66
+ console.error('authorize callback error:', error);
67
+ res.writeHead(500, { 'Content-Type': 'text/html; charset=utf-8' });
68
+ res.end('<h1>服务器错误</h1>');
69
+ }
70
+ });
71
+
72
+ server.on('error', (error) => {
73
+ if (!serverClosed) {
74
+ serverClosed = true;
75
+ if (timeoutId) clearTimeout(timeoutId);
76
+ onError?.(error);
77
+ if (!promiseResolved) {
78
+ promiseResolved = true;
79
+ reject(error);
80
+ }
81
+ }
82
+ });
83
+
84
+ server.listen(port, () => {
85
+ // 设置超时
86
+ timeoutId = setTimeout(() => {
87
+ if (!serverClosed) {
88
+ serverClosed = true;
89
+ server.close();
90
+ const error = new Error('authorize timeout');
91
+ onError?.(error);
92
+ if (!promiseResolved) {
93
+ promiseResolved = true;
94
+ reject(error);
95
+ }
96
+ }
97
+ }, timeout);
98
+ });
99
+
100
+ // 服务器关闭时解析Promise
101
+ server.on('close', () => {
102
+ if (timeoutId) clearTimeout(timeoutId);
103
+ if (!promiseResolved) {
104
+ promiseResolved = true;
105
+ resolve();
106
+ }
107
+ });
108
+ });
109
+ }
@@ -1,57 +1,57 @@
1
-
2
- import { createClawCloudClient } from '../apis/claw-cloud.js';
3
- import { isOKResponse } from '../apis/index.js';
4
- import type { HonorUserInfo } from '../types.js';
5
- import { getConfigManager, takeApiHost } from '../modules/claw-configs/index.js';
6
- import { getDeviceInfo } from '../modules/device/device-info.js';
7
- import { clearToken } from './token-manager.js';
8
-
9
-
10
- /**
11
- * 执行登出流程
12
- */
13
- export async function performLogout(): Promise<void> {
14
- try {
15
- const configManager = getConfigManager();
16
- const userConfig = configManager.getUserConfig();
17
-
18
- if (!userConfig || !userConfig.token) {
19
- console.log('⚠️ Not logged in');
20
- return;
21
- }
22
-
23
- // 获取设备信息
24
- const deviceInfo = getDeviceInfo();
25
-
26
- // 调用登出接口
27
- const hosts = takeApiHost();
28
- const baseUrl = `https://${hosts.clawCloud}/aicloud/yoyo-claw-service`;
29
-
30
- // 如果有灰度标签,设置默认headers
31
- const options = hosts.grayTag ? {
32
- defaultHeaders: {
33
- 'x-gray': hosts.grayTag
34
- }
35
- } : undefined;
36
-
37
- const client = createClawCloudClient(baseUrl, options);
38
-
39
- const userInfo: HonorUserInfo = {
40
- userId: userConfig.userId,
41
- token: userConfig.token,
42
- userName: userConfig.userName,
43
- };
44
-
45
- const response = await client.logoutDevice(deviceInfo, userInfo);
46
-
47
- if (!isOKResponse(response)) {
48
- throw new Error(`Logout failed: ${response.data?.cnMessage || 'Unknown error'}`);
49
- }
50
-
51
- // 清除Token
52
- await clearToken();
53
- } catch (error) {
54
- const errorMessage = error instanceof Error ? error.message : String(error);
55
- throw new Error(`failed to logout: ${errorMessage}`);
56
- }
57
- }
1
+
2
+ import { createClawCloudClient } from '../apis/claw-cloud.js';
3
+ import { isOKResponse } from '../apis/index.js';
4
+ import type { HonorUserInfo } from '../types.js';
5
+ import { getConfigManager, takeApiHost } from '../modules/claw-configs/index.js';
6
+ import { getDeviceInfo } from '../modules/device/device-info.js';
7
+ import { clearToken } from './token-manager.js';
8
+
9
+
10
+ /**
11
+ * 执行登出流程
12
+ */
13
+ export async function performLogout(): Promise<void> {
14
+ try {
15
+ const configManager = getConfigManager();
16
+ const userConfig = configManager.getUserConfig();
17
+
18
+ if (!userConfig || !userConfig.token) {
19
+ console.log('⚠️ Not logged in');
20
+ return;
21
+ }
22
+
23
+ // 获取设备信息
24
+ const deviceInfo = getDeviceInfo();
25
+
26
+ // 调用登出接口
27
+ const hosts = takeApiHost();
28
+ const baseUrl = `https://${hosts.clawCloud}/aicloud/yoyo-claw-service`;
29
+
30
+ // 如果有灰度标签,设置默认headers
31
+ const options = hosts.grayTag ? {
32
+ defaultHeaders: {
33
+ 'x-gray': hosts.grayTag
34
+ }
35
+ } : undefined;
36
+
37
+ const client = createClawCloudClient(baseUrl, options);
38
+
39
+ const userInfo: HonorUserInfo = {
40
+ userId: userConfig.userId,
41
+ token: userConfig.token,
42
+ userName: userConfig.userName,
43
+ };
44
+
45
+ const response = await client.logoutDevice(deviceInfo, userInfo);
46
+
47
+ if (!isOKResponse(response)) {
48
+ throw new Error(`Logout failed: ${response.data?.cnMessage || 'Unknown error'}`);
49
+ }
50
+
51
+ // 清除Token
52
+ await clearToken();
53
+ } catch (error) {
54
+ const errorMessage = error instanceof Error ? error.message : String(error);
55
+ throw new Error(`failed to logout: ${errorMessage}`);
56
+ }
57
+ }