dsh-provider-proxy 0.5.0 → 0.5.1

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/README.md CHANGED
@@ -37,7 +37,7 @@ dsh plugin --profile web add dsh-provider-proxy
37
37
  | 开关 | 该 provider 是否走代理 |
38
38
  | 使用默认代理 | 勾选后本卡片的传输字段整体取自页面顶部「默认代理」区块,无需逐个重填 |
39
39
  | 类型 | `HTTP` / `HTTPS` / `SOCKS5` |
40
- | IP / 主机 | 只填主机名或 IP,不要带 `http://` 或路径 |
40
+ | IP / 主机 | 只填 IPv4、IPv6 或 ASCII 域名;不要带协议前缀、端口、路径或凭据。IDN 需先转 punycode |
41
41
  | 端口 | 1–65535 的整数 |
42
42
  | 用户名 | 可选(与密码成对填写) |
43
43
  | 密码 | 可选(与用户名成对填写)。作为代理认证口令发给代理(`HTTP` / `HTTPS` / `SOCKS5` 均支持) |
@@ -45,18 +45,29 @@ dsh plugin --profile web add dsh-provider-proxy
45
45
  同一个代理要给多张卡片用时,只在页面顶部的 **默认代理** 区块填一次,再在每张卡片勾上 **使用默认代理**。
46
46
  勾上之后该卡片的传输字段(类型 / 主机 / 端口 / 用户名 / 密码)**整体**取自默认区块,卡片不再显示这些输入框,
47
47
  改为显示它实际会用的地址——所以不会出现「填了一半、另一半不知道从哪来」的模糊状态。目标域名规则与自检目标
48
- 始终是卡片自己的。默认区块本身不可用时(未填地址、地址带了协议前缀或路径、端口非法、凭据只填了一半),
49
- 勾了继承的卡片会被拒绝并说明原因(列在「连接诊断」里),卡片上也直接显示这条原因;默认块的绿点与批量按钮
50
- 用的是同一个判定,所以不会出现「亮着绿灯却一张卡也用不上」。
48
+ 始终是卡片自己的。默认区块本身不可用时(未填地址、地址不是合法 IPv4/IPv6/域名、端口非法、凭据只填了一半),
49
+ 勾了继承的卡片会被拒绝并说明原因(列在「连接诊断」里),卡片上也直接显示这条原因;默认块的「配置完整」
50
+ 状态与批量按钮用的是同一个判定,所以不会出现「亮着绿灯却一张卡也用不上」。
51
51
 
52
52
  **端点输入不随开关变化**:关闭的卡片照样可以填写、也可以测试。这样就能**先验证再启用**,避开了
53
53
  「必须先打开代理才能测,而配置是坏的」这个窗口。
54
54
 
55
+ 卡片头上的状态只描述**路由**:
56
+
57
+ | 状态 | 含义 |
58
+ | --- | --- |
59
+ | 配置被拒 | 已启用,但端点 / 凭据不完整或 Host 无法建立路由。该 provider 的请求**不会经过本插件代理**;原因直接显示在卡片内,也列在「连接诊断」里 |
60
+ | 走代理 | 已启用且配置可建立路由。单次请求仍可能因目标域名规则直连;它不代表代理**可达**,连通性看「测试」与「最近调用」 |
61
+ | 直连 | 未启用,流量走宿主原有路径 |
62
+
63
+ Host catalog 是否列出某个 provider(`live`)不影响已保存路由的卡片状态;它只决定**未配置**的 provider 是否出现在列表里。
64
+
55
65
  页面上的几处便利:
56
66
 
57
67
  - **过滤框**:provider 多时按 id 或名称筛掉不必看的卡片。它纯粹是视图,不写任何设置。
58
68
  - **粘贴完整代理 URL**:把 `socks5://user:pass@host:1080` 粘进任一「IP / 主机」输入框,会自动拆成
59
- 协议 / 主机 / 端口 / 用户名 / 密码,并且是**一次**写入(不是五个字段各写一次)。
69
+ 协议 / 主机 / 端口 / 用户名 / 密码,并且是**一次**写入(不是五个字段各写一次)。显式写出的 `:80` / `:443`
70
+ 会保留;完全没写端口时保持「未配置」,不会自动补默认端口。
60
71
  - **设为默认代理**(卡片上,仅在该卡片有自己的端点时出现):把它当前的端点一次性提升为顶部的默认端点。
61
72
  - **所有 provider 使用默认代理**(默认区块里):一条批量写把每张卡片都指向默认端点;默认端点不可用时按钮禁用。
62
73
  - **最近一次调用**:卡片头上会显示「最近成功 3 分钟前」,失败时显示「最近失败 ECONNREFUSED」。
@@ -77,11 +88,12 @@ dsh plugin --profile web add dsh-provider-proxy
77
88
 
78
89
  列表只包含**已激活**的 provider(`llm.listProviders()` 能列出的那些)。仅在配置里声明、
79
90
  但没有实际注册的可配置 provider 不显示——它的请求根本不会被发出去。
80
- 已经在 `providers` 里配过代理的条目即使暂时不激活也仍然保留,避免已保存的设置悄悄消失。
91
+ 已经在 `providers` 里配过代理的条目即使暂时不激活也仍然保留,避免已保存的设置悄悄消失;
92
+ catalog 的 `live` 只影响未配置 provider 是否出现在列表里,不参与已保存卡片的状态判定。
81
93
 
82
94
  保存立即对新请求生效,不需要重启;正在进行中的流会继续用它启动时的那条连接。
83
95
 
84
- 每张卡片还有一个 **测试** 按钮:点它会让 Host 通过**该 provider 自己的代理**发一次请求,回报延迟与(探测目标返回时)出口 IP。只要该卡片有完整端点它就会出现——**不必先启用**;未启用的检查会标注为「未启用,仅测试」。代理不可达时它会明确失败,而不是假通过。
96
+ 每张卡片还有一个 **测试** 按钮:点它会让 Host 通过**该 provider 自己的代理**发一次请求,回报延迟与(探测目标返回时)出口 IP。只要该卡片有完整端点它就会出现——**不必先启用**;未启用的检查会标注为「未启用,仅测试」。代理不可达时它会明确失败,而不是假通过。结果与当前配置绑定:改端点 / 凭据 / 自检目标 / 域名规则后旧结果会立即消失;点「测试」前会先把防抖中的设置写入,Host 测的是刚填的值。
85
97
 
86
98
  **目标与判定口径**:目标按三级取用——卡片的 `自检目标` → 该 provider 的真实上游(见下一节)→ 顶层 `testUrl`(可写多个候选,按序回退,命中任一即停;`407` 会提前终止,因为那是代理的问题)。结果按状态码分类:
87
99
 
@@ -107,7 +119,7 @@ dsh plugin --profile web add dsh-provider-proxy
107
119
 
108
120
  两者都按后缀匹配(`example.com` 覆盖 `api.example.com`),`*` 表示全部,大小写不敏感。**默认是 fail-closed**:启用了代理的路由默认走代理,只有三种显式例外才直连——「目标命中本机 / 内网地址」「`bypassHosts` 命中」「`onlyHosts` 非空且未命中」;解析不出目标主机时**仍走代理**,避免畸形 URL 把带凭据的请求悄悄直连出去。
109
121
 
110
- **指向本机或内网的请求始终直连。** 目标主机命中 `localhost`(含子域)、`127.0.0.0/8`、`::1`、`10.0.0.0/8`、`172.16.0.0/12`、`192.168.0.0/16`、`169.254.0.0/16` 时不经代理。这类目标通常是跑在同一台机器上的中转(LiteLLM、Ollama、本地 mock),正向代理根本到不了它,硬走代理只会失败,而且失败看起来像「代理坏了」。顶层 `localDirect: false` 可关掉这条(例如代理本身就是目标)。
122
+ **指向本机或内网的请求默认直连。** 目标主机命中 `localhost`(含子域)、`127.0.0.0/8`、`::1`、`10.0.0.0/8`、`172.16.0.0/12`、`192.168.0.0/16`、`169.254.0.0/16` 时不经代理。这类目标通常是跑在同一台机器上的中转(LiteLLM、Ollama、本地 mock),正向代理根本到不了它,硬走代理只会失败,而且失败看起来像「代理坏了」。顶层 `localDirect: false` 可关掉这条(例如代理本身就是目标)。
111
123
 
112
124
  带协议前缀(`https://…`)或路径(`example.com/v1`)的条目永远匹配不上——规则只认主机名。这类条目会在输入框下以错误色标出,因为后果是静默的:`onlyHosts` 里的死条目会让 fail-closed 把流量直连出去,而用户以为已经走代理。
113
125
 
@@ -142,7 +154,8 @@ dsh plugin --profile web add dsh-provider-proxy
142
154
  ## 已知限制
143
155
 
144
156
  - **SOCKS5 由 `undici` 内置的 `Socks5ProxyAgent` 实现**(RFC 1928 / RFC 1929),API 稳定性标记为 *Experimental*;`undici` 若在未来移除,需要同步调整。
145
- - **代理认证字段成对填写:用户名与密码要么都填,要么都不填。** 只填任一项都会被拒绝并给出提示。SOCKS5 侧的依据是 `Socks5ProxyAgent` 仅在两者齐备时才发起认证——只填用户名会静默广告无认证,只填密码则密码根本不会被发送(对开放代理能用,对要求认证的代理必然失败,且失败原因看起来像密码错误);HTTP/HTTPS 侧基本认证本可只发用户名(`alice:`,空密码),这里仍按成对拒绝:半填的凭据几乎总是漏填,三种传输共用一条规则比「哪种传输能承载哪种组合」更好记。代价如实写明——凭据真的使用空密码的代理无法在这里配置。不合规则的配置会被拒绝,原因列在设置页的「连接诊断」面板里(该路由的「测试」也会返回同一条),而不是被静默忽略——否则在强制认证的代理端,报错会指向代理而真正原因是设置缺项。
157
+ - **代理地址只接受 IPv4、IPv6 或 ASCII DNS 域名。** IDN 需先转 punycode;下划线、纯数字单标签(如 `127`),以及把端口写进主机字段(`127.0.0.1:7890`)都会被拒绝。粘贴完整 URL 时显式 `:80` / `:443` 会保留,未写端口仍保持「未配置」。旧配置里不合规的主机名升级后会显示「配置被拒」,需要改成合法地址。
158
+ - **代理认证字段成对填写:用户名与密码要么都填,要么都不填。** 只填任一项都会被拒绝并给出提示;用户名在配对前会 `trim()`,纯空白的用户名视为未填。SOCKS5 侧的依据是 `Socks5ProxyAgent` 仅在两者齐备时才发起认证——只填用户名会静默广告无认证,只填密码则密码根本不会被发送(对开放代理能用,对要求认证的代理必然失败,且失败原因看起来像密码错误);HTTP/HTTPS 侧基本认证本可只发用户名(`alice:`,空密码),这里仍按成对拒绝:半填的凭据几乎总是漏填,三种传输共用一条规则比「哪种传输能承载哪种组合」更好记。代价如实写明——凭据真的使用空密码的代理无法在这里配置。不合规则的配置会被拒绝,原因列在设置页的「连接诊断」面板里(该路由的「测试」也会返回同一条),而不是被静默忽略——否则在强制认证的代理端,报错会指向代理而真正原因是设置缺项。
146
159
  - **SOCKS5 不支持 `socks://` 别名与 SOCKS5 over TLS**(`proxyTls`)。
147
160
  - **`bypassHosts` 命中时由本机解析并连接目标**(DNS 不经过代理)。SOCKS5 下这一点后果最明显:命中的域名不再由代理端解析,本机 DNS 会暴露该次查询。
148
161
  - **`web_search` 可以走代理,`web_fetch` 不行。** 搜索 provider(`dsh-web-search-deepseek`)用全局 `fetch`,插件通过包裹 `ctx.web.search` 把它送进代理作用域;这条成立的前提是:工具每次调用都重新取 `ctx.web.search`,且 provider 的 `search()` 是 await-to-completion(不是惰性消费的流)。`web_fetch` 则用 `undici` 自带的 `dispatcher`(来自官方的进程级 env 策略),没有 per-provider 注入点,本插件覆盖不到——需要覆盖它请改用 `HTTP_PROXY` 之类的环境变量。
@@ -168,7 +181,7 @@ dsh plugin --profile web add dsh-provider-proxy
168
181
 
169
182
  ```sh
170
183
  npm run build # 构建 lib/index.js 与 lib/client.js
171
- npm test # 199 个用例,跑的是构建产物
184
+ npm test # 218 个用例,跑的是构建产物
172
185
  npm run typecheck # 类型检查(仅覆盖 src/)
173
186
  npm run verify # 上面三件事,按顺序
174
187
  ```