Pular para o conteúdo principal
L

dsh-fetch-router

leolee9086/dsh-fetch-router

Route and rewrite the harness's outbound HTTP requests by host and path, with a native right-sidebar monitor.

Instalar

dsh plugin --profile web add github:leolee9086/dsh-fetch-router

README

@leolee9086/dsh-fetch-router

host + path 路由 DSH 的出网 HTTP 请求:可注入/改写请求头、改写目标、本地应答;带一个 DSH 原生右侧栏监控面板。默认规则解决 OpenCode Zen 网关的 400 MissingSessionID(该网关要求 x-opencode-session,缺失即拒)。

安装

dsh plugin --profile web add @leolee9086/dsh-fetch-router
dsh plugin --profile web remove @leolee9086/dsh-fetch-router

装完重启 DSH 让宿主半边生效。

包自带 bundle patch(cordis.patch.yml),安装后由 dsh plugin 并入 profile layers,不需要手改 profile 的 cordis.patch.yml

依赖 @leolee9086/sac-path-router(同为 npm 包,安装时不跑构建脚本)。

配置

默认配置在包内 cordis.patch.yml;在 profile 的 cordis.patch.yml 里用同 id: fetch-router 覆盖 config 即可改规则。

    - id: fetch-router
      name: "dsh-fetch-router"
      config:
        reserved: [user-agent]          # 永不被规则覆盖的请求头
        ifAbsent: true                  # 目标头已存在则不覆盖
        allowMock: false                # 允许 respond 本地应答(伪造响应不进会话日志)
        onMissing: fail                 # 规则 require 不满足时:fail | skip
        log: { matched: true, passthrough: false, headers: false, buffer: 200 }
        panel: { enabled: true, path: '/fetch-router' }
        routes:
          - id: opencode-session-chat
            match: { host: "opencode.ai", path: "/zen/go/v1/chat/completions", methods: [POST], provider: "opencode-go*" }
            require: [session]
            headers: { x-opencode-session: "$session" }
  • matchhost(必需,支持 *.example.com)、path(radix 通配,默认 /**)、methodsprovidermodelpurpose(后三者取自当前请求的模型调用作用域)。
  • 模板:$session$provider$model$purpose$requestId;取不到值即报错(onMissing: fail)。
  • rewrite.url:把请求改到另一个目标;rewrite.path / rewrite.search 可选。
  • respond:本地应答,需 allowMock: true。伪造响应会进入模型上下文但不进会话日志,破坏 "Model-visible ⟺ logged",仅测试 profile 使用。
  • 同一 path 上多条规则按声明顺序取第一条满足条件的;未命中任何规则 ⇒ 原样透传(不构造 Request)。

面板

界面半边注册一个原生右侧栏 tab(sidebarRightTabs + sidebar.right.pane.tab),入口按钮在左侧栏底部(sidebar.footer.action,无会话时置灰)。

  • 逐请求行:时间 / host+path / 方法 / 命中规则 / 被改动的头名(值默认只以名字呈现)/ 结果(forward·mock·skipped·error)/ provider·model / 上游状态码 / 耗时。
  • 顶部:命中、透传、本地应答、错误计数;当前生效路由表;暂停记录按钮。
  • 数据面:GET {panel.path}/stats.jsonGET {panel.path}/events(SSE)、POST {panel.path}/recording。仅接受 loopback 请求。
  • 隐私:不写会话日志、不发 session 事件;默认不记录 body;authorizationcookie*token**secret* 等永不显示值。

行为与边界

  • 未命中直接调用原 fetch,不构造对象、不读 body。
  • 配置非法 ⇒ 拒绝安装,保持原 fetch
  • dispose 后先变为纯透传,再按身份还原 globalThis.fetch
  • 改写 ctx.path 的重派那趟不发网,body 只在最终转发时消费一次。
  • 不覆盖:node:http 直连的 SDK;pi-ai transport: 'websocket' 路由。

开发

pnpm install
node test/rules.test.js && node test/interceptor.test.js && node test/scope.test.js

node --test 会派生子进程,在受限沙箱里会被拒;逐文件执行等价。)

赞赏

赞赏码

联系作者:逐暝(leolee9086)· 点击链接加入群聊【工具软件爱好者折腾群-综合讨论】:https://qm.qq.com/q/RAHJuyhQQ (群号 1017854502,群主 逐暝)

许可

MIT


作者:逐暝 · QQ 群:1017854502 — https://qm.qq.com/q/RAHJuyhQQ

Plugins relacionados