dsh-proxy-client — 远程访问(反向代理)
把本机终端里的 dsh web 通过 dsh-proxy-server 反向暴露给同账号的其它端: 侧边栏底部新增「远程访问」面板,填好服务器地址后用 textwork.cn 账号登录, 设备一上线,就能在服务器上打开这台机器的完整 Harness 界面 —— 浏览器不需要能访问目标机器。
| npm 包 | @jaxzhou/dsh-proxy-client |
|---|---|
| 版本 / 许可 | v0.4.1 · MIT(v0.4.0 已废弃,请用 v0.4.1+) |
| 源码 | github.com/jaxzhou/dsh-proxy(packages/dsh-proxy-client) |
| 生产服务器 | https://dsh.textwork.cn |
| 环境要求 | Node.js ≥ 22.19;零运行时依赖(用 Node 内置 WebSocket) |
| 配置 | 自动写入 $DSH_HOME/dsh-proxy-client.json(0600),无需手工编辑 |
$ dsh --profile web # bundle 成员在启动时读取
id: jaxzhou-proxy-client)会在安装后自动插入插件行。
如果你以前在 profile 的 cordis.patch.yml 里手工加过同一行,请删掉手工行,否则会因
duplicate loader entry id 启动失败。
npm 信息
版本 / 说明 / 发布时间来自 npm registry,页面加载后会再校验一次最新版本。
npm registry 说明(英文原样): DeepSeek Harness plugin: connects this terminal's local dsh web to a dsh-proxy-server and lets the same account's other ends reach it through that server (reverse access). Signs in with the textwork.cn account (phone + SMS code, or username + password), a
数据源 plugins.json · 由 tools/sync-plugins.py 从 npm registry 同步 ·
页面加载后自动向 npm 校验最新版本
两半结构
| 半边 | 作用 |
|---|---|
宿主半lib/index.js | cordis 插件:本地配置与令牌存储、出站 WebSocket 持久连接与自动重连、把服务器开出的虚拟流桥接到 ctx.webServer.port 上的本机 dsh web、注册面板 API。启动路径上不做任何网络 I/O。 |
浏览器半lib/client.js | window.__ModuleLoader__ bundle:侧边栏底部「远程访问」入口 + 键控主面板,提供服务器地址、账号登录(手机号验证码 / 账号密码)、连接开关、设备列表与「切换到此端」。 |
配置面板
| 区块 | 内容 |
|---|---|
| 状态 | 已连接 / 连接中 / 认证失败 / 未配置,以及当前连接的细节 |
| 本机 DSH Web | 将要暴露的本机地址(自动取自 DSH 实际监听端口)与设备名 / ID |
| 服务器 | 服务器地址、设备名、自动连接、反向访问(是否共享本机启动令牌)、连接 / 断开、保存并应用;另有一行只读的「登录账号」状态(可切换账号 / 退出登录) |
| 同账号在线端 | 设备名、ID、连接时间、「本机」标记,以及「在服务器中打开 →」(新标签页打开服务器同源的设备视图,由服务器经隧道代理到对方本机的 dsh web) |
连接与登录流程
- 1填写服务器地址默认生产地址
https://dsh.textwork.cn;面板本身只有「地址 + 连接」,凭据只在弹窗里输入。 - 2点「连接」本机已有可用 token 就直接连接,不打扰;没有或已失效则弹出账号输入框。
- 3选择登录方式手机号验证码登录(可注册,含人机验证)或账号密码登录。弹窗内容随服务器能力变化。
- 4换取长效 token凭据提交给代理服务器校验,服务器返回长效 token(默认 30 天),本机只保存 token,密码不落盘。
- 5自动上线连接建立后本机出现在「同账号在线端」列表;同账号其它端即可打开这台机器的 Harness 界面。
/config 检测到地址变化时会清掉上一个服务器签发的 token,下次「连接」重新弹窗,避免拿 A 服务器的 token 去连 B 服务器。面板 API
路由与 DSH GUI 同源、默认只在回环可达;令牌始终留在宿主半,浏览器半拿不到。
| 方法与路径 | 说明 |
|---|---|
GET /dsh-proxy-client/api/status | 连接状态、脱敏配置、本机 dsh web 地址、同账号设备(带 self 标记) |
GET /dsh-proxy-client/api/auth-config | 目标服务器支持的登录方式(authMode / phoneLogin / passwordLogin / register) |
GET /dsh-proxy-client/api/captcha-session | 人机验证风险预判(转发给代理服务器 → textwork 上游) |
POST /dsh-proxy-client/api/send-code | 发送短信验证码 |
POST /dsh-proxy-client/api/login · /register | 登录 / 注册并保存 token、发起连接 |
POST /dsh-proxy-client/api/config | 保存配置并重连;地址变化时清除上一个服务器的 token |
POST /dsh-proxy-client/api/connect · /disconnect · /logout | 手动连接控制与注销 |
POST /dsh-proxy-client/api/attach | 按设备 ID 取回服务器同源的代理地址,浏览器无需能访问目标机器 |
故障隔离
本插件是可选增强:代理服务器宕机、网络不可达、地址写错,甚至本地配置不可写,都不应影响 DSH 与其它插件。
- 1不阻塞启动
apply()不做网络 I/O,首次连接用setTimeout(0)推迟到启动路径之外。 - 2全程有超时上界连接 20s(含 TCP / TLS / WS 升级)、握手 10s、
stop()3s;超时即放弃并按 1s → 30s 指数退避重试。 - 3绝不产生 unhandled rejection连接循环、重连、事件回调、节流定时器全部自带捕获,后台任务不以 rejection 收尾。
- 4配置不可写就降级读 / 写 / 解析失败一律降级为内存配置(记录
store.lastError),插件继续可用。 - 5GUI 错误边界注入的两个 slot 都包在错误边界里,本插件面板崩溃只显示「已隔离」小卡片,不会白屏 DSH。
常见问题
这个插件需要额外的服务器吗?
需要。它只是客户端半:把本机 dsh web 通过出站 WebSocket 接到 dsh-proxy-server(生产地址 https://dsh.textwork.cn)之后,同账号的其它端才能在浏览器里打开这台机器。没有连接服务器时插件安静待机,不影响 DSH 本体。
用什么账号登录?和 textwork.cn 是同一个吗?
是同一个。手机号 + 短信验证码(含京东云人机验证)或账号密码都可以;登录由代理服务器内部转调 textwork.cn 后端完成。独立部署的服务器若以 --auth local 启动,面板只显示账号密码登录。
密码会存在本机吗?
不会。弹窗里的凭据只提交给代理服务器,服务器校验后下发长效 token(默认 30 天);本机只在 $DSH_HOME/dsh-proxy-client.json(权限 0600)保存该 token,密码与短信验证码从不写入。
代理服务器挂了会影响我的 DSH 吗?
不会,这是刻意的故障隔离设计:apply() 不做任何网络 I/O,首次连接推迟到启动路径之外;连接阶段 20s 上限、握手 10s 上限,超时按指数退避重试(1s → 30s);stop() 最多等 3s;两个注入的 slot 都包在错误边界里,面板崩溃只会显示一块「已隔离」卡片。
什么是「反向访问」?
目标端 DSH 的首页需要它自己的进程启动令牌。宿主半通过 DSH Connection 服务的 ctx.connection.authenticatedUrl() 读到该令牌(受「反向访问」开关控制),随 hello 上报给服务器;服务器在设备视图地址上拼上 ticket 与 token,浏览器停在代理服务器同源,由服务器经隧道转发。
为什么不能用 v0.4.0?
v0.4.0 的浏览器半注册了改名前的旧 id dsh-proxy-client,DSH 会以 loaded without registering "@jaxzhou/dsh-proxy-client" 拒绝加载。请使用 v0.4.1 及以上。
安装后启动失败,提示 duplicate loader entry id?
该包自带 bundle 声明,安装即自动激活。若此前在 profile 的 cordis.patch.yml 里手工加过 id: jaxzhou-proxy-client 一行,会与本包插入的行重复导致启动失败;把手工行删掉(该文件恢复为 [])再重启即可。