feat: T2 freeze src/types.ts (shared contracts)

- All ARCHITECTURE §3 interfaces as pure types; dependency-free (no ws/node/DOM)
  so both backend and frontend can import it
- Refinements vs §3 (documented): EnvLike (not NodeJS.ProcessEnv), WebSocketLike +
  WS_OPEN (not ws.WebSocket), added Config.wsPath (invariant 8)
- ARCHITECTURE §3.1/§3.4 reconciled to match (anti-drift)
- tsc --noEmit passes

T2 of docs/PLAN.md
This commit is contained in:
Yaojia Wang
2026-06-16 07:58:52 +02:00
parent 409b208928
commit 0e10dc21c3
3 changed files with 203 additions and 8 deletions

View File

@@ -90,6 +90,7 @@ export interface Config {
readonly idleTtlMs: number; // IDLE_TTL,默认 24h
readonly scrollbackBytes: number; // ring buffer 容量,默认 2MB
readonly maxPayloadBytes: number; // 单条 WS 帧上限,默认 1MB(远超正常键盘输入,防巨帧打爆内存)
readonly wsPath: string; // WS 升级路径,默认 '/term'(L3;不变量 8:路径入 config 不硬编码)
readonly allowedOrigins: readonly string[]; // 见下方推导规则
}
@@ -106,9 +107,14 @@ export interface Config {
* isOriginAllowed 应同时比对 host 与 port。
* 否则 F4(局域网任意设备访问)会被 F9(Origin 校验)误判 401 —— 二者直接打架。
*/
export function loadConfig(env: NodeJS.ProcessEnv): Config;
export function loadConfig(env: EnvLike): Config; // EnvLike = Readonly<Record<string,string|undefined>>
```
> **T2 已冻结的实现以 [`src/types.ts`](../src/types.ts) 为准**。其中三处可移植性精化:`loadConfig` 用 `EnvLike`
> 替代 `NodeJS.ProcessEnv`(process.env 可赋值);`Session.attachedWs` 用 `WebSocketLike` 替代 `ws` 的 `WebSocket`
> (真实 ws 结构兼容,并导出 `WS_OPEN=1` 供 M5 守卫);`Config.wsPath` 新增。原因:types.ts 同时被前后端 import,
> 必须无 `ws`/`NodeJS`/DOM 外部类型依赖。
### 3.2 `protocol.ts`(纯函数,先用 TDD 实现)
消息形状即 TECH_DOC §4用可辨识联合(discriminated union)表达:
@@ -178,8 +184,9 @@ export interface Session {
readonly meta: SessionMeta;
/** 输出环形缓冲(2MB),重连回放用。淘汰语义见下方 RingBuffer。 */
readonly buffer: RingBuffer;
/** 当前附着的 ws,null = 已 detach 但 PTY 仍活(vibe coding 核心)。 */
attachedWs: WebSocket | null;
/** 当前附着的 ws,null = 已 detach 但 PTY 仍活(vibe coding 核心)。
* 类型为 WebSocketLike(types.ts;真实 ws.WebSocket 结构兼容)。 */
attachedWs: WebSocketLike | null;
detachedAt: number | null; // detach 时刻
/** 最近一次 pty.onData 的时间戳。孤儿回收用它近似"是否仍在跑前台作业"(M3)。 */
lastOutputAt: number;