chaimi-bookkeeping-mcp 3.1.13 → 3.1.14
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 +1 -1
- package/server.js +27 -76
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -241,7 +241,7 @@ let lastRefreshTime = 0;
|
|
|
241
241
|
async function getToken() {
|
|
242
242
|
// 检查是否已授权
|
|
243
243
|
if (!authState.isAuthorized) {
|
|
244
|
-
//
|
|
244
|
+
// 先检查是否有保存的授权状态(从文件加载)
|
|
245
245
|
const savedAuthState = await oauthManager.loadAuthState();
|
|
246
246
|
if (savedAuthState && savedAuthState.deviceCode) {
|
|
247
247
|
// 有保存的授权状态,尝试直接获取token(用户可能已授权)
|
|
@@ -252,38 +252,28 @@ async function getToken() {
|
|
|
252
252
|
cachedToken = token.accessToken;
|
|
253
253
|
tokenExpireTime = token.expiresAt;
|
|
254
254
|
authState.isAuthorized = true;
|
|
255
|
-
|
|
255
|
+
await oauthManager.tokenStorage.save(token);
|
|
256
256
|
await oauthManager.clearAuthState();
|
|
257
257
|
console.error('✅ 授权成功!可以继续使用记账功能');
|
|
258
258
|
return cachedToken;
|
|
259
259
|
}
|
|
260
|
+
// 用户还未授权,返回同一个验证码
|
|
261
|
+
authState.deviceCode = savedAuthState.deviceCode;
|
|
262
|
+
authState.userCode = savedAuthState.userCode;
|
|
263
|
+
throw new Error(`NEED_AUTH:${savedAuthState.userCode}`);
|
|
260
264
|
} catch (err) {
|
|
261
|
-
|
|
265
|
+
if (err.message.startsWith('NEED_AUTH:')) {
|
|
266
|
+
throw err;
|
|
267
|
+
}
|
|
268
|
+
// 其他错误,继续获取新的验证码
|
|
262
269
|
console.error('⚠️ 检查授权状态失败:', err.message);
|
|
263
270
|
}
|
|
264
271
|
}
|
|
265
272
|
|
|
266
|
-
//
|
|
267
|
-
|
|
268
|
-
await startBackgroundAuth();
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// 等待一段时间,让后台轮询有机会完成授权
|
|
272
|
-
// 最多等待10秒,每500ms检查一次
|
|
273
|
-
let waitAttempts = 0;
|
|
274
|
-
const maxWaitAttempts = 20; // 10秒
|
|
273
|
+
// 没有保存的授权状态,启动新的授权流程
|
|
274
|
+
await startAuthFlow();
|
|
275
275
|
|
|
276
|
-
|
|
277
|
-
await delay(500);
|
|
278
|
-
waitAttempts++;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// 再次检查是否已授权
|
|
282
|
-
if (authState.isAuthorized) {
|
|
283
|
-
return cachedToken;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// 仍未授权,返回验证码给Agent
|
|
276
|
+
// 返回验证码给Agent
|
|
287
277
|
throw new Error(`NEED_AUTH:${authState.userCode || '等待生成验证码'}`);
|
|
288
278
|
}
|
|
289
279
|
|
|
@@ -805,22 +795,25 @@ async function checkAuthInBackground() {
|
|
|
805
795
|
}
|
|
806
796
|
}
|
|
807
797
|
|
|
808
|
-
//
|
|
809
|
-
async function
|
|
810
|
-
if (authState.isWaiting) {
|
|
811
|
-
return; // 已经在等待授权
|
|
812
|
-
}
|
|
813
|
-
|
|
798
|
+
// 启动授权流程(获取验证码,不轮询,因为mcporter 30秒超时)
|
|
799
|
+
async function startAuthFlow() {
|
|
814
800
|
try {
|
|
815
|
-
|
|
816
|
-
|
|
801
|
+
// 先检查是否有保存的授权状态
|
|
802
|
+
const savedAuthState = await oauthManager.loadAuthState();
|
|
803
|
+
if (savedAuthState && savedAuthState.userCode) {
|
|
804
|
+
// 有保存的验证码,直接使用
|
|
805
|
+
authState.deviceCode = savedAuthState.deviceCode;
|
|
806
|
+
authState.userCode = savedAuthState.userCode;
|
|
807
|
+
console.error(`🔑 使用已保存的验证码:${savedAuthState.userCode}`);
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
817
810
|
|
|
818
|
-
//
|
|
811
|
+
// 获取新的设备码
|
|
819
812
|
const deviceCodeRes = await oauthManager.requestDeviceCode(false);
|
|
820
813
|
authState.deviceCode = deviceCodeRes.deviceCode;
|
|
821
814
|
authState.userCode = deviceCodeRes.userCode;
|
|
822
815
|
|
|
823
|
-
//
|
|
816
|
+
// 保存授权状态(30分钟有效)
|
|
824
817
|
await oauthManager.saveAuthState({
|
|
825
818
|
deviceCode: deviceCodeRes.deviceCode,
|
|
826
819
|
userCode: deviceCodeRes.userCode,
|
|
@@ -828,56 +821,14 @@ async function startBackgroundAuth() {
|
|
|
828
821
|
});
|
|
829
822
|
|
|
830
823
|
console.error(`🔑 验证码:${deviceCodeRes.userCode}`);
|
|
831
|
-
console.error('⏳
|
|
832
|
-
|
|
833
|
-
// 后台轮询(不阻塞)
|
|
834
|
-
pollForAuthInBackground(deviceCodeRes.deviceCode, deviceCodeRes.interval * 1000 || 5000);
|
|
824
|
+
console.error('⏳ 请在小程序中完成授权,然后再次调用');
|
|
835
825
|
|
|
836
826
|
} catch (err) {
|
|
837
827
|
authState.error = err.message;
|
|
838
|
-
authState.isWaiting = false;
|
|
839
828
|
console.error('❌ 启动授权失败:', err.message);
|
|
840
829
|
}
|
|
841
830
|
}
|
|
842
831
|
|
|
843
|
-
// 后台轮询授权状态(简化版,只轮询几次就停止,因为mcporter 30秒超时)
|
|
844
|
-
async function pollForAuthInBackground(deviceCode, interval) {
|
|
845
|
-
const maxAttempts = 5; // 只轮询5次(25秒),因为mcporter 30秒超时
|
|
846
|
-
let attempts = 0;
|
|
847
|
-
|
|
848
|
-
while (attempts < maxAttempts && authState.isWaiting) {
|
|
849
|
-
attempts++;
|
|
850
|
-
await delay(interval);
|
|
851
|
-
|
|
852
|
-
try {
|
|
853
|
-
const token = await oauthManager.pollForTokenOnce(deviceCode);
|
|
854
|
-
if (token) {
|
|
855
|
-
// 授权成功
|
|
856
|
-
cachedToken = token.accessToken;
|
|
857
|
-
tokenExpireTime = token.expiresAt;
|
|
858
|
-
authState.isAuthorized = true;
|
|
859
|
-
authState.isWaiting = false;
|
|
860
|
-
await oauthManager.tokenStorage.save(token); // 保存token到文件
|
|
861
|
-
await oauthManager.clearAuthState();
|
|
862
|
-
console.error('✅ 授权成功!可以继续使用记账功能');
|
|
863
|
-
return;
|
|
864
|
-
}
|
|
865
|
-
} catch (err) {
|
|
866
|
-
if (err.message.includes('expired') || err.message.includes('invalid')) {
|
|
867
|
-
authState.error = err.message;
|
|
868
|
-
authState.isWaiting = false;
|
|
869
|
-
console.error('❌ 授权失败:', err.message);
|
|
870
|
-
return;
|
|
871
|
-
}
|
|
872
|
-
// 继续轮询
|
|
873
|
-
}
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
// 轮询结束(可能是超时或达到最大次数)
|
|
877
|
-
authState.isWaiting = false;
|
|
878
|
-
console.error('⏳ 授权检查完成,如果已授权请再次调用');
|
|
879
|
-
}
|
|
880
|
-
|
|
881
832
|
// 延迟函数
|
|
882
833
|
function delay(ms) {
|
|
883
834
|
return new Promise(resolve => setTimeout(resolve, ms));
|