@mzzsfy/dsh-tunnel 0.1.2 → 0.1.3

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
@@ -29,15 +29,19 @@
29
29
  - 持久化 `~/.dsh/dsh-tunnel/tunnels.json`(随 `DSH_HOME`), 重启自动恢复; 目标拒连 502, 响应头等待超时(默认 10s, 头到即解除, SSE 不受影响)504
30
30
  - REST: `/api/tunnel/tunnels`(GET/POST/DELETE `/api/tunnel/tunnels/:name`) + `/api/tunnel/status` + `/api/tunnel/ui-settings`(POST: aiTools / sidebarTab), 与 GUI/ai 同一入口
31
31
 
32
+ ## client 依赖
33
+
34
+ 看板通过 `@mzzsfy/dsh-common-tools/client` 订阅数据变更。安装时同时启用 `dsh-session-manager`,由其唯一代挂条目装载公共 client,并排在 tunnel 前物化。公共模块缺失时装载层会报告具体依赖错误;宿主 React 模块缺失时控制台报告原因并禁用面板。
35
+
32
36
  ## 验证
33
37
 
34
- - `node --test "test/*.test.mjs"`: 37 场景 + 8 api 用例 + 11 ai 开关注册面 + 11 守卫断言 + client 端 8 用例(id 守卫 + 总线生命周期;mock webServer + 真实 http/net 端到端)
38
+ - `npm test`(经 _mocks.common-tools.mjs 预载公共依赖桩): 37 场景 + 8 api 用例 + 11 ai 开关注册面 + 11 守卫断言 + client 端 8 用例(id 守卫 + 总线生命周期;mock webServer + 真实 http/net 端到端)
35
39
  - `node scripts/compat/tunnel-fullchain.mjs`: 隔离 dsh 实例全链路(真实激活/恢复/分发面七项探针)
36
40
 
37
41
  ## 设计文档
38
42
 
39
- `docs/调研-路径穿透插件.md`(「方案设计」两节为本包实施规格, 含已知限制); `docs/设计-隧道GUI.md`(GUI/设置/侧边栏注入实施规格)。
43
+ `docs/调研-路径穿透插件.md`(「方案设计」两节为本包实施规格, 含已知限制); `docs/设计-隧道GUI.md`(GUI/设置/侧边栏注入实施规格)。两份均为仓库本地维护文档,不入库,npm 安装读者不可见。
40
44
 
41
45
  ## dsh 版本兼容
42
46
 
43
- 按仓库动态窗口验证(scripts/compat/window.mjs),不预置任何固定版本槽:主测 = 渠道 dist-tag 最新 rc,完全适配口径;基线 = npm latest,不崩溃底线口径;主测与基线同版时收敛单槽。兼容面以窗口实测为准,不逐版本承诺。逐轮实测结论见 `docs/兼容性测试/逐包测试进度.md` 与本包 `兼容性测试.md`。
47
+ 按仓库动态窗口验证(scripts/compat/window.mjs),不预置任何固定版本槽:主测 = 渠道 dist-tag 最新 rc,完全适配口径;基线 = npm latest,不崩溃底线口径;主测与基线同版时收敛单槽。兼容面以窗口实测为准,不逐版本承诺。逐轮实测结论见 `docs/兼容性测试/逐包测试进度.md`(本地维护,不入库)与本包 `兼容性测试.md`。
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mzzsfy/dsh-tunnel",
3
3
  "description": "路径穿透隧道:在 dsh 宿主进程内把 /p/<name> 反向代理到本地 TCP 端口(HTTP strip 转发 + 声明式 WS upgrade + 3xx Location 单头改写),支持 <name>.* 子域名全路径透传(任意 WS 路径);GUI 看板手动管理隧道,设置页独立配置节与侧边栏注入开关;向 ai 注册 tunnel_open/tunnel_list/tunnel_close 工具且「允许 ai 使用」可开关(关闭即注销);代理逻辑全在插件进程内,不引入 nginx/caddy 等外部反代",
4
- "version": "0.1.2",
4
+ "version": "0.1.3",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
7
7
  "exports": {
package/src/client.js CHANGED
@@ -169,15 +169,14 @@ if (typeof window !== 'undefined' && window.__ModuleLoader__) {
169
169
  function factory(require) {
170
170
  let React = null
171
171
  let ReactDOMClient = null
172
- let tools = null
173
172
  try {
174
173
  React = require('react')
175
174
  ReactDOMClient = require('react-dom/client')
176
- // 公共工具库:bus 订阅是数据刷新唯一通道,缺失即整面板禁用(无轮询回退)
177
- tools = require('@mzzsfy/dsh-common-tools/client')
178
- } catch {
175
+ } catch (error) {
176
+ console.error('[dsh-tunnel] 宿主 React 模块加载失败', error)
179
177
  return noopFactory()
180
178
  }
179
+ const tools = require('@mzzsfy/dsh-common-tools/client')
181
180
  const { useState, useEffect, useRef, useCallback } = React
182
181
  const h = (type, props, ...children) => React.createElement(type, props ?? null, ...children)
183
182
 
@@ -0,0 +1,29 @@
1
+ import test from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+ import { readFileSync } from 'node:fs'
4
+ import vm from 'node:vm'
5
+
6
+ const source = readFileSync(new URL('../src/client.js', import.meta.url), 'utf8')
7
+ function materialize(missing) {
8
+ let definition
9
+ const diagnostics = []
10
+ const window = { __ModuleLoader__: { load(value) { definition = value } } }
11
+ vm.runInNewContext(source, { window, console: { error: (...args) => diagnostics.push(args) } })
12
+ const require = name => {
13
+ if (name === missing) throw new Error(`module missing: ${name}`)
14
+ return {}
15
+ }
16
+ return { definition, require, diagnostics }
17
+ }
18
+
19
+ test('Given 缺公共client When 物化隧道模块 Then 向装载层抛出具体依赖错误', () => {
20
+ const f = materialize('@mzzsfy/dsh-common-tools/client')
21
+ assert.throws(() => f.definition.factory(f.require), /module missing: @mzzsfy\/dsh-common-tools\/client/)
22
+ })
23
+ for (const missing of ['react', 'react-dom/client']) test(`Given 缺${missing} When 物化 Then 禁用并报告宿主依赖原因`, () => {
24
+ const f = materialize(missing)
25
+ const module = f.definition.factory(f.require)
26
+ assert.deepEqual(Array.from(module.inject), [])
27
+ assert.equal(f.diagnostics.length, 1)
28
+ assert.match(String(f.diagnostics[0]), new RegExp(missing))
29
+ })