@honor-claw/yoyo 1.1.4-beta.2 → 1.1.4-beta.3
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
package/src/apis/honor-auth.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { uuid } from "../utils/id.js";
|
|
|
10
10
|
import { isOKResponse } from "./helpers.js";
|
|
11
11
|
import { HttpClient, type HttpClientOptions } from "./http-client.js";
|
|
12
12
|
import type { HttpApiWrapper } from "./types.js";
|
|
13
|
+
import { wrapError } from "../utils/error.js";
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* PKCE参数
|
|
@@ -138,9 +139,7 @@ export class HonorAuthClient {
|
|
|
138
139
|
|
|
139
140
|
throw new Error(`failed to get token: ${response.data?.cnMessage}`);
|
|
140
141
|
} catch (error) {
|
|
141
|
-
throw
|
|
142
|
-
`failed to get token: ${error instanceof Error ? error.message : String(error)}`,
|
|
143
|
-
);
|
|
142
|
+
throw wrapError(error, "failed to get token");
|
|
144
143
|
}
|
|
145
144
|
}
|
|
146
145
|
|
|
@@ -2,6 +2,7 @@ import open from "open";
|
|
|
2
2
|
import { createHonorAuthClient } from "../apis/honor-auth.js";
|
|
3
3
|
import type { DeviceInfo, HonorUserInfo } from "../types.js";
|
|
4
4
|
import { useClawLogger } from "../utils/logger.js";
|
|
5
|
+
import { wrapError } from "../utils/error.js";
|
|
5
6
|
import { startCallbackServer } from "./callback-server.js";
|
|
6
7
|
import { getConfig } from "./config.js";
|
|
7
8
|
import { saveToken } from "./token-manager.js";
|
|
@@ -46,16 +47,14 @@ export async function performOAuth2AuthWithBrowser(
|
|
|
46
47
|
try {
|
|
47
48
|
await open(authUrl);
|
|
48
49
|
} catch (error) {
|
|
49
|
-
throw
|
|
50
|
+
throw wrapError(error, "failed to open browser, check your permissions");
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
// 等待回调
|
|
53
54
|
try {
|
|
54
55
|
await serverPromise;
|
|
55
56
|
} catch (error) {
|
|
56
|
-
throw
|
|
57
|
-
`authorization timeout: ${error instanceof Error ? error.message : String(error)}`,
|
|
58
|
-
);
|
|
57
|
+
throw wrapError(error, "authorization timeout");
|
|
59
58
|
}
|
|
60
59
|
|
|
61
60
|
if (!receivedCode) {
|
|
@@ -79,6 +78,6 @@ export async function performOAuth2AuthWithBrowser(
|
|
|
79
78
|
userName: tokenInfo.userInfo.displayName,
|
|
80
79
|
} as HonorUserInfo;
|
|
81
80
|
} catch (error) {
|
|
82
|
-
throw
|
|
81
|
+
throw wrapError(error, "get token failed");
|
|
83
82
|
}
|
|
84
83
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { safeReadFile, safeWriteFile
|
|
2
|
+
import { safeReadFile, safeWriteFile } from "../../utils/fs-safe.js";
|
|
3
3
|
import { resolveEffectiveHomeDir } from "../../utils/home-dir.js";
|
|
4
|
+
import { useClawLogger } from "../../utils/logger.js";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Identity 配置版本枚举
|
|
@@ -43,12 +44,7 @@ function getConfigPath(): string {
|
|
|
43
44
|
/**
|
|
44
45
|
* 内部方法:读取配置
|
|
45
46
|
*/
|
|
46
|
-
async function loadConfig(): Promise<PersistedIdentity> {
|
|
47
|
-
const homeDir = resolveEffectiveHomeDir();
|
|
48
|
-
if (!homeDir) {
|
|
49
|
-
throw new SafeFsError("not-found", "failed to find home dir");
|
|
50
|
-
}
|
|
51
|
-
|
|
47
|
+
async function loadConfig(homeDir: string): Promise<PersistedIdentity | null> {
|
|
52
48
|
const configPath = getConfigPath();
|
|
53
49
|
|
|
54
50
|
try {
|
|
@@ -70,13 +66,8 @@ async function loadConfig(): Promise<PersistedIdentity> {
|
|
|
70
66
|
...parsed,
|
|
71
67
|
};
|
|
72
68
|
} catch (error) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
if (error instanceof SyntaxError) {
|
|
77
|
-
return createDefaultConfig();
|
|
78
|
-
}
|
|
79
|
-
throw error;
|
|
69
|
+
useClawLogger().warn(`[yoyo-identity] failed to read identity: ${error.message}`);
|
|
70
|
+
return null;
|
|
80
71
|
}
|
|
81
72
|
}
|
|
82
73
|
|
|
@@ -85,7 +76,13 @@ async function loadConfig(): Promise<PersistedIdentity> {
|
|
|
85
76
|
* @returns 如果存在则返回 Identity,否则返回 null
|
|
86
77
|
*/
|
|
87
78
|
export async function getPersistedIdentity(): Promise<PersistedIdentity | null> {
|
|
88
|
-
const
|
|
79
|
+
const homeDir = resolveEffectiveHomeDir();
|
|
80
|
+
if (!homeDir) {
|
|
81
|
+
useClawLogger().warn("[yoyo-identity] failed to find home dir");
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const config = await loadConfig(homeDir);
|
|
89
86
|
|
|
90
87
|
if (config) {
|
|
91
88
|
return config;
|
|
@@ -101,19 +98,21 @@ export async function getPersistedIdentity(): Promise<PersistedIdentity | null>
|
|
|
101
98
|
* @throws SafeFsError 当写入失败时
|
|
102
99
|
*/
|
|
103
100
|
export async function updatePersistedIdentity(
|
|
104
|
-
identity: Partial<PersistedIdentity
|
|
105
|
-
): Promise<PersistedIdentity> {
|
|
101
|
+
identity: Partial<PersistedIdentity>,
|
|
102
|
+
): Promise<PersistedIdentity | null> {
|
|
106
103
|
const homeDir = resolveEffectiveHomeDir();
|
|
107
104
|
if (!homeDir) {
|
|
108
|
-
|
|
105
|
+
useClawLogger().warn("[yoyo-identity] failed to find home dir");
|
|
106
|
+
return null;
|
|
109
107
|
}
|
|
110
108
|
|
|
111
109
|
// 读取现有配置
|
|
112
|
-
const existingConfig = await loadConfig();
|
|
110
|
+
const existingConfig = await loadConfig(homeDir);
|
|
113
111
|
|
|
114
112
|
// 合并配置
|
|
115
113
|
const updatedConfig: PersistedIdentity = {
|
|
116
114
|
...existingConfig,
|
|
115
|
+
version: existingConfig?.version || IdentityVersion.LEGACY,
|
|
117
116
|
};
|
|
118
117
|
|
|
119
118
|
if (identity.legacyDeviceId) {
|
|
@@ -162,25 +161,22 @@ function createDefaultConfig(): PersistedIdentity {
|
|
|
162
161
|
export async function upgradeIdentityToV2(): Promise<PersistedIdentity | null> {
|
|
163
162
|
const homeDir = resolveEffectiveHomeDir();
|
|
164
163
|
if (!homeDir) {
|
|
165
|
-
|
|
164
|
+
useClawLogger().warn("[yoyo-identity] failed to find home dir");
|
|
165
|
+
return null;
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
// 读取现有配置
|
|
169
|
-
const existingConfig = await loadConfig();
|
|
169
|
+
const existingConfig = await loadConfig(homeDir);
|
|
170
170
|
|
|
171
|
-
//
|
|
172
|
-
if (existingConfig
|
|
171
|
+
// 如果已经有配置了,不做处理,这里老版本不删除这个问题就不走缓存咧
|
|
172
|
+
if (existingConfig) {
|
|
173
|
+
useClawLogger().warn("[yoyo-identity] identity exist, upgrade ignored");
|
|
173
174
|
return null;
|
|
174
175
|
}
|
|
175
176
|
|
|
176
177
|
// 升级到 v2,移除 legacyDeviceId
|
|
177
178
|
const upgradedConfig: PersistedIdentity = {
|
|
178
179
|
version: IdentityVersion.NEW,
|
|
179
|
-
deviceId: existingConfig.deviceId,
|
|
180
|
-
publicKeyPem: existingConfig.publicKeyPem,
|
|
181
|
-
privateKeyPem: existingConfig.privateKeyPem,
|
|
182
|
-
createdAtMs: existingConfig.createdAtMs,
|
|
183
|
-
// 故意不复制 legacyDeviceId,实现移除
|
|
184
180
|
};
|
|
185
181
|
|
|
186
182
|
// 写入升级后的配置
|
|
@@ -194,4 +190,4 @@ export async function upgradeIdentityToV2(): Promise<PersistedIdentity | null> {
|
|
|
194
190
|
});
|
|
195
191
|
|
|
196
192
|
return upgradedConfig;
|
|
197
|
-
}
|
|
193
|
+
}
|
|
@@ -55,7 +55,7 @@ function fingerprintPublicKey(publicKeyPem: string): string {
|
|
|
55
55
|
/**
|
|
56
56
|
* Generate a new device identity with ED25519 key pair
|
|
57
57
|
*/
|
|
58
|
-
function generateIdentity(identity: PersistedIdentity): DeviceIdentity {
|
|
58
|
+
function generateIdentity(identity: PersistedIdentity | null): DeviceIdentity {
|
|
59
59
|
const { publicKey, privateKey } = crypto.generateKeyPairSync("ed25519");
|
|
60
60
|
const publicKeyPem = publicKey.export({ type: "spki", format: "pem" }).toString();
|
|
61
61
|
const privateKeyPem = privateKey.export({ type: "pkcs8", format: "pem" }).toString();
|
|
@@ -68,7 +68,7 @@ function generateIdentity(identity: PersistedIdentity): DeviceIdentity {
|
|
|
68
68
|
createdAtMs: Date.now(),
|
|
69
69
|
} as DeviceIdentity;
|
|
70
70
|
|
|
71
|
-
if (identity.version === IdentityVersion.LEGACY) {
|
|
71
|
+
if (!identity || identity.version === IdentityVersion.LEGACY) {
|
|
72
72
|
// 补充legacyDeviceId
|
|
73
73
|
const provider = getDeviceInfoProvider();
|
|
74
74
|
fullIdentity.legacyDeviceId = provider.getDeviceId();
|
|
@@ -87,6 +87,7 @@ export async function loadOrCreateDeviceIdentity(): Promise<DeviceIdentity> {
|
|
|
87
87
|
const persisted = await getPersistedIdentity();
|
|
88
88
|
|
|
89
89
|
if (
|
|
90
|
+
persisted &&
|
|
90
91
|
persisted.deviceId &&
|
|
91
92
|
persisted.publicKeyPem &&
|
|
92
93
|
persisted.privateKeyPem &&
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 将错误封装为带有上下文信息的 Error
|
|
3
|
+
* @param error 原始错误
|
|
4
|
+
* @param context 错误上下文描述
|
|
5
|
+
* @returns 封装后的 Error 对象
|
|
6
|
+
*/
|
|
7
|
+
export function wrapError(error: unknown, context: string): Error {
|
|
8
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
9
|
+
|
|
10
|
+
return new Error(`${context}: ${message}`, {
|
|
11
|
+
cause: error,
|
|
12
|
+
});
|
|
13
|
+
}
|