@mzzsfy/dsh-tunnel 0.1.3 → 0.1.4

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +19 -2
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.3",
4
+ "version": "0.1.4",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
7
7
  "exports": {
package/src/index.js CHANGED
@@ -90,10 +90,12 @@ export const SETTINGS_SCHEMA = z.object({
90
90
 
91
91
  const normalizeWsPath = (value) => value.replace(/\/+$/, '')
92
92
 
93
- // 校验作用于归一前的原始值; '/' 为合法输入
93
+ // 校验作用于归一前的原始值; '/' 为合法输入。空串 = 根路径归一产物(F26:
94
+ // '/' 去尾斜杠得 '',恢复校验须接受,否则根 WS 隧道重启丢)
94
95
  function normalizeWsPaths(raw) {
95
96
  if (raw === undefined) return []
96
- if (!Array.isArray(raw) || raw.some((item) => typeof item !== 'string' || !WS_PATH_CHARS_RE.test(item))) return undefined
97
+ const legal = (item) => typeof item === 'string' && (item === '' || WS_PATH_CHARS_RE.test(item))
98
+ if (!Array.isArray(raw) || raw.some((item) => !legal(item))) return undefined
97
99
  return [...new Set(raw.map(normalizeWsPath))]
98
100
  }
99
101
 
@@ -201,6 +203,11 @@ function forwardHttp(req, res, record, connectTimeoutMs) {
201
203
  }
202
204
  res.writeHead(proxyRes.statusCode, headers)
203
205
  proxyRes.pipe(res)
206
+ // 上游响应中断即终止下游(F25,与 res close 反向联动成对):
207
+ // aborted 覆盖请求体阶段中断,error 覆盖响应期套接字错误;
208
+ // 两态都是"响应不再完整",挂着的下游连接应立刻回收
209
+ proxyRes.on('aborted', () => res.destroy())
210
+ proxyRes.on('error', () => res.destroy())
204
211
  })
205
212
  proxyReq.on('error', (error) => {
206
213
  if (res.headersSent) return res.destroy()
@@ -385,6 +392,11 @@ export function apply(ctx, config) {
385
392
  if (!VALID_ENTRIES.has(entry)) {
386
393
  return { ok: false, error: `entry 不合法: 须为 ${ENTRY_PATH} 或 ${ENTRY_SUBDOMAIN}` }
387
394
  }
395
+ // 自代理拒绝(F27):target 指向本监听端口时,子域名全路径透传+Host 原样
396
+ // 会把上游请求再导回自身,形成无限自代理环
397
+ if (args.targetPort === webServer.port) {
398
+ return { ok: false, error: `targetPort 不得为宿主监听端口 ${webServer.port}(自代理环)` }
399
+ }
388
400
  // 子域名全路径全协议透传, wsPaths 无意义
389
401
  const wsPaths = entry === ENTRY_SUBDOMAIN ? [] : normalizeWsPaths(args.wsPaths)
390
402
  if (wsPaths === undefined) {
@@ -521,6 +533,11 @@ export function apply(ctx, config) {
521
533
  console.warn(`${WARN_TAG}隧道表存在非法行, 已跳过: ${JSON.stringify(row)}`)
522
534
  continue
523
535
  }
536
+ // 自代理拒绝同 open(F27):恢复面不放行指向宿主监听端口的环
537
+ if (row.targetPort === webServer.port) {
538
+ console.warn(`${WARN_TAG}隧道 ${row.name} 的 targetPort 为宿主监听端口 ${webServer.port}(自代理环), 已跳过`)
539
+ continue
540
+ }
524
541
  if (tunnels.has(row.name)) {
525
542
  console.warn(`${WARN_TAG}隧道表存在重复名 ${row.name}, 仅恢复首行`)
526
543
  continue