dsh-deepseek-web-login 0.3.0 → 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 +54 -0
- package/lib/client.js +34 -1
- package/lib/client.js.map +1 -1
- package/lib/index.js +180 -10
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
- package/tools/panel-preview.mjs +5 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,60 @@
|
|
|
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
|
+
|
|
35
|
+
## 0.3.1 — 2026-09-26
|
|
36
|
+
|
|
37
|
+
> 报错文案瘦身。功能没变,但限流与封禁的提示不再长篇解释。
|
|
38
|
+
|
|
39
|
+
### 改进
|
|
40
|
+
|
|
41
|
+
- **封禁提示只说到几时结束**:改为「DeepSeek 网页端已封禁本账号,X 解除(约 N 分钟)」。
|
|
42
|
+
原来那段 150 字的解释(登录态其实有效、建会话也正常、建议改用 API key、
|
|
43
|
+
刚跑过大量工具步骤的会话尤其容易被限……)全部移到代码注释 —— 用户看报错时只需要
|
|
44
|
+
「是什么 + 到几时结束」,解释会把这两件事淹没。
|
|
45
|
+
- **限流统一叫「网页版限流」**:账号节流(`发得太频繁`)与「同一账号同时只能生成一条消息」
|
|
46
|
+
两种情况共用这个前缀,后缀只保留成因 + 会自动重试。HTTP 限流的提示同样是这三个字。
|
|
47
|
+
- 设置页上的账号级限制提示同步收紧(去掉「只读调用不受影响」等补充)。
|
|
48
|
+
|
|
49
|
+
### 说明
|
|
50
|
+
|
|
51
|
+
- 结构化字段一个没动:`RATE_LIMIT` 分类、`providerRetryAfterMs`(解除时间很远时让重试策略
|
|
52
|
+
放弃空转)、`rateLimitKind` 均照旧 —— 只有文案层变短,重试行为与账号级限制记录不受影响。
|
|
53
|
+
|
|
54
|
+
### 工程
|
|
55
|
+
|
|
56
|
+
- `check-session-lifecycle` 的封禁文案断言原本绑死旧措辞(`/临时限制|muted/i`),
|
|
57
|
+
改为断意图(含「封禁/限制」+ 含「解除」),并新增**长度上限 80 字**阀门防止回退。
|
|
58
|
+
|
|
5
59
|
## 0.3.0 — 2026-09-26
|
|
6
60
|
|
|
7
61
|
> 上下文范围可调。原来硬编码 1M,现在能按需调小。
|
package/lib/client.js
CHANGED
|
@@ -692,7 +692,7 @@ background:var(--bg2);white-space:pre-wrap;font-size:12px}
|
|
|
692
692
|
}
|
|
693
693
|
const text = countdown(activeLimitUntilMs);
|
|
694
694
|
limitRow.style.display = "";
|
|
695
|
-
limitRow.textContent = text === "已解除" ? `账号级限制已解除(${shortTime(activeLimitUntilMs)})。` : `⚠️ 账号级限制:${text}(${shortTime(activeLimitUntilMs)}
|
|
695
|
+
limitRow.textContent = text === "已解除" ? `账号级限制已解除(${shortTime(activeLimitUntilMs)})。` : `⚠️ 账号级限制:${text}(${shortTime(activeLimitUntilMs)} 解除,期间生成会被拒)`;
|
|
696
696
|
};
|
|
697
697
|
const accountCard = el("div", "dsw-card");
|
|
698
698
|
accountCard.append(el("div", "dsw-cardhead", "当前账号"));
|
|
@@ -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";
|