dsh-deepseek-web-login 0.6.6 → 0.6.7
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/CHANGELOG.md +28 -0
- package/lib/client.js +73 -12
- package/lib/client.js.map +1 -1
- package/lib/index.js +35 -7
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
- package/tools/panel-preview.mjs +4 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
本项目遵循大致语义化版本;日期为本地时间。
|
|
4
4
|
|
|
5
|
+
## 0.6.7 — 2026-09-30
|
|
6
|
+
|
|
7
|
+
**修「点切换像没反应、报错在列表底部看不见」+「探活超时被当成登录态失效」。**
|
|
8
|
+
|
|
9
|
+
现场(用户截图):点一个**正常**账号的「切换」,界面上像什么都没发生;过一会儿列表底部才冒出
|
|
10
|
+
一行红字 —— `切换失败:该账号登录态校验未通过(The operation was aborted due to timeout),
|
|
11
|
+
请重新登录后再切换`。用户的原话是"这样一点也不明显"。
|
|
12
|
+
|
|
13
|
+
两件事叠在一起:
|
|
14
|
+
|
|
15
|
+
- **失败分类又漏了一处**。0.6.6 给探活分了「授权类 / 网络类」,但**切换前那次探活没跟上**:
|
|
16
|
+
不管哪一类失败都拦下来、都建议"重新登录"。而那次真因只是超时(网络抖了一下),凭证完全可用。
|
|
17
|
+
- **反馈位置不对**。切换的反馈只写卡片底部那一条消息,而用户的视线还停在他点的那颗按钮上;
|
|
18
|
+
探活最长 20 秒,这段时间里按钮毫无变化 ⇒ 体感就是"点了没反应"。
|
|
19
|
+
|
|
20
|
+
改法:
|
|
21
|
+
|
|
22
|
+
1. **切换前探活按类型分流**(新纯函数 `switchGateFromProbe`,有专门用例守):
|
|
23
|
+
- 授权失效 ⇒ 拦下,说清「这个号的登录态已失效,需要重新登录一次才能切换」;
|
|
24
|
+
- 网络类(超时/断网) ⇒ **放行**,只提示「已切换,但没能校验(网络问题)—— 登录态未必失效」;
|
|
25
|
+
- 探活通过 ⇒ 直接切。
|
|
26
|
+
与 `staleAuthRecord` 同一取舍:**网络问题不该冒充授权结论**。
|
|
27
|
+
(判据本身还是纯函数,宿主真的会调用它 —— 用例里连这条也守着,防"判据写好了没人调用"。)
|
|
28
|
+
2. **交互路径的探活超时 20s → 10s**(`SWITCH_PROBE_TIMEOUT_MS`)。后台定时探活仍是 20s。
|
|
29
|
+
3. **反馈落在那一行**:新增行内提示条(`.dsw-rowmsg`),切换的结果直接写在账号行里;
|
|
30
|
+
按钮自身进入「切换中…」禁用态。列表重建后按账号 id 把结果写回新行(顺序反了会被冲掉)。
|
|
31
|
+
4. **「重登」同样落到行内** —— 它是同一类"慢操作 + 只在底部说话"的问题。
|
|
32
|
+
|
|
5
33
|
## 0.6.6 — 2026-09-29
|
|
6
34
|
|
|
7
35
|
**修「网络一抖,整库账号被标成需要重新登录,点重登还得重敲密码」。**
|
package/lib/client.js
CHANGED
|
@@ -409,6 +409,17 @@ border:1px solid var(--bd);border-left:3px solid var(--fg3);white-space:pre-wrap
|
|
|
409
409
|
overflow:auto;font-size:12px;line-height:1.6;color:var(--fg)}
|
|
410
410
|
.dsw-msg.err{border-left-color:var(--err);color:color-mix(in srgb,var(--err) 78%,var(--fg))}
|
|
411
411
|
.dsw-msg.ok{border-left-color:var(--ok)}
|
|
412
|
+
.dsw-msg.warn{border-left-color:var(--warn);color:color-mix(in srgb,var(--warn) 80%,var(--fg))}
|
|
413
|
+
/* 行内结果条:由**某一行上的按钮**触发的操作(切换 / 重登),结果必须留在那一行。
|
|
414
|
+
为什么(2026-09-30 用户反馈「点切换没反应,报错在下面显示,一点也不明显」):
|
|
415
|
+
反馈原先只写卡片底部那条消息,用户点完按钮视线还在原处 —— 列表一长,等于没反馈。 */
|
|
416
|
+
.dsw-rowmsg{margin-top:6px;padding:6px 10px;border-radius:var(--r-sm);background:var(--bg2);
|
|
417
|
+
border-left:3px solid var(--fg3);color:var(--fg2);font-size:12px;line-height:1.55;
|
|
418
|
+
white-space:pre-wrap;word-break:break-word}
|
|
419
|
+
.dsw-rowmsg:empty{display:none}
|
|
420
|
+
.dsw-rowmsg.err{border-left-color:var(--err);color:color-mix(in srgb,var(--err) 78%,var(--fg))}
|
|
421
|
+
.dsw-rowmsg.ok{border-left-color:var(--ok)}
|
|
422
|
+
.dsw-rowmsg.warn{border-left-color:var(--warn);color:color-mix(in srgb,var(--warn) 80%,var(--fg))}
|
|
412
423
|
.dsw-models{list-style:none;margin:0;padding:0}
|
|
413
424
|
.dsw-models li{padding:10px 0;border-top:1px solid var(--bd)}
|
|
414
425
|
.dsw-models li:first-child{border-top:none;padding-top:2px}
|
|
@@ -901,34 +912,47 @@ background:var(--bg2);white-space:pre-wrap;font-size:12px}
|
|
|
901
912
|
const reloginAccount = (id, title) => {
|
|
902
913
|
(async () => {
|
|
903
914
|
accountsMsg.textContent = `正在校验「${title}」并准备登录窗口……`;
|
|
915
|
+
paintRowMsg(id, "正在校验登录态并准备登录窗口……", "info");
|
|
904
916
|
try {
|
|
905
917
|
const prep = await api("/login/relogin", {
|
|
906
918
|
method: "POST",
|
|
907
919
|
body: JSON.stringify({ id })
|
|
908
920
|
});
|
|
909
921
|
if (prep?.alreadyValid) {
|
|
910
|
-
|
|
922
|
+
const text = String(prep.hint ?? "这条账号校验通过,不需要重新登录");
|
|
923
|
+
accountsMsg.textContent = text;
|
|
924
|
+
paintRowMsg(id, `✅ ${text}`, "ok");
|
|
911
925
|
await loadAccounts();
|
|
912
926
|
return;
|
|
913
927
|
}
|
|
914
928
|
if (prep?.ok === false) {
|
|
915
|
-
|
|
929
|
+
const text = String(prep?.error ?? "未知原因");
|
|
930
|
+
accountsMsg.textContent = text;
|
|
931
|
+
paintRowMsg(id, `⚠️ ${text}`, "warn");
|
|
916
932
|
return;
|
|
917
933
|
}
|
|
918
934
|
boostUntil = Date.now() + 3e5;
|
|
919
|
-
|
|
935
|
+
const opened = String(prep?.hint ?? "登录窗口已打开:如果浏览器里还留着这个账号的登录态会立刻复用,否则在里面重新登录一次……");
|
|
936
|
+
accountsMsg.textContent = opened;
|
|
937
|
+
paintRowMsg(id, opened, "info");
|
|
920
938
|
const result = await api("/login/browser", {
|
|
921
939
|
method: "POST",
|
|
922
940
|
body: "{}"
|
|
923
941
|
});
|
|
924
942
|
if (result?.started === false) {
|
|
925
|
-
|
|
943
|
+
const text = `打开登录窗口失败:${result?.reason ?? "未知原因"}(可改用「手动粘贴 Token」)`;
|
|
944
|
+
accountsMsg.textContent = text;
|
|
945
|
+
paintRowMsg(id, `❌ ${text}`, "err");
|
|
926
946
|
return;
|
|
927
947
|
}
|
|
928
|
-
|
|
948
|
+
const done = result?.relogin ? `「${title}」的凭证已原地更新(同一条记录、当前账号未变),旧的失败标记也清掉了。` : result?.added ? `「${title}」已加入账号库 —— 当前使用的账号没有改变。` : "已捕获并保存凭证。";
|
|
949
|
+
accountsMsg.textContent = done;
|
|
929
950
|
await loadAccounts();
|
|
951
|
+
paintRowMsg(id, `✅ ${done}`, "ok");
|
|
930
952
|
} catch (error) {
|
|
931
|
-
|
|
953
|
+
const message = `重新登录失败:${error?.message ?? error}`;
|
|
954
|
+
accountsMsg.textContent = message;
|
|
955
|
+
paintRowMsg(id, `❌ ${message}`, "err");
|
|
932
956
|
} finally {
|
|
933
957
|
await refresh(false).catch(() => void 0);
|
|
934
958
|
}
|
|
@@ -954,6 +978,9 @@ background:var(--bg2);white-space:pre-wrap;font-size:12px}
|
|
|
954
978
|
main.append(el("div", "dsw-account-meta", meta.join(" · ")));
|
|
955
979
|
if (item.lastVerifyError) main.append(el("div", "dsw-account-fix", `⚠️ ${relTime(item.lastVerifyError.at)}校验失败(登录态已失效):${item.lastVerifyError.message}`));
|
|
956
980
|
else if (item.lastCheckError) main.append(el("div", "dsw-account-fix", `⚠️ ${relTime(item.lastCheckError.at)}未能校验(网络问题,账号未必失效):${item.lastCheckError.message}`));
|
|
981
|
+
const rowMsg = el("div", "dsw-rowmsg");
|
|
982
|
+
rowMsg.dataset.rowMsg = String(item.id);
|
|
983
|
+
main.append(rowMsg);
|
|
957
984
|
row.append(main);
|
|
958
985
|
const actions = el("div", "dsw-account-actions");
|
|
959
986
|
if (item.lastVerifyError || item.lastCheckError) {
|
|
@@ -965,7 +992,7 @@ background:var(--bg2);white-space:pre-wrap;font-size:12px}
|
|
|
965
992
|
if (item.isActive) actions.append(el("span", "dsw-hint", "使用中"));
|
|
966
993
|
else {
|
|
967
994
|
const useBtn = el("button", "dsw-btn ghost dsw-preset", "切换");
|
|
968
|
-
useBtn.addEventListener("click", () => void switchToAccount(item.id));
|
|
995
|
+
useBtn.addEventListener("click", () => void switchToAccount(item.id, useBtn));
|
|
969
996
|
actions.append(useBtn);
|
|
970
997
|
}
|
|
971
998
|
const renameBtn = el("button", "dsw-btn ghost dsw-preset", "备注");
|
|
@@ -1167,7 +1194,26 @@ background:var(--bg2);white-space:pre-wrap;font-size:12px}
|
|
|
1167
1194
|
};
|
|
1168
1195
|
refreshAccountsBtn.addEventListener("click", () => void refreshAccountStates());
|
|
1169
1196
|
newGroupBtn.addEventListener("click", () => promptNewGroup());
|
|
1170
|
-
|
|
1197
|
+
/**
|
|
1198
|
+
* 把结果写进**某一行的行内提示条**(按账号 id 找回节点 —— 列表重建过也能写回新的那条)。
|
|
1199
|
+
*
|
|
1200
|
+
* 为什么要有它(2026-09-30 用户反馈「点切换没反应,报错在下面显示,一点也不明显」):
|
|
1201
|
+
* 切换的反馈原先只写卡片底部那一条,而用户的视线还停在他点的那颗按钮上 ——
|
|
1202
|
+
* 列表一长,那条消息在屏幕外,体感就是"点了没反应"。所以结果必须在**那一行**里出现。
|
|
1203
|
+
*/
|
|
1204
|
+
const paintRowMsg = (id, text, kind) => {
|
|
1205
|
+
const node = accountsList.querySelector(`.dsw-rowmsg[data-row-msg="${id}"]`);
|
|
1206
|
+
if (!node) return;
|
|
1207
|
+
node.className = kind === "info" ? "dsw-rowmsg" : `dsw-rowmsg ${kind}`;
|
|
1208
|
+
node.textContent = text;
|
|
1209
|
+
};
|
|
1210
|
+
const switchToAccount = async (id, btn) => {
|
|
1211
|
+
const originalLabel = btn?.textContent ?? "";
|
|
1212
|
+
if (btn) {
|
|
1213
|
+
btn.disabled = true;
|
|
1214
|
+
btn.textContent = "切换中…";
|
|
1215
|
+
}
|
|
1216
|
+
paintRowMsg(id, "正在校验登录态并切换……", "info");
|
|
1171
1217
|
accountsMsg.textContent = "切换中……";
|
|
1172
1218
|
try {
|
|
1173
1219
|
const result = await api("/accounts/switch", {
|
|
@@ -1175,15 +1221,30 @@ background:var(--bg2);white-space:pre-wrap;font-size:12px}
|
|
|
1175
1221
|
body: JSON.stringify({ id })
|
|
1176
1222
|
});
|
|
1177
1223
|
if (!result?.ok) {
|
|
1178
|
-
|
|
1224
|
+
const message = `切换失败:${result?.error ?? "未知原因"}`;
|
|
1225
|
+
paintRowMsg(id, `❌ ${message}`, "err");
|
|
1226
|
+
accountsMsg.textContent = message;
|
|
1179
1227
|
return;
|
|
1180
1228
|
}
|
|
1181
|
-
accountsMsg.textContent = "已切换(下一次请求生效)。正在刷新登录状态……";
|
|
1182
1229
|
await loadAccounts();
|
|
1183
1230
|
await refresh(false);
|
|
1184
|
-
|
|
1231
|
+
if (result?.warning) {
|
|
1232
|
+
const text = `⚠️ ${String(result.warning)}`;
|
|
1233
|
+
paintRowMsg(id, text, "warn");
|
|
1234
|
+
accountsMsg.textContent = text;
|
|
1235
|
+
} else {
|
|
1236
|
+
paintRowMsg(id, "✅ 已切换(下一次请求生效)", "ok");
|
|
1237
|
+
accountsMsg.textContent = "已切换(下一次请求生效)";
|
|
1238
|
+
}
|
|
1185
1239
|
} catch (error) {
|
|
1186
|
-
|
|
1240
|
+
const message = `切换失败:${error?.message ?? error}`;
|
|
1241
|
+
paintRowMsg(id, `❌ ${message}`, "err");
|
|
1242
|
+
accountsMsg.textContent = message;
|
|
1243
|
+
} finally {
|
|
1244
|
+
if (btn) {
|
|
1245
|
+
btn.disabled = false;
|
|
1246
|
+
btn.textContent = originalLabel;
|
|
1247
|
+
}
|
|
1187
1248
|
}
|
|
1188
1249
|
};
|
|
1189
1250
|
const removeAccountById = async (id) => {
|