@deepseek-ai/dsh-client-connection 0.1.6-alpha.1 → 0.1.6-alpha.2
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.i18n.yaml +2 -2
- package/README.md +4 -0
- package/README.zh.md +4 -0
- package/lib/index.js +1 -1
- package/lib/types/client/index.d.ts +2 -0
- package/lib/types/index.d.ts +14 -0
- package/package.json +7 -7
package/README.i18n.yaml
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
3
|
# after editing either side, bring the other along and re-record with:
|
|
4
4
|
# pnpm run verify-translation-pairing --write packages/client/connection/README.md
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: f72dd40db4c6414c368e039300198151cf2bd96a
|
|
6
|
+
README.zh.md: 4644dfb23074338bdd5888d20e0f0115811115d8
|
package/README.md
CHANGED
|
@@ -25,6 +25,8 @@ The package carries browser-to-Host Remote calls, exact Fetch responses, and con
|
|
|
25
25
|
<a id="use-this-package"></a>
|
|
26
26
|
## Use this package
|
|
27
27
|
|
|
28
|
+
A static desktop page can provide `__DSH_TRANSPORT__.streamBaseUrl` for the HTTP origin of its owned Host. The Gateway uses that origin for its WebSocket while HTTP transport remains independently selected. The desktop carrier owns authentication; setting the origin alone grants no access.
|
|
29
|
+
|
|
28
30
|
The browser uses HTTP POST for Remote unary calls. API Gateway owns the `/api/remote.mux` WebSocket and its logical streams; shell-owned compositions provide equivalent Remote streams through `connection.rpc.open` without opening a WebSocket. The browser plugin reads the page transport, recovery settings, and location, then delegates to `installConnection(ctx, options)`. A composition that owns its carrier may call the same installer directly; the whole-client test tier does so. Each invocation creates one Context-owned service, so several Client trees can use different carriers in one realm. The Host half always provides the carrier-neutral RPC and exact `GET`/`HEAD`/`POST` route registries. When a Web carrier is present it also owns the sole `/api` route, Fetch bridge, browser authentication, and Host/Origin checks; a shell-owned carrier dispatches the shared Fetch handler directly. Each exact route declares buffered or streaming request-body handling before the bridge reads any bytes. Typert Gateway claims generated Remote endpoints, feature packages register non-JSON responses such as Session-log downloads and raw file uploads, and unclaimed requests return 404. Loopback hostname classification remains package-internal to the browser-facing Client state. Browser raw-body transfer is provided by [`dsh-client-file-upload`](../file-upload/README.md).
|
|
29
31
|
|
|
30
32
|
-----
|
|
@@ -38,6 +40,8 @@ The cookie signing secret is the owner-scoped `client-connection/browser-session
|
|
|
38
40
|
|
|
39
41
|
Before authentication, every request still passes `src/api-request-trust.ts`. Its `Host` must be loopback or match a `trustedHosts` entry: exact on `host:port`, any port on port-less entries, both sides WHATWG-normalized. An attached `Origin` must equal that Host and `sec-fetch-site: cross-site` is refused. Malformed configured authorities fail plugin load. These checks defend DNS rebinding and cross-site browser requests; they never establish identity. A failed Host/Origin check returns 403, while a trusted but unauthenticated request returns 401. `dsh web --host 0.0.0.0` remains unsupported. Decision records: [browser request trust](../../../.agents/notes/implemented/architecture/2026-07-28-api-browser-trust-boundary.md) and [browser token authentication](../../../.agents/notes/implemented/architecture/2026-08-24-browser-token-authentication.md).
|
|
40
42
|
|
|
43
|
+
Authenticated shared HTTP requests pass through the `connection/request` waterfall before body transfer. A listener may refuse new requests or await `next()` through response completion; removing its owning fiber removes admission behavior. Desktop uses this hook to lock new API work during an approved installation without canceling already-admitted work. WebSocket stream ownership remains with API Gateway.
|
|
44
|
+
|
|
41
45
|
<a id="connection-generation"></a>
|
|
42
46
|
## Connection generation
|
|
43
47
|
|
package/README.zh.md
CHANGED
|
@@ -25,6 +25,8 @@ kind: "package-reference"
|
|
|
25
25
|
<a id="use-this-package"></a>
|
|
26
26
|
## 使用本包
|
|
27
27
|
|
|
28
|
+
静态桌面页面可以通过 `__DSH_TRANSPORT__.streamBaseUrl` 提供其所拥有 Host 的 HTTP origin。Gateway 将该 origin 用于 WebSocket,HTTP 传输仍独立选择。桌面载体负责认证;仅设置 origin 不会授予访问权限。
|
|
29
|
+
|
|
28
30
|
浏览器通过 HTTP POST 执行 Remote 一元调用;API Gateway 自己拥有 `/api/remote.mux` WebSocket 及其逻辑流。由 shell 持有的组合通过 `connection.rpc.open` 提供等价的 Remote 流,不打开 WebSocket。浏览器插件读取页面 transport、恢复设置与 location,再委托 `installConnection(ctx, options)`。持有自身载体的组合可以直接调用同一个安装函数;整机客户端测试档就是这一消费者。每次调用都会创建一个归所属 Context 的服务,因此同一 realm 中的多棵 Client 树可以使用不同载体。Host half 始终提供与载体无关的 RPC 注册表和精确 `GET`/`HEAD`/`POST` 路由注册表。存在 Web 载体时,它还持有唯一 `/api` route、Fetch bridge、浏览器认证与 Host/Origin 校验;由 shell 持有的载体则直接分派共享 Fetch handler。每条精确路由会在 bridge 读取任何字节前声明缓冲或流式请求体处理方式。Typert Gateway 认领生成的 Remote endpoint,功能包注册 Session 日志下载、原始文件上传等非 JSON 响应,未认领的请求返回 404。Loopback hostname 判定只供浏览器侧当前页面状态使用,留在包内。浏览器原始请求体传输由 [`dsh-client-file-upload`](../file-upload/README.zh.md) 提供。
|
|
29
31
|
|
|
30
32
|
-----
|
|
@@ -38,6 +40,8 @@ cookie 签名密钥是 `ctx.credentials` 中由 `client-connection/browser-sessi
|
|
|
38
40
|
|
|
39
41
|
认证之前,每个请求仍经过 `src/api-request-trust.ts`。其 `Host` 必须是 loopback,或与 `trustedHosts` 条目匹配:带端口的 `host:port` 精确匹配,不带端口的条目匹配任意端口,两侧均经 WHATWG 归一化。若附带 `Origin`,它必须等于该 Host;`sec-fetch-site: cross-site` 一律拒绝。畸形配置 authority 会让插件加载失败。这些检查防御 DNS rebinding 与跨站浏览器请求,绝不建立身份。Host/Origin 校验失败返回 403;Host 可信但未认证的请求返回 401。`dsh web --host 0.0.0.0` 仍不受支持。决策记录:[浏览器请求信任](../../../.agents/notes/implemented/architecture/2026-07-28-api-browser-trust-boundary.zh.md)与[浏览器令牌认证](../../../.agents/notes/implemented/architecture/2026-08-24-browser-token-authentication.zh.md)。
|
|
40
42
|
|
|
43
|
+
通过认证的共享 HTTP 请求在传输请求体之前经过 `connection/request` waterfall。监听器可以拒绝新请求,或等待 `next()` 直到响应完成;释放所属 fiber 会移除准入行为。Desktop 使用此扩展点,在已批准的安装期间锁住新的 API 工作,而不取消已接纳的工作。WebSocket 流仍由 API Gateway 负责。
|
|
44
|
+
|
|
41
45
|
<a id="connection-generation"></a>
|
|
42
46
|
## Connection generation
|
|
43
47
|
|
package/lib/index.js
CHANGED
|
@@ -775,7 +775,7 @@ async function apply(ctx, config) {
|
|
|
775
775
|
res.end(rejection === 401 ? "unauthorized" : "forbidden");
|
|
776
776
|
return;
|
|
777
777
|
}
|
|
778
|
-
await bridge(req, res, fetchHandler, maxRequestBodyBytes);
|
|
778
|
+
await webCtx.waterfall("connection/request", req, res, () => bridge(req, res, fetchHandler, maxRequestBodyBytes));
|
|
779
779
|
}
|
|
780
780
|
};
|
|
781
781
|
webCtx.effect(() => webCtx.webServer.register(route), "client-connection: /api route");
|
|
@@ -66,6 +66,8 @@ export interface ClientTransportHooks {
|
|
|
66
66
|
* transport can set this; served pages never carry the global at all.
|
|
67
67
|
*/
|
|
68
68
|
ownsHost?: boolean;
|
|
69
|
+
/** HTTP origin of a shell-owned Host when its WebSocket uses a different page origin. */
|
|
70
|
+
streamBaseUrl?: string;
|
|
69
71
|
}
|
|
70
72
|
/** Browser location fields used to classify loopback authority. */
|
|
71
73
|
export interface ConnectionLocation {
|
package/lib/types/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/** Host HTTP bridge for browser-client RPC. */
|
|
2
2
|
import type { Context } from '@deepseek-ai/cordis';
|
|
3
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
3
4
|
import z from '@deepseek-ai/schemastery';
|
|
4
5
|
import { type ConnectionRecoveryConfig } from './recovery-config.ts';
|
|
5
6
|
export type { ConnectionFetchMethod, ConnectionFetchHandler, ConnectionFetchRoute, ConnectionIndexRequest, ConnectionIndexResponse, ConnectionRpcEndpointMatcher, ConnectionRpcFailure, ConnectionRpcHandler, ConnectionRequestRejection, ConnectionRpcResult, ConnectionRequestBodyMode, ConnectionTrustRequest, ClientRequest, HostConnectionHandle, HostConnectionFetch, HostConnectionRpc, RpcMessage, ServerResponse, } from './rpc.ts';
|
|
@@ -9,6 +10,19 @@ export { HostConnectionService } from './rpc-host.ts';
|
|
|
9
10
|
export { API_PATH } from './api-path.ts';
|
|
10
11
|
/** Stable Cordis plugin name. */
|
|
11
12
|
export declare const name = "client-connection";
|
|
13
|
+
declare module '@deepseek-ai/cordis' {
|
|
14
|
+
interface Events {
|
|
15
|
+
/**
|
|
16
|
+
* Admit or wrap an authenticated shared API request, including body transfer.
|
|
17
|
+
* Existing requests continue when a listener refuses subsequent requests.
|
|
18
|
+
* @param request - Authenticated incoming HTTP request.
|
|
19
|
+
* @param response - Response owned until the delegated bridge settles.
|
|
20
|
+
* @param next - Delegate to the next listener or the shared API bridge.
|
|
21
|
+
* @mode waterfall
|
|
22
|
+
*/
|
|
23
|
+
'connection/request'(request: IncomingMessage, response: ServerResponse, next: () => Promise<void>): Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
12
26
|
/** Services required before providing Connection. */
|
|
13
27
|
export declare const inject: string[];
|
|
14
28
|
/** Browser authentication, request limits, and connection recovery configuration. */
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-client-connection",
|
|
3
3
|
"description": "Authenticated RPC transport and generation lifecycle",
|
|
4
|
-
"version": "0.1.6-alpha.
|
|
4
|
+
"version": "0.1.6-alpha.2",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"license": "MIT",
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"zod": "^4.4.3",
|
|
38
|
-
"@deepseek-ai/dsh-credentials": "^0.1.6-alpha.
|
|
38
|
+
"@deepseek-ai/dsh-credentials": "^0.1.6-alpha.2",
|
|
39
39
|
"@deepseek-ai/schemastery": "^3.18.2"
|
|
40
40
|
},
|
|
41
41
|
"files": [
|
|
@@ -47,11 +47,11 @@
|
|
|
47
47
|
"@deepseek-ai/cordis": "^4.0.2"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
+
"@deepseek-ai/dsh-attachment": "^0.1.6-alpha.2",
|
|
50
51
|
"@deepseek-ai/cordis": "^4.0.2",
|
|
51
|
-
"@deepseek-ai/dsh-
|
|
52
|
-
"@deepseek-ai/dsh-host-webserver": "^0.1.6-alpha.
|
|
53
|
-
"@deepseek-ai/dsh-
|
|
54
|
-
"@deepseek-ai/dsh-llm": "^0.1.6-alpha.
|
|
55
|
-
"@deepseek-ai/dsh-session": "^0.1.6-alpha.1"
|
|
52
|
+
"@deepseek-ai/dsh-brand": "^0.1.6-alpha.2",
|
|
53
|
+
"@deepseek-ai/dsh-host-webserver": "^0.1.6-alpha.2",
|
|
54
|
+
"@deepseek-ai/dsh-session": "^0.1.6-alpha.2",
|
|
55
|
+
"@deepseek-ai/dsh-llm": "^0.1.6-alpha.2"
|
|
56
56
|
}
|
|
57
57
|
}
|