deepseeker-app/DeepSeeker--packages-client-connection ↗★ 0

@deepseek-ai/dsh-client-connection

Wire consumer layer: HTTP-up/WebSocket-down client, ConnectionController dual streams with reconnect, and fixture api 供开发客户端插件的工程师使用,处理连接与重连逻辑。

パッケージ
@deepseek-ai/dsh-client-connection
互換性
未検証
Harness ピア範囲
workspace:^
Cordis ピア範囲
workspace:^
バージョン
0.1.0-rc.5
ライセンス
MIT
最終更新
2026/09/10

同名パッケージの別リポジトリ

インストール

検証済み bundle がないか、互換性チェックに失敗しています。先にリポジトリの説明を読んでください。 README 全文を読む ↗

ドキュメント

README 全文を読む ↗

@deepseek-ai/dsh-client-connection

English | 中文

Wire consumer layer: the client plugin's apply mounts ctx.connection (shared api client + current-page loopback state + observable generation-scoped hostDescription + single-consumer stream-loop starter); the export face carries the wire contract types, the AbstractApiClient abstraction, and the loop's sink/config types. Each successful readiness handshake publishes the exact host.describe value before onConnected; generation loss and explicit stop clear it, so native-capability consumers never retain a disconnected answer. The browser carrier uses HTTP POST for unary and respond operations and opens one downlink-only WebSocket each for events.mux and events.host; the in-process carrier satisfies the same two-stream abstraction. The Host half owns the single /api route and its Fetch bridge; a registered Typert interceptor claims its Remote endpoints before the API Proxy fallback. Loopback hostname classification stays package-internal: the /api Host fence and WebSocket upgrades use it directly, while other client plugins consume the derived ctx.connection.isLoopback state. The node half's /api route pins the privileged method set (host.pickDirectory, host.listDirectory, host.createDirectory, host.openPath, workspace.create, and the whole configuration plane — settings.describe/openDocument/update/replace/mutate and credentials.describe/set/unset; reads and native actions included, since describing returns the exposed configuration, opening acts on the Host desktop, and probing an arbitrary reference reports where a credential comes from — and the agent-preset authoring plane, agentPreset.read/copy/openDocument/remove, since a composition names the plugins a session runs, so reading one is reconnaissance, and copy/remove/openDocument manage the roster and drive the host desktop (authoring is copy-only, so none of them accepts composition text or a path); agentPreset.list and agentPreset.select stay out — the roster carries only ids and trust, and choosing a preset grants nothing session.create's own agentPreset did not, over a default that already carries bash) to loopback by passing the trust fence with an empty trust list — a declared trustedHosts authority reaches every other method, while these stay loopback-local until a real authentication layer exists. A paired client may still call session.create with a registered workspaceId; a caller-supplied cwd is rejected before RPC dispatch. The platform carriers and ConnectionController loop are package-internal; apply selects and drives them. The downlink boundary is documented in the WebSocket downlink carrier Agent Note.

/api browser-trust fence

The node half guards every entry under /api before bridging or upgrading (src/api-request-trust.ts). Every request — browser-marked or not — must present a valid serving authority, and attached browser markers must be same-origin. A genuine loopback request needs a loopback Host, a loopback TCP peer, and no proxy client headers; this keeps LAN clients and loopback-origin Cloudflare requests from inheriting the desktop shortcut even when an upstream rewrites Host. When remote-web-ui/authorize-http is mounted, its explicit allow or deny decision is authoritative for every non-loopback request, so a revoked pair cannot fall through to trustedHosts. With requireRemoteAuthorization: true, a non-loopback HTTP request or WebSocket upgrade is rejected whenever that event has no explicit decision. The default is false, preserving the trustedHosts fallback for legacy deployments. Without that optional authorizer, those deployments may still use explicit trustedHosts entries: exact on host:port, any port on port-less host, both compared through WHATWG normalization. When markers are present, an attached Origin must equal the Host authority, and sec-fetch-site: cross-site is refused. Malformed trustedHosts entries fail plugin load loudly. HTTP failures answer 403 before RPC dispatch; upgrade failures reject before an event stream starts. After remote-web-ui broadcasts remote-web-ui/authorization-changed, Connection rechecks every existing non-loopback event WebSocket and destroys sockets whose live authorizer now denies them; loopback sockets are untouched. The Web runtime derives LAN IP literals from an all-interfaces server config, while trustedHosts in cordis.yml and the CLI's --trusted-host flag declare named authorities. Decision record: the api browser-trust boundary Agent Note.

/api WebSocket downlinks

/api/events.mux and /api/events.host each accept a WebSocket upgrade and send only the corresponding ServerRequest text messages to the browser; the client sends no application data over these sockets. If either socket ends, the current connection generation fails and rebuilds both streams; readiness still requires both sockets to be open and the host.describe HTTP call to succeed. Host teardown terminates both sockets, aborts their sources, and waits for source cleanup before returning. Ordinary network GETs to these paths return 426 with no SSE fallback; toFetchHandler's SSE codec serves only the isomorphic in-process carrier.

Model Experience

None, as the wire consumer layer moves already-composed messages between browser and host; nothing here reaches a model request.

KV Cache effect

None; this package neither assembles nor sends a provider request.

Known Limitations and Deferred Work

  • History resumes an unattached session — opening history may create the host-side agent and add latency to the first open; there is no persistence-only read path.
  • The /api bridge buffers each request body in memory — maxRequestBodyBytes (default 160 MiB, sized for the default 100 MiB aggregate image limit after base64 expansion plus envelope headroom) is therefore also the per-request resident bound; a streaming body path would be needed to lower it without shrinking the image limits.