dsh-mesh-access 0.0.0-stage → 1.0.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/CHANGELOG.md ADDED
@@ -0,0 +1,65 @@
1
+ # 更新日志
2
+
3
+ ## 1.0.1 — 修「一直重新连接中」
4
+
5
+ `Origin` 没有跟着 `Host` 一起改写,DSH 的 WebSocket 升级被自己的同源校验挡成 **403**,
6
+ 于是 HTTP 一切正常(页面能开、API 能通),但实时通道连不上,界面底部一直显示「重新连接中…」。这一版修掉它,并顺手把长连接的 TCP keepalive 打开。
7
+
8
+ - `rewrite()` 在改写 `Host` 的同时改写 `Origin`(`http://<upstream>`);
9
+ - upgrade 路径两个 socket 都 `setNoDelay(true)` + `setKeepAlive(true, 30000)`,让中继上的空闲长连接不容易被悄悄丢掉。
10
+
11
+ ## 1.0.0 — 改名(原名 dsh-phone-tunnel)
12
+
13
+ 插件和「手机」没关系:它做的是把组网地址上的请求转给本进程。所以改了名,顺便把定位放宽。
14
+
15
+ - **包名 / 仓库名**:`dsh-phone-tunnel` → `dsh-mesh-access`(npm 上的旧名已 `deprecate`,仍可按旧名装到最后那版 0.1.5);
16
+ - 面板文案、「不只手机」章节、npm 描述、市场条目描述都改成「组网里的任何设备」;
17
+ - API 路径 `/api/dsh-phone-tunnel/*` → `/api/dsh-mesh-access/*`;
18
+ - 挂载 id `mesh` → `mesh-access`;
19
+ - 命名空间变了,所以版本从 1.0.0 重新起(不是 0.1.6)。
20
+
21
+ 从 0.1.5 升级:先 `dsh plugin --profile web remove dsh-phone-tunnel`,再 `add dsh-mesh-access@1.0.0`,然后重启 `dsh web`。
22
+
23
+ ## 0.1.5
24
+
25
+ - **把定位从「手机」放宽到「组网里的任何设备」**:手机、平板、另一台电脑、带图形界面的 NAS(DSM / QTS / TrueNAS Scale)、电视盒子,只要能连到组网 IP 就能打开,对方设备**不需要装任何东西**;
26
+ - 面板文案跟着改:「手机地址」→「访问地址」,说明里写清「组网里的任何设备」;
27
+ - npm 描述与市场条目描述同步放宽,关键词补 `nas` / `remote-desktop`。
28
+
29
+ ## 0.1.4
30
+
31
+ - 面板的请求改成**可中止**(`AbortController`):动作请求 20 秒、状态轮询 6 秒,超时就 abort,不会再把界面吊死;
32
+ - 加了**看门狗**:按钮「处理中…」超过 22 秒会自动解除并提示,配合「刷新」按钮自愈;
33
+ - 说明一下:这两个数字是给「进程正忙」留的余量 —— DSH 正在推流生成回答时,同一个 Node 进程处理面板请求会明显变慢,看起来像卡住。
34
+
35
+ ## 0.1.3
36
+
37
+ - **修「点第二次就卡死」**:`start()` 原来会 `await server.close()`,而 `close()` 要等所有连接结束 —— DSH 的实时通道是长连接,于是永远等不到。现在同端口重复点击直接返回现状,并发的点击单飞;
38
+ - 关闭改成「先拒绝新连接 → `closeAllConnections()` → 强制销毁自管 socket → 最多等 500ms」,不再阻塞;
39
+ - 面板:反代运行时「③ 回到上面开端口」变「③ 端口已开」并禁用;动作请求加 20 秒超时兜底,不会再永远「处理中…」。
40
+
41
+ ## 0.1.2
42
+
43
+ - 面板直接给出**带 token 的完整地址**(借用 `connection` 服务的 `authenticatedUrl()`),复制到手机点开即可,不必再去终端里找 token。
44
+ - 「第一次用星空组网?」改成引导式三步按钮:注册 / 下载客户端 / 回到上面开端口。邀请链接只放在按钮的 `href` 里,不再把 URL 明文印在页面上。
45
+ - `inject` 增加 `connection`;`proxy.urlPlain` 保留不带 token 的裸地址。
46
+
47
+ ## 0.1.1 — 2026-11-07
48
+
49
+ 文档语言调整,功能与 0.1.0 完全一致。
50
+
51
+ - `README.md`、`INSTALL.md`、`CHANGELOG.md`、`docs/architecture.md` 改为**中文**(这个包主要面向中文用户);
52
+ 英文原文保留在 `README.en.md`、`INSTALL.en.md`,两个 README 开头互相跳转。
53
+ - 修掉导航行被反引号包住、在 GitHub 上渲染成代码而点不动的问题。
54
+ - 包的 `files` 白名单显式列出四个文档文件;构建产物 `*.tgz` 不再进仓库。
55
+
56
+ ## 0.1.0 — 2026-11-07
57
+
58
+ 第一个版本。已发布到 npm:`dsh-mesh-access@0.1.0`。
59
+
60
+ - **宿主半边**:组网网卡探测(`192.168.*` 上的 `StarVPN`、`utun*`、`tap*`、`tun*`、`wg*`、`gpd*`、
61
+ `ppp*`、`ipsec*`)、进程内反代并改写 `Host`、WebSocket / upgrade 转发、
62
+ `GET /api/dsh-mesh-access/status`、`POST /api/dsh-mesh-access/proxy`。
63
+ - **客户端半边**:`sidebar.panellist` + `main` 两个槽位的面板(状态、开/关端口、手机地址与复制、
64
+ 首次使用星空组网的提示),每 5 秒轮询一次。
65
+ - **没有构建步骤**:两边都是普通的 ESM / 浏览器 JS,所以发布出去的包就是源码本身。
package/INSTALL.en.md ADDED
@@ -0,0 +1,96 @@
1
+ # Install
2
+
3
+ [English](INSTALL.en.md) | [中文](INSTALL.md)
4
+
5
+ ## Requirement
6
+
7
+ - DSH `>= 0.2.1-rc.2` (`dsh --version`)
8
+ - Node `>= 22` (whatever DSH already runs on)
9
+ - An initialized `web` profile (`~/.dsh/profiles/web` exists — DSH creates it on first `dsh web`)
10
+
11
+ ## From npm (one line)
12
+
13
+ ```bash
14
+ dsh plugin --profile web add dsh-mesh-access
15
+ ```
16
+
17
+ Current: `dsh-mesh-access@0.1.3` (published 2026-11-07).
18
+
19
+ > If your machine points npm at a China mirror (`registry.npmmirror.com`), the mirror can lag
20
+ > behind or serve a partially synced record, and pnpm then fails with
21
+ > `numeric field was not a number: when getting size for package`. Add the registry explicitly:
22
+ >
23
+ > ```bash
24
+ > dsh plugin --profile web add dsh-mesh-access@0.1.3 --registry=https://registry.npmjs.org
25
+ > ```
26
+
27
+ ## From the release tarball (no npm account, any registry)
28
+
29
+ ```bash
30
+ dsh plugin --profile web add \
31
+ https://github.com/SilverKurali/dsh-mesh-access/releases/latest/download/dsh-mesh-access.tgz
32
+ ```
33
+
34
+ ## From a local checkout
35
+
36
+ ```bash
37
+ git clone https://github.com/SilverKurali/dsh-mesh-access
38
+ dsh plugin --profile web add link:"$PWD/dsh-mesh-access"
39
+ ```
40
+
41
+ `link:` installs the directory itself; pnpm prints a peer-resolution warning that is expected for
42
+ link installs and harmless here (the plugin has no peer for `@deepseek-ai/dsh` beyond the host).
43
+
44
+ ## From a git URL
45
+
46
+ ```bash
47
+ dsh plugin --profile web add git+https://github.com/SilverKurali/dsh-mesh-access.git
48
+ ```
49
+
50
+ ## Verify
51
+
52
+ ```bash
53
+ # 1. the profile now lists the plugin
54
+ grep -n 'dsh-mesh-access' ~/.dsh/profiles/web/package.json
55
+
56
+ # 2. restart the profile, then ask the host directly
57
+ curl -s http://127.0.0.1:3080/api/dsh-mesh-access/status | head -20
58
+ ```
59
+
60
+ A healthy answer looks like:
61
+
62
+ ```json
63
+ {
64
+ "ok": true,
65
+ "host": { "upstream": "127.0.0.1", "port": 3080 },
66
+ "mesh": [{ "iface": "StarVPN", "address": "192.168.188.1", "netmask": "255.255.255.0" }],
67
+ "proxy": { "running": false, "port": 3081, "url": null }
68
+ }
69
+ ```
70
+
71
+ Then open the **组网访问** panel and press *在组网地址上开端口*, or:
72
+
73
+ ```bash
74
+ curl -s -X POST -H 'content-type: application/json' \
75
+ -d '{"action":"start","port":3081}' \
76
+ http://127.0.0.1:3080/api/dsh-mesh-access/proxy
77
+ ```
78
+
79
+ ## Uninstall
80
+
81
+ ```bash
82
+ dsh plugin --profile web remove dsh-mesh-access
83
+ ```
84
+
85
+ Nothing is written outside the profile directory and `~/.dsh`; there is no service, no autostart,
86
+ no firewall rule. Stopping the proxy (or restarting the profile) closes the mesh port.
87
+
88
+ ## Troubleshooting
89
+
90
+ | Symptom | Cause and fix |
91
+ |---|---|
92
+ | `没找到组网网卡` | The mesh client is not connected, or the interface is named differently. Run `ip -br addr` / `ifconfig` and set `interfacePattern` to match, and check `addressPrefix`. |
93
+ | Panel shows the proxy running but the phone times out | Something between the phone and this host drops it — on Linux check `firewall-cmd --zone=<mesh zone> --list-ports`, on Windows the inbound rule for the port. |
94
+ | Phone gets the page but every API call fails | The page was opened on a stale token/cookie; open a fresh `?token=` URL once. |
95
+ | `listen EADDRINUSE` | Another process owns the port (a previous `dsh web` or the kit's script). Stop it, or start this proxy on a different port. |
96
+ | Port opens, phone sees `401` | Expected: no cookie yet. `?token=` once. |
package/INSTALL.md ADDED
@@ -0,0 +1,97 @@
1
+ # 安装
2
+
3
+ [中文](INSTALL.md) | [English](INSTALL.en.md)
4
+
5
+ ## 前置条件
6
+
7
+ - DSH `>= 0.2.1-rc.2`(`dsh --version`)
8
+ - Node `>= 22`(DSH 本身就在用的那个即可)
9
+ - 已经初始化过 `web` profile(`~/.dsh/profiles/web` 存在 —— 第一次 `dsh web` 时 DSH 会创建)
10
+
11
+ ## 一、从 npm 装(一条命令)
12
+
13
+ ```bash
14
+ dsh plugin --profile web add dsh-mesh-access
15
+ ```
16
+
17
+ 最新版:`dsh-mesh-access@0.1.3`(2026-11-07 发布)。
18
+
19
+ > **国内镜像的坑**:如果你的 npm 指向 `registry.npmmirror.com`,镜像可能只同步了一半元数据,
20
+ > pnpm 会报
21
+ > `numeric field was not a number: when getting size for package`。
22
+ > 这时显式给官方源:
23
+ >
24
+ > ```bash
25
+ > dsh plugin --profile web add dsh-mesh-access@0.1.3 --registry=https://registry.npmjs.org
26
+ > ```
27
+
28
+ ## 二、从 Release 的 tgz 装(不需要 npm 账号,任何镜像都行)
29
+
30
+ ```bash
31
+ dsh plugin --profile web add \
32
+ https://github.com/SilverKurali/dsh-mesh-access/releases/latest/download/dsh-mesh-access.tgz
33
+ ```
34
+
35
+ ## 三、从本地检出装(改代码时用)
36
+
37
+ ```bash
38
+ git clone https://github.com/SilverKurali/dsh-mesh-access
39
+ dsh plugin --profile web add link:"$PWD/dsh-mesh-access"
40
+ ```
41
+
42
+ `link:` 装的是目录本身。pnpm 会打印一条 peer 依赖解析的警告,`link:` 装法必然出现,
43
+ 这里无害(本插件对 `@deepseek-ai/dsh` 没有运行时依赖,只是声明了 peer)。
44
+
45
+ ## 四、从 git 地址装
46
+
47
+ ```bash
48
+ dsh plugin --profile web add git+https://github.com/SilverKurali/dsh-mesh-access.git
49
+ ```
50
+
51
+ ## 验证
52
+
53
+ ```bash
54
+ # 1. profile 里已经有这个插件
55
+ grep -n 'dsh-mesh-access' ~/.dsh/profiles/web/package.json
56
+
57
+ # 2. 重启 profile,然后直接问宿主
58
+ curl -s http://127.0.0.1:3080/api/dsh-mesh-access/status | head -20
59
+ ```
60
+
61
+ 正常的样子:
62
+
63
+ ```json
64
+ {
65
+ "ok": true,
66
+ "host": { "upstream": "127.0.0.1", "port": 3080 },
67
+ "mesh": [{ "iface": "StarVPN", "address": "192.168.188.1", "netmask": "255.255.255.0" }],
68
+ "proxy": { "running": false, "port": 3081, "url": null }
69
+ }
70
+ ```
71
+
72
+ 然后打开**「组网访问」**面板点「在组网地址上开端口」,或者:
73
+
74
+ ```bash
75
+ curl -s -X POST -H 'content-type: application/json' \
76
+ -d '{"action":"start","port":3081}' \
77
+ http://127.0.0.1:3080/api/dsh-mesh-access/proxy
78
+ ```
79
+
80
+ ## 卸载
81
+
82
+ ```bash
83
+ dsh plugin --profile web remove dsh-mesh-access
84
+ ```
85
+
86
+ 除了 profile 目录和 `~/.dsh` 之外什么都没写:没有系统服务、没有开机自启、没有防火墙规则。
87
+ 关掉反代(或重启 profile)组网端口就关了。
88
+
89
+ ## 故障排查
90
+
91
+ | 现象 | 原因与处理 |
92
+ |---|---|
93
+ | 面板显示「没找到组网网卡」 | 组网客户端没连上,或者网卡名字不在默认正则里。用 `ip -br addr` 或 `ifconfig` 看真实名字,改配置里的 `interfacePattern`,并检查 `addressPrefix`。 |
94
+ | 面板说反代在跑,但手机超时 | 手机到这台机器之间被拦了。Linux 上查 `firewall-cmd --zone=<组网域> --list-ports`,Windows 上查该端口的入站规则。 |
95
+ | 手机能打开页面,但每个接口都失败 | 页面用的是过期 token/cookie。重新点一次带 `?token=` 的地址。 |
96
+ | `listen EADDRINUSE` | 端口被别的进程占了(上一次的 `dsh web`,或者 kit 脚本起的实例)。先停掉它,或换个端口起反代。 |
97
+ | 端口开了,手机看到 `401` | 正常:还没有 cookie。用带 `?token=` 的地址访问一次。 |
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 SilverKurali
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.en.md ADDED
@@ -0,0 +1,115 @@
1
+ # dsh-mesh-access
2
+
3
+ Expose the **running** DeepSeek Harness web UI on a mesh/VPN interface — from inside the server,
4
+ without a second instance, without SSH, without touching the router.
5
+
6
+ [English](#what-it-does) | [中文](README.md)
7
+
8
+ ![The “组网访问” (mesh access) panel in the sidebar](assets/screenshot-1.png)
9
+
10
+ ## What it does
11
+
12
+ `dsh web --host` binds exactly one concrete interface address, and it rejects wildcards. So a
13
+ server that serves `127.0.0.1:3080` is invisible to your mesh, and a TAP (`StarVPN`) or `utun`
14
+ interface created *after* boot is not where it listens.
15
+
16
+ This plugin adds a mesh port **inside the running process**:
17
+
18
+ ```
19
+ any device ──▶ 192.168.188.1:3081 ──▶ (plugin proxy) ──▶ 127.0.0.1:3080 (the same dsh you are using)
20
+ ```
21
+
22
+ One instance. One session list. No `task-board ledger is already owned by …` warning, no
23
+ half-synced state between two servers.
24
+
25
+ ## Install
26
+
27
+ ```bash
28
+ dsh plugin --profile web add dsh-mesh-access
29
+ ```
30
+
31
+ No npm / behind a China mirror? Use the release tarball:
32
+
33
+ ```bash
34
+ dsh plugin --profile web add \
35
+ https://github.com/SilverKurali/dsh-mesh-access/releases/latest/download/dsh-mesh-access.tgz
36
+ ```
37
+
38
+ From a checkout: `dsh plugin --profile web add link:/absolute/path/to/dsh-mesh-access`.
39
+ Full matrix (npm / tarball / checkout / git URL), verification and troubleshooting: [INSTALL.en.md](INSTALL.en.md).
40
+
41
+ Restart the profile. A **组网访问 / Mesh access** entry appears in the left rail:
42
+
43
+ | Block | What it shows |
44
+ |---|---|
45
+ | 当前状态 | proxy state, DSH's own listen port, how many mesh interfaces were found |
46
+ | 动作 | open the mesh port / close it / refresh |
47
+ | 手机地址 | the URL to open on the phone, with a copy button |
48
+ | 第一次用星空组网? | the referral sign-up link and the member-account rule |
49
+
50
+ ## HTTP surface
51
+
52
+ The panel is a view over two routes kept deliberately small:
53
+
54
+ ```
55
+ GET /api/dsh-mesh-access/status → { host:{upstream,port}, interfaces[], mesh[], proxy{...}, referral }
56
+ POST /api/dsh-mesh-access/proxy → {action:'start'|'stop', port?}
57
+ ```
58
+
59
+ `curl -s localhost:3090/api/dsh-mesh-access/status` is enough to debug without a browser.
60
+
61
+ ## Configuration
62
+
63
+ Optional, written in the profile's patch layer; every key has a default:
64
+
65
+ ```yaml
66
+ - id: mesh
67
+ name: dsh-mesh-access
68
+ config:
69
+ interfacePattern: '^(StarVPN|utun\d+|tap\d+|tun\d+|wg\d+|gpd\d+|ppp\d+|ipsec\d+)$'
70
+ addressPrefix: '192.168.'
71
+ proxyPort: 3081
72
+ upstream: 127.0.0.1
73
+ ```
74
+
75
+ `addressPrefix` exists so a public address on a `tun*` interface is never mistaken for a mesh
76
+ address.
77
+
78
+ ## Why the cookie survives
79
+
80
+ A request with `?token=` answers `303` and sets `dsh-auth-*` (`HttpOnly`, `SameSite=Strict`,
81
+ `Max-Age=2592000`). The cookie payload embeds the **authority it was issued for**, signed with a
82
+ secret kept in a persistent credential record — not a per-process random — so it outlives a
83
+ restart. The proxy rewrites `Host` to the upstream authority on every request, which keeps the
84
+ baked-in authority equal to what the server expects, which is why the same cookie keeps working
85
+ through the mesh port.
86
+
87
+ Corollary: change the mesh IP or the port and you must open a fresh token URL once.
88
+
89
+ ## Limitations
90
+
91
+ - It cannot move *its own* server's listener; a plugin runs inside a process that is already
92
+ listening. The mesh port is a proxy, not a second bind of the primary server.
93
+ - Only IPv4 mesh addresses are considered.
94
+ - Still requires the phone to reach the mesh address — the tunnel's own quality applies. On
95
+ StarVPN's relay path expect ~0.4 MB/s and occasional multi-second RTT spikes, which can stall a
96
+ long streaming answer; reload resumes it.
97
+
98
+ ## Not just phones
99
+
100
+ The name says phone, the mechanism says otherwise: the plugin forwards requests that arrive on a
101
+ mesh address to the port this process already serves. Anything that can open a web page on the
102
+ mesh works — a phone or tablet, another Windows/macOS/Linux laptop, a NAS with a GUI
103
+ (Synology DSM, QNAP QTS, TrueNAS Scale), even a TV stick's browser.
104
+
105
+ Requirements are only: same mesh, a route to the mesh IP, and a browser. **Nothing** has to be
106
+ installed on the other device, and no SSH is involved.
107
+
108
+ ## Companion
109
+
110
+ The shell-script edition (Linux/macOS/Windows launchers that start a *second* dsh instance bound
111
+ to the mesh IP, with firewall rules and QR codes) is
112
+ [dsh-mesh-kit](https://github.com/SilverKurali/dsh-mesh-kit). Use this plugin when you want one
113
+ instance; use that kit when DSH is not running yet, or on a machine without a Node plugin install.
114
+
115
+ MIT.
package/README.md CHANGED
@@ -1,3 +1,132 @@
1
- # Temporary Holding Version
1
+ # dsh-mesh-access
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ 把**正在运行**的 DeepSeek Harness 网页界面挂到组网网卡上 —— 在服务进程内部完成,
4
+ 不需要第二个实例,不需要 SSH,也不用碰路由器。
5
+
6
+ [中文](#它做什么) | [English](README.en.md)
7
+
8
+ ![侧边栏里的「组网访问」面板](assets/screenshot-1.png)
9
+
10
+ ## 它做什么
11
+
12
+ `dsh web --host` 只接受**一个具体的网卡地址**,并且拒绝通配。所以只监听 `127.0.0.1:3080` 的实例,
13
+ 组网里的手机、笔记本、另一台电脑、带图形界面的 NAS 都看不见;而开机之后才出现的 TAP(星空组网的 `StarVPN`)或 `utun` 网卡,也不在它启动时的那一份地址表里。
14
+
15
+ 这个插件在**已经在跑的那个进程内部**多开一个组网端口:
16
+
17
+ ```
18
+ 任何设备 ──▶ 192.168.188.1:3081 ──▶(插件反代)──▶ 127.0.0.1:3080(你正在用的这个 dsh)
19
+ ```
20
+
21
+ 一个实例、一份会话列表:不会出现 `task-board ledger is already owned by …`,也不会出现两台服务状态不同步。
22
+
23
+ ## 安装
24
+
25
+ ```bash
26
+ dsh plugin --profile web add dsh-mesh-access
27
+ ```
28
+
29
+ 不方便用 npm,或者你的 npm 指向国内镜像?用 Release 里的 tgz:
30
+
31
+ ```bash
32
+ dsh plugin --profile web add \
33
+ https://github.com/SilverKurali/dsh-mesh-access/releases/latest/download/dsh-mesh-access.tgz
34
+ ```
35
+
36
+ 从本地目录装(改代码的人用这个):
37
+
38
+ ```bash
39
+ dsh plugin --profile web add link:/绝对路径/dsh-mesh-access
40
+ ```
41
+
42
+ 完整的四种装法、验证步骤、卸载与故障表见 [INSTALL.md](INSTALL.md)。
43
+
44
+ 装完重启 profile,左侧导航会多出**「组网访问」**:
45
+
46
+ | 功能块 | 内容 |
47
+ |---|---|
48
+ | 当前状态 | 反代是否在跑、DSH 自己的监听端口、找到几张组网网卡 |
49
+ | 动作 | 在组网地址上开端口 / 关闭 / 刷新 |
50
+ | 访问地址 | 给组网内任何设备打开的地址(带 token,可直接复制) |
51
+ | 第一次用星空组网? | 邀请注册链接 + 成员账号规则 |
52
+
53
+ ## HTTP 接口
54
+
55
+ 面板只是两个接口的外壳,故意做得极小:
56
+
57
+ ```
58
+ GET /api/dsh-mesh-access/status → { ok, host:{upstream,port}, interfaces[], mesh[], proxy{...}, referral }
59
+ POST /api/dsh-mesh-access/proxy → { action:'start' | 'stop', port? }
60
+ ```
61
+
62
+ 不开浏览器也能排查:
63
+
64
+ ```bash
65
+ curl -s http://127.0.0.1:3080/api/dsh-mesh-access/status
66
+ ```
67
+
68
+ ## 配置(可选)
69
+
70
+ 写在 profile 的 patch 层里,每一项都有默认值:
71
+
72
+ ```yaml
73
+ - id: mesh
74
+ name: dsh-mesh-access
75
+ config:
76
+ interfacePattern: '^(StarVPN|utun\d+|tap\d+|tun\d+|wg\d+|gpd\d+|ppp\d+|ipsec\d+)$'
77
+ addressPrefix: '192.168.'
78
+ proxyPort: 3081
79
+ upstream: 127.0.0.1
80
+ ```
81
+
82
+ `addressPrefix` 的作用是别把 `tun*` 上的公网地址当成组网地址。
83
+
84
+ ## 为什么 cookie 能一直用
85
+
86
+ 带 `?token=` 的请求返回 `303` 并种下 `dsh-auth-*`(`HttpOnly`、`SameSite=Strict`、`Max-Age=2592000`,
87
+ 即 30 天)。cookie 载荷里写死了**签发时的 authority**:
88
+
89
+ ```json
90
+ {"version":1,"authority":"192.168.188.1:3081","issuedAt":…,"expiresAt":…}
91
+ ```
92
+
93
+ 签名密钥存在**持久的凭据记录**里(不是每进程随机),所以重启也在。反代每次请求都把 `Host`
94
+ 改写成上游 authority,于是 cookie 里的 authority 与服务端期望的一致 —— 这就是换个端口访问还能继续用
95
+ 同一份 cookie 的原因。
96
+
97
+ 反过来也成立:**换了组网 IP 或端口,就得重新点一次 token 链接。**
98
+
99
+ ## 限制
100
+
101
+ - 插件动不了**自己进程**的监听地址。组网端口是反代,不是把主服务再绑一次。
102
+ - 只考虑 IPv4 组网地址。
103
+ - 仍然依赖隧道本身的质量。星空组网走中继时实测单向约 0.4 MB/s,`[SN-RTT]` 会抖到几秒,
104
+ 长回答可能中途停住,刷新一下能接回来。
105
+ - 同一份 `~/.dsh` 只允许一个实例持有 task-board 锁;这是刻意的,本插件就是为避开它而存在。
106
+
107
+ ## 不只手机
108
+
109
+ 名字叫 phone,但插件本身跟“手机”没有关系 —— 它做的是**把组网地址上的请求转给本进程**。
110
+ 组网里任何能打开网页的设备都能用:
111
+
112
+ | 设备 | 用法 |
113
+ |---|---|
114
+ | 手机 / 平板 | 浏览器打开那条带 token 的地址,可加到桌面当 App |
115
+ | 另一台电脑(Win / macOS / Linux) | 同一个地址,直接开;不用装 DSH,也不用装这个插件 |
116
+ | 带图形界面的 NAS(群晖 DSM、威联通 QTS、TrueNAS Scale 等) | NAS 上的浏览器打开即可 |
117
+ | 电视盒子 / 平板上的浏览器 | 同理,只要能连到 `192.168.188.1` |
118
+
119
+ 条件是三条:它在**同一个星空组网**里、能路由到组网 IP、浏览器能发 HTTP。
120
+ **不需要**在对方设备上装任何东西,也不需要 SSH。
121
+
122
+ ## 配套
123
+
124
+ 命令行版(在 DSH 还没启动、或者机器上没有 Node 插件环境时使用:
125
+ 起**第二个**实例绑到组网 IP,附带防火墙规则与二维码):
126
+ [dsh-mesh-kit](https://github.com/SilverKurali/dsh-mesh-kit),支持 Linux / macOS / Windows。
127
+
128
+ 设计取舍与实测数据见 [docs/architecture.md](docs/architecture.md)。
129
+
130
+ ## 许可
131
+
132
+ MIT。
Binary file
Binary file
@@ -0,0 +1,8 @@
1
+ # dsh-mesh-access — bundle patch
2
+ #
3
+ # Mounts the mesh-access plugin into the web profile. Install with:
4
+ # dsh plugin --profile web add dsh-mesh-access
5
+ # dsh plugin --profile web add link:/absolute/path/to/dsh-mesh-access # local dev
6
+ - insert:
7
+ - id: mesh-access
8
+ name: dsh-mesh-access
@@ -0,0 +1,63 @@
1
+ # 发布清单
2
+
3
+ 每改一次代码,下面四块**必须一起动**,否则就会出现「npm 上是新版、Release 还是旧版、文档写着上上个版本」这种漂移。
4
+
5
+ ## 1. 版本号
6
+
7
+ - `package.json` 的 `version`
8
+ - `CHANGELOG.md` 顶部加一节
9
+ - `INSTALL.md` / `INSTALL.en.md` 里出现的 `dsh-mesh-access@x.y.z` 命令
10
+ - `README.md` / `README.en.md` 里若有版本号(能不带就不带,用 `dsh-mesh-access` 拉 latest)
11
+
12
+ ## 2. npm
13
+
14
+ ```bash
15
+ npm publish --registry=https://registry.npmjs.org
16
+ ```
17
+
18
+ ⚠️ `+ dsh-mesh-access@x.y.z` 只代表**元数据**提交成功,tarball 可能还要几分钟才可下载。必须探到 200 才算发完:
19
+
20
+ ```bash
21
+ curl -sI https://registry.npmjs.org/dsh-mesh-access/-/dsh-mesh-access-<版本>.tgz | head -1 # 期望 200
22
+ ```
23
+
24
+ 再看一眼 dist-tags 与 shasum 对不对:
25
+
26
+ ```bash
27
+ curl -s https://registry.npmjs.org/dsh-mesh-access | python3 -c "import json,sys;d=json.load(sys.stdin);v=d['versions'][d['dist-tags']['latest']];print(d['dist-tags']['latest'], v['dist']['shasum'])"
28
+ ```
29
+
30
+ 2026-11-07 那次实测:404 持续了约 6 分钟才变 200。这期间 `npm install` 会报 `npm error 404`,看着像发布失败。
31
+
32
+ ## 3. GitHub Release
33
+
34
+ ```bash
35
+ npm pack --registry=https://registry.npmjs.org
36
+ mv dsh-mesh-access-<版本>.tgz dsh-mesh-access.tgz # 附件名不带版本号
37
+ git -c tag.gpgSign=false tag -a v<版本> -m "<摘要>"
38
+ git -c http.version=HTTP/1.1 push origin refs/tags/v<版本>
39
+ gh release create v<版本> dsh-mesh-access.tgz --title "v<版本> — <摘要>" --notes-file /tmp/rel-notes.md
40
+ ```
41
+
42
+ 附件名**必须不带版本号**,因为文档里用的是稳定地址
43
+ `https://github.com/SilverKurali/dsh-mesh-access/releases/latest/download/dsh-mesh-access.tgz`。
44
+ 发完验一次:
45
+
46
+ ```bash
47
+ curl -sIL .../releases/latest/download/dsh-mesh-access.tgz | grep -i '^HTTP'
48
+ tar -xzOf dsh-mesh-access.tgz package/package.json | grep version
49
+ ```
50
+
51
+ ## 4. 装一次(别信代码,信安装)
52
+
53
+ ```bash
54
+ rm -rf ~/.dsh/profiles/reltest && cp -a ~/.dsh/profiles/headless ~/.dsh/profiles/reltest
55
+ dsh plugin --profile reltest add dsh-mesh-access@<版本> --registry=https://registry.npmjs.org
56
+ # 起临时实例 → GET /api/dsh-mesh-access/status → POST proxy start → curl 期望 401
57
+ rm -rf ~/.dsh/profiles/reltest
58
+ ```
59
+
60
+ ## 5. 市场条目
61
+
62
+ `store/dsh-mesh-access.yml` 只在**分类、描述、图标、tarball 地址**变化时才需要改;`npm:` 键由 registry 自动采集,**不要手写**。
63
+ 提交给 `awesome-dsh-plugin` 的 PR 由仓库所有者本人开,AI 只备料。