@wenbin_wb/dsh-bridge 2.10.6 → 2.10.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 +13 -0
- package/README.md +1 -1
- package/client/client.js +7 -0
- package/client/index.js +7 -0
- package/docs/cloudflare-fixed-domain.md +158 -0
- package/lib/cloudflared-manager.mjs +31 -4
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,19 @@
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## [v2.10.7] - 2026-09-08
|
|
8
|
+
|
|
9
|
+
### 🐞 修复
|
|
10
|
+
|
|
11
|
+
- **修复 Cloudflare 固定域名(Token 模式)隧道秒退**(issue #35):v2.10.6 引入的 `--no-autoupdate` 参数位置错误(写在 `run` 之后)导致 cloudflared 报 `Incorrect Usage` 秒退、固定域名隧道永远起不来(免费临时隧道不受影响)。已改为放在 `run` 之前,与临时隧道分支保持一致。
|
|
12
|
+
- **确定性配置错误直接提示**:`Incorrect Usage` / 无效 Token 等配置错误不再误判为"意外退出"退避重连 12 次,而是直接置 error 显示配置错误原因,便于定位问题。
|
|
13
|
+
|
|
14
|
+
### ✨ 优化
|
|
15
|
+
|
|
16
|
+
- **Cloudflare 固定域名配置区新增教程入口**:「查看 Cloudflare 固定域名申请与配置教程」链接,覆盖账号注册 → 域名接入 → 创建固定隧道 → 复制 Token → 绑定子域名(Public Hostname)→ 填回面板的完整图文步骤,中英文菜单对照。
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
7
20
|
## [v2.10.6] - 2026-09-07
|
|
8
21
|
|
|
9
22
|
### 🐞 修复
|
package/README.md
CHANGED
|
@@ -139,7 +139,7 @@ dsh plugin --profile web add @wenbin_wb/dsh-bridge@latest
|
|
|
139
139
|
3. 几秒内自动生成公网 URL 和二维码,点「重置链接」可随时换新。
|
|
140
140
|
|
|
141
141
|
- **模式 2:Cloudflare Token 固定域名(永久不变 · 免费)**
|
|
142
|
-
1. 在 [Cloudflare Zero Trust 控制台](https://one.dash.cloudflare.com/) 免费创建 Tunnel 并绑定域名(如 `dsh.yourdomain.com
|
|
142
|
+
1. 在 [Cloudflare Zero Trust 控制台](https://one.dash.cloudflare.com/) 免费创建 Tunnel 并绑定域名(如 `dsh.yourdomain.com`)——**[📖 从零申请/配置完整教程](docs/cloudflare-fixed-domain.md)**(注册账号 → 接入域名 → 建隧道 → 取 Token → 绑定子域名 → 填回面板);
|
|
143
143
|
2. 展开卡片底部的 **「⚙️ 高级配置:固定域名 (Cloudflare Token)」**,填入自定义域名与 Tunnel Token 并保存;
|
|
144
144
|
3. 勾选 **「随 DSH 启动自动开启」**,每次 DSH 重启即可自动恢复隧道,**URL 永久固定不变**!
|
|
145
145
|
|
package/client/client.js
CHANGED
|
@@ -1085,6 +1085,7 @@ var GITHUB_URL = "https://github.com/wenbin-wb/dsh-bridge";
|
|
|
1085
1085
|
var RELEASES_URL = "https://github.com/wenbin-wb/dsh-bridge/releases";
|
|
1086
1086
|
var ISSUES_URL = "https://github.com/wenbin-wb/dsh-bridge/issues/new";
|
|
1087
1087
|
var TUNNEL_DOCS_URL = "https://github.com/wenbin-wb/dsh-bridge/blob/main/docs/custom-tunnel.md";
|
|
1088
|
+
var CLOUDFLARE_TUTORIAL_URL = "https://github.com/wenbin-wb/dsh-bridge/blob/main/docs/cloudflare-fixed-domain.md";
|
|
1088
1089
|
function upgradeCommands(latest) {
|
|
1089
1090
|
const spec = `@wenbin_wb/dsh-bridge@${latest}`;
|
|
1090
1091
|
return [
|
|
@@ -1849,6 +1850,12 @@ var CloudflareConfigForm = React.memo(function CloudflareConfigForm2({ token, ho
|
|
|
1849
1850
|
{ style: { fontSize: 12, color: "var(--dsw-alias-label-secondary, #6b7280)", marginBottom: 8, lineHeight: 1.5 } },
|
|
1850
1851
|
"\u5728 Cloudflare Zero Trust \u63A7\u5236\u53F0\u521B\u5EFA Tunnel \u5373\u53EF\u83B7\u53D6\u4E13\u5C5E Token \u5E76\u7ED1\u5B9A\u81EA\u5DF1\u7684\u57DF\u540D\uFF08\u5982 dsh.yourname.com\uFF09\uFF0C\u6BCF\u6B21\u91CD\u542F URL \u6C38\u4E0D\u53D8\u66F4\u3002\u4E0D\u586B\u5219\u4F7F\u7528\u9ED8\u8BA4\u514D\u767B\u5F55\u4E34\u65F6\u968F\u673A\u57DF\u540D\u3002"
|
|
1851
1852
|
),
|
|
1853
|
+
React.createElement("a", {
|
|
1854
|
+
href: CLOUDFLARE_TUTORIAL_URL,
|
|
1855
|
+
target: "_blank",
|
|
1856
|
+
rel: "noreferrer",
|
|
1857
|
+
style: { ...s.btnLink, marginBottom: 10 }
|
|
1858
|
+
}, "\u{1F4D6} \u67E5\u770B\u300CCloudflare \u56FA\u5B9A\u57DF\u540D\u300D\u7533\u8BF7\u4E0E\u914D\u7F6E\u6559\u7A0B"),
|
|
1852
1859
|
React.createElement(
|
|
1853
1860
|
"div",
|
|
1854
1861
|
{ style: { marginBottom: 8 } },
|
package/client/index.js
CHANGED
|
@@ -84,6 +84,7 @@ const GITHUB_URL = 'https://github.com/wenbin-wb/dsh-bridge';
|
|
|
84
84
|
const RELEASES_URL = 'https://github.com/wenbin-wb/dsh-bridge/releases';
|
|
85
85
|
const ISSUES_URL = 'https://github.com/wenbin-wb/dsh-bridge/issues/new';
|
|
86
86
|
const TUNNEL_DOCS_URL = 'https://github.com/wenbin-wb/dsh-bridge/blob/main/docs/custom-tunnel.md';
|
|
87
|
+
const CLOUDFLARE_TUTORIAL_URL = 'https://github.com/wenbin-wb/dsh-bridge/blob/main/docs/cloudflare-fixed-domain.md';
|
|
87
88
|
|
|
88
89
|
// 生成升级命令(拼接具体版本号;用 add 而非 update,update --latest 受已安装依赖版本约束可能无法升级到最新版)
|
|
89
90
|
function upgradeCommands(latest) {
|
|
@@ -753,6 +754,12 @@ const CloudflareConfigForm = React.memo(function CloudflareConfigForm({ token, h
|
|
|
753
754
|
React.createElement('div', { style: { fontSize: 12, color: 'var(--dsw-alias-label-secondary, #6b7280)', marginBottom: 8, lineHeight: 1.5 } },
|
|
754
755
|
'在 Cloudflare Zero Trust 控制台创建 Tunnel 即可获取专属 Token 并绑定自己的域名(如 dsh.yourname.com),每次重启 URL 永不变更。不填则使用默认免登录临时随机域名。'
|
|
755
756
|
),
|
|
757
|
+
React.createElement('a', {
|
|
758
|
+
href: CLOUDFLARE_TUTORIAL_URL,
|
|
759
|
+
target: '_blank',
|
|
760
|
+
rel: 'noreferrer',
|
|
761
|
+
style: { ...s.btnLink, marginBottom: 10 },
|
|
762
|
+
}, '📖 查看「Cloudflare 固定域名」申请与配置教程'),
|
|
756
763
|
React.createElement('div', { style: { marginBottom: 8 } },
|
|
757
764
|
React.createElement('input', {
|
|
758
765
|
style: s.input,
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# Cloudflare 固定域名(Token 模式)申请与配置教程
|
|
2
|
+
|
|
3
|
+
> 适用:想让 dsh-bridge 的公网入口**固定不变**(如 `dsh.yourdomain.com`),而不是每次开启都换新的
|
|
4
|
+
> `trycloudflare.com` 随机地址。全程免费(Cloudflare 免费套餐即可),无需公网 IP、无需备案(境外流量)。
|
|
5
|
+
|
|
6
|
+
- 预计耗时:20–40 分钟(含域名生效等待)
|
|
7
|
+
- 费用:Cloudflare 免费套餐 $0;域名需自购(约 ¥30–80/年,.com/.net/.xyz 等均可)
|
|
8
|
+
- 💡 **界面语言**:Cloudflare 控制台支持中文。切换方式:页面右上角头像/语言菜单选择「中文(简体)」。本教程同时给出**中英文菜单对照**(如「添加站点 / Add a site」——斜杠前是中文界面名称,斜杠后是英文原名),用哪个界面都能对上。
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 原理一句话
|
|
13
|
+
|
|
14
|
+
你在 Cloudflare 建一条 **Named Tunnel(固定隧道)**,把 `dsh.yourdomain.com` 这个子域名的流量经 Cloudflare 边缘转发到
|
|
15
|
+
你电脑上 dsh-bridge 的本地端口(默认 `3082`)。dsh-bridge 只需要拿到这条隧道的 **Token** 就能替你后台运行
|
|
16
|
+
`cloudflared tunnel run --token <TOKEN>`,隧道进程由 dsh-bridge 托管(崩溃自动重启、随 DSH 启动自愈),域名永不改变。
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
手机/浏览器 → https://dsh.yourdomain.com → Cloudflare 边缘 → 加密隧道 → 你的电脑:3082 → DSH
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 第 1 步:注册 Cloudflare 账号
|
|
25
|
+
|
|
26
|
+
1. 打开 <https://dash.cloudflare.com/sign-up>,用邮箱注册(或 Google 账号登录)。
|
|
27
|
+
2. 登录后进入 Dashboard。
|
|
28
|
+
|
|
29
|
+
## 第 2 步:准备一个域名
|
|
30
|
+
|
|
31
|
+
两种方式任选:
|
|
32
|
+
|
|
33
|
+
- **已有域名**:确保域名的 DNS 托管在 Cloudflare(见第 3 步)。
|
|
34
|
+
- **没有域名**:
|
|
35
|
+
1. 在任意注册商购买一个(.com / .net / .xyz / .top 均可,便宜的先练手也行);
|
|
36
|
+
2. 拿到域名的 **NS 记录**(或注册商 API 权限),准备迁到 Cloudflare。
|
|
37
|
+
|
|
38
|
+
## 第 3 步:把域名接入 Cloudflare(DNS 托管)
|
|
39
|
+
|
|
40
|
+
> 固定域名隧道要求域名由 Cloudflare 托管(DNS 生效才能签发证书、路由流量)。若域名已在 Cloudflare 可跳过本步。
|
|
41
|
+
|
|
42
|
+
1. Cloudflare Dashboard(控制台)→「**添加站点 / Add a site**」→ 输入你的域名 → 选 **Free(免费)** 套餐 → Continue(继续)。
|
|
43
|
+
2. Cloudflare 会扫描现有 DNS 记录并导入(自动保留)。
|
|
44
|
+
3. 按提示到**域名注册商**处,把域名的 NS(Name Server/名称服务器)改成 Cloudflare 给的两条(形如 `xxx.ns.cloudflare.com`)。
|
|
45
|
+
4. 回 Cloudflare 点「**检查名称服务器 / Check nameservers**」,等待生效(通常几分钟到 24 小时,多数 1 小时内)。
|
|
46
|
+
5. 状态变 **Active(有效)** 即托管完成。
|
|
47
|
+
|
|
48
|
+
## 第 4 步:进入 Zero Trust 创建固定隧道
|
|
49
|
+
|
|
50
|
+
1. 打开 Zero Trust 控制台:<https://one.dash.cloudflare.com/>
|
|
51
|
+
(或 Cloudflare Dashboard 左侧 → **Zero Trust**)。
|
|
52
|
+
2. 首次使用会让你选团队名、套餐——选 **Free(免费)** 计划即可。
|
|
53
|
+
3. 左侧菜单:**Networks(网络)→ Tunnels(隧道)**。
|
|
54
|
+
4. 点 **Create a tunnel(创建隧道)**:
|
|
55
|
+
- 连接器类型选 **Cloudflared**;
|
|
56
|
+
- Tunnel name(隧道名称):起个名,如 `dsh-home`;
|
|
57
|
+
- 点 **Save tunnel(保存隧道)**。
|
|
58
|
+
5. **⚠️ 立即复制并保存 Token(这一步最要紧!)**
|
|
59
|
+
保存后页面会给出**安装并运行连接器**的命令,里面带一长串 Token:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
cloudflared tunnel run --token eyJhIjoi...(极长的一串)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**请现在就把 `--token` 后面那一长串完整复制出来**,粘贴到记事本/密码管理器存好(可以顺手存好 `dsh.yourdomain.com` 这个域名一起备忘)。**复制完再点任何下一步/关闭页面**——万一丢了,见本步下方"Token 找不回来了怎么办"。
|
|
66
|
+
|
|
67
|
+
> 🤖 **这段命令不用你自己在电脑上运行**(无论 Windows / macOS / Linux 都不需要)——dsh-bridge 会在后台替你执行
|
|
68
|
+
> `cloudflared tunnel run --token ...`。这里展示命令只是为了让你看清 Token 长在哪、方便复制那一长串。
|
|
69
|
+
|
|
70
|
+
> 💡 **Token 找不回来了怎么办**(不用重建隧道,随时可取):
|
|
71
|
+
>
|
|
72
|
+
> 回到 **Networks(网络)→ Tunnels(隧道)** 列表 → 点你的**隧道名称**进入详情页 → 找 **Configure(配置)**按钮或右上角 **⋯** 菜单(不同时期界面略有差异),点击后页面会显示该隧道的 **Token**,或重新给出 `cloudflared tunnel run --token ...` 的安装命令——复制其中那一长串即可。
|
|
73
|
+
>
|
|
74
|
+
> 取 token 时**无需在电脑上运行任何命令**,Token 就在网页里,直接复制即可。
|
|
75
|
+
|
|
76
|
+
## 第 5 步:给隧道绑定你的固定子域名(Public Hostname / 公共主机名)
|
|
77
|
+
|
|
78
|
+
> ⚠️ **关键**:隧道本身不含"域名→本地端口"的路由规则,必须在这里配。而且这个子域名要和你之后在
|
|
79
|
+
> dsh-bridge 面板里填的「自定义固定域名」**完全一致**。
|
|
80
|
+
|
|
81
|
+
1. 隧道创建后进入隧道详情页 → 切到 **Public Hostname(公共主机名)** 标签 → **Add a public hostname(添加公共主机名)**。
|
|
82
|
+
2. 填写(中英文界面字段对照):
|
|
83
|
+
- **Subdomain(子域)**:如 `dsh`
|
|
84
|
+
- **Domain(域)**:下拉选你的域名(如 `yourdomain.com`)
|
|
85
|
+
- 即最终 = `dsh.yourdomain.com`
|
|
86
|
+
- **Service(服务)→ Type(类型)**:`HTTP`
|
|
87
|
+
- **URL**:`localhost:3082`(dsh-bridge 代理端口;如果你改过 dsh-bridge 端口则填对应端口)
|
|
88
|
+
3. 保存(**Save / 保存**)。Cloudflare 会自动为你签发该域名的免费 TLS 证书并创建 DNS 记录(Tunnel 类型,CNAME 指向 `*.cfargotunnel.com`),无需手动配 DNS。
|
|
89
|
+
4. 状态稍后变为 **Healthy(运行正常)**(见隧道详情的 Connectors(连接器)与 Public Hostname(公共主机名)状态)。
|
|
90
|
+
|
|
91
|
+
> 端口说明:dsh-bridge 默认把面板代理在 `3082`(`proxyPort`),DSH 原生在 `3080`。**必须指向 3082**(走 dsh-bridge 的
|
|
92
|
+
> 认证/会话/二维码/隧道控制逻辑),不要直接指 3080。
|
|
93
|
+
|
|
94
|
+
> 端口说明:dsh-bridge 默认把面板代理在 `3082`(`proxyPort`),DSH 原生在 `3080`。**必须指向 3082**(走 dsh-bridge 的
|
|
95
|
+
> 认证/会话/二维码/隧道控制逻辑),不要直接指 3080。
|
|
96
|
+
|
|
97
|
+
## 第 6 步:把 Token 和域名填回 dsh-bridge
|
|
98
|
+
|
|
99
|
+
1. 打开 dsh-bridge 面板 → **公网隧道** tab。
|
|
100
|
+
2. 展开底部「**⚙️ 隧道配置**」→「**Cloudflare 隧道**」卡 → 展开「**高级配置:固定域名 (Cloudflare Token)**」。
|
|
101
|
+
3. 填写两项并「保存固定域名配置」:
|
|
102
|
+
- **自定义固定域名**:`dsh.yourdomain.com`(与第 5 步 Public Hostname **完全一致**,不要带 `https://`)
|
|
103
|
+
- **Tunnel Token**:第 4/5 步复制的 `cloudflared tunnel run --token` 后的那一长串
|
|
104
|
+
4. 回到顶部「**公网访问入口**」卡 → 点「**开启**」(token 模式下该卡显示固定域名模式)。
|
|
105
|
+
5. 几秒后状态变 **固定隧道已建立 (https://dsh.yourdomain.com)**。
|
|
106
|
+
|
|
107
|
+
## 第 7 步:验证
|
|
108
|
+
|
|
109
|
+
1. 浏览器打开 `https://dsh.yourdomain.com` → 应出现 DSH 登录页/面板(取决于你的访问认证设置)。
|
|
110
|
+
2. Cloudflare Zero Trust → **Networks(网络)→ Tunnels(隧道)** → 该隧道 → **Healthy(运行正常)**,Connectors(连接器)有连接。
|
|
111
|
+
3. 重启 DSH 服务或重启电脑,勾选「随 DSH 启动自动开启」后域名保持不变、自动恢复。
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## 常见问题
|
|
116
|
+
|
|
117
|
+
### Q1:面板显示"已建立"但浏览器打不开?
|
|
118
|
+
几乎都是 **Public Hostname 与面板填的域名不一致**,或 Service URL 端口写错(应为 `localhost:3082` 而非 3080)。
|
|
119
|
+
逐项核对第 5、6 步。
|
|
120
|
+
|
|
121
|
+
### Q2:提示"cloudflared 启动失败: Incorrect Usage / flag provided but not defined"?
|
|
122
|
+
请确认 dsh-bridge ≥ **v2.10.7**(v2.10.6 曾因 `--no-autoupdate` 参数位置导致固定域名隧道秒退,已修复)。
|
|
123
|
+
|
|
124
|
+
### Q3:隧道一直"自动重连中"然后 error?
|
|
125
|
+
先看面板 error 文案:
|
|
126
|
+
- 含 **Incorrect Usage / 配置错误** → Token 复制不完整或参数问题,重新复制整串 Token;
|
|
127
|
+
- 含 **退出 code≠0 / 连接失败** → 多为网络到 Cloudflare 边缘不通或 Token 无效,检查网络后点「开启」重试(自愈已内置退避重试)。
|
|
128
|
+
|
|
129
|
+
### Q4:需要买最贵的套餐吗?
|
|
130
|
+
不用。Cloudflare **Free** 套餐即可创建固定隧道、绑定子域名、免费 TLS。仅当你想在同一域名下加很多复杂规则或团队审计时才需付费。
|
|
131
|
+
|
|
132
|
+
### Q5:域名必须在 Cloudflare 托管吗?
|
|
133
|
+
**固定域名隧道是的**(要在 Cloudflare DNS 建 `CNAME → *.cfargotunnel.com` 的记录)。不想迁移主域名的话,
|
|
134
|
+
可以买一个便宜小域名专门做隧道入口,把主域名留在原注册商。
|
|
135
|
+
|
|
136
|
+
### Q6:为什么面板里"复制 Token"和 Cloudflare 命令里看到的不一样长?
|
|
137
|
+
Token 就是 `cloudflared tunnel run --token` 后面那一长串(不含引号、不含 `--token` 字样本身)。
|
|
138
|
+
若你在别处看到的 token 是用于 `cloudflared tunnel login` 的,那是不同的东西——固定域名模式要的是 **run --token** 那个。
|
|
139
|
+
|
|
140
|
+
### Q7:创建隧道时忘了复制 Token,页面也关了,去哪找?
|
|
141
|
+
**不需要重建隧道**,Token 随时能在网页里取回:
|
|
142
|
+
|
|
143
|
+
1. 打开 Zero Trust 控制台 → 左侧 **Networks(网络)→ Tunnels(隧道)**;
|
|
144
|
+
2. 在隧道列表里**点击你那条隧道的名称**(不是行尾的按钮,是名称本身)进入详情;
|
|
145
|
+
3. 详情页找 **Configure(配置)** 按钮,或页面右上角的 **⋯ / 更多** 菜单(不同时期的界面位置可能略有差异,但一定在隧道详情页里);
|
|
146
|
+
4. 点击后页面会显示该隧道的 **Token**,或者重新给出带 Token 的安装命令(`cloudflared tunnel run --token ...`);
|
|
147
|
+
5. 复制命令中 `--token` 后面那一长串即可。
|
|
148
|
+
|
|
149
|
+
> 提示:如果你在列表页只看到 **⋯** 下拉里有 **Edit / 编辑 / Delete / 删除** 而没有 Token,就点**隧道名称先进详情**,
|
|
150
|
+
> Token 在详情页内。整个过程都在浏览器网页里完成,**不需要在电脑上装 cloudflared 或执行任何命令**。
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## 相关链接
|
|
155
|
+
|
|
156
|
+
- [Cloudflare Zero Trust 控制台](https://one.dash.cloudflare.com/)
|
|
157
|
+
- [Cloudflare 官方:Create a tunnel (dashboard)](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/get-started/create-remote-tunnel/)
|
|
158
|
+
- [Cloudflare 官方:Tunnel run 参数(--token / --no-autoupdate)](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/configure-tunnels/run-parameters/)
|
|
@@ -15,6 +15,14 @@ const RETRY_BASE_MS = 5 * 1000; // 自愈退避起点 5s
|
|
|
15
15
|
const RETRY_MAX_MS = 5 * 60 * 1000; // 自愈退避封顶 5min
|
|
16
16
|
const DEFAULT_MAX_RETRIES = 12; // 连续失败超过该次数转为 error,不再无限重试
|
|
17
17
|
|
|
18
|
+
// ── 确定性失败特征:cloudflared 因配置/用法错误退出(非网络瞬态)─────────
|
|
19
|
+
// 这类失败重试无意义,识别后直接置 error 让用户看到明确原因,而不是
|
|
20
|
+
// 误判成"意外退出"退避重连 N 次(issue #35 作者建议)。
|
|
21
|
+
function isFatalCloudflaredError(stderrTail) {
|
|
22
|
+
if (!stderrTail) return false;
|
|
23
|
+
return /Incorrect Usage|flag provided but not defined|invalid.*token|unauthorized/i.test(stderrTail);
|
|
24
|
+
}
|
|
25
|
+
|
|
18
26
|
// 上游 release 不提供任何官方校验和文件(已核实 2024.10.0 资产清单),
|
|
19
27
|
// 因此无法做下载校验和比对;退而求其次:记录产物 SHA-256 指纹供事后审计比对。
|
|
20
28
|
async function sha256File(filePath) {
|
|
@@ -181,7 +189,12 @@ export class CloudflaredManager {
|
|
|
181
189
|
this._setState('connecting', '正在初始化...');
|
|
182
190
|
this._run().catch((err) => {
|
|
183
191
|
this.logger?.error('cloudflared 启动失败: %s', err.message);
|
|
184
|
-
//
|
|
192
|
+
// 确定性失败(用法错误/配置错误,如 Incorrect Usage)重试无意义 → 直接 error,
|
|
193
|
+
// 让用户看到明确原因;瞬态失败(网络/握手/秒退)才退避自愈
|
|
194
|
+
if (err && err.fatal) {
|
|
195
|
+
this._setState('error', err.message);
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
185
198
|
this._scheduleRestart(`cloudflared 启动失败: ${err.message}`);
|
|
186
199
|
});
|
|
187
200
|
}
|
|
@@ -223,6 +236,11 @@ export class CloudflaredManager {
|
|
|
223
236
|
this._setState('connecting', '正在自动重连...');
|
|
224
237
|
this._run().catch((err) => {
|
|
225
238
|
this.logger?.error('cloudflared 自动重连失败: %s', err.message);
|
|
239
|
+
// 自愈期间遇到确定性失败同样终止重试(如用户改坏配置后重启)
|
|
240
|
+
if (err && err.fatal) {
|
|
241
|
+
this._setState('error', err.message);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
226
244
|
this._scheduleRestart(`cloudflared 启动失败: ${err.message}`);
|
|
227
245
|
});
|
|
228
246
|
}
|
|
@@ -364,7 +382,8 @@ export class CloudflaredManager {
|
|
|
364
382
|
this._setState('connecting', this._restartCount > 0 ? '正在自动重连...' : '正在连接 Cloudflare...');
|
|
365
383
|
|
|
366
384
|
const args = this.token
|
|
367
|
-
|
|
385
|
+
// --no-autoupdate 是 tunnel 子命令的全局 flag,须在 run 之前(cloudflared 2024.10.0,issue #35)
|
|
386
|
+
? ['tunnel', ...(this.noAutoupdate ? ['--no-autoupdate'] : []), 'run', '--token', this.token]
|
|
368
387
|
: ['tunnel', ...(this.noAutoupdate ? ['--no-autoupdate'] : []), '--url', `http://127.0.0.1:${this.port}`];
|
|
369
388
|
|
|
370
389
|
// 隐藏日志中的 token 敏感字段
|
|
@@ -385,6 +404,8 @@ export class CloudflaredManager {
|
|
|
385
404
|
|
|
386
405
|
let resolved = false;
|
|
387
406
|
let timeoutTimer = null;
|
|
407
|
+
// 累积 stderr 尾部(供 exit 时判断确定性失败:CLI 用法错误 / 配置错误)
|
|
408
|
+
let stderrTail = '';
|
|
388
409
|
|
|
389
410
|
// 仅当当前引用的仍是本次 spawn 的进程时才清空——自愈重启后旧进程的
|
|
390
411
|
// exit 事件可能晚于新进程 spawn 触发;exit handler 内用 stillCurrent
|
|
@@ -443,6 +464,7 @@ export class CloudflaredManager {
|
|
|
443
464
|
proc.stderr.on('data', (d) => {
|
|
444
465
|
const text = d.toString();
|
|
445
466
|
this.logger?.debug('cloudflared: %s', text.trim());
|
|
467
|
+
stderrTail = (stderrTail + text).slice(-2000); // 只保留尾部 2KB
|
|
446
468
|
parseUrl(text);
|
|
447
469
|
if (text.includes('Registered tunnel') && !resolved) {
|
|
448
470
|
this._setState('connecting', '隧道已注册,等待就绪...');
|
|
@@ -461,8 +483,13 @@ export class CloudflaredManager {
|
|
|
461
483
|
if (stillCurrent) this.process = null;
|
|
462
484
|
this.url = null;
|
|
463
485
|
if (!resolved) {
|
|
464
|
-
// 就绪前退出 = 启动失败,交给 reject → start()/restart 的 catch
|
|
465
|
-
|
|
486
|
+
// 就绪前退出 = 启动失败,交给 reject → start()/restart 的 catch 进入退避自愈。
|
|
487
|
+
// 若 stderr 显示确定性配置/用法错误(Incorrect Usage 等)→ 标 fatal,
|
|
488
|
+
// catch 收到后直接置 error,不再无意义退避重连。
|
|
489
|
+
const msg = `cloudflared 启动失败: ${isFatalCloudflaredError(stderrTail) ? '配置错误(' + (stderrTail.trim().split('\n').pop() || '请检查 Token 与参数') + ')' : `cloudflared 退出,code=${code ?? ''} signal=${signal ?? ''}`}`;
|
|
490
|
+
const err = new Error(msg);
|
|
491
|
+
if (isFatalCloudflaredError(stderrTail)) err.fatal = true;
|
|
492
|
+
reject(err);
|
|
466
493
|
} else if (!this._stopped && stillCurrent) {
|
|
467
494
|
// 就绪后的意外退出(崩溃 / OOM / 误杀 / autoupdate 残留自替换)→ 退避自愈
|
|
468
495
|
this._scheduleRestart(`cloudflared 进程意外退出 (code=${code ?? ''}${signal ? `, ${signal}` : ''})`);
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wenbin_wb/dsh-bridge",
|
|
3
|
-
"version": "2.10.
|
|
3
|
+
"version": "2.10.7",
|
|
4
4
|
"description": "手机扫码即可在移动端/公网继续用 DeepSeek Harness,人不在电脑前也能接着干。一键局域网二维码、Cloudflare 公网隧道、自建隧道与微信 / QQ / 飞书 / Telegram Bot(多工作区/会话持久化/媒体/卡片审批/流式输出),无需自己搭公网服务器。",
|
|
5
|
-
"releaseNotes": "【v2.10.
|
|
5
|
+
"releaseNotes": "【v2.10.7】\n• 修复:Cloudflare 固定域名(Token 模式)隧道秒退(issue #35)——`--no-autoupdate` 参数位置修正(v2.10.6 引入),固定域名隧道现在可正常建立并保持;同时将 Incorrect Usage / 无效 Token 等确定性配置错误直接提示为配置错误,不再误判为\"意外退出\"退避重连 12 次\n• 优化:Cloudflare 固定域名配置区新增「查看申请与配置教程」入口(含账号注册、域名接入、创建隧道、绑定子域名到面板的完整图文步骤)",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "lib/index.js",
|
|
8
8
|
"exports": {
|
|
@@ -103,4 +103,4 @@
|
|
|
103
103
|
"access": "public",
|
|
104
104
|
"registry": "https://registry.npmjs.org/"
|
|
105
105
|
}
|
|
106
|
-
}
|
|
106
|
+
}
|