dsh-deepseek-web-login 0.3.1 → 0.4.0

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 CHANGED
@@ -2,6 +2,36 @@
2
2
 
3
3
  本项目遵循大致语义化版本;日期为本地时间。
4
4
 
5
+ ## 0.4.0 — 2026-09-26
6
+
7
+ > 两件事:一个「自动换号」滑块,以及一条会把限流误判成"不可重试"的修复。
8
+
9
+ ### 新增
10
+
11
+ - **「自动换号」滑块**(设置页 → 请求节流,紧邻「上下文」):**0~120 分钟,0 = 关闭**(默认关闭)。
12
+ 每满 N 分钟,换到账号库里的下一个可用账号。
13
+ 它的语义是**按时间均衡轮换** —— 让每个账号分到的请求都变少,把单账号密度摊薄。
14
+ ⚠️ 这跟"一被限流就换号"方向相反:后者会让同一个出口 IP 上多个账号交替活跃,更像有组织的规避。
15
+ 所以判据**只看时间**:失效或正在受限的账号会被跳过,但不会因为它们受限就提前切。
16
+ - 换号发生在**两个请求之间**(不会打断正在进行的生成)
17
+ - 切之前先探活(切到一个失效账号 = 白费一轮全量重发);探活失败的号本轮不再试
18
+ - 当前账号自己失效/受限时**立刻**切走,不必等满间隔
19
+ - 可用账号不足两个就不切;**手动切号后计时重置**
20
+ - ⚠️ 代价:换号会让投喂链断掉 —— 下一轮要全量重发、历史图重新上传。**间隔越短越频繁**。
21
+
22
+ ### 修复
23
+
24
+ - **信封形式的限流不再被误判为"不可重试"**:「操作过于频繁」除了 HTTP 429 与 SSE 错误事件,
25
+ 还可能以 **HTTP 200 + 业务码 40029** 的信封形式返回。此前只认前两条路,走信封的这一路会落到
26
+ `PROVIDER_ERROR`(不可重试)—— **恰好在最该退避的时候让整轮直接失败**。
27
+ 现在把「码 40029」与「文案族」合并成同一个判据,统一按限流退避重试。
28
+ (线索来自同类项目 cuckoo-code 0.6.1 的实测记录:它为此加了 60 秒退避重试。)
29
+
30
+ ### 工程
31
+
32
+ - 新增 `src/auto-switch.ts`(纯逻辑,可单测:`isUsable` / `isSwitchDue` / `pickNextAccount` /
33
+ `decideAutoSwitch`)与 `tests/check-auto-switch.mjs`(17 项:纯逻辑边界 + 真 POST 路由再读回 `gate.json`)。
34
+
5
35
  ## 0.3.1 — 2026-09-26
6
36
 
7
37
  > 报错文案瘦身。功能没变,但限流与封禁的提示不再长篇解释。
package/lib/client.js CHANGED
@@ -1574,6 +1574,31 @@ background:var(--bg2);white-space:pre-wrap;font-size:12px}
1574
1574
  paintContextWindow();
1575
1575
  saveGate({ contextWindow: currentCtxTokens() });
1576
1576
  });
1577
+ const swRow = el("div", "dsw-gate-row");
1578
+ swRow.append(el("span", "dsw-gate-label", "自动换号"));
1579
+ const swRange = el("input", "dsw-range");
1580
+ swRange.type = "range";
1581
+ swRange.min = "0";
1582
+ swRange.max = "120";
1583
+ swRange.step = "1";
1584
+ swRange.setAttribute("aria-label", "自动切换账号的间隔(分钟),0 表示关闭");
1585
+ swRange.title = "每隔这么久换到账号库里的下一个可用账号;0 = 关闭";
1586
+ const swValue = el("span", "dsw-gate-pair-value", "—");
1587
+ swRow.append(swRange, swValue);
1588
+ gateCard.append(swRow);
1589
+ const swHint = el("p", "dsw-hint", "");
1590
+ gateCard.append(swHint);
1591
+ const currentSwitchMinutes = () => Math.max(0, Math.round(Number(swRange.value) || 0));
1592
+ const paintAutoSwitch = () => {
1593
+ const minutes = currentSwitchMinutes();
1594
+ swValue.textContent = minutes === 0 ? "关闭" : `${minutes} 分钟`;
1595
+ swHint.textContent = minutes === 0 ? "关闭时不会自动换号 —— 当前账号一直用到你手动切换为止。" : `每 ${minutes} 分钟换到账号库里的下一个可用账号(失效或正在受限的会跳过;可用的不足两个就不换)。换号会让投喂链断掉:下一轮要全量重发,历史图也要重新上传 —— 间隔越短,这个代价出现得越频繁。`;
1596
+ };
1597
+ swRange.addEventListener("input", paintAutoSwitch);
1598
+ swRange.addEventListener("change", () => {
1599
+ paintAutoSwitch();
1600
+ saveGate({ autoSwitchMinutes: currentSwitchMinutes() });
1601
+ });
1577
1602
  const cleanupRow = el("div", "dsw-gate-row");
1578
1603
  cleanupRow.append(el("span", "dsw-gate-label", "会话清理"));
1579
1604
  const cleanupBtns = {};
@@ -2019,6 +2044,14 @@ background:var(--bg2);white-space:pre-wrap;font-size:12px}
2019
2044
  ctxRange.max = String(Math.max(0, ctxOptions.length - 1));
2020
2045
  ctxRange.value = String(nearestCtxIndex(Number(g.contextWindow ?? g.contextWindowDefault ?? ctxOptions[ctxOptions.length - 1])));
2021
2046
  paintContextWindow();
2047
+ const swBounds = g.autoSwitchBounds ?? {
2048
+ min: 0,
2049
+ max: 120
2050
+ };
2051
+ swRange.min = String(swBounds.min);
2052
+ swRange.max = String(swBounds.max);
2053
+ swRange.value = String(g.autoSwitchMinutes ?? g.autoSwitchDefault ?? 0);
2054
+ paintAutoSwitch();
2022
2055
  const mode = g.cleanup?.mode ?? "deferred";
2023
2056
  for (const key of Object.keys(cleanupBtns)) cleanupBtns[key].classList.toggle("active", key === mode);
2024
2057
  const showRanges = mode === "deferred";