# dsh-connection-rpc-fix

[English](README.md) | 中文

一个社区**组合包（bundle）**：恢复 DeepSeek Harness Web 组合里面向插件的 `connection.rpc.handle()` API。

作者 [@Robin1987China](https://github.com/Robin1987China)

## 症状

第三方插件注册一个私有 Web RPC 通道，浏览器端每次调用都失败：

```text
cannot get property "webServer" without inject
```

插件侧看不到任何日志，浏览器请求落到静态处理器，返回 **HTTP 405**。

## 影响谁

任何通过 `connection.rpc.handle(channel, handler)` 提供浏览器可达通道的插件作者。**官方 `/api` 传输不受影响** —— 只有面向插件的那条 API 坏了。

## 根因

在 `@deepseek-ai/dsh-client-connection` 里：

```js
const inject = ['credentials'];                       // 包自身的注入只有 credentials

async function apply(ctx, config) {
  const connection = new HostConnectionService(ctx, ...);   // 服务持有这个 ctx
  ctx.inject(['webServer'], (webCtx) => {
    webCtx.effect(() => webCtx.webServer.register(route), ...);   // 官方 /api —— 能通
  });
}

// 服务内部：
const owner = this.ctx;                                // = apply 的 ctx：没有 webServer
  handle: (channel, handler) => this.register(owner, channel, handler),

register(owner, channel, handler) {
  return owner.effect(() => owner.webServer.register(route), ...);   // 抛错并被吞掉
}
```

插件行声明的是 `inject: [webRuntime]`，所以服务的 ctx 上从来没有 `webServer`。属性访问在 `owner.effect` 内部抛错、被吞掉，通道于是从未挂载。

包自己的注释写着它会在 “当 `webServer` 存在时”挂载浏览器传输 —— 而面向插件的 API 却无条件假设它存在。

## 修复

本 bundle 只改一行，把服务读取的服务交给它自己的 ctx：

```yaml
- id: connection
  inject: [webRuntime, webServer]
```

## 安装

作为组合包（官方分发形态）：

```sh
cd ~/.dsh/profiles/web
npm install dsh-connection-rpc-fix
```

然后在该 profile 的 `package.json` 里列出它：

```json
{"dsh": {"profile": {"bundles": ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app", "dsh-connection-rpc-fix"]}}}
```

或者**不装任何东西**，直接在 `~/.dsh/profiles/web/cordis.patch.yml` 里自己打两行：

```yaml
- id: connection
  inject: [webRuntime, webServer]
```

## 验证方法

一个探针插件在启动时调用 `ctx.connection.rpc.handle('/lab-probe', handler)`，随后用 HTTP 探测该通道。**已注册**的通道在连接鉴权栅栏之后，未认证请求返回 **401**；**未注册**的会落到静态处理器返回 **405**。

| | 插件日志 | `POST /lab-probe` |
|---|---|---|
| 修复前 | `THREW: cannot get property "webServer" without inject` | **405** |
| 修复后 | `returned without throwing (disposer: function)` | **401** |

两次运行都用**隔离的 `DSH_HOME`** 和独立端口；对照组 `POST /api` 两次都是 401。

补丁也验证过以**组合包**形式（列在 `dsh.profile.bundles`）交付同样有效 —— 那正是本包采用的形式。

## 边界与限制

- 修的是**组合行**，不是包本身。底层的无守卫访问依然存在，所以升级前请看下面的上游报告
- 它针对 **Web** 组合。若某部署挂了 `connection` 却没有 web server，这条 API 本来就是坏的，本包帮不上
- 它**不是**让 `rpc.handle()` 容忍缺失的 web server，而是让 web server 就位

## 上游报告

- [#6105](https://github.com/deepseek-ai/deepseek-harness/discussions/6105) —— rpc.handle() 无法注册插件 RPC 通道（浏览器 405）
- [#6179](https://github.com/deepseek-ai/deepseek-harness/discussions/6179) —— 必然抛错（cannot get property webServer without inject）
- [#6289](https://github.com/deepseek-ai/deepseek-harness/discussions/6289) —— 无法挂载第三方 Web RPC 通道
- [#6081](https://github.com/deepseek-ai/deepseek-harness/discussions/6081) —— Web bundle 应声明 modules → webServer 激活依赖

## 许可证

MIT
