@dev-anywhere/relay 0.9.14 → 0.9.16

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server.ts","../../../packages/shared/src/schemas/id.ts","../../../packages/shared/src/schemas/envelope.ts","../../../packages/shared/src/constants/envelope.ts","../../../packages/shared/src/schemas/chat.ts","../../../packages/shared/src/schemas/tool.ts","../../../packages/shared/src/schemas/session.ts","../../../packages/shared/src/constants/enums.ts","../../../packages/shared/src/constants/pty.ts","../../../packages/shared/src/schemas/system.ts","../../../packages/shared/src/schemas/voice.ts","../../../packages/shared/src/schemas/preview-scope.ts","../../../packages/shared/src/schemas/proxy-upgrade-bootstrap.ts","../../../packages/shared/src/schemas/web-preview.ts","../../../packages/shared/src/schemas/device-preview.ts","../../../packages/shared/src/schemas/voice-stream.ts","../../../packages/shared/src/builders/index.ts","../../../packages/shared/src/schemas/relay-control.ts","../../../packages/shared/src/constants/relay-errors.ts","../../../packages/shared/src/constants/control-errors.ts","../../../packages/shared/src/constants/session-create.ts","../../../packages/shared/src/constants/relay-close-codes.ts","../../../packages/shared/src/constants/wire-limits.ts","../../../packages/shared/src/binary-frame.ts","../../../packages/shared/src/device-preview-frame.ts","../../../packages/shared/src/voice-audio-codec.ts","../../../packages/shared/src/state-machine.ts","../src/registry.ts","../src/health.ts","../src/version.ts","../src/handlers/proxy.ts","../src/router.ts","../src/latency-probes.ts","../src/preview-route-registry.ts","../src/web-preview-route-registry.ts","../src/forwarded-control.ts","../src/proxy-upgrade-bootstrap.ts","../src/handlers/client.ts","../src/voice/bailian-asr.ts","../src/voice/bailian-endpoints.ts","../src/voice/bailian-tts.ts","../src/voice/pcm-resample.ts","../src/voice/config-test.ts","../src/voice/client-controls.ts","../src/device-preview-route-registry.ts","../src/client-registration-admission.ts","../src/heartbeat.ts","../src/chaos.ts","../src/voice/config-store.ts","../src/voice/asr-ws.ts","../src/voice/tts-ws.ts","../src/voice/capabilities.ts","../src/voice/bailian-provider.ts","../src/voice/provider.ts","../src/remote-file-bridge.ts","../src/web-app.ts","../src/pty-snapshot-route-registry.ts","../src/session-history-route-registry.ts","../src/device-preview-bridge.ts"],"sourcesContent":["import express from \"express\";\nimport { existsSync } from \"node:fs\";\nimport { createServer, type IncomingMessage, type Server } from \"node:http\";\nimport { homedir } from \"node:os\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { WebSocketServer } from \"ws\";\nimport { DEVICE_PREVIEW_FRAME_MAX_BYTES } from \"@dev-anywhere/shared\";\nimport type { Logger } from \"@dev-anywhere/shared/logger\";\nimport { RelayRegistry } from \"./registry.js\";\nimport { healthRouter } from \"./health.js\";\nimport { handleProxyConnection } from \"./handlers/proxy.js\";\nimport { handleClientConnection } from \"./handlers/client.js\";\nimport { setupHeartbeat } from \"./heartbeat.js\";\nimport { createRelayChaos, type RelayChaosOptions } from \"./chaos.js\";\nimport { createVoiceConfigStore } from \"./voice/config-store.js\";\nimport { handleVoiceAsrConnection, type VoiceAsrClientFactory } from \"./voice/asr-ws.js\";\nimport { handleVoiceTtsConnection, type VoiceTtsClientFactory } from \"./voice/tts-ws.js\";\nimport { createBailianVoiceProvider } from \"./voice/bailian-provider.js\";\nimport type { VoiceCapabilitiesProvider } from \"./voice/capabilities.js\";\nimport type { VoiceConfigTester } from \"./voice/config-test.js\";\nimport { createVoiceProviderRegistry, type VoiceProviderRegistry } from \"./voice/provider.js\";\nimport { RemoteFileBridge } from \"./remote-file-bridge.js\";\nimport { mountWebApp } from \"./web-app.js\";\nimport { PtySnapshotRouteRegistry } from \"./pty-snapshot-route-registry.js\";\nimport { SessionHistoryRouteRegistry } from \"./session-history-route-registry.js\";\nimport { WebPreviewRouteRegistry } from \"./web-preview-route-registry.js\";\nimport { DevicePreviewBridge } from \"./device-preview-bridge.js\";\n\nexport interface RelayServerOptions {\n port?: number;\n heartbeatInterval?: number;\n // Maximum time a raw /proxy WebSocket may occupy resources before completing registration.\n // Primarily configurable for embedding and deterministic integration tests.\n proxyAdmissionTimeoutMs?: number;\n // Maximum time a raw /client WebSocket may occupy resources before completing registration.\n // Primarily configurable for embedding and deterministic integration tests.\n clientAdmissionTimeoutMs?: number;\n logger: Logger;\n dataDir?: string;\n // proxy 注册预共享 token; 不传 / 空串则关闭鉴权 (开发默认)\n proxyToken?: string;\n // client 连接预共享 token; 不传 / 空串则关闭鉴权 (开发默认)\n clientToken?: string;\n // ws upgrade 时校验的 Origin 列表 (匹配 request.headers.origin)。空数组 / undefined 不\n // 校验, 向后兼容现有部署 (本地 dev 跨端口 / Capacitor 等)。设置后只放白名单, 阻挡\n // CSWSH——攻击者站点诱导用户浏览器直接发 ws upgrade 到 relay 时, 没有合法 Origin。\n allowedOrigins?: readonly string[];\n chaos?: RelayChaosOptions;\n fontAssetDir?: string;\n webAssetDir?: string | false;\n voiceDefaults?: {\n region?: \"cn\" | \"intl\";\n asrModel?: string;\n ttsModel?: string;\n ttsVoice?: string;\n };\n voiceAsrClientFactory?: VoiceAsrClientFactory;\n voiceTtsClientFactory?: VoiceTtsClientFactory;\n voiceCapabilitiesProvider?: VoiceCapabilitiesProvider;\n voiceConfigTester?: VoiceConfigTester;\n voiceProviderRegistry?: VoiceProviderRegistry;\n}\n\nexport interface RelayServer {\n httpServer: Server;\n registry: RelayRegistry;\n close: () => Promise<void>;\n}\n\nconst MODULE_DIR = dirname(fileURLToPath(import.meta.url));\nconst PACKAGED_FONTS_DIR = resolve(MODULE_DIR, \"../assets/fonts\");\nconst PACKAGED_WEB_DIR = resolve(MODULE_DIR, \"../assets/web\");\nconst DATA_CHANNEL_MAX_PAYLOAD_BYTES = 10 * 1024 * 1024;\nconst DATA_CHANNEL_COMPRESSION = {\n clientNoContextTakeover: true,\n serverNoContextTakeover: true,\n threshold: 32 * 1024,\n concurrencyLimit: 4,\n zlibDeflateOptions: {\n level: 3,\n memLevel: 7,\n },\n} as const;\n\nfunction firstHeaderValue(value: string | string[] | undefined): string | undefined {\n if (Array.isArray(value)) return value[0];\n return value;\n}\n\nfunction requestRemoteAddress(request: IncomingMessage): string | undefined {\n const forwardedFor = firstHeaderValue(request.headers[\"x-forwarded-for\"]);\n const firstForwarded = forwardedFor?.split(\",\")[0]?.trim();\n return firstForwarded || request.socket.remoteAddress;\n}\n\n// 创建中转服务器,Express HTTP + ws WebSocket 双端点\nexport function createRelayServer(options: RelayServerOptions): RelayServer {\n const { heartbeatInterval = 30000, logger, dataDir, proxyToken, clientToken, chaos } = options;\n const proxyTokenRequired = typeof proxyToken === \"string\" && proxyToken.length > 0;\n const clientTokenRequired = typeof clientToken === \"string\" && clientToken.length > 0;\n const allowedOriginsSet =\n options.allowedOrigins && options.allowedOrigins.length > 0\n ? new Set(options.allowedOrigins)\n : null;\n const checkOrigin = (origin: string | undefined): boolean => {\n if (!allowedOriginsSet) return true;\n return typeof origin === \"string\" && allowedOriginsSet.has(origin);\n };\n if (!proxyTokenRequired) {\n logger.warn(\n \"proxy auth token not set, /proxy endpoint is open — ok for dev, not for public relay\",\n );\n }\n if (!clientTokenRequired) {\n logger.warn(\n \"client auth token not set, /client endpoint is open — ok for dev, not for public relay\",\n );\n }\n\n const registry = new RelayRegistry();\n const ptySnapshotRoutes = new PtySnapshotRouteRegistry();\n const sessionHistoryRoutes = new SessionHistoryRouteRegistry();\n const webPreviewRoutes = new WebPreviewRouteRegistry();\n const remoteFileBridge = new RemoteFileBridge({ registry, logger });\n const voiceConfigStore = createVoiceConfigStore({\n dataDir,\n defaults: options.voiceDefaults,\n });\n const voiceProviders =\n options.voiceProviderRegistry ??\n createVoiceProviderRegistry([\n createBailianVoiceProvider({\n asrClientFactory: options.voiceAsrClientFactory,\n ttsClientFactory: options.voiceTtsClientFactory,\n capabilitiesProvider: options.voiceCapabilitiesProvider,\n configTester: options.voiceConfigTester,\n }),\n ]);\n const relayChaos = chaos?.enabled ? createRelayChaos(chaos, logger) : undefined;\n const devicePreviewBridge = new DevicePreviewBridge({\n registry,\n logger,\n chaos: relayChaos,\n clientTokenRequired,\n validateClientToken: (token) => token === clientToken,\n });\n if (chaos?.enabled) {\n logger.warn(\n {\n delayMs: chaos.delayMs,\n duplicate: chaos.duplicate,\n reorder: chaos.reorder,\n types: chaos.types ? [...chaos.types] : \"all\",\n },\n \"Relay chaos mode enabled\",\n );\n }\n const app = express();\n app.disable(\"x-powered-by\");\n\n // 字体优先读持久化目录;Docker 镜像再回退到随包内置字体,避免空 volume 让 Web 字体 404。\n const fontsDir = dataDir ? `${dataDir}/fonts` : `${homedir()}/.dev-anywhere/relay-data/fonts`;\n const fontAssetDir = options.fontAssetDir ?? PACKAGED_FONTS_DIR;\n app.use(\n \"/fonts\",\n (req, res, next) => {\n res.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n next();\n },\n express.static(fontsDir, {\n maxAge: \"30d\",\n immutable: true,\n }),\n );\n if (existsSync(fontAssetDir)) {\n app.use(\n \"/fonts\",\n express.static(fontAssetDir, {\n maxAge: \"30d\",\n immutable: true,\n }),\n );\n }\n\n app.use(\n healthRouter(registry, {\n proxyTokenRequired,\n clientTokenRequired,\n validateClientToken: (token) => token === clientToken,\n validateProxyToken: (token) => token === proxyToken,\n getClientToken: () => clientToken ?? null,\n }),\n );\n app.get(\"/api/remote-files/:token\", (req, res) => {\n remoteFileBridge.handleHttpRequest(req, res);\n });\n app.put(\"/api/remote-uploads/:token\", (req, res) => {\n remoteFileBridge.handleUploadHttpRequest(req, res);\n });\n app.get(\"/api/device-preview-streams/:token\", (req, res) => {\n devicePreviewBridge.handleHttpRequest(req, res);\n });\n const webAssetDir =\n options.webAssetDir === false ? undefined : (options.webAssetDir ?? PACKAGED_WEB_DIR);\n if (webAssetDir) {\n mountWebApp(app, { webAssetDir, logger });\n }\n\n // 使用 createServer 而非 app.listen,确保 WebSocket upgrade 可在同一端口上处理\n const httpServer = createServer(app);\n\n const proxyWss = new WebSocketServer({\n noServer: true,\n maxPayload: DATA_CHANNEL_MAX_PAYLOAD_BYTES,\n perMessageDeflate: DATA_CHANNEL_COMPRESSION,\n });\n const clientWss = new WebSocketServer({\n noServer: true,\n maxPayload: DATA_CHANNEL_MAX_PAYLOAD_BYTES,\n perMessageDeflate: DATA_CHANNEL_COMPRESSION,\n });\n // JPEG frames use a dedicated, non-compressed socket so large bursts cannot head-of-line block\n // PTY/control traffic on the Proxy's main WebSocket.\n const devicePreviewStreamWss = new WebSocketServer({\n noServer: true,\n maxPayload: DEVICE_PREVIEW_FRAME_MAX_BYTES + 512,\n perMessageDeflate: false,\n });\n // Voice sockets intentionally do not negotiate permessage-deflate: audio is already compressed\n // or latency-sensitive, so deflating it only adds CPU and head-of-line delay.\n const voiceAsrWss = new WebSocketServer({ noServer: true });\n const voiceTtsWss = new WebSocketServer({ noServer: true });\n\n httpServer.on(\"upgrade\", (request, socket, head) => {\n const url = new URL(request.url ?? \"/\", \"http://localhost\");\n const { pathname } = url;\n const origin = request.headers.origin;\n\n if (!checkOrigin(origin)) {\n logger.warn(\n { ip: request.socket.remoteAddress, origin: origin ?? \"(missing)\", pathname },\n \"rejected upgrade: origin not in allowedOrigins\",\n );\n socket.write(\"HTTP/1.1 403 Forbidden\\r\\n\\r\\n\");\n socket.destroy();\n return;\n }\n\n if (pathname === \"/proxy\" || pathname === \"/proxy-stream\") {\n if (proxyTokenRequired) {\n const token = url.searchParams.get(\"token\");\n if (token !== proxyToken) {\n logger.warn(\n { ip: request.socket.remoteAddress, pathname },\n \"rejected Proxy-side upgrade: invalid token\",\n );\n socket.write(\"HTTP/1.1 401 Unauthorized\\r\\n\\r\\n\");\n socket.destroy();\n return;\n }\n }\n const targetWss = pathname === \"/proxy\" ? proxyWss : devicePreviewStreamWss;\n targetWss.handleUpgrade(request, socket, head, (ws) => {\n targetWss.emit(\"connection\", ws, request);\n });\n return;\n }\n\n if (pathname === \"/client\" || pathname === \"/voice/asr\" || pathname === \"/voice/tts\") {\n if (clientTokenRequired) {\n const token = url.searchParams.get(\"token\");\n if (token !== clientToken) {\n logger.warn(\n { ip: request.socket.remoteAddress, pathname },\n \"rejected client-side upgrade: invalid token\",\n );\n socket.write(\"HTTP/1.1 401 Unauthorized\\r\\n\\r\\n\");\n socket.destroy();\n return;\n }\n }\n if (pathname === \"/client\") {\n clientWss.handleUpgrade(request, socket, head, (ws) => {\n clientWss.emit(\"connection\", ws, request);\n });\n } else if (pathname === \"/voice/asr\") {\n voiceAsrWss.handleUpgrade(request, socket, head, (ws) => {\n voiceAsrWss.emit(\"connection\", ws, request);\n });\n } else {\n voiceTtsWss.handleUpgrade(request, socket, head, (ws) => {\n voiceTtsWss.emit(\"connection\", ws, request);\n });\n }\n return;\n }\n\n socket.destroy();\n });\n\n proxyWss.on(\"connection\", (ws) => {\n handleProxyConnection(\n ws,\n registry,\n logger,\n ptySnapshotRoutes,\n sessionHistoryRoutes,\n webPreviewRoutes,\n devicePreviewBridge,\n relayChaos,\n remoteFileBridge,\n options.proxyAdmissionTimeoutMs,\n );\n });\n\n devicePreviewStreamWss.on(\"connection\", (ws) => {\n devicePreviewBridge.handleStreamTransportConnection(ws);\n });\n\n clientWss.on(\"connection\", (ws, request) => {\n handleClientConnection(\n ws,\n registry,\n logger,\n ptySnapshotRoutes,\n sessionHistoryRoutes,\n webPreviewRoutes,\n devicePreviewBridge,\n relayChaos,\n voiceConfigStore,\n voiceProviders,\n remoteFileBridge,\n {\n userAgent: firstHeaderValue(request.headers[\"user-agent\"]),\n remoteAddress: requestRemoteAddress(request),\n },\n options.clientAdmissionTimeoutMs,\n );\n });\n\n voiceAsrWss.on(\"connection\", (ws) => {\n handleVoiceAsrConnection(ws, voiceConfigStore, logger, voiceProviders);\n });\n\n voiceTtsWss.on(\"connection\", (ws) => {\n handleVoiceTtsConnection(ws, voiceConfigStore, logger, voiceProviders);\n });\n\n const proxyHeartbeat = setupHeartbeat(proxyWss, heartbeatInterval, {\n logger,\n peerType: \"proxy\",\n describePeer: (ws) => ({ proxyId: (ws as { proxyId?: string }).proxyId }),\n });\n const clientHeartbeat = setupHeartbeat(clientWss, heartbeatInterval, {\n logger,\n peerType: \"client\",\n describePeer: (ws) => ({\n clientId: (ws as { clientId?: string }).clientId,\n boundProxyId: (ws as { boundProxyId?: string }).boundProxyId,\n }),\n });\n const devicePreviewStreamHeartbeat = setupHeartbeat(devicePreviewStreamWss, heartbeatInterval, {\n logger,\n peerType: \"device-preview-stream\",\n describePeer: (ws) => ({\n proxyId: (ws as { devicePreviewProxyId?: string }).devicePreviewProxyId,\n }),\n });\n const voiceAsrHeartbeat = setupHeartbeat(voiceAsrWss, heartbeatInterval, {\n logger,\n peerType: \"voice-asr\",\n });\n const voiceTtsHeartbeat = setupHeartbeat(voiceTtsWss, heartbeatInterval, {\n logger,\n peerType: \"voice-tts\",\n });\n\n async function close(): Promise<void> {\n clearInterval(proxyHeartbeat);\n clearInterval(clientHeartbeat);\n clearInterval(devicePreviewStreamHeartbeat);\n clearInterval(voiceAsrHeartbeat);\n clearInterval(voiceTtsHeartbeat);\n webPreviewRoutes.dispose();\n devicePreviewBridge.dispose();\n\n for (const ws of proxyWss.clients) {\n ws.terminate();\n }\n for (const ws of clientWss.clients) {\n ws.terminate();\n }\n for (const ws of devicePreviewStreamWss.clients) {\n ws.terminate();\n }\n for (const ws of voiceAsrWss.clients) {\n ws.terminate();\n }\n for (const ws of voiceTtsWss.clients) {\n ws.terminate();\n }\n\n await Promise.all([\n new Promise<void>((resolve, reject) => {\n proxyWss.close((err) => {\n if (err) reject(err);\n else resolve();\n });\n }),\n new Promise<void>((resolve, reject) => {\n clientWss.close((err) => {\n if (err) reject(err);\n else resolve();\n });\n }),\n new Promise<void>((resolve, reject) => {\n devicePreviewStreamWss.close((err) => {\n if (err) reject(err);\n else resolve();\n });\n }),\n new Promise<void>((resolve, reject) => {\n voiceAsrWss.close((err) => {\n if (err) reject(err);\n else resolve();\n });\n }),\n new Promise<void>((resolve, reject) => {\n voiceTtsWss.close((err) => {\n if (err) reject(err);\n else resolve();\n });\n }),\n ]);\n\n await new Promise<void>((resolve, reject) => {\n httpServer.close((err) => {\n if (err) reject(err);\n else resolve();\n });\n });\n }\n\n return { httpServer, registry, close };\n}\n","import { z } from \"zod\";\n\n// 所有跨进程传递的标识符 (proxyId / clientId / sessionId / requestId / toolId) 的统一上限。\n// 设计原因:\n// - nanoid (proxy/session/client 服务端默认生成) = 21 字符\n// - claude tool_use id (toolu_<base64ish>) ≈ 30-40 字符\n// - codex tool id 类似量级\n// 256 给协议演进留余量, 同时挡住 wire 上来的恶意超长 ID:\n// - Map<id, _> key 占用 (memory DoS)\n// - 日志行膨胀 (operator/磁盘压力)\n// - 拼到 disk path (虽然当前没有此路径, defense in depth)\nconst MAX_ID_LENGTH = 256;\n\nexport const IdSchema = z.string().min(1).max(MAX_ID_LENGTH);\n","import { z } from \"zod\";\nimport { MESSAGE_ENVELOPE_VERSION } from \"../constants/envelope.js\";\nimport { IdSchema } from \"./id.js\";\nimport {\n UserInputPayloadSchema,\n AssistantMessagePayloadSchema,\n ThinkingPayloadSchema,\n} from \"./chat.js\";\nimport { ToolUseRequestPayloadSchema, ToolResultPayloadSchema } from \"./tool.js\";\nimport { SessionListPayloadSchema, SessionStatusPayloadSchema } from \"./session.js\";\nimport {\n HeartbeatPayloadSchema,\n AuthPayloadSchema,\n SyncRequestPayloadSchema,\n SyncResponsePayloadSchema,\n} from \"./system.js\";\n\n// 信封基础字段:序列号、时间戳、来源、协议版本——所有 envelope 共用。\nconst BaseEnvelopeFields = {\n seq: z.number().int().nonnegative(),\n timestamp: z.number(),\n source: z.enum([\"proxy\", \"client\"]),\n version: z.literal(MESSAGE_ENVELOPE_VERSION),\n};\n\n// session-scoped envelope: 携带 sessionId 路由到具体会话, 大多数业务 envelope 走这里。\nconst SessionedEnvelopeFields = {\n ...BaseEnvelopeFields,\n sessionId: IdSchema,\n};\n\nconst GlobalEnvelopeFields = {\n ...BaseEnvelopeFields,\n sessionId: z.never().optional(),\n};\n\n// 按 type 字段区分的 discriminatedUnion 信封\n// 推送和结果剥离未知描述字段;操作输入仍严格校验。\nexport const MessageEnvelopeSchema = z.discriminatedUnion(\"type\", [\n // chat (3)\n z\n .object({\n ...SessionedEnvelopeFields,\n type: z.literal(\"user_input\"),\n payload: UserInputPayloadSchema,\n })\n .strict(),\n z.object({\n ...SessionedEnvelopeFields,\n type: z.literal(\"assistant_message\"),\n payload: AssistantMessagePayloadSchema,\n }),\n z.object({\n ...SessionedEnvelopeFields,\n type: z.literal(\"thinking\"),\n payload: ThinkingPayloadSchema,\n }),\n // tool (4): 工具审批决策属于 relay control,不进入会话消息信封。\n // tool_use_request: 审批流请求(proxy → client),toolId 是 approval requestId\n z.object({\n ...SessionedEnvelopeFields,\n type: z.literal(\"tool_use_request\"),\n payload: ToolUseRequestPayloadSchema,\n }),\n // tool_result: 工具执行结果(proxy → client),toolId 对应 assistant_tool_use / tool_use_request 的 toolId\n z.object({\n ...SessionedEnvelopeFields,\n type: z.literal(\"tool_result\"),\n payload: ToolResultPayloadSchema,\n }),\n // assistant_tool_use: 纯展示型工具调用(proxy → client),区别于 tool_use_request 无审批语义\n // payload 结构复用 ToolUseRequestPayloadSchema;toolId 是 Claude 分配的 tool_use id\n z.object({\n ...SessionedEnvelopeFields,\n type: z.literal(\"assistant_tool_use\"),\n payload: ToolUseRequestPayloadSchema,\n }),\n // session (2)\n // session_list 是全局广播 (列出所有 session), 不绑定具体 sessionId, 不携带该字段。\n z.object({\n ...GlobalEnvelopeFields,\n type: z.literal(\"session_list\"),\n payload: SessionListPayloadSchema,\n }),\n z.object({\n ...SessionedEnvelopeFields,\n type: z.literal(\"session_status\"),\n payload: SessionStatusPayloadSchema,\n }),\n // system (5): 心跳 / 认证 / 同步——全局, 无 sessionId\n z.object({\n ...GlobalEnvelopeFields,\n type: z.literal(\"heartbeat\"),\n payload: HeartbeatPayloadSchema,\n }),\n z\n .object({\n ...GlobalEnvelopeFields,\n type: z.literal(\"auth\"),\n payload: AuthPayloadSchema,\n })\n .strict(),\n z\n .object({\n ...GlobalEnvelopeFields,\n type: z.literal(\"sync_request\"),\n payload: SyncRequestPayloadSchema,\n })\n .strict(),\n z.object({\n ...GlobalEnvelopeFields,\n type: z.literal(\"sync_response\"),\n payload: SyncResponsePayloadSchema,\n }),\n]);\n\nexport type MessageEnvelope = z.infer<typeof MessageEnvelopeSchema>;\n\nexport type MessageType = MessageEnvelope[\"type\"];\n\nexport type MessageSource = MessageEnvelope[\"source\"];\n","export const MESSAGE_ENVELOPE_VERSION = \"1.0\" as const;\n","import { z } from \"zod\";\n\n// 用户输入消息\nexport const UserInputPayloadSchema = z\n .object({\n text: z.string().min(1),\n messageId: z.string().min(1).optional(),\n })\n .strict();\n\nexport type UserInputPayload = z.infer<typeof UserInputPayloadSchema>;\n\n// 助手回复全文快照。相同 turnId 只接受更高 revision,避免重连后的重复与乱序覆盖。\nexport const AssistantMessagePayloadSchema = z.object({\n turnId: z.string().min(1).max(256),\n revision: z.number().int().positive(),\n text: z.string(),\n status: z.enum([\"streaming\", \"completed\"]),\n});\n\nexport type AssistantMessagePayload = z.infer<typeof AssistantMessagePayloadSchema>;\n\n// 思考过程消息\nexport const ThinkingPayloadSchema = z.object({\n text: z.string(),\n});\n\nexport type ThinkingPayload = z.infer<typeof ThinkingPayloadSchema>;\n","import { z } from \"zod\";\nimport { IdSchema } from \"./id.js\";\n\nexport const ApprovalOptionKindSchema = z.enum([\n \"allow_once\",\n \"allow_always\",\n \"reject_once\",\n \"reject_always\",\n]);\n\nexport type ApprovalOptionKind = z.infer<typeof ApprovalOptionKindSchema>;\n\nexport const ApprovalOptionSchema = z.object({\n optionId: IdSchema,\n name: z.string().min(1),\n kind: ApprovalOptionKindSchema,\n});\n\nexport type ApprovalOption = z.infer<typeof ApprovalOptionSchema>;\n\n// 工具调用请求\nexport const ToolUseRequestPayloadSchema = z.object({\n toolName: z.string(),\n toolId: IdSchema,\n parameters: z.record(z.string(), z.unknown()),\n options: z.array(ApprovalOptionSchema).optional(),\n});\n\nexport type ToolUseRequestPayload = z.infer<typeof ToolUseRequestPayloadSchema>;\n\n// 工具调用批准,whitelistTool 为 true 时将该工具加入会话级白名单自动审批\nexport const ToolApprovePayloadSchema = z.object({\n toolId: IdSchema,\n whitelistTool: z.boolean().optional(),\n optionId: IdSchema.optional(),\n});\n\nexport type ToolApprovePayload = z.infer<typeof ToolApprovePayloadSchema>;\n\n// 工具调用拒绝\nexport const ToolDenyPayloadSchema = z.object({\n toolId: IdSchema,\n reason: z.string().optional(),\n optionId: IdSchema.optional(),\n});\n\nexport type ToolDenyPayload = z.infer<typeof ToolDenyPayloadSchema>;\n\n// 工具调用结果\nexport const ToolResultPayloadSchema = z.object({\n toolId: IdSchema,\n result: z.unknown(),\n isError: z.boolean(),\n});\n\nexport type ToolResultPayload = z.infer<typeof ToolResultPayloadSchema>;\n","import { z } from \"zod\";\nimport { providerValues, ptyOwnerValues } from \"../constants/enums.js\";\nimport { ptySemanticStateValues } from \"../constants/pty.js\";\nimport { IdSchema } from \"./id.js\";\n\nexport const TerminalShellFamilySchema = z.enum([\"bash\", \"zsh\", \"fish\", \"powershell\", \"cmd\"]);\nexport type TerminalShellFamily = z.infer<typeof TerminalShellFamilySchema>;\n\nexport const sessionStateValues = [\n \"idle\",\n \"working\",\n \"compacting\",\n \"waiting_approval\",\n \"error\",\n \"terminated\",\n] as const;\nconst agentStatusPhaseValues = [\n \"idle\",\n \"thinking\",\n \"tool_use\",\n \"outputting\",\n \"waiting_permission\",\n \"error\",\n] as const;\n\n/**\n * 在所有会话协议中复用同一组身份约束。调用方只提供自身的公共字段,\n * 这里负责约束三种合法的会话形态,同时剥离不认识的描述字段。\n */\nexport function createSessionIdentitySchema<T extends z.ZodRawShape>(commonFields: T) {\n return z.union([\n z.object({\n ...commonFields,\n kind: z.literal(\"agent\"),\n mode: z.literal(\"json\"),\n provider: z.enum(providerValues),\n ptyOwner: z.never().optional(),\n }),\n z.object({\n ...commonFields,\n kind: z.literal(\"agent\"),\n mode: z.literal(\"pty\"),\n provider: z.enum(providerValues),\n ptyOwner: z.enum(ptyOwnerValues),\n }),\n z.object({\n ...commonFields,\n kind: z.literal(\"terminal\"),\n mode: z.literal(\"pty\"),\n provider: z.literal(\"claude\"),\n ptyOwner: z.literal(\"proxy-hosted\"),\n shellFamily: TerminalShellFamilySchema.optional(),\n }),\n ]);\n}\n\n// 会话信息,用于会话列表展示\n// lastActive: 最近一次状态变更或运行时活动时间戳 (ms),用于列表“最近活动 N 分钟前”显示。\nexport const SessionInfoSchema = createSessionIdentitySchema({\n sessionId: IdSchema,\n name: z.string().optional(),\n // cwd 只用于展示完整路径/tooltip,不作为前端路由或权限判断来源。\n cwd: z.string(),\n // true 表示 name 是用户显式命名,PTY UI 不再让 OSC terminal_title 覆盖它。\n nameLocked: z.boolean().optional(),\n state: z.enum(sessionStateValues),\n lastActive: z.number(),\n});\nexport type SessionInfo = z.infer<typeof SessionInfoSchema>;\n\n// 会话列表\nexport const SessionListPayloadSchema = z.object({\n sessions: z.array(SessionInfoSchema),\n});\n\nexport type SessionListPayload = z.infer<typeof SessionListPayloadSchema>;\n\n// 会话状态变更\n// lastActive: 触发本次状态迁移或活动刷新的时间戳 (ms),用于列表相对时间显示。\nexport const SessionStatusPayloadSchema = z.object({\n sessionId: IdSchema,\n state: z.enum(sessionStateValues),\n lastActive: z.number(),\n});\n\nexport type SessionStatusPayload = z.infer<typeof SessionStatusPayloadSchema>;\n\n// PTY 语义状态事件,描述当前 PTY 处于何种状态\nexport const PtyStatePayloadSchema = z.object({\n state: z.enum(ptySemanticStateValues),\n seq: z.number().int().nonnegative(),\n title: z.string().optional(),\n tool: z.string().optional(),\n});\nexport type PtyStatePayload = z.infer<typeof PtyStatePayloadSchema>;\n\nexport const AgentStatusPayloadSchema = z.object({\n provider: z.enum(providerValues),\n phase: z.enum(agentStatusPhaseValues),\n seq: z.number().int().nonnegative(),\n updatedAt: z.number(),\n toolName: z.string().optional(),\n toolInput: z.record(z.string(), z.unknown()).optional(),\n permissionRequest: z\n .object({\n requestId: IdSchema,\n toolName: z.string(),\n input: z.record(z.string(), z.unknown()),\n })\n .optional(),\n permissionResolution: z\n .object({\n requestId: IdSchema,\n outcome: z.enum([\"allow\", \"deny\"]),\n })\n .optional(),\n summary: z.string().optional(),\n});\nexport type AgentStatusPayload = z.infer<typeof AgentStatusPayloadSchema>;\n","// 协议层共用的枚举字面量集合。Zod schema、TypeScript 类型、运行时常量都从这里派生,\n// 避免在 relay-control / session / chat / web 各自手写 provider 字面量集合而产生漂移。\n\nexport const providerValues = [\"claude\", \"codex\", \"kimi\"] as const;\nexport type ProviderId = (typeof providerValues)[number];\n\nexport const ptyOwnerValues = [\"local-terminal\", \"proxy-hosted\"] as const;\nexport type PtyOwner = (typeof ptyOwnerValues)[number];\n\nexport const sessionModeValues = [\"pty\", \"json\"] as const;\nexport type SessionMode = (typeof sessionModeValues)[number];\n\nexport const sessionKindValues = [\"agent\", \"terminal\"] as const;\n","// PTY 局部语义状态。仅承载明确语义信号; title/spinner 变化时事件的 state 取 null,\n// 让上层不参与 FSM 切换, 只走 title 推送通道。\n// 单一 source of truth: osc-extractor / ipc-protocol / shared schema 都从这里取。\nexport const PtySemanticState = {\n WORKING: \"working\",\n TURN_COMPLETE: \"turn_complete\",\n APPROVAL_WAIT: \"approval_wait\",\n} as const;\n\nexport type PtySemanticState = (typeof PtySemanticState)[keyof typeof PtySemanticState];\n\n// zod / 类型字面量场景下复用的 const tuple, z.enum 直接吃。\nexport const ptySemanticStateValues = [\n PtySemanticState.WORKING,\n PtySemanticState.TURN_COMPLETE,\n PtySemanticState.APPROVAL_WAIT,\n] as const;\n\n// Web 创建 PTY 时可以按可用视口放大初始几何,但不能低于传统 80x24。\n// 这个底线既保证常见 TUI 布局,也避免 Claude Code / Codex 等 CLI 因终端过窄\n// 省略二维码或启动信息。上限用于拦截异常客户端提交的不合理 PTY 尺寸。\nexport const PTY_INITIAL_MIN_COLS = 80;\nexport const PTY_INITIAL_MIN_ROWS = 24;\nexport const PTY_INITIAL_MAX_COLS = 500;\nexport const PTY_INITIAL_MAX_ROWS = 200;\n","import { z } from \"zod\";\n\n// 心跳消息,空 payload\nexport const HeartbeatPayloadSchema = z.object({});\n\nexport type HeartbeatPayload = z.infer<typeof HeartbeatPayloadSchema>;\n\n// 认证消息,支持配对码和 token 两种方式\nexport const AuthPayloadSchema = z\n .object({\n pairingCode: z.string().optional(),\n token: z.string().optional(),\n })\n .strict();\n\nexport type AuthPayload = z.infer<typeof AuthPayloadSchema>;\n\n// 同步请求,客户端发送已收到的最大序列号\nexport const SyncRequestPayloadSchema = z\n .object({\n lastSeq: z.number().int().nonnegative(),\n })\n .strict();\n\nexport type SyncRequestPayload = z.infer<typeof SyncRequestPayloadSchema>;\n\n// 同步响应,使用 z.unknown 数组避免循环引用;恢复协议稳定后再收紧类型\nexport const SyncResponsePayloadSchema = z.object({\n messages: z.array(z.record(z.string(), z.unknown())),\n});\n\nexport type SyncResponsePayload = z.infer<typeof SyncResponsePayloadSchema>;\n","import { z } from \"zod\";\n\nexport const voiceProviderValues = [\"aliyun-bailian\"] as const;\nexport const voiceRegionValues = [\"cn\", \"intl\"] as const;\nexport const voiceOptionSourceValues = [\"official\", \"custom\"] as const;\nexport const voiceOptionGenderValues = [\"male\", \"female\", \"unknown\"] as const;\n\nexport const VoiceProviderConfigSchema = z.object({\n provider: z.enum(voiceProviderValues),\n configured: z.boolean(),\n region: z.enum(voiceRegionValues),\n asrModel: z.string().min(1),\n ttsModel: z.string().min(1),\n ttsVoice: z.string().min(1),\n turnIdleSeconds: z.number().int().positive().safe().default(3),\n // 密钥及其写入操作不属于可公开的配置描述。\n apiKey: z.never().optional(),\n clearApiKey: z.never().optional(),\n});\nexport type VoiceProviderConfig = z.infer<typeof VoiceProviderConfigSchema>;\n\nexport const VoiceConfigUpdateSchema = z\n .object({\n provider: z.enum(voiceProviderValues).optional(),\n apiKey: z.string().min(1).optional(),\n clearApiKey: z.boolean().optional(),\n region: z.enum(voiceRegionValues).optional(),\n asrModel: z.string().min(1).optional(),\n ttsModel: z.string().min(1).optional(),\n ttsVoice: z.string().min(1).optional(),\n turnIdleSeconds: z.number().int().positive().safe().optional(),\n })\n .strict();\nexport type VoiceConfigUpdate = z.infer<typeof VoiceConfigUpdateSchema>;\n\nexport const VoiceOptionSchema = z.object({\n value: z.string().min(1),\n label: z.string().min(1),\n description: z.string().min(1).optional(),\n gender: z.enum(voiceOptionGenderValues).optional(),\n age: z.string().min(1).optional(),\n model: z.string().min(1).optional(),\n source: z.enum(voiceOptionSourceValues),\n});\nexport type VoiceOption = z.infer<typeof VoiceOptionSchema>;\n\nexport const VoiceCapabilitiesSchema = z.object({\n asrModels: z.array(VoiceOptionSchema),\n ttsModels: z.array(VoiceOptionSchema),\n ttsVoices: z.array(VoiceOptionSchema),\n fetchedAt: z.number().optional(),\n});\nexport type VoiceCapabilities = z.infer<typeof VoiceCapabilitiesSchema>;\n\n// Official snapshot from Alibaba Cloud Bailian docs, captured 2026-05-18.\n// Alibaba does not currently expose a clean API-key-scoped catalog endpoint for these system models.\nconst BUNDLED_BAILIAN_ASR_MODELS: VoiceOption[] = [\n {\n value: \"qwen3-asr-flash-realtime\",\n label: \"Qwen3 ASR Flash Realtime\",\n source: \"official\",\n },\n {\n value: \"qwen3-asr-flash-realtime-2026-02-10\",\n label: \"Qwen3 ASR Flash Realtime · 2026-02-10\",\n source: \"official\",\n },\n {\n value: \"qwen3-asr-flash-realtime-2025-10-27\",\n label: \"Qwen3 ASR Flash Realtime · 2025-10-27\",\n source: \"official\",\n },\n];\n\nconst BUNDLED_BAILIAN_TTS_MODELS: VoiceOption[] = [\n {\n value: \"cosyvoice-v3-flash\",\n label: \"CosyVoice V3 Flash · 系统音色\",\n source: \"official\",\n },\n {\n value: \"cosyvoice-v3-plus\",\n label: \"CosyVoice V3 Plus · 系统音色\",\n source: \"official\",\n },\n {\n value: \"cosyvoice-v3.5-flash\",\n label: \"CosyVoice V3.5 Flash · 自定义音色\",\n source: \"official\",\n },\n {\n value: \"cosyvoice-v3.5-plus\",\n label: \"CosyVoice V3.5 Plus · 自定义音色\",\n source: \"official\",\n },\n];\n\nconst BUNDLED_BAILIAN_TTS_VOICES: VoiceOption[] = [\n {\n value: \"longanyang\",\n label: \"龙安洋 · 男 · 阳光大男孩 · 年龄 20-30\",\n gender: \"male\",\n age: \"20-30\",\n model: \"cosyvoice-v3-flash\",\n source: \"official\",\n },\n {\n value: \"longanhuan\",\n label: \"龙安欢 · 女 · 欢脱元气 · 年龄 20-30\",\n gender: \"female\",\n age: \"20-30\",\n model: \"cosyvoice-v3-flash\",\n source: \"official\",\n },\n {\n value: \"longhuhu_v3\",\n label: \"龙呼呼 · 女 · 天真烂漫女童 · 年龄 6-10\",\n gender: \"female\",\n age: \"6-10\",\n model: \"cosyvoice-v3-flash\",\n source: \"official\",\n },\n {\n value: \"longpaopao_v3\",\n label: \"龙泡泡 · 未知 · 飞天泡泡音 · 年龄 6-15\",\n gender: \"unknown\",\n age: \"6-15\",\n model: \"cosyvoice-v3-flash\",\n source: \"official\",\n },\n {\n value: \"longjielidou_v3\",\n label: \"龙杰力豆 · 男 · 阳光顽皮 · 年龄 10\",\n gender: \"male\",\n age: \"10\",\n model: \"cosyvoice-v3-flash\",\n source: \"official\",\n },\n {\n value: \"longxian_v3\",\n label: \"龙仙 · 女 · 豪放可爱 · 年龄 12\",\n gender: \"female\",\n age: \"12\",\n model: \"cosyvoice-v3-flash\",\n source: \"official\",\n },\n {\n value: \"longling_v3\",\n label: \"龙铃 · 女 · 稚气呆板 · 年龄 10\",\n gender: \"female\",\n age: \"10\",\n model: \"cosyvoice-v3-flash\",\n source: \"official\",\n },\n {\n value: \"longjiaxin_v3\",\n label: \"龙嘉欣 · 女 · 优雅粤语 · 年龄 30-35\",\n gender: \"female\",\n age: \"30-35\",\n model: \"cosyvoice-v3-flash\",\n source: \"official\",\n },\n {\n value: \"longanyue_v3\",\n label: \"龙安粤 · 男 · 欢脱粤语 · 年龄 25-35\",\n gender: \"male\",\n age: \"25-35\",\n model: \"cosyvoice-v3-flash\",\n source: \"official\",\n },\n {\n value: \"longlaotie_v3\",\n label: \"龙老铁 · 男 · 东北直率 · 年龄 25-30\",\n gender: \"male\",\n age: \"25-30\",\n model: \"cosyvoice-v3-flash\",\n source: \"official\",\n },\n {\n value: \"longanyang\",\n label: \"龙安洋 · 男 · 阳光大男孩 · 年龄 20-30\",\n gender: \"male\",\n age: \"20-30\",\n model: \"cosyvoice-v3-plus\",\n source: \"official\",\n },\n {\n value: \"longanhuan\",\n label: \"龙安欢 · 女 · 欢脱元气 · 年龄 20-30\",\n gender: \"female\",\n age: \"20-30\",\n model: \"cosyvoice-v3-plus\",\n source: \"official\",\n },\n];\n\nfunction cloneVoiceOption(option: VoiceOption): VoiceOption {\n return { ...option };\n}\n\nexport function createBundledBailianVoiceCapabilities(fetchedAt?: number): VoiceCapabilities {\n return {\n asrModels: BUNDLED_BAILIAN_ASR_MODELS.map(cloneVoiceOption),\n ttsModels: BUNDLED_BAILIAN_TTS_MODELS.map(cloneVoiceOption),\n ttsVoices: BUNDLED_BAILIAN_TTS_VOICES.map(cloneVoiceOption),\n ...(typeof fetchedAt === \"number\" ? { fetchedAt } : {}),\n };\n}\n\nexport const VoiceSummaryReasonSchema = z.enum([\n \"code\",\n \"table\",\n \"diff\",\n \"log\",\n \"stack_trace\",\n \"long_list\",\n \"long_text\",\n \"mixed\",\n \"approval\",\n]);\nexport type VoiceSummaryReason = z.infer<typeof VoiceSummaryReasonSchema>;\n","import { z } from \"zod\";\nimport { IdSchema } from \"./id.js\";\n\nexport const PreviewScopeSchema = z\n .object({\n proxyId: IdSchema,\n bindingId: IdSchema,\n })\n .strict();\n\nexport type PreviewScope = z.infer<typeof PreviewScopeSchema>;\n","import { z } from \"zod\";\n\nexport const PROXY_UPGRADE_BOOTSTRAP_VERSION = 1 as const;\n\nconst StableVersionSchema = z.string().regex(/^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)$/);\n\n// This small HTTP contract is deliberately separate from RelayControlSchema. A Proxy can discover\n// the version it needs before it is able to speak the Relay's current WebSocket control protocol.\n// Keep the reader forward-compatible: future Relays may append negotiation hints, and an older\n// Proxy must still be able to read relayVersion and update itself instead of rejecting the very\n// response intended to recover it.\nexport const ProxyUpgradeBootstrapResponseSchema = z.object({\n bootstrapVersion: z.literal(PROXY_UPGRADE_BOOTSTRAP_VERSION),\n relayVersion: StableVersionSchema,\n controlProtocolVersion: z.number().int().positive(),\n});\n\nexport type ProxyUpgradeBootstrapResponse = z.infer<typeof ProxyUpgradeBootstrapResponseSchema>;\n","import { z } from \"zod\";\nimport { IdSchema } from \"./id.js\";\n\nconst WEB_PREVIEW_PATH_MAX_LENGTH = 4_096;\nconst WEB_PREVIEW_SOURCE_URL_MAX_LENGTH = 4_096;\nconst WEB_PREVIEW_PUBLIC_URL_MAX_LENGTH = 65_536;\nconst WEB_PREVIEW_NAME_MAX_LENGTH = 256;\nconst WEB_PREVIEW_ERROR_MAX_LENGTH = 4_096;\nconst WEB_PREVIEW_HTML_ENTRY_MAX_COUNT = 1_000;\n\nexport const WebPreviewNameSchema = z.string().trim().min(1).max(WEB_PREVIEW_NAME_MAX_LENGTH);\n\nexport const tunnelProviderValues = [\"cloudflare\", \"cpolar\"] as const;\nexport const TunnelProviderSchema = z.enum(tunnelProviderValues);\nexport type TunnelProvider = z.infer<typeof TunnelProviderSchema>;\n\nexport const WebPreviewPathSchema = z.string().min(1).max(WEB_PREVIEW_PATH_MAX_LENGTH);\n\nfunction parseUrlSafely(value: string): URL | null {\n try {\n return new URL(value);\n } catch {\n return null;\n }\n}\n\nconst LoopbackHttpUrlSchema = z\n .string()\n .min(1)\n .max(WEB_PREVIEW_SOURCE_URL_MAX_LENGTH)\n .url()\n .refine((value) => {\n const url = parseUrlSafely(value);\n if (!url) return false;\n if (url.protocol !== \"http:\" || url.username !== \"\" || url.password !== \"\") return false;\n return url.hostname === \"localhost\" || url.hostname === \"127.0.0.1\" || url.hostname === \"[::1]\";\n }, \"Local preview URL must use http:// with a loopback host and no credentials\");\n\nconst PublicPreviewUrlSchema = z\n .string()\n .min(1)\n .max(WEB_PREVIEW_PUBLIC_URL_MAX_LENGTH)\n .url()\n .refine((value) => {\n const url = parseUrlSafely(value);\n if (!url) return false;\n return (\n url.protocol === \"https:\" && url.username === \"\" && url.password === \"\" && url.port === \"\"\n );\n }, \"Preview public URL must use standard HTTPS without credentials\");\n\nconst DNS_LABEL_PATTERN = \"[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\";\nconst CLOUDFLARE_PUBLIC_HOST_PATTERN = new RegExp(\n `^${DNS_LABEL_PATTERN}\\\\.trycloudflare\\\\.com$`,\n \"i\",\n);\nconst CPOLAR_PUBLIC_HOST_PATTERN = new RegExp(\n `^(?:${DNS_LABEL_PATTERN}\\\\.)+cpolar\\\\.(?:top|cn|io)$`,\n \"i\",\n);\n\nconst WebPreviewTunnelSuggestionsSchema = z\n .array(z.string().min(1).max(WEB_PREVIEW_PATH_MAX_LENGTH))\n .max(32)\n .optional();\n\nexport const WebPreviewTunnelStatusSchema = z.discriminatedUnion(\"available\", [\n z.object({\n available: z.literal(true),\n command: z.string().min(1).max(WEB_PREVIEW_PATH_MAX_LENGTH),\n version: z.string().min(1).max(256).optional(),\n error: z.never().optional(),\n suggestions: WebPreviewTunnelSuggestionsSchema,\n }),\n z.object({\n available: z.literal(false),\n command: z.never().optional(),\n version: z.never().optional(),\n error: z.string().min(1).max(WEB_PREVIEW_ERROR_MAX_LENGTH),\n suggestions: WebPreviewTunnelSuggestionsSchema,\n }),\n]);\nexport type WebPreviewTunnelStatus = z.infer<typeof WebPreviewTunnelStatusSchema>;\n\nexport const WebPreviewCapabilitySchema = z.object({\n cloudflared: WebPreviewTunnelStatusSchema,\n cpolar: WebPreviewTunnelStatusSchema,\n});\nexport type WebPreviewCapability = z.infer<typeof WebPreviewCapabilitySchema>;\n\nexport const WebPreviewSourceInputSchema = z.discriminatedUnion(\"kind\", [\n z\n .object({\n kind: z.literal(\"local\"),\n url: LoopbackHttpUrlSchema,\n })\n .strict(),\n z\n .object({\n kind: z.literal(\"static\"),\n path: WebPreviewPathSchema,\n entryPath: WebPreviewPathSchema,\n })\n .strict(),\n]);\nexport type WebPreviewSourceInput = z.infer<typeof WebPreviewSourceInputSchema>;\n\nexport const PreviewSourceSchema = z.discriminatedUnion(\"kind\", [\n z.object({\n kind: z.literal(\"local\"),\n rootPath: z.never().optional(),\n entryPath: z.never().optional(),\n url: LoopbackHttpUrlSchema,\n }),\n z.object({\n kind: z.literal(\"static\"),\n url: z.never().optional(),\n rootPath: WebPreviewPathSchema,\n entryPath: WebPreviewPathSchema,\n }),\n]);\nexport type PreviewSource = z.infer<typeof PreviewSourceSchema>;\n\nexport const previewStateValues = [\n \"starting\",\n \"ready\",\n \"disconnected\",\n \"failed\",\n \"stopping\",\n] as const;\nexport const PreviewStateSchema = z.enum(previewStateValues);\nexport type PreviewState = z.infer<typeof PreviewStateSchema>;\n\nconst PreviewSummaryBaseSchema = z.object({\n previewId: IdSchema,\n name: WebPreviewNameSchema,\n source: PreviewSourceSchema,\n tunnelProvider: TunnelProviderSchema,\n createdAt: z.number().int().nonnegative(),\n updatedAt: z.number().int().nonnegative(),\n});\n\nconst PreviewSummaryInactiveShape = {\n publicUrl: z.never().optional(),\n error: z.never().optional(),\n};\n\nexport const PreviewSummarySchema = z\n .discriminatedUnion(\"state\", [\n PreviewSummaryBaseSchema.extend({\n state: z.literal(\"starting\"),\n ...PreviewSummaryInactiveShape,\n }),\n PreviewSummaryBaseSchema.extend({\n state: z.literal(\"ready\"),\n publicUrl: PublicPreviewUrlSchema,\n error: z.never().optional(),\n }),\n PreviewSummaryBaseSchema.extend({\n state: z.literal(\"disconnected\"),\n ...PreviewSummaryInactiveShape,\n }),\n PreviewSummaryBaseSchema.extend({\n state: z.literal(\"failed\"),\n publicUrl: z.never().optional(),\n error: z.string().min(1).max(WEB_PREVIEW_ERROR_MAX_LENGTH),\n }),\n PreviewSummaryBaseSchema.extend({\n state: z.literal(\"stopping\"),\n ...PreviewSummaryInactiveShape,\n }),\n ])\n .superRefine((preview, context) => {\n if (preview.state !== \"ready\") return;\n const publicUrl = parseUrlSafely(preview.publicUrl);\n // PublicPreviewUrlSchema reports malformed URLs. Do not let cross-field validation turn\n // safeParse into a throwing parser when URL construction itself fails.\n if (!publicUrl) return;\n const hostname = publicUrl.hostname;\n const provider = preview.tunnelProvider;\n const valid =\n provider === \"cloudflare\"\n ? CLOUDFLARE_PUBLIC_HOST_PATTERN.test(hostname)\n : CPOLAR_PUBLIC_HOST_PATTERN.test(hostname);\n if (!valid) {\n context.addIssue({\n code: \"custom\",\n path: [\"publicUrl\"],\n message: `Preview public URL hostname does not match tunnel provider ${provider}`,\n });\n }\n });\nexport type PreviewSummary = z.infer<typeof PreviewSummarySchema>;\n\nexport const PreviewHtmlEntriesSchema = z\n .array(WebPreviewPathSchema)\n .max(WEB_PREVIEW_HTML_ENTRY_MAX_COUNT);\n","import { z } from \"zod\";\nimport { IdSchema } from \"./id.js\";\n\nconst DEVICE_PREVIEW_PATH_MAX_LENGTH = 4_096;\nconst DEVICE_PREVIEW_TEXT_MAX_LENGTH = 4_096;\nconst DEVICE_PREVIEW_ERROR_MAX_LENGTH = 4_096;\nconst DEVICE_PREVIEW_NAME_MAX_LENGTH = 256;\nconst DEVICE_PREVIEW_VERSION_MAX_LENGTH = 256;\nconst DEVICE_PREVIEW_SCREEN_EDGE_MAX = 16_384;\n\nexport const DevicePreviewNameSchema = z.string().trim().min(1).max(DEVICE_PREVIEW_NAME_MAX_LENGTH);\n\nexport const devicePreviewStreamFormatValues = [\"jpeg\", \"h264_annex_b\"] as const;\nexport const DevicePreviewStreamFormatSchema = z.enum(devicePreviewStreamFormatValues);\nexport type DevicePreviewStreamFormat = z.infer<typeof DevicePreviewStreamFormatSchema>;\n\nexport const devicePreviewPlatformValues = [\"ios\", \"android\"] as const;\nexport const DevicePreviewPlatformSchema = z.enum(devicePreviewPlatformValues);\nexport type DevicePreviewPlatform = z.infer<typeof DevicePreviewPlatformSchema>;\n\nconst DevicePreviewToolSuggestionsSchema = z\n .array(z.string().min(1).max(DEVICE_PREVIEW_PATH_MAX_LENGTH))\n .max(32)\n .optional();\n\nexport const DevicePreviewToolStatusSchema = z.union([\n z.object({\n supported: z.literal(false),\n available: z.literal(false),\n interactive: z.literal(false),\n command: z.never().optional(),\n version: z.never().optional(),\n error: z.string().min(1).max(DEVICE_PREVIEW_ERROR_MAX_LENGTH),\n suggestions: DevicePreviewToolSuggestionsSchema,\n }),\n z.object({\n supported: z.literal(true),\n available: z.literal(false),\n interactive: z.literal(false),\n command: z.string().min(1).max(DEVICE_PREVIEW_PATH_MAX_LENGTH).optional(),\n version: z.string().min(1).max(DEVICE_PREVIEW_VERSION_MAX_LENGTH).optional(),\n error: z.string().min(1).max(DEVICE_PREVIEW_ERROR_MAX_LENGTH),\n suggestions: DevicePreviewToolSuggestionsSchema,\n }),\n z.object({\n supported: z.literal(true),\n available: z.literal(true),\n interactive: z.literal(true),\n command: z.string().min(1).max(DEVICE_PREVIEW_PATH_MAX_LENGTH),\n version: z.string().min(1).max(DEVICE_PREVIEW_VERSION_MAX_LENGTH).optional(),\n error: z.never().optional(),\n suggestions: DevicePreviewToolSuggestionsSchema,\n }),\n]);\nexport type DevicePreviewToolStatus = z.infer<typeof DevicePreviewToolStatusSchema>;\n\nexport const DevicePreviewCapabilitySchema = z.object({\n ios: DevicePreviewToolStatusSchema,\n android: DevicePreviewToolStatusSchema,\n});\nexport type DevicePreviewCapability = z.infer<typeof DevicePreviewCapabilitySchema>;\n\nconst DevicePreviewTargetBaseSchema = z.object({\n targetId: IdSchema,\n platform: DevicePreviewPlatformSchema,\n name: z.string().min(1).max(DEVICE_PREVIEW_NAME_MAX_LENGTH),\n model: z.string().min(1).max(DEVICE_PREVIEW_NAME_MAX_LENGTH),\n osVersion: z.string().min(1).max(DEVICE_PREVIEW_VERSION_MAX_LENGTH),\n interactive: z.boolean(),\n});\n\nconst DevicePreviewScreenEdgeSchema = z\n .number()\n .int()\n .positive()\n .max(DEVICE_PREVIEW_SCREEN_EDGE_MAX);\n\nexport const DevicePreviewTargetSchema = z.union([\n DevicePreviewTargetBaseSchema.extend({\n width: DevicePreviewScreenEdgeSchema,\n height: DevicePreviewScreenEdgeSchema,\n }),\n DevicePreviewTargetBaseSchema.extend({\n width: z.never().optional(),\n height: z.never().optional(),\n }),\n]);\nexport type DevicePreviewTarget = z.infer<typeof DevicePreviewTargetSchema>;\n\nexport const DevicePreviewStateSchema = z.enum([\"ready\", \"disconnected\"]);\nexport type DevicePreviewState = z.infer<typeof DevicePreviewStateSchema>;\n\nconst DevicePreviewSummaryBaseSchema = z.object({\n previewId: IdSchema,\n name: DevicePreviewNameSchema,\n platform: DevicePreviewPlatformSchema,\n targetId: IdSchema,\n model: z.string().min(1).max(DEVICE_PREVIEW_NAME_MAX_LENGTH),\n osVersion: z.string().min(1).max(DEVICE_PREVIEW_VERSION_MAX_LENGTH),\n interactive: z.boolean(),\n createdAt: z.number().int().nonnegative(),\n updatedAt: z.number().int().nonnegative(),\n});\n\nexport const DevicePreviewSummarySchema = z.discriminatedUnion(\"state\", [\n DevicePreviewSummaryBaseSchema.extend({\n state: z.literal(\"ready\"),\n error: z.never().optional(),\n }),\n DevicePreviewSummaryBaseSchema.extend({\n state: z.literal(\"disconnected\"),\n error: z.never().optional(),\n }),\n]);\nexport type DevicePreviewSummary = z.infer<typeof DevicePreviewSummarySchema>;\n\nexport const DevicePreviewJpegStreamProfileSchema = z\n .object({\n format: z.literal(\"jpeg\"),\n maxFps: z.number().int().min(1).max(30).optional(),\n })\n .strict();\n\nexport const DevicePreviewH264StreamProfileSchema = z\n .object({\n format: z.literal(\"h264_annex_b\"),\n })\n .strict();\n\nexport const DevicePreviewStreamProfileSchema = z.discriminatedUnion(\"format\", [\n DevicePreviewJpegStreamProfileSchema,\n DevicePreviewH264StreamProfileSchema,\n]);\nexport type DevicePreviewStreamProfile = z.infer<typeof DevicePreviewStreamProfileSchema>;\n\nexport const devicePreviewStreamStopReasonValues = [\n \"client_closed\",\n \"preview_closed\",\n \"proxy_offline\",\n \"relay_shutdown\",\n \"stream_error\",\n] as const;\nexport const DevicePreviewStreamStopReasonSchema = z.enum(devicePreviewStreamStopReasonValues);\nexport type DevicePreviewStreamStopReason = z.infer<typeof DevicePreviewStreamStopReasonSchema>;\n\nconst NormalizedCoordinateSchema = z.number().finite().min(0).max(1);\nexport const devicePreviewTouchPhaseValues = [\"down\", \"move\", \"up\"] as const;\nexport const DevicePreviewTouchPhaseSchema = z.enum(devicePreviewTouchPhaseValues);\nexport type DevicePreviewTouchPhase = z.infer<typeof DevicePreviewTouchPhaseSchema>;\n\nexport const devicePreviewOrientationValues = [\n \"portrait\",\n \"landscape_left\",\n \"landscape_right\",\n \"portrait_upside_down\",\n \"auto\",\n] as const;\nexport const DevicePreviewOrientationSchema = z.enum(devicePreviewOrientationValues);\nexport type DevicePreviewOrientation = z.infer<typeof DevicePreviewOrientationSchema>;\n\n// Browser coordinates are normalized. Only the Proxy adapter may turn them into device pixels or\n// iOS points; this keeps stale frame dimensions and rotated screens out of the wire contract.\nexport const DevicePreviewInputSchema = z.discriminatedUnion(\"kind\", [\n z\n .object({\n kind: z.literal(\"touch\"),\n phase: DevicePreviewTouchPhaseSchema,\n x: NormalizedCoordinateSchema,\n y: NormalizedCoordinateSchema,\n })\n .strict(),\n z\n .object({\n kind: z.literal(\"text\"),\n text: z.string().min(1).max(DEVICE_PREVIEW_TEXT_MAX_LENGTH),\n })\n .strict(),\n z\n .object({\n kind: z.literal(\"button\"),\n button: z.enum([\"home\", \"back\"]),\n })\n .strict(),\n z\n .object({\n kind: z.literal(\"orientation\"),\n orientation: DevicePreviewOrientationSchema,\n })\n .strict(),\n]);\nexport type DevicePreviewInput = z.infer<typeof DevicePreviewInputSchema>;\n\n// `/proxy-stream` is a dedicated, authenticated image data channel. Its small JSON handshake and\n// flow-control messages deliberately stay outside RelayControlSchema: they must never be accepted\n// on the main `/proxy` or `/client` sockets.\nexport const DevicePreviewStreamRegisterSchema = z.object({\n type: z.literal(\"device_preview_stream_register\"),\n proxyId: IdSchema,\n connectionId: IdSchema,\n});\nexport type DevicePreviewStreamRegister = z.infer<typeof DevicePreviewStreamRegisterSchema>;\n\nexport const DevicePreviewStreamRegisterResponseSchema = z.discriminatedUnion(\"success\", [\n z.object({\n type: z.literal(\"device_preview_stream_register_response\"),\n success: z.literal(true),\n error: z.never().optional(),\n }),\n z.object({\n type: z.literal(\"device_preview_stream_register_response\"),\n success: z.literal(false),\n error: z.string().min(1).max(DEVICE_PREVIEW_ERROR_MAX_LENGTH),\n }),\n]);\nexport type DevicePreviewStreamRegisterResponse = z.infer<\n typeof DevicePreviewStreamRegisterResponseSchema\n>;\n\nconst DevicePreviewStreamFlowBaseSchema = z.object({\n type: z.literal(\"device_preview_stream_flow\"),\n streamId: IdSchema,\n});\n\nexport const DevicePreviewStreamFlowSchema = z.discriminatedUnion(\"paused\", [\n DevicePreviewStreamFlowBaseSchema.extend({\n paused: z.literal(true),\n resyncRequired: z.literal(false),\n }).strict(),\n DevicePreviewStreamFlowBaseSchema.extend({\n paused: z.literal(false),\n resyncRequired: z.boolean(),\n }).strict(),\n]);\nexport type DevicePreviewStreamFlow = z.infer<typeof DevicePreviewStreamFlowSchema>;\n\nexport const DevicePreviewStreamServerMessageSchema = z.union([\n DevicePreviewStreamRegisterResponseSchema,\n DevicePreviewStreamFlowSchema,\n]);\nexport type DevicePreviewStreamServerMessage = z.infer<\n typeof DevicePreviewStreamServerMessageSchema\n>;\n","import { z } from \"zod\";\n\nexport const VoiceAsrAudioEncodingSchema = z.enum([\"pcm_s16le\", \"mulaw\"]);\n\nexport const VoiceAsrStartMessageSchema = z.object({\n type: z.literal(\"start\"),\n sessionId: z.string().min(1),\n attemptId: z.string().min(1),\n sampleRate: z.number().int().positive(),\n encoding: VoiceAsrAudioEncodingSchema,\n});\n\nexport const VoiceAsrStopMessageSchema = z.object({\n type: z.literal(\"stop\"),\n attemptId: z.string().min(1),\n});\n\nexport const VoiceAsrClientMessageSchema = z.discriminatedUnion(\"type\", [\n VoiceAsrStartMessageSchema,\n VoiceAsrStopMessageSchema,\n]);\n\nexport const VoiceAsrServerMessageSchema = z.discriminatedUnion(\"type\", [\n z.object({ type: z.literal(\"ready\"), attemptId: z.string().min(1) }),\n z.object({\n type: z.literal(\"audio_ack\"),\n attemptId: z.string().min(1),\n encodedBytes: z.number().int().nonnegative(),\n pcmBytes: z.number().int().nonnegative(),\n chunks: z.number().int().nonnegative(),\n }),\n z.object({ type: z.literal(\"partial\"), attemptId: z.string().min(1), text: z.string() }),\n z.object({ type: z.literal(\"final\"), attemptId: z.string().min(1), text: z.string() }),\n z.object({\n type: z.literal(\"closed\"),\n attemptId: z.string().min(1),\n code: z.number().int().optional(),\n reason: z.string().optional(),\n }),\n z.object({\n type: z.literal(\"error\"),\n attemptId: z.string().min(1),\n error: z.string().optional(),\n errorCode: z.string().optional(),\n }),\n]);\n\nexport type VoiceAsrAudioEncoding = z.infer<typeof VoiceAsrAudioEncodingSchema>;\nexport type VoiceAsrStartMessage = z.infer<typeof VoiceAsrStartMessageSchema>;\nexport type VoiceAsrStopMessage = z.infer<typeof VoiceAsrStopMessageSchema>;\nexport type VoiceAsrClientMessage = z.infer<typeof VoiceAsrClientMessageSchema>;\nexport type VoiceAsrServerMessage = z.infer<typeof VoiceAsrServerMessageSchema>;\n","import type { MessageEnvelope } from \"../schemas/envelope.js\";\nimport { MessageEnvelopeSchema } from \"../schemas/envelope.js\";\nimport type { RelayControlMessage } from \"../schemas/relay-control.js\";\nimport { MESSAGE_ENVELOPE_VERSION } from \"../constants/envelope.js\";\n\n// 构建经过 schema 验证的消息信封\n// seq 由调用方提供;session-scoped envelope 应使用该会话单调递增的发送序号。\n// sessionId 仅 session-scoped envelope 携带; 全局广播 (session_list / heartbeat / auth /\n// sync_*) 传 null 或省略, 否则要求合法 ID。\nexport function buildMessage<T extends MessageEnvelope[\"type\"]>(\n type: T,\n sessionId: string | null,\n seq: number,\n payload: Extract<MessageEnvelope, { type: T }>[\"payload\"],\n source: \"proxy\" | \"client\",\n): Extract<MessageEnvelope, { type: T }> {\n const envelope = {\n seq,\n ...(sessionId !== null ? { sessionId } : {}),\n type,\n payload,\n timestamp: Date.now(),\n source,\n version: MESSAGE_ENVELOPE_VERSION,\n };\n return MessageEnvelopeSchema.parse(envelope) as Extract<MessageEnvelope, { type: T }>;\n}\n\n// 序列化 relay control 消息。借助 RelayControlMessage 这个 discriminated union,\n// 调用方传入 { type, ... } 时 TypeScript 会按 type 反查出该消息允许携带的字段集,\n// 替代之前散落的 sendRaw(JSON.stringify({ type: \"...\", ... })) 模式 —— 后者在编译期\n// 完全没有约束,任何字段拼写错误 / 字段漏填都到 wire 上才暴露。\n//\n// 这里没有再做一次 RelayControlSchema.parse(msg):proxy 在热路径每条 envelope 都要发,\n// 重复 zod 解析对吞吐有压力;编译期类型检查已经能挡住大部分错误。\n// 真要做运行时校验时,调用 RelayControlSchema.parse(msg) 再 stringify 即可。\nexport function serializeControl(msg: RelayControlMessage): string {\n return JSON.stringify(msg);\n}\n","import { z } from \"zod\";\nimport { IdSchema } from \"./id.js\";\nimport {\n AgentStatusPayloadSchema,\n createSessionIdentitySchema,\n PtyStatePayloadSchema,\n sessionStateValues,\n TerminalShellFamilySchema,\n} from \"./session.js\";\nimport { ApprovalOptionSchema, ToolApprovePayloadSchema, ToolDenyPayloadSchema } from \"./tool.js\";\nimport {\n VoiceCapabilitiesSchema,\n VoiceConfigUpdateSchema,\n VoiceProviderConfigSchema,\n VoiceSummaryReasonSchema,\n voiceRegionValues,\n} from \"./voice.js\";\nimport { RelayErrorCode } from \"../constants/relay-errors.js\";\nimport { ControlErrorCode } from \"../constants/control-errors.js\";\nimport { providerValues, ptyOwnerValues, sessionModeValues } from \"../constants/enums.js\";\nimport { PTY_INITIAL_MAX_COLS, PTY_INITIAL_MAX_ROWS } from \"../constants/pty.js\";\nimport {\n PreviewHtmlEntriesSchema,\n WebPreviewNameSchema,\n PreviewSummarySchema,\n TunnelProviderSchema,\n WebPreviewCapabilitySchema,\n WebPreviewPathSchema,\n WebPreviewSourceInputSchema,\n} from \"./web-preview.js\";\nimport {\n DevicePreviewCapabilitySchema,\n DevicePreviewH264StreamProfileSchema,\n DevicePreviewInputSchema,\n DevicePreviewJpegStreamProfileSchema,\n DevicePreviewNameSchema,\n DevicePreviewStreamFormatSchema,\n DevicePreviewStreamProfileSchema,\n DevicePreviewStreamStopReasonSchema,\n DevicePreviewSummarySchema,\n DevicePreviewTargetSchema,\n} from \"./device-preview.js\";\nimport { PreviewScopeSchema } from \"./preview-scope.js\";\n\n// Web, Relay 与 Proxy 的控制协议版本。只在握手或消息协议不兼容时递增,\n// 不与任何组件的 npm 版本绑定。\n// 注册、响应和状态推送允许新增非必需的描述字段:接收方校验已知字段并剥离未知字段。\n// 改变必填字段、状态或执行语义仍属于协议变更,不能依赖未知字段被忽略。\nexport const RELAY_CONTROL_PROTOCOL_VERSION = 1 as const;\n\n// 控制消息中复用的子类型\nexport const ProxyInfoSchema = z.object({\n proxyId: IdSchema,\n name: z.string().optional(),\n osName: z.string().min(1).max(64).optional(),\n version: z.string().min(1).max(64),\n online: z.boolean(),\n sessions: z.array(z.string()),\n});\nexport type ProxyInfo = z.infer<typeof ProxyInfoSchema>;\n\nexport const RelayClientInfoSchema = z.object({\n clientId: IdSchema,\n proxyId: IdSchema.optional(),\n connectedAt: z.number().int().nonnegative(),\n current: z.boolean().optional(),\n userAgent: z.string().optional(),\n platform: z.string().optional(),\n maxTouchPoints: z.number().int().nonnegative().optional(),\n browserName: z.string().min(1),\n osName: z.string().min(1),\n deviceKind: z.enum([\"desktop\", \"tablet\", \"phone\", \"unknown\"]),\n remoteAddress: z.string().optional(),\n});\nexport type RelayClientInfo = z.infer<typeof RelayClientInfoSchema>;\n\nexport const AgentCliAvailabilitySchema = z.object({\n available: z.boolean(),\n command: z.string().optional(),\n error: z.string().optional(),\n suggestions: z.array(z.string()).optional(),\n});\nexport type AgentCliAvailability = z.infer<typeof AgentCliAvailabilitySchema>;\n\nexport const AgentCliStatusSchema = z.object({\n claude: AgentCliAvailabilitySchema,\n codex: AgentCliAvailabilitySchema,\n kimi: AgentCliAvailabilitySchema,\n});\nexport type AgentCliStatus = z.infer<typeof AgentCliStatusSchema>;\n\nexport const TerminalShellSchema = z.enum([\"powershell\", \"cmd\"]);\nexport type TerminalShell = z.infer<typeof TerminalShellSchema>;\n\nexport const TerminalShellOptionSchema = z.object({\n id: TerminalShellSchema,\n label: z.string().min(1),\n});\nexport type TerminalShellOption = z.infer<typeof TerminalShellOptionSchema>;\n\nexport const DirEntrySchema = z.object({ name: z.string(), isDir: z.boolean() });\nexport type DirEntry = z.infer<typeof DirEntrySchema>;\n\nexport const FileSystemRootSchema = z.object({ name: z.string(), path: z.string() });\nexport type FileSystemRoot = z.infer<typeof FileSystemRootSchema>;\n\nexport const FileTreeGroupSchema = z.object({\n path: z.string(),\n entries: z.array(DirEntrySchema),\n});\nexport type FileTreeGroup = z.infer<typeof FileTreeGroupSchema>;\n\nexport const CommandEntrySchema = z.object({\n name: z.string(),\n description: z.string(),\n argumentHint: z.string().optional(),\n source: z.string(),\n});\nexport type CommandEntry = z.infer<typeof CommandEntrySchema>;\n\nexport const HistorySessionSchema = z.object({\n id: z.string(),\n title: z.string(),\n projectDir: z.string(),\n updatedAt: z.number(),\n provider: z.enum(providerValues),\n preferredMode: z.enum(sessionModeValues).optional(),\n});\nexport type HistorySession = z.infer<typeof HistorySessionSchema>;\n\nconst SessionHistoryPositionShape = {\n timestamp: z.number().optional(),\n cursor: z.string().optional(),\n};\n\nexport const SessionHistoryMessageSchema = z.discriminatedUnion(\"role\", [\n z.object({\n role: z.enum([\"user\", \"assistant\", \"system\"]),\n text: z.string(),\n ...SessionHistoryPositionShape,\n }),\n z.object({\n role: z.literal(\"activity\"),\n text: z.string(),\n toolId: IdSchema,\n toolName: z.string(),\n parameters: z.record(z.string(), z.unknown()).optional(),\n status: z.enum([\"running\", \"done\", \"error\"]),\n ...SessionHistoryPositionShape,\n }),\n]);\nexport type SessionHistoryMessage = z.infer<typeof SessionHistoryMessageSchema>;\n\ntype RelayControlDirection = \"proxy_to_client\" | \"client_to_proxy\";\ntype EmptyShape = Record<never, never>;\nconst RequestIdShape = { requestId: IdSchema.optional() };\nconst RequiredRequestIdShape = { requestId: IdSchema };\nconst ControlErrorCodeSchema = z.enum(\n Object.values(ControlErrorCode) as [ControlErrorCode, ...ControlErrorCode[]],\n);\nconst RequestErrorShape = {\n error: z.string().optional(),\n errorCode: ControlErrorCodeSchema.optional(),\n};\nconst NoRequestErrorShape = {\n error: z.never().optional(),\n errorCode: z.never().optional(),\n};\nconst RequiredRequestErrorShape = {\n error: z.string().min(1),\n errorCode: ControlErrorCodeSchema,\n};\nconst RemoteFileDispositionSchema = z.enum([\"inline\", \"download\"]);\nconst RemoteFileUploadKindSchema = z.enum([\"clipboard_image\", \"file\"]);\n\ntype ControlDefinition<T extends string, S extends z.ZodRawShape> = {\n type: T;\n directions: ReadonlySet<RelayControlDirection>;\n schema: z.ZodObject<{ type: z.ZodLiteral<T> } & S>;\n};\n\nfunction control<T extends string>(type: T): ControlDefinition<T, EmptyShape>;\nfunction control<T extends string>(\n type: T,\n shape: undefined,\n directions: RelayControlDirection | RelayControlDirection[],\n): ControlDefinition<T, EmptyShape>;\nfunction control<T extends string, S extends z.ZodRawShape>(\n type: T,\n shape: S,\n directions?: RelayControlDirection | RelayControlDirection[],\n): ControlDefinition<T, S>;\nfunction control<T extends string, S extends z.ZodRawShape>(\n type: T,\n shape?: S,\n directions?: RelayControlDirection | RelayControlDirection[],\n): ControlDefinition<T, S | EmptyShape> {\n return {\n type,\n directions: new Set(Array.isArray(directions) ? directions : directions ? [directions] : []),\n schema: z.object({\n type: z.literal(type),\n ...(shape ?? {}),\n }) as z.ZodObject<{ type: z.ZodLiteral<T> } & (S | EmptyShape)>,\n };\n}\n\nfunction strictControl<T extends string, S extends z.ZodRawShape>(\n type: T,\n shape: S,\n directions?: RelayControlDirection | RelayControlDirection[],\n): ControlDefinition<T, S> {\n return {\n type,\n directions: new Set(Array.isArray(directions) ? directions : directions ? [directions] : []),\n schema: z\n .object({\n type: z.literal(type),\n ...shape,\n })\n .strict() as ControlDefinition<T, S>[\"schema\"],\n };\n}\n\nfunction controlSchema<T extends string, S extends z.ZodType>(\n type: T,\n schema: S,\n directions?: RelayControlDirection | RelayControlDirection[],\n): { type: T; directions: ReadonlySet<RelayControlDirection>; schema: S } {\n return {\n type,\n directions: new Set(Array.isArray(directions) ? directions : directions ? [directions] : []),\n schema,\n };\n}\n\nconst ProxySelectResponseSchema = z.discriminatedUnion(\"success\", [\n z.object({\n type: z.literal(\"proxy_select_response\"),\n ...RequestIdShape,\n success: z.literal(true),\n ...NoRequestErrorShape,\n proxyId: IdSchema,\n bindingId: IdSchema,\n }),\n z.object({\n type: z.literal(\"proxy_select_response\"),\n ...RequestIdShape,\n success: z.literal(false),\n proxyId: z.never().optional(),\n bindingId: z.never().optional(),\n ...RequestErrorShape,\n }),\n]);\n\nconst ClientRegisterResponseSchema = z.discriminatedUnion(\"status\", [\n z.object({\n type: z.literal(\"client_register_response\"),\n protocolVersion: z.literal(RELAY_CONTROL_PROTOCOL_VERSION),\n status: z.literal(\"restored\"),\n proxyId: IdSchema,\n bindingId: IdSchema,\n }),\n z.object({\n type: z.literal(\"client_register_response\"),\n protocolVersion: z.literal(RELAY_CONTROL_PROTOCOL_VERSION),\n status: z.literal(\"proxy_offline\"),\n proxyId: IdSchema,\n bindingId: IdSchema,\n }),\n z.object({\n type: z.literal(\"client_register_response\"),\n protocolVersion: z.literal(RELAY_CONTROL_PROTOCOL_VERSION),\n status: z.literal(\"new\"),\n // 已知的绑定字段不能作为扩展信息被忽略;new 状态明确表示尚未绑定。\n proxyId: z.never().optional(),\n bindingId: z.never().optional(),\n }),\n]);\n\nconst PreviewCreateResponseSchema = z.discriminatedUnion(\"accepted\", [\n z.object({\n type: z.literal(\"preview_create_response\"),\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n operationId: IdSchema,\n accepted: z.literal(true),\n ...NoRequestErrorShape,\n previewId: IdSchema,\n }),\n z.object({\n type: z.literal(\"preview_create_response\"),\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n operationId: IdSchema,\n accepted: z.literal(false),\n previewId: z.never().optional(),\n ...RequiredRequestErrorShape,\n }),\n]);\n\nconst DevicePreviewCreateResponseSchema = z.discriminatedUnion(\"accepted\", [\n z.object({\n type: z.literal(\"device_preview_create_response\"),\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n operationId: IdSchema,\n accepted: z.literal(true),\n ...NoRequestErrorShape,\n previewId: IdSchema,\n }),\n z.object({\n type: z.literal(\"device_preview_create_response\"),\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n operationId: IdSchema,\n accepted: z.literal(false),\n previewId: z.never().optional(),\n ...RequiredRequestErrorShape,\n }),\n]);\n\nconst PreviewCapabilityResponseSchema = z.discriminatedUnion(\"success\", [\n z.object({\n type: z.literal(\"preview_capability_response\"),\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n success: z.literal(true),\n ...NoRequestErrorShape,\n capability: WebPreviewCapabilitySchema,\n }),\n z.object({\n type: z.literal(\"preview_capability_response\"),\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n success: z.literal(false),\n capability: z.never().optional(),\n ...RequiredRequestErrorShape,\n }),\n]);\n\nconst DevicePreviewCapabilityResponseSchema = z.discriminatedUnion(\"success\", [\n z.object({\n type: z.literal(\"device_preview_capability_response\"),\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n success: z.literal(true),\n ...NoRequestErrorShape,\n capability: DevicePreviewCapabilitySchema,\n }),\n z.object({\n type: z.literal(\"device_preview_capability_response\"),\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n success: z.literal(false),\n capability: z.never().optional(),\n ...RequiredRequestErrorShape,\n }),\n]);\n\nconst ProxyInfoRequestSchema = z\n .object({\n type: z.literal(\"proxy_info_request\"),\n ...RequestIdShape,\n })\n .strict();\n\nconst ProxyInfoResponseSchema = z.object({\n type: z.literal(\"proxy_info\"),\n ...RequestIdShape,\n homePath: z.string(),\n agentCli: AgentCliStatusSchema,\n terminalShells: z.array(TerminalShellOptionSchema).optional(),\n});\nconst PreviewStaticInspectResponseSchema = z.discriminatedUnion(\"success\", [\n z.object({\n type: z.literal(\"preview_static_inspect_response\"),\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n success: z.literal(true),\n ...NoRequestErrorShape,\n entryPath: WebPreviewPathSchema.optional(),\n htmlEntries: PreviewHtmlEntriesSchema,\n }),\n z.object({\n type: z.literal(\"preview_static_inspect_response\"),\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n success: z.literal(false),\n entryPath: z.never().optional(),\n htmlEntries: z.never().optional(),\n ...RequiredRequestErrorShape,\n }),\n]);\n\nconst PreviewRenameResponseSchema = z.discriminatedUnion(\"success\", [\n z.object({\n type: z.literal(\"preview_rename_response\"),\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n operationId: IdSchema,\n previewId: IdSchema,\n success: z.literal(true),\n ...NoRequestErrorShape,\n }),\n z.object({\n type: z.literal(\"preview_rename_response\"),\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n operationId: IdSchema,\n previewId: IdSchema,\n success: z.literal(false),\n ...RequiredRequestErrorShape,\n }),\n]);\n\nconst PreviewReconnectResponseSchema = z.discriminatedUnion(\"success\", [\n z.object({\n type: z.literal(\"preview_reconnect_response\"),\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n operationId: IdSchema,\n previewId: IdSchema,\n success: z.literal(true),\n ...NoRequestErrorShape,\n }),\n z.object({\n type: z.literal(\"preview_reconnect_response\"),\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n operationId: IdSchema,\n previewId: IdSchema,\n success: z.literal(false),\n ...RequiredRequestErrorShape,\n }),\n]);\n\nconst PreviewCloseResponseSchema = z.discriminatedUnion(\"success\", [\n z.object({\n type: z.literal(\"preview_close_response\"),\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n operationId: IdSchema,\n previewId: IdSchema,\n success: z.literal(true),\n ...NoRequestErrorShape,\n }),\n z.object({\n type: z.literal(\"preview_close_response\"),\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n operationId: IdSchema,\n previewId: IdSchema,\n success: z.literal(false),\n ...RequiredRequestErrorShape,\n }),\n]);\n\nconst DevicePreviewTargetsResponseSchema = z.discriminatedUnion(\"success\", [\n z.object({\n type: z.literal(\"device_preview_targets_response\"),\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n success: z.literal(true),\n ...NoRequestErrorShape,\n targets: z.array(DevicePreviewTargetSchema).max(1_024),\n }),\n z.object({\n type: z.literal(\"device_preview_targets_response\"),\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n success: z.literal(false),\n targets: z.never().optional(),\n ...RequiredRequestErrorShape,\n }),\n]);\n\nconst DevicePreviewRenameResponseSchema = z.discriminatedUnion(\"success\", [\n z.object({\n type: z.literal(\"device_preview_rename_response\"),\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n operationId: IdSchema,\n previewId: IdSchema,\n success: z.literal(true),\n ...NoRequestErrorShape,\n }),\n z.object({\n type: z.literal(\"device_preview_rename_response\"),\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n operationId: IdSchema,\n previewId: IdSchema,\n success: z.literal(false),\n ...RequiredRequestErrorShape,\n }),\n]);\n\nconst DevicePreviewReconnectResponseSchema = z.discriminatedUnion(\"success\", [\n z.object({\n type: z.literal(\"device_preview_reconnect_response\"),\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n operationId: IdSchema,\n previewId: IdSchema,\n success: z.literal(true),\n ...NoRequestErrorShape,\n }),\n z.object({\n type: z.literal(\"device_preview_reconnect_response\"),\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n operationId: IdSchema,\n previewId: IdSchema,\n success: z.literal(false),\n ...RequiredRequestErrorShape,\n }),\n]);\n\nconst DevicePreviewCloseResponseSchema = z.discriminatedUnion(\"success\", [\n z.object({\n type: z.literal(\"device_preview_close_response\"),\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n operationId: IdSchema,\n previewId: IdSchema,\n success: z.literal(true),\n ...NoRequestErrorShape,\n }),\n z.object({\n type: z.literal(\"device_preview_close_response\"),\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n operationId: IdSchema,\n previewId: IdSchema,\n success: z.literal(false),\n ...RequiredRequestErrorShape,\n }),\n]);\n\nconst DevicePreviewStreamUrlResponseSchema = z.discriminatedUnion(\"success\", [\n z.object({\n type: z.literal(\"device_preview_stream_url_response\"),\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n previewId: IdSchema,\n success: z.literal(true),\n ...NoRequestErrorShape,\n url: z.string().min(1).max(4_096),\n leaseId: IdSchema,\n expiresAt: z.number().int().nonnegative(),\n controlMode: z.enum([\"controller\", \"view_only\"]),\n }),\n z.object({\n type: z.literal(\"device_preview_stream_url_response\"),\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n previewId: IdSchema,\n success: z.literal(false),\n url: z.never().optional(),\n leaseId: z.never().optional(),\n expiresAt: z.never().optional(),\n controlMode: z.never().optional(),\n ...RequiredRequestErrorShape,\n }),\n]);\n\nconst DevicePreviewStreamStartResponseBaseShape = {\n type: z.literal(\"device_preview_stream_start_response\"),\n streamId: IdSchema,\n leaseId: IdSchema,\n previewId: IdSchema,\n};\n\nconst DevicePreviewStreamStartSuccessSchema = z\n .object({\n ...DevicePreviewStreamStartResponseBaseShape,\n success: z.literal(true),\n ...NoRequestErrorShape,\n format: DevicePreviewStreamFormatSchema,\n width: z.number().int().positive().max(16_384).optional(),\n height: z.number().int().positive().max(16_384).optional(),\n })\n\n .superRefine((response, context) => {\n if ((response.width === undefined) === (response.height === undefined)) return;\n context.addIssue({\n code: \"custom\",\n path: response.width === undefined ? [\"width\"] : [\"height\"],\n message: \"Device preview stream dimensions must include both width and height\",\n });\n });\n\nconst DevicePreviewStreamStartResponseSchema = z.discriminatedUnion(\"success\", [\n DevicePreviewStreamStartSuccessSchema,\n z.object({\n ...DevicePreviewStreamStartResponseBaseShape,\n success: z.literal(false),\n format: z.never().optional(),\n width: z.never().optional(),\n height: z.never().optional(),\n ...RequiredRequestErrorShape,\n }),\n]);\n\nconst DevicePreviewStreamCompleteSchema = z.object({\n type: z.literal(\"device_preview_stream_complete\"),\n streamId: IdSchema,\n leaseId: IdSchema,\n previewId: IdSchema,\n success: z.literal(false),\n error: z.string().min(1),\n});\nconst DevicePreviewStreamStartBaseShape = {\n type: z.literal(\"device_preview_stream_start\"),\n streamId: IdSchema,\n leaseId: IdSchema,\n previewId: IdSchema,\n};\n\nconst DevicePreviewStreamStartSchema = z.discriminatedUnion(\"format\", [\n z\n .object({\n ...DevicePreviewStreamStartBaseShape,\n ...DevicePreviewJpegStreamProfileSchema.shape,\n })\n .strict(),\n z\n .object({\n ...DevicePreviewStreamStartBaseShape,\n ...DevicePreviewH264StreamProfileSchema.shape,\n })\n .strict(),\n]);\n\nconst DevicePreviewInputAckSchema = z.discriminatedUnion(\"success\", [\n z.object({\n type: z.literal(\"device_preview_input_ack\"),\n scope: PreviewScopeSchema,\n leaseId: IdSchema,\n inputSeq: z.number().int().min(0).max(0xffffffff),\n success: z.literal(true),\n ...NoRequestErrorShape,\n }),\n z.object({\n type: z.literal(\"device_preview_input_ack\"),\n scope: PreviewScopeSchema,\n leaseId: IdSchema,\n inputSeq: z.number().int().min(0).max(0xffffffff),\n success: z.literal(false),\n ...RequiredRequestErrorShape,\n }),\n]);\n\nconst DevicePreviewControlClaimResponseSchema = z.discriminatedUnion(\"success\", [\n z.object({\n type: z.literal(\"device_preview_control_claim_response\"),\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n leaseId: IdSchema,\n success: z.literal(true),\n ...NoRequestErrorShape,\n controlMode: z.literal(\"controller\"),\n }),\n z.object({\n type: z.literal(\"device_preview_control_claim_response\"),\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n leaseId: IdSchema,\n success: z.literal(false),\n controlMode: z.never().optional(),\n ...RequiredRequestErrorShape,\n }),\n]);\n\nconst SessionPermissionModeSchema = z.enum([\n \"default\",\n \"auto\",\n \"acceptEdits\",\n \"plan\",\n \"bypassPermissions\",\n \"dontAsk\",\n]);\n\nconst AgentJsonSessionCreateSchema = z\n .object({\n type: z.literal(\"session_create\"),\n ...RequiredRequestIdShape,\n kind: z.literal(\"agent\"),\n cwd: z.string(),\n name: z.string().optional(),\n provider: z.enum(providerValues),\n mode: z.literal(\"json\"),\n resumeSessionId: z.string().optional(),\n permissionMode: SessionPermissionModeSchema.optional(),\n })\n .strict();\n\nconst AgentPtySessionCreateSchema = z\n .object({\n type: z.literal(\"session_create\"),\n ...RequiredRequestIdShape,\n kind: z.literal(\"agent\"),\n cwd: z.string(),\n name: z.string().optional(),\n provider: z.enum(providerValues),\n mode: z.literal(\"pty\"),\n resumeSessionId: z.string().optional(),\n cols: z.number().int().positive().max(PTY_INITIAL_MAX_COLS),\n rows: z.number().int().positive().max(PTY_INITIAL_MAX_ROWS),\n permissionMode: SessionPermissionModeSchema.optional(),\n })\n .strict();\n\nconst TerminalSessionCreateSchema = z\n .object({\n type: z.literal(\"session_create\"),\n ...RequiredRequestIdShape,\n kind: z.literal(\"terminal\"),\n name: z.string().optional(),\n shell: TerminalShellSchema.optional(),\n mode: z.literal(\"pty\"),\n cols: z.number().int().positive().max(PTY_INITIAL_MAX_COLS),\n rows: z.number().int().positive().max(PTY_INITIAL_MAX_ROWS),\n })\n .strict();\n\nconst SessionCreateSchema = z.discriminatedUnion(\"mode\", [\n AgentJsonSessionCreateSchema,\n z.discriminatedUnion(\"kind\", [AgentPtySessionCreateSchema, TerminalSessionCreateSchema]),\n]);\n\nconst SessionCreateSuccessBaseShape = {\n ...NoRequestErrorShape,\n activeWriterPid: z.never().optional(),\n type: z.literal(\"session_create_response\"),\n ...RequiredRequestIdShape,\n success: z.literal(true),\n sessionId: IdSchema,\n cwd: z.string(),\n lastActive: z.number(),\n name: z.string().optional(),\n nameLocked: z.boolean().optional(),\n};\n\nconst SessionCreateSuccessResponseSchema = z.discriminatedUnion(\"mode\", [\n z.object({\n ...SessionCreateSuccessBaseShape,\n kind: z.literal(\"agent\"),\n mode: z.literal(\"json\"),\n ptyOwner: z.never().optional(),\n provider: z.enum(providerValues),\n }),\n z.discriminatedUnion(\"kind\", [\n z.object({\n ...SessionCreateSuccessBaseShape,\n kind: z.literal(\"agent\"),\n mode: z.literal(\"pty\"),\n provider: z.enum(providerValues),\n ptyOwner: z.enum(ptyOwnerValues),\n }),\n z.object({\n ...SessionCreateSuccessBaseShape,\n kind: z.literal(\"terminal\"),\n mode: z.literal(\"pty\"),\n provider: z.literal(\"claude\"),\n ptyOwner: z.literal(\"proxy-hosted\"),\n shellFamily: TerminalShellFamilySchema.optional(),\n }),\n ]),\n]);\n\nconst SessionCreateResponseSchema = z.discriminatedUnion(\"success\", [\n SessionCreateSuccessResponseSchema,\n z.object({\n type: z.literal(\"session_create_response\"),\n ...RequiredRequestIdShape,\n success: z.literal(false),\n sessionId: z.never().optional(),\n cwd: z.never().optional(),\n lastActive: z.never().optional(),\n name: z.never().optional(),\n nameLocked: z.never().optional(),\n kind: z.never().optional(),\n mode: z.never().optional(),\n provider: z.never().optional(),\n ptyOwner: z.never().optional(),\n ...RequiredRequestErrorShape,\n activeWriterPid: z.number().int().positive().optional(),\n }),\n]);\n\n// 中转服务器控制消息,独立于 MessageEnvelope 的传输层协议\nconst relayControlDefinitions = [\n control(\"proxy_register\", {\n protocolVersion: z.literal(RELAY_CONTROL_PROTOCOL_VERSION),\n proxyId: IdSchema,\n name: z.string().optional(),\n osName: z.string().min(1).max(64).optional(),\n proxyVersion: z.string().min(1).max(64),\n }),\n control(\"proxy_register_response\", {\n protocolVersion: z.literal(RELAY_CONTROL_PROTOCOL_VERSION),\n status: z.enum([\"new\", \"reconnected\"]),\n relayVersion: z.string().min(1).max(64),\n // Relay rotates this nonce for every successful main Proxy registration. The dedicated image\n // stream socket must present it before Relay accepts frames, so a superseded Proxy connection\n // cannot keep publishing into a newly registered Proxy with the same persistent proxyId.\n connectionId: IdSchema,\n }),\n control(\"proxy_list_request\", RequestIdShape),\n control(\"proxy_list_response\", {\n ...RequestIdShape,\n proxies: z.array(ProxyInfoSchema),\n }),\n control(\"proxy_remove\", {\n ...RequiredRequestIdShape,\n proxyId: IdSchema,\n }),\n control(\"proxy_remove_response\", {\n ...RequiredRequestIdShape,\n proxyId: IdSchema,\n success: z.boolean(),\n ...RequestErrorShape,\n }),\n control(\"relay_client_list_request\", RequestIdShape),\n control(\"relay_client_list_response\", {\n ...RequestIdShape,\n clients: z.array(RelayClientInfoSchema),\n }),\n control(\"relay_client_kick\", { ...RequiredRequestIdShape, clientId: IdSchema }),\n control(\"relay_client_kick_response\", {\n ...RequiredRequestIdShape,\n clientId: IdSchema,\n success: z.boolean(),\n ...RequestErrorShape,\n }),\n control(\"relay_client_kicked\", {\n reason: z.string().optional(),\n }),\n control(\"remote_file_url_request\", {\n ...RequiredRequestIdShape,\n sessionId: IdSchema,\n path: z.string().min(1),\n disposition: RemoteFileDispositionSchema,\n }),\n control(\"remote_file_url_response\", {\n ...RequiredRequestIdShape,\n ...RequestErrorShape,\n sessionId: IdSchema,\n path: z.string().optional(),\n success: z.boolean(),\n url: z.string().optional(),\n expiresAt: z.number().int().nonnegative().optional(),\n }),\n control(\"remote_file_metadata_request\", {\n ...RequiredRequestIdShape,\n sessionId: IdSchema,\n path: z.string().min(1),\n }),\n control(\"remote_file_metadata_response\", {\n ...RequiredRequestIdShape,\n ...RequestErrorShape,\n sessionId: IdSchema,\n path: z.string().optional(),\n success: z.boolean(),\n mimeType: z.string().optional(),\n size: z.number().int().nonnegative().optional(),\n fileName: z.string().optional(),\n }),\n control(\"remote_file_stream_request\", {\n streamId: IdSchema,\n sessionId: IdSchema,\n path: z.string().min(1),\n disposition: RemoteFileDispositionSchema,\n }),\n control(\"remote_file_stream_response\", {\n ...RequestErrorShape,\n streamId: IdSchema,\n sessionId: IdSchema,\n success: z.boolean(),\n path: z.string().optional(),\n mimeType: z.string().optional(),\n size: z.number().int().nonnegative().optional(),\n fileName: z.string().optional(),\n }),\n control(\"remote_file_stream_complete\", {\n ...RequestErrorShape,\n streamId: IdSchema,\n success: z.boolean(),\n }),\n control(\"remote_file_stream_cancel\", {\n streamId: IdSchema,\n }),\n control(\"remote_file_upload_url_request\", {\n ...RequiredRequestIdShape,\n sessionId: IdSchema,\n kind: RemoteFileUploadKindSchema,\n fileName: z.string().optional(),\n mimeType: z.string().min(1),\n size: z.number().int().nonnegative().optional(),\n }),\n control(\"remote_file_upload_url_response\", {\n ...RequiredRequestIdShape,\n ...RequestErrorShape,\n sessionId: IdSchema,\n success: z.boolean(),\n uploadUrl: z.string().optional(),\n expiresAt: z.number().int().nonnegative().optional(),\n }),\n control(\"remote_file_upload_stream_request\", {\n uploadId: IdSchema,\n sessionId: IdSchema,\n kind: RemoteFileUploadKindSchema,\n fileName: z.string().optional(),\n mimeType: z.string().min(1),\n size: z.number().int().nonnegative().optional(),\n }),\n control(\"remote_file_upload_stream_complete\", {\n uploadId: IdSchema,\n }),\n control(\"remote_file_upload_stream_cancel\", {\n uploadId: IdSchema,\n }),\n control(\"remote_file_upload_stream_response\", {\n ...RequestErrorShape,\n uploadId: IdSchema,\n sessionId: IdSchema,\n success: z.boolean(),\n path: z.string().optional(),\n }),\n control(\"proxy_select\", { ...RequestIdShape, proxyId: IdSchema }),\n controlSchema(\"proxy_select_response\", ProxySelectResponseSchema),\n control(\"relay_error\", {\n code: z.enum(Object.values(RelayErrorCode) as [RelayErrorCode, ...RelayErrorCode[]]),\n message: z.string(),\n // 可选 requestId: relay 把 client 发来 raw 的 requestId 字段透传回来,\n // client 侧 waitForMessage 据此把对应 pending request 立即拒掉而不必等到 timeout。\n requestId: IdSchema.optional(),\n }),\n\n // Voice Pilot config is relay-local: client reads/updates the relay's stored provider settings.\n control(\"voice_config_request\", RequestIdShape),\n control(\"voice_config_response\", {\n ...RequestIdShape,\n ...RequestErrorShape,\n config: VoiceProviderConfigSchema.optional(),\n }),\n control(\"voice_config_update\", {\n ...RequestIdShape,\n config: VoiceConfigUpdateSchema,\n }),\n control(\"voice_config_update_response\", {\n ...RequestIdShape,\n ...RequestErrorShape,\n success: z.boolean(),\n config: VoiceProviderConfigSchema.optional(),\n }),\n control(\"voice_config_test\", {\n ...RequestIdShape,\n config: VoiceConfigUpdateSchema.optional(),\n }),\n control(\"voice_config_test_response\", {\n ...RequestIdShape,\n ...RequestErrorShape,\n success: z.boolean(),\n audioBase64: z.string().optional(),\n audioSampleRate: z.number().int().positive().optional(),\n audioEncoding: z.literal(\"pcm_s16le\").optional(),\n transcript: z.string().optional(),\n }),\n control(\"voice_capabilities_request\", {\n ...RequestIdShape,\n region: z.enum(voiceRegionValues).optional(),\n }),\n control(\"voice_capabilities_response\", {\n ...RequestIdShape,\n ...RequestErrorShape,\n capabilities: VoiceCapabilitiesSchema.optional(),\n }),\n\n // Lightweight latency probes. These measure synthetic round-trip latency for the transport\n // segments and intentionally stay separate from PTY input echo tracing.\n control(\"latency_web_relay_ping\", RequiredRequestIdShape),\n control(\"latency_web_relay_pong\", {\n ...RequiredRequestIdShape,\n relayNow: z.number().optional(),\n }),\n control(\"latency_relay_proxy_request\", RequiredRequestIdShape),\n control(\"latency_relay_proxy_response\", {\n ...RequiredRequestIdShape,\n success: z.boolean(),\n rttMs: z.number().nonnegative().optional(),\n error: z.string().optional(),\n }),\n control(\"latency_relay_proxy_ping\", {\n ...RequiredRequestIdShape,\n relayNow: z.number().optional(),\n }),\n control(\"latency_relay_proxy_pong\", {\n ...RequiredRequestIdShape,\n proxyNow: z.number().optional(),\n }),\n control(\"latency_web_proxy_ping\", RequiredRequestIdShape, \"client_to_proxy\"),\n control(\n \"latency_web_proxy_pong\",\n { ...RequiredRequestIdShape, proxyNow: z.number().optional() },\n \"proxy_to_client\",\n ),\n\n // Web preview is independent from Agent/terminal sessions. Relay rewrites requestId and routes\n // every response to the exact requesting WebSocket; only the two push messages are broadcast.\n strictControl(\n \"preview_capability_request\",\n {\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n refreshPath: z.boolean(),\n },\n \"client_to_proxy\",\n ),\n controlSchema(\"preview_capability_response\", PreviewCapabilityResponseSchema, \"proxy_to_client\"),\n strictControl(\n \"preview_static_inspect_request\",\n {\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n path: WebPreviewPathSchema,\n },\n \"client_to_proxy\",\n ),\n controlSchema(\n \"preview_static_inspect_response\",\n PreviewStaticInspectResponseSchema,\n \"proxy_to_client\",\n ),\n strictControl(\n \"preview_create_request\",\n {\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n operationId: IdSchema,\n source: WebPreviewSourceInputSchema,\n tunnelProvider: TunnelProviderSchema,\n name: WebPreviewNameSchema.optional(),\n },\n \"client_to_proxy\",\n ),\n controlSchema(\"preview_create_response\", PreviewCreateResponseSchema, \"proxy_to_client\"),\n strictControl(\n \"preview_list_request\",\n { ...RequiredRequestIdShape, scope: PreviewScopeSchema },\n \"client_to_proxy\",\n ),\n control(\n \"preview_list_response\",\n {\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n epoch: IdSchema,\n revision: z.number().int().nonnegative(),\n previews: z.array(PreviewSummarySchema),\n },\n \"proxy_to_client\",\n ),\n strictControl(\n \"preview_rename_request\",\n {\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n operationId: IdSchema,\n previewId: IdSchema,\n name: WebPreviewNameSchema,\n },\n \"client_to_proxy\",\n ),\n controlSchema(\"preview_rename_response\", PreviewRenameResponseSchema, \"proxy_to_client\"),\n strictControl(\n \"preview_reconnect_request\",\n {\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n operationId: IdSchema,\n previewId: IdSchema,\n },\n \"client_to_proxy\",\n ),\n controlSchema(\"preview_reconnect_response\", PreviewReconnectResponseSchema, \"proxy_to_client\"),\n strictControl(\n \"preview_close_request\",\n {\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n operationId: IdSchema,\n previewId: IdSchema,\n },\n \"client_to_proxy\",\n ),\n controlSchema(\"preview_close_response\", PreviewCloseResponseSchema, \"proxy_to_client\"),\n control(\"preview_state_event\", {\n epoch: IdSchema,\n revision: z.number().int().nonnegative(),\n preview: PreviewSummarySchema,\n }),\n control(\"preview_removed_event\", {\n epoch: IdSchema,\n revision: z.number().int().nonnegative(),\n previewId: IdSchema,\n }),\n control(\n \"preview_state_push\",\n {\n scope: PreviewScopeSchema,\n epoch: IdSchema,\n revision: z.number().int().nonnegative(),\n preview: PreviewSummarySchema,\n },\n \"proxy_to_client\",\n ),\n control(\n \"preview_removed_push\",\n {\n scope: PreviewScopeSchema,\n epoch: IdSchema,\n revision: z.number().int().nonnegative(),\n previewId: IdSchema,\n },\n \"proxy_to_client\",\n ),\n\n // Device previews are a sibling of Web previews under the product-level Preview entry, but\n // their data plane is private. Management and input use the authenticated main sockets;\n // JPEG/H.264 frames use `/proxy-stream` plus a one-use HTTP stream URL issued by Relay.\n strictControl(\n \"device_preview_capability_request\",\n {\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n refreshPath: z.boolean(),\n },\n \"client_to_proxy\",\n ),\n controlSchema(\n \"device_preview_capability_response\",\n DevicePreviewCapabilityResponseSchema,\n \"proxy_to_client\",\n ),\n strictControl(\n \"device_preview_targets_request\",\n {\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n refresh: z.boolean(),\n },\n \"client_to_proxy\",\n ),\n controlSchema(\n \"device_preview_targets_response\",\n DevicePreviewTargetsResponseSchema,\n \"proxy_to_client\",\n ),\n strictControl(\n \"device_preview_create_request\",\n {\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n operationId: IdSchema,\n targetId: IdSchema,\n name: DevicePreviewNameSchema.optional(),\n },\n \"client_to_proxy\",\n ),\n controlSchema(\n \"device_preview_create_response\",\n DevicePreviewCreateResponseSchema,\n \"proxy_to_client\",\n ),\n strictControl(\n \"device_preview_list_request\",\n { ...RequiredRequestIdShape, scope: PreviewScopeSchema },\n \"client_to_proxy\",\n ),\n control(\n \"device_preview_list_response\",\n {\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n epoch: IdSchema,\n revision: z.number().int().nonnegative(),\n previews: z.array(DevicePreviewSummarySchema).max(1_024),\n },\n \"proxy_to_client\",\n ),\n strictControl(\n \"device_preview_rename_request\",\n {\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n operationId: IdSchema,\n previewId: IdSchema,\n name: DevicePreviewNameSchema,\n },\n \"client_to_proxy\",\n ),\n controlSchema(\n \"device_preview_rename_response\",\n DevicePreviewRenameResponseSchema,\n \"proxy_to_client\",\n ),\n strictControl(\n \"device_preview_reconnect_request\",\n {\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n operationId: IdSchema,\n previewId: IdSchema,\n },\n \"client_to_proxy\",\n ),\n controlSchema(\n \"device_preview_reconnect_response\",\n DevicePreviewReconnectResponseSchema,\n \"proxy_to_client\",\n ),\n strictControl(\n \"device_preview_close_request\",\n {\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n operationId: IdSchema,\n previewId: IdSchema,\n },\n \"client_to_proxy\",\n ),\n controlSchema(\n \"device_preview_close_response\",\n DevicePreviewCloseResponseSchema,\n \"proxy_to_client\",\n ),\n control(\"device_preview_state_event\", {\n epoch: IdSchema,\n revision: z.number().int().nonnegative(),\n preview: DevicePreviewSummarySchema,\n }),\n control(\"device_preview_removed_event\", {\n epoch: IdSchema,\n revision: z.number().int().nonnegative(),\n previewId: IdSchema,\n }),\n control(\n \"device_preview_state_push\",\n {\n scope: PreviewScopeSchema,\n epoch: IdSchema,\n revision: z.number().int().nonnegative(),\n preview: DevicePreviewSummarySchema,\n },\n \"proxy_to_client\",\n ),\n control(\n \"device_preview_removed_push\",\n {\n scope: PreviewScopeSchema,\n epoch: IdSchema,\n revision: z.number().int().nonnegative(),\n previewId: IdSchema,\n },\n \"proxy_to_client\",\n ),\n strictControl(\"device_preview_stream_url_request\", {\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n previewId: IdSchema,\n profile: DevicePreviewStreamProfileSchema,\n }),\n controlSchema(\"device_preview_stream_url_response\", DevicePreviewStreamUrlResponseSchema),\n controlSchema(\"device_preview_stream_start\", DevicePreviewStreamStartSchema),\n controlSchema(\"device_preview_stream_start_response\", DevicePreviewStreamStartResponseSchema),\n strictControl(\"device_preview_stream_stop\", {\n streamId: IdSchema,\n reason: DevicePreviewStreamStopReasonSchema,\n }),\n controlSchema(\"device_preview_stream_complete\", DevicePreviewStreamCompleteSchema),\n strictControl(\n \"device_preview_input\",\n {\n scope: PreviewScopeSchema,\n leaseId: IdSchema,\n inputSeq: z.number().int().min(0).max(0xffffffff),\n input: DevicePreviewInputSchema,\n },\n \"client_to_proxy\",\n ),\n controlSchema(\"device_preview_input_ack\", DevicePreviewInputAckSchema, \"proxy_to_client\"),\n // Relay-internal ordering barrier. It is deliberately absent from both public direction sets:\n // browsers cannot abort another viewer's queued input, and Proxy never sends it to browsers.\n strictControl(\"device_preview_input_revoke\", {\n leaseId: IdSchema,\n reason: z.literal(\"control_taken_over\"),\n }),\n strictControl(\"device_preview_control_claim_request\", {\n ...RequiredRequestIdShape,\n scope: PreviewScopeSchema,\n leaseId: IdSchema,\n }),\n controlSchema(\"device_preview_control_claim_response\", DevicePreviewControlClaimResponseSchema),\n control(\"device_preview_control_revoked_push\", {\n scope: PreviewScopeSchema,\n leaseId: IdSchema,\n reason: z.enum([\"taken_over\", \"stream_closed\", \"proxy_offline\", \"lease_expired\"]),\n }),\n\n // 客户端注册协议\n control(\"client_register\", {\n protocolVersion: z.literal(RELAY_CONTROL_PROTOCOL_VERSION),\n clientId: IdSchema,\n userAgent: z.string().optional(),\n platform: z.string().optional(),\n maxTouchPoints: z.number().int().nonnegative().optional(),\n browserName: z.string().min(1),\n osName: z.string().min(1),\n deviceKind: z.enum([\"desktop\", \"tablet\", \"phone\", \"unknown\"]),\n }),\n controlSchema(\"client_register_response\", ClientRegisterResponseSchema),\n\n // Proxy 离线通知\n control(\"proxy_offline\", {\n proxyId: IdSchema,\n }),\n\n // 用户明确删除了离线 Proxy。与列表暂时缺项分开建模,客户端据此永久清理选择态。\n control(\"proxy_removed\", {\n proxyId: IdSchema,\n }),\n\n // Proxy 主动断开,relay 立即清理资源\n control(\"proxy_disconnect\", {\n proxyId: IdSchema,\n }),\n\n // Proxy 重连后通知 client 恢复\n control(\"proxy_online\", {\n proxyId: IdSchema,\n }),\n\n strictControl(\"filesystem_roots_request\", { ...RequestIdShape }, \"client_to_proxy\"),\n control(\n \"filesystem_roots_response\",\n {\n ...RequestIdShape,\n ...RequestErrorShape,\n roots: z.array(FileSystemRootSchema),\n },\n \"proxy_to_client\",\n ),\n\n // 目录列表请求与响应\n strictControl(\n \"dir_list_request\",\n {\n ...RequestIdShape,\n path: z.string(),\n includeHidden: z.boolean(),\n },\n \"client_to_proxy\",\n ),\n control(\n \"dir_list_response\",\n {\n ...RequestIdShape,\n ...RequestErrorShape,\n entries: z.array(DirEntrySchema),\n path: z.string(),\n includeHidden: z.boolean(),\n },\n \"proxy_to_client\",\n ),\n\n // 目录创建请求与响应\n control(\"dir_create_request\", { ...RequestIdShape, path: z.string() }, \"client_to_proxy\"),\n control(\n \"dir_create_response\",\n {\n ...RequestIdShape,\n ...RequestErrorShape,\n path: z.string(),\n success: z.boolean(),\n },\n \"proxy_to_client\",\n ),\n\n // 命令列表推送,proxy 将可用命令列表推给 client\n control(\n \"command_list_push\",\n {\n sessionId: IdSchema,\n commands: z.array(CommandEntrySchema),\n },\n \"proxy_to_client\",\n ),\n\n // 文件树推送: 按目录分组, 首组 path 即为 session cwd。\n // 前端把它写入普通目录树;includeHidden=true 的按需响应使用独立缓存。\n control(\n \"file_tree_push\",\n {\n groups: z.array(FileTreeGroupSchema),\n },\n \"proxy_to_client\",\n ),\n\n // 会话列表请求与权限模式变更\n strictControl(\"session_list_request\", {}, \"client_to_proxy\"),\n control(\n \"permission_mode_change\",\n {\n mode: z.enum([\"default\", \"auto_accept\", \"plan\"]),\n // sessionId 可选:传入时 proxy 按该会话的 mode 分叉(PTY 发 Tab ANSI),未传走全局日志行为\n sessionId: IdSchema.optional(),\n },\n \"client_to_proxy\",\n ),\n\n // 会话历史浏览\n control(\"session_history_request\", RequiredRequestIdShape, \"client_to_proxy\"),\n control(\n \"session_history_response\",\n {\n ...RequiredRequestIdShape,\n ...RequestErrorShape,\n success: z.boolean(),\n sessions: z.array(HistorySessionSchema),\n },\n \"proxy_to_client\",\n ),\n\n // PTY 语义状态,从 Envelope 迁移到 Control 层\n control(\"pty_state\", { sessionId: IdSchema, payload: PtyStatePayloadSchema }, \"proxy_to_client\"),\n\n // Provider 语义状态,来自 Claude/Codex hook 等结构化事件,不从 PTY 字节推断\n control(\n \"agent_status\",\n { sessionId: IdSchema, payload: AgentStatusPayloadSchema },\n \"proxy_to_client\",\n ),\n\n // 终端标题变化,proxy -> client\n control(\"terminal_title\", { sessionId: IdSchema, title: z.string() }, \"proxy_to_client\"),\n\n // 终端尺寸变化,proxy -> client\n control(\n \"terminal_resize\",\n {\n sessionId: IdSchema,\n cols: z.number().int().positive(),\n rows: z.number().int().positive(),\n // PTY output and resize events share one ordered render sequence. The client can therefore\n // place a resize between the exact byte frames that preceded and followed it.\n outputSeq: z.number().int().nonnegative(),\n },\n \"proxy_to_client\",\n ),\n control(\n \"terminal_resize_request\",\n { sessionId: IdSchema, cols: z.number().int().positive(), rows: z.number().int().positive() },\n \"client_to_proxy\",\n ),\n\n // 远程终止 JSON 会话,client -> proxy\n strictControl(\"session_terminate\", { sessionId: IdSchema }, \"client_to_proxy\"),\n control(\n \"session_rename\",\n { ...RequestIdShape, sessionId: IdSchema, name: z.string() },\n \"client_to_proxy\",\n ),\n control(\n \"session_rename_response\",\n {\n ...RequestIdShape,\n sessionId: IdSchema,\n success: z.boolean(),\n name: z.string().optional(),\n ...RequestErrorShape,\n },\n \"proxy_to_client\",\n ),\n\n // 中断当前 turn,client -> proxy;JSON 由 session-worker 打断 Claude 子进程并保留会话。\n control(\"session_worker_abort\", { sessionId: IdSchema }, \"client_to_proxy\"),\n\n // turn 完成信号,proxy -> client,对应 claude stream-json 的 result 事件\n control(\n \"turn_result\",\n {\n sessionId: IdSchema,\n success: z.boolean(),\n isError: z.boolean(),\n // stream-json result.result 是本轮最终文本。assistant_message 流丢失或 CLI 未发增量时,\n // Web 用它作为 JSON 模式兜底展示,避免 turn 已结束但界面空白。\n result: z.string().optional(),\n },\n \"proxy_to_client\",\n ),\n\n // 客户端发送到 PTY 的原始字节(ANSI 序列),不追加换行\n control(\n \"remote_input_raw\",\n { sessionId: IdSchema, data: z.string(), traceId: IdSchema.optional() },\n \"client_to_proxy\",\n ),\n // 客户端询问 proxy 的环境信息 (home 路径等), client -> proxy -> response\n // FilePathPicker 用 homePath 作为 select 模式下的默认起点, 新建会话时打开即可浏览\n controlSchema(\"proxy_info_request\", ProxyInfoRequestSchema, \"client_to_proxy\"),\n controlSchema(\"proxy_info\", ProxyInfoResponseSchema, \"proxy_to_client\"),\n control(\n \"agent_cli_config_update\",\n { ...RequestIdShape, provider: z.enum(providerValues), path: z.string().min(1) },\n \"client_to_proxy\",\n ),\n control(\n \"agent_cli_config_update_response\",\n {\n ...RequestIdShape,\n provider: z.enum(providerValues),\n agentCli: AgentCliStatusSchema.optional(),\n ...RequestErrorShape,\n },\n \"proxy_to_client\",\n ),\n\n // 远程创建会话,client -> proxy -> response。PTY 初始几何是一次性的;\n // 创建后尺寸由会话端持有,浏览器刷新、重连或换设备不重排既有内容。\n controlSchema(\"session_create\", SessionCreateSchema, \"client_to_proxy\"),\n controlSchema(\"session_create_response\", SessionCreateResponseSchema, \"proxy_to_client\"),\n\n // 会话创建响应已经成功返回、页面已进入终端后,Provider 仍可能在 bootstrap 阶段\n // 非零退出。把可识别的运行时错误结构化推给 Web,避免关键错误只留在终端闪屏里。\n control(\n \"session_runtime_error\",\n {\n sessionId: IdSchema,\n error: z.string(),\n errorCode: ControlErrorCodeSchema,\n activeWriterPid: z.number().int().positive().optional(),\n },\n \"proxy_to_client\",\n ),\n\n // 客户端请求会话历史消息,client -> proxy\n control(\n \"session_messages_request\",\n {\n ...RequestIdShape,\n sessionId: IdSchema,\n limit: z.number().int().min(1).max(200).optional(),\n before: z.string().optional(),\n },\n \"client_to_proxy\",\n ),\n\n // 客户端请求会话资源(命令列表 + 文件树),client -> proxy\n control(\n \"session_resources_request\",\n { ...RequiredRequestIdShape, sessionId: IdSchema },\n \"client_to_proxy\",\n ),\n control(\n \"session_resources_response\",\n {\n ...RequiredRequestIdShape,\n ...RequestErrorShape,\n sessionId: IdSchema,\n commands: z.array(CommandEntrySchema),\n groups: z.array(FileTreeGroupSchema),\n },\n \"proxy_to_client\",\n ),\n\n // 客户端请求当前 provider 语义状态;不经 relay 缓存,由 proxy 返回当前值\n control(\n \"agent_status_request\",\n { ...RequestIdShape, sessionId: IdSchema.optional() },\n \"client_to_proxy\",\n ),\n control(\n \"agent_status_response\",\n {\n ...RequestIdShape,\n statuses: z.array(z.object({ sessionId: IdSchema, payload: AgentStatusPayloadSchema })),\n },\n \"proxy_to_client\",\n ),\n\n // 客户端确认已收到审批请求;proxy 只记录送达状态,不把它当成用户决策\n control(\n \"permission_request_delivered\",\n { sessionId: IdSchema, requestId: IdSchema },\n \"client_to_proxy\",\n ),\n control(\n \"tool_approve\",\n { sessionId: IdSchema, payload: ToolApprovePayloadSchema },\n \"client_to_proxy\",\n ),\n control(\"tool_deny\", { sessionId: IdSchema, payload: ToolDenyPayloadSchema }, \"client_to_proxy\"),\n\n // proxy 确认用户决策已进入 provider/worker 路径;web 用它更新审批卡片状态\n control(\n \"permission_decision_result\",\n {\n sessionId: IdSchema,\n requestId: IdSchema,\n outcome: z.enum([\"allow\", \"deny\"]),\n delivered: z.boolean(),\n message: z.string().optional(),\n },\n \"proxy_to_client\",\n ),\n\n // proxy 推送当前 pending 的工具审批列表,client 据此恢复审批卡片\n control(\n \"pending_approvals_push\",\n {\n sessionId: IdSchema,\n approvals: z.array(\n z.object({\n requestId: IdSchema,\n toolName: z.string(),\n input: z.record(z.string(), z.unknown()),\n options: z.array(ApprovalOptionSchema).optional(),\n }),\n ),\n },\n \"proxy_to_client\",\n ),\n\n // Voice Pilot speech summaries are produced by proxy-side Claude Code so it can read project context.\n control(\n \"voice_summary_request\",\n {\n ...RequestIdShape,\n sessionId: IdSchema,\n messageId: IdSchema,\n text: z.string().min(1),\n reason: VoiceSummaryReasonSchema,\n },\n \"client_to_proxy\",\n ),\n control(\n \"voice_summary_response\",\n {\n ...RequestIdShape,\n ...RequestErrorShape,\n sessionId: IdSchema,\n messageId: IdSchema,\n success: z.boolean(),\n summary: z.string().min(1).optional(),\n },\n \"proxy_to_client\",\n ),\n\n // 恢复会话时推送历史消息,proxy -> client\n control(\n \"session_history_messages\",\n {\n ...RequestIdShape,\n sessionId: IdSchema,\n before: z.string().optional(),\n messages: z.array(SessionHistoryMessageSchema),\n hasMore: z.boolean().optional(),\n nextBefore: z.string().optional(),\n },\n \"proxy_to_client\",\n ),\n\n // proxy 重连后同步活跃 session 列表给 relay。session_sync 由 relay 自消费(更新 proxy-session\n // 关联)不转发给 client,因此**没有** direction 标注——RelayControlDirection 只描述转发流。\n control(\"session_sync\", {\n sessions: z.array(\n createSessionIdentitySchema({\n id: z.string(),\n cwd: z.string(),\n name: z.string().optional(),\n nameLocked: z.boolean().optional(),\n state: z.enum(sessionStateValues),\n }),\n ),\n }),\n\n // PTY 会话订阅,client -> proxy,触发 terminal serialize() 返回当前状态\n control(\"session_subscribe\", { sessionId: IdSchema, requestId: IdSchema }, \"client_to_proxy\"),\n\n // PTY 会话快照,proxy -> client,serialize() 的全量终端状态\n control(\n \"session_snapshot\",\n {\n sessionId: IdSchema,\n cols: z.number().int().positive(),\n rows: z.number().int().positive(),\n data: z.string(),\n outputSeq: z.number().int().nonnegative(),\n requestId: IdSchema,\n },\n \"proxy_to_client\",\n ),\n] as const;\n\nconst relayControlSchemas = relayControlDefinitions.map((definition) => definition.schema) as [\n (typeof relayControlDefinitions)[number][\"schema\"],\n ...Array<(typeof relayControlDefinitions)[number][\"schema\"]>,\n];\n\nexport const RelayControlSchema = z.discriminatedUnion(\"type\", relayControlSchemas);\n\nexport type RelayControlMessage = z.infer<typeof RelayControlSchema>;\nexport type RelayControlType = RelayControlMessage[\"type\"];\n\nexport const ProxyToClientRelayControlTypes = new Set(\n relayControlDefinitions\n .filter((definition) => definition.directions.has(\"proxy_to_client\"))\n .map((definition) => definition.type),\n);\n\nexport function isProxyToClientRelayControlType(type: RelayControlType): boolean {\n return ProxyToClientRelayControlTypes.has(type);\n}\n\nexport const ClientToProxyRelayControlTypes = new Set(\n relayControlDefinitions\n .filter((definition) => definition.directions.has(\"client_to_proxy\"))\n .map((definition) => definition.type),\n);\n\nexport function isClientToProxyRelayControlType(type: RelayControlType): boolean {\n return ClientToProxyRelayControlTypes.has(type);\n}\n","// relay 实际发出的 6 个错误码。schema 侧 RelayControlSchema.relay_error.code 用 z.enum 收紧,\n// handler 侧用这个常量引用避免裸字面量拼错。\nexport const RelayErrorCode = {\n NOT_REGISTERED: \"NOT_REGISTERED\",\n NOT_BOUND: \"NOT_BOUND\",\n PROXY_OFFLINE: \"PROXY_OFFLINE\",\n INVALID_MESSAGE: \"INVALID_MESSAGE\",\n STALE_BINDING: \"STALE_BINDING\",\n UNSUPPORTED: \"UNSUPPORTED\",\n INVALID_RANGE: \"INVALID_RANGE\",\n} as const;\n\nexport type RelayErrorCode = (typeof RelayErrorCode)[keyof typeof RelayErrorCode];\n","export const ControlErrorCode = {\n INVALID_PATH: \"INVALID_PATH\",\n PATH_NOT_FOUND: \"PATH_NOT_FOUND\",\n PATH_NOT_DIRECTORY: \"PATH_NOT_DIRECTORY\",\n PATH_ACCESS_DENIED: \"PATH_ACCESS_DENIED\",\n PROXY_OFFLINE: \"PROXY_OFFLINE\",\n PROXY_NOT_FOUND: \"PROXY_NOT_FOUND\",\n PROXY_ONLINE: \"PROXY_ONLINE\",\n SESSION_NOT_FOUND: \"SESSION_NOT_FOUND\",\n SESSION_ALREADY_ACTIVE: \"SESSION_ALREADY_ACTIVE\",\n PROVIDER_UNSUPPORTED: \"PROVIDER_UNSUPPORTED\",\n APPROVAL_POLICY_UNSUPPORTED: \"APPROVAL_POLICY_UNSUPPORTED\",\n WORKER_START_FAILED: \"WORKER_START_FAILED\",\n PROCESS_START_FAILED: \"PROCESS_START_FAILED\",\n STREAM_CAPACITY_EXCEEDED: \"STREAM_CAPACITY_EXCEEDED\",\n CONTROL_LEASE_INVALID: \"CONTROL_LEASE_INVALID\",\n OPERATION_CONFLICT: \"OPERATION_CONFLICT\",\n RATE_LIMITED: \"RATE_LIMITED\",\n UNKNOWN: \"UNKNOWN\",\n} as const;\n\nexport type ControlErrorCode = (typeof ControlErrorCode)[keyof typeof ControlErrorCode];\n","// Session creation is a two-sided deadline contract. The proxy must finish startup and\n// respond before its deadline; the browser waits a little longer so the failure response\n// can cross the relay instead of racing an equal local timeout.\nexport const SESSION_CREATE_SERVER_DEADLINE_MS = 30_000;\nexport const SESSION_CREATE_RESPONSE_GRACE_MS = 5_000;\nexport const SESSION_CREATE_CLIENT_TIMEOUT_MS =\n SESSION_CREATE_SERVER_DEADLINE_MS + SESSION_CREATE_RESPONSE_GRACE_MS;\n","// WebSocket close codes in the private 4000-4999 range.\nexport const RelayCloseCode = {\n CLIENT_KICKED: 4401,\n CLIENT_PROTOCOL_REJECTED: 4402,\n DEVICE_STREAM_PROTOCOL_REJECTED: 4403,\n DEVICE_STREAM_BINDING_REJECTED: 4404,\n PROXY_PROTOCOL_REJECTED: 4405,\n} as const;\n\n// Stable machine-readable reasons used by the HTTP/WS admission layer. They intentionally live\n// outside the versioned Relay business-message schema so incompatible peers can still explain\n// which side needs updating.\nexport const RelayProtocolRejectReason = {\n PAGE_OUTDATED: \"page_outdated\",\n SERVICE_OUTDATED: \"service_outdated\",\n PROTOCOL_MISMATCH: \"protocol_mismatch\",\n} as const;\n\nexport type RelayProtocolRejectReasonType =\n (typeof RelayProtocolRejectReason)[keyof typeof RelayProtocolRejectReason];\n\n// Proxy <-> Relay admission is intentionally separate from the Web client admission reasons\n// above. These values are carried as WebSocket close reasons, before either side may safely parse\n// the versioned RelayControl schema.\nexport const ProxyProtocolAdmissionDirection = {\n COMPATIBLE: \"compatible\",\n PROXY_OUTDATED: \"proxy_outdated\",\n RELAY_OUTDATED: \"relay_outdated\",\n PROTOCOL_MISMATCH: \"protocol_mismatch\",\n} as const;\n\nexport type ProxyProtocolAdmissionDirectionType =\n (typeof ProxyProtocolAdmissionDirection)[keyof typeof ProxyProtocolAdmissionDirection];\n\nexport type ProxyProtocolRejectDirection = Exclude<\n ProxyProtocolAdmissionDirectionType,\n typeof ProxyProtocolAdmissionDirection.COMPATIBLE\n>;\n\nfunction isPositiveSafeProtocolVersion(value: unknown): value is number {\n return Number.isSafeInteger(value) && (value as number) > 0;\n}\n\n/**\n * The sole ordering rule for Proxy <-> Relay control-protocol admission.\n *\n * Invalid or absent inputs deliberately fail closed instead of being ordered. Callers must not\n * infer upgrade direction from package versions or from versioned business-message parse errors.\n */\nexport function compareProxyRelayProtocolVersions(\n proxyProtocolVersion: unknown,\n relayProtocolVersion: unknown,\n): ProxyProtocolAdmissionDirectionType {\n if (\n !isPositiveSafeProtocolVersion(proxyProtocolVersion) ||\n !isPositiveSafeProtocolVersion(relayProtocolVersion)\n ) {\n return ProxyProtocolAdmissionDirection.PROTOCOL_MISMATCH;\n }\n if (proxyProtocolVersion === relayProtocolVersion) {\n return ProxyProtocolAdmissionDirection.COMPATIBLE;\n }\n return proxyProtocolVersion < relayProtocolVersion\n ? ProxyProtocolAdmissionDirection.PROXY_OUTDATED\n : ProxyProtocolAdmissionDirection.RELAY_OUTDATED;\n}\n\nexport function isProxyProtocolRejectDirection(\n value: unknown,\n): value is ProxyProtocolRejectDirection {\n return (\n value === ProxyProtocolAdmissionDirection.PROXY_OUTDATED ||\n value === ProxyProtocolAdmissionDirection.RELAY_OUTDATED ||\n value === ProxyProtocolAdmissionDirection.PROTOCOL_MISMATCH\n );\n}\n","// WebSocket wire limits shared by relay and proxy.\n//\n// PTY initial snapshots use JSON control messages because xterm serialize()\n// returns ANSI text. A long 5000-line scrollback can legitimately exceed 1 MiB,\n// so the JSON cap must cover terminal snapshots while still bounding parse cost.\nexport const RELAY_JSON_MESSAGE_MAX_BYTES = 8 * 1024 * 1024;\n\n// Raw PTY output and remote-file chunks use binary frames. Keep this aligned\n// with the relay-side frame guard.\nexport const RELAY_BINARY_FRAME_MAX_BYTES = 10 * 1024 * 1024;\n","// PTY binary 帧 wire 格式(跨 proxy / relay / web 三方通用):\n// [1B sessionId_len][sessionId UTF-8][4B outputSeq uint32LE][PTY data]\n// 任一方手写偏移量都极易在协议演进时漂移,统一走这里编/解码避免分叉。\n//\n// 用 Uint8Array 而非 Buffer:shared 包必须可以在浏览器构建里跑,\n// 不能依赖 Node-only 的 Buffer 全局。Node 调用方拿到的也是 Uint8Array\n// (Buffer 是 Uint8Array 的子类,反向兼容),传给 ws.send 等 API 没问题。\n\nexport interface DecodedBinaryFrame {\n sessionId: string;\n outputSeq: number;\n data: Uint8Array;\n}\n\nexport interface DecodedFileStreamFrame {\n streamId: string;\n chunkSeq: number;\n data: Uint8Array;\n}\n\nconst SID_LEN_BYTES = 1;\nconst SEQ_BYTES = 4;\nconst HEADER_FIXED_BYTES = SID_LEN_BYTES + SEQ_BYTES;\nconst FILE_STREAM_MARKER = 0;\nconst FILE_STREAM_ID_LEN_BYTES = 1;\nconst FILE_STREAM_HEADER_FIXED_BYTES = 1 /* marker */ + FILE_STREAM_ID_LEN_BYTES + SEQ_BYTES;\n\nexport function encodeBinaryFrame(\n sessionId: string,\n outputSeq: number,\n data: Uint8Array,\n): Uint8Array {\n const sidBytes = new TextEncoder().encode(sessionId);\n if (sidBytes.length === 0 || sidBytes.length > 255) {\n throw new RangeError(\n `sessionId byte length must be 1-255, got ${sidBytes.length} (sessionId=${sessionId})`,\n );\n }\n if (!Number.isInteger(outputSeq) || outputSeq < 0 || outputSeq > 0xffffffff) {\n throw new RangeError(`outputSeq must be a uint32, got ${outputSeq}`);\n }\n\n const frame = new Uint8Array(SID_LEN_BYTES + sidBytes.length + SEQ_BYTES + data.length);\n frame[0] = sidBytes.length;\n frame.set(sidBytes, SID_LEN_BYTES);\n const seqOffset = SID_LEN_BYTES + sidBytes.length;\n // little-endian 与 Node 端 Buffer.writeUInt32LE / 浏览器 DataView setUint32(_, _, true) 保持一致\n new DataView(frame.buffer, frame.byteOffset + seqOffset, SEQ_BYTES).setUint32(0, outputSeq, true);\n frame.set(data, seqOffset + SEQ_BYTES);\n return frame;\n}\n\n// 解码失败一律返回 null,调用方按业务诉求决定是丢帧还是关连接。\nexport function decodeBinaryFrame(view: Uint8Array): DecodedBinaryFrame | null {\n if (view.length < SID_LEN_BYTES + SEQ_BYTES) return null;\n const sidLen = view[0];\n if (sidLen === 0) return null;\n if (view.length < SID_LEN_BYTES + sidLen + SEQ_BYTES) return null;\n\n const sessionId = new TextDecoder().decode(view.subarray(SID_LEN_BYTES, SID_LEN_BYTES + sidLen));\n const seqOffset = SID_LEN_BYTES + sidLen;\n const outputSeq = new DataView(view.buffer, view.byteOffset + seqOffset, SEQ_BYTES).getUint32(\n 0,\n true,\n );\n const data = view.subarray(seqOffset + SEQ_BYTES);\n return { sessionId, outputSeq, data };\n}\n\n// 帧头长度(不含 payload data):调用方在做 chunk 拆分 / 估算缓冲时用得到。\nexport function binaryFrameHeaderLength(sessionId: string): number {\n const sidBytes = new TextEncoder().encode(sessionId);\n return HEADER_FIXED_BYTES + sidBytes.length;\n}\n\nexport function encodeFileStreamFrame(\n streamId: string,\n chunkSeq: number,\n data: Uint8Array,\n): Uint8Array {\n const streamIdBytes = new TextEncoder().encode(streamId);\n if (streamIdBytes.length === 0 || streamIdBytes.length > 255) {\n throw new RangeError(\n `streamId byte length must be 1-255, got ${streamIdBytes.length} (streamId=${streamId})`,\n );\n }\n if (!Number.isInteger(chunkSeq) || chunkSeq < 0 || chunkSeq > 0xffffffff) {\n throw new RangeError(`chunkSeq must be a uint32, got ${chunkSeq}`);\n }\n\n const frame = new Uint8Array(\n 1 + FILE_STREAM_ID_LEN_BYTES + streamIdBytes.length + SEQ_BYTES + data.length,\n );\n frame[0] = FILE_STREAM_MARKER;\n frame[1] = streamIdBytes.length;\n frame.set(streamIdBytes, 1 + FILE_STREAM_ID_LEN_BYTES);\n const seqOffset = 1 + FILE_STREAM_ID_LEN_BYTES + streamIdBytes.length;\n new DataView(frame.buffer, frame.byteOffset + seqOffset, SEQ_BYTES).setUint32(0, chunkSeq, true);\n frame.set(data, seqOffset + SEQ_BYTES);\n return frame;\n}\n\nexport function decodeFileStreamFrame(view: Uint8Array): DecodedFileStreamFrame | null {\n if (view.length < FILE_STREAM_HEADER_FIXED_BYTES) return null;\n if (view[0] !== FILE_STREAM_MARKER) return null;\n const streamIdLen = view[1];\n if (streamIdLen === 0) return null;\n if (view.length < 1 + FILE_STREAM_ID_LEN_BYTES + streamIdLen + SEQ_BYTES) return null;\n\n const streamId = new TextDecoder().decode(\n view.subarray(1 + FILE_STREAM_ID_LEN_BYTES, 1 + FILE_STREAM_ID_LEN_BYTES + streamIdLen),\n );\n const seqOffset = 1 + FILE_STREAM_ID_LEN_BYTES + streamIdLen;\n const chunkSeq = new DataView(view.buffer, view.byteOffset + seqOffset, SEQ_BYTES).getUint32(\n 0,\n true,\n );\n const data = view.subarray(seqOffset + SEQ_BYTES);\n return { streamId, chunkSeq, data };\n}\n\nexport function fileStreamFrameHeaderLength(streamId: string): number {\n const streamIdBytes = new TextEncoder().encode(streamId);\n return FILE_STREAM_HEADER_FIXED_BYTES + streamIdBytes.length;\n}\n","// Dedicated Proxy stream WebSocket frame:\n// [1B streamId byte length][streamId UTF-8][4B frame sequence uint32LE][JPEG bytes]\n//\n// Device frames intentionally do not share the main PTY WebSocket. Keeping a separate codec makes\n// it impossible for Relay/Web to accidentally treat image bytes as terminal output.\n\nconst STREAM_ID_LENGTH_BYTES = 1;\nconst FRAME_SEQUENCE_BYTES = 4;\nconst STREAM_FRAME_FIXED_HEADER_BYTES = STREAM_ID_LENGTH_BYTES + FRAME_SEQUENCE_BYTES;\nexport const DEVICE_PREVIEW_FRAME_MAX_BYTES = 2 * 1024 * 1024;\n\nconst H264_PACKET_SENTINEL_BYTES = 1;\nconst H264_PACKET_VERSION_BYTES = 1;\nconst H264_PACKET_FLAGS_BYTES = 1;\nconst H264_PACKET_DURATION_BYTES = 2;\nconst H264_PACKET_PAYLOAD_LENGTH_BYTES = 4;\nconst H264_PROXY_STREAM_ID_LENGTH_OFFSET =\n H264_PACKET_SENTINEL_BYTES + H264_PACKET_VERSION_BYTES + H264_PACKET_FLAGS_BYTES;\nconst H264_PROXY_STREAM_ID_OFFSET = H264_PROXY_STREAM_ID_LENGTH_OFFSET + STREAM_ID_LENGTH_BYTES;\nconst H264_HTTP_PAYLOAD_LENGTH_OFFSET =\n H264_PACKET_SENTINEL_BYTES + H264_PACKET_VERSION_BYTES + H264_PACKET_FLAGS_BYTES;\nconst H264_HTTP_SEQUENCE_OFFSET =\n H264_HTTP_PAYLOAD_LENGTH_OFFSET + H264_PACKET_PAYLOAD_LENGTH_BYTES;\nconst H264_HTTP_DURATION_OFFSET = H264_HTTP_SEQUENCE_OFFSET + FRAME_SEQUENCE_BYTES;\n\nexport const DEVICE_PREVIEW_H264_PACKET_SENTINEL = 0;\nexport const DEVICE_PREVIEW_H264_PACKET_VERSION = 1;\nexport const DEVICE_PREVIEW_H264_FLAG_CONFIGURATION = 1 << 0;\nexport const DEVICE_PREVIEW_H264_FLAG_KEYFRAME = 1 << 1;\nconst H264_PACKET_KNOWN_FLAGS =\n DEVICE_PREVIEW_H264_FLAG_CONFIGURATION | DEVICE_PREVIEW_H264_FLAG_KEYFRAME;\n\n// Excludes the variable-length stream ID and Annex-B payload.\nexport const DEVICE_PREVIEW_H264_PROXY_PACKET_FIXED_HEADER_BYTES =\n H264_PROXY_STREAM_ID_OFFSET + FRAME_SEQUENCE_BYTES + H264_PACKET_DURATION_BYTES;\n// HTTP records omit streamId but include payload length because fetch chunks have arbitrary bounds.\nexport const DEVICE_PREVIEW_H264_HTTP_PACKET_HEADER_BYTES =\n H264_HTTP_DURATION_OFFSET + H264_PACKET_DURATION_BYTES;\n\nexport interface DecodedDevicePreviewFrame {\n streamId: string;\n frameSequence: number;\n jpeg: Uint8Array;\n}\n\nexport interface DecodedDevicePreviewHttpFrameHeader {\n jpegLength: number;\n frameSequence: number;\n}\n\nexport interface DevicePreviewH264Packet {\n packetSequence: number;\n configuration: boolean;\n keyframe: boolean;\n durationMs: number;\n annexB: Uint8Array;\n}\n\nexport interface DecodedDevicePreviewH264ProxyPacket extends DevicePreviewH264Packet {\n streamId: string;\n}\n\nexport interface DecodedDevicePreviewH264HttpPacketHeader {\n annexBLength: number;\n packetSequence: number;\n configuration: boolean;\n keyframe: boolean;\n durationMs: number;\n}\n\nfunction isJpeg(data: Uint8Array): boolean {\n return (\n data.length >= 4 &&\n data[0] === 0xff &&\n data[1] === 0xd8 &&\n data[data.length - 2] === 0xff &&\n data[data.length - 1] === 0xd9\n );\n}\n\nfunction assertJpeg(jpeg: Uint8Array): void {\n if (jpeg.length === 0 || jpeg.length > DEVICE_PREVIEW_FRAME_MAX_BYTES) {\n throw new RangeError(\n `device preview JPEG must be 1-${DEVICE_PREVIEW_FRAME_MAX_BYTES} bytes, got ${jpeg.length}`,\n );\n }\n if (!isJpeg(jpeg)) throw new TypeError(\"device preview frame is not a complete JPEG image\");\n}\n\nfunction isAnnexB(data: Uint8Array): boolean {\n return (\n (data.length >= 4 && data[0] === 0 && data[1] === 0 && data[2] === 1) ||\n (data.length >= 5 && data[0] === 0 && data[1] === 0 && data[2] === 0 && data[3] === 1)\n );\n}\n\nfunction assertPacketSequence(packetSequence: number): void {\n if (!Number.isInteger(packetSequence) || packetSequence < 0 || packetSequence > 0xffffffff) {\n throw new RangeError(`packetSequence must be a uint32, got ${packetSequence}`);\n }\n}\n\nfunction assertPacketDuration(durationMs: number): void {\n if (!Number.isInteger(durationMs) || durationMs < 0 || durationMs > 0xffff) {\n throw new RangeError(`durationMs must be a uint16, got ${durationMs}`);\n }\n}\n\nfunction assertAnnexB(annexB: Uint8Array): void {\n if (annexB.length === 0 || annexB.length > DEVICE_PREVIEW_FRAME_MAX_BYTES) {\n throw new RangeError(\n `device preview H.264 payload must be 1-${DEVICE_PREVIEW_FRAME_MAX_BYTES} bytes, got ${annexB.length}`,\n );\n }\n if (!isAnnexB(annexB)) {\n throw new TypeError(\"device preview H.264 payload must use Annex-B start codes\");\n }\n}\n\nfunction h264PacketFlags(packet: Pick<DevicePreviewH264Packet, \"configuration\" | \"keyframe\">) {\n if (packet.configuration && packet.keyframe) {\n throw new TypeError(\n \"device preview H.264 configuration and keyframe flags are mutually exclusive\",\n );\n }\n return (\n (packet.configuration ? DEVICE_PREVIEW_H264_FLAG_CONFIGURATION : 0) |\n (packet.keyframe ? DEVICE_PREVIEW_H264_FLAG_KEYFRAME : 0)\n );\n}\n\nfunction decodeH264PacketFlags(\n flags: number,\n): Pick<DevicePreviewH264Packet, \"configuration\" | \"keyframe\"> | null {\n if ((flags & ~H264_PACKET_KNOWN_FLAGS) !== 0) return null;\n if (\n (flags & (DEVICE_PREVIEW_H264_FLAG_CONFIGURATION | DEVICE_PREVIEW_H264_FLAG_KEYFRAME)) ===\n (DEVICE_PREVIEW_H264_FLAG_CONFIGURATION | DEVICE_PREVIEW_H264_FLAG_KEYFRAME)\n ) {\n return null;\n }\n return {\n configuration: (flags & DEVICE_PREVIEW_H264_FLAG_CONFIGURATION) !== 0,\n keyframe: (flags & DEVICE_PREVIEW_H264_FLAG_KEYFRAME) !== 0,\n };\n}\n\nexport function encodeDevicePreviewFrame(\n streamId: string,\n frameSequence: number,\n jpeg: Uint8Array,\n): Uint8Array {\n const streamIdBytes = new TextEncoder().encode(streamId);\n if (streamIdBytes.length === 0 || streamIdBytes.length > 255) {\n throw new RangeError(`streamId byte length must be 1-255, got ${streamIdBytes.length}`);\n }\n if (!Number.isInteger(frameSequence) || frameSequence < 0 || frameSequence > 0xffffffff) {\n throw new RangeError(`frameSequence must be a uint32, got ${frameSequence}`);\n }\n assertJpeg(jpeg);\n\n const frame = new Uint8Array(\n STREAM_ID_LENGTH_BYTES + streamIdBytes.length + FRAME_SEQUENCE_BYTES + jpeg.length,\n );\n frame[0] = streamIdBytes.length;\n frame.set(streamIdBytes, STREAM_ID_LENGTH_BYTES);\n const sequenceOffset = STREAM_ID_LENGTH_BYTES + streamIdBytes.length;\n new DataView(frame.buffer, frame.byteOffset + sequenceOffset, FRAME_SEQUENCE_BYTES).setUint32(\n 0,\n frameSequence,\n true,\n );\n frame.set(jpeg, sequenceOffset + FRAME_SEQUENCE_BYTES);\n return frame;\n}\n\nexport function decodeDevicePreviewFrame(view: Uint8Array): DecodedDevicePreviewFrame | null {\n if (view.length < STREAM_FRAME_FIXED_HEADER_BYTES + 1) return null;\n const streamIdLength = view[0];\n if (streamIdLength === 0) return null;\n const sequenceOffset = STREAM_ID_LENGTH_BYTES + streamIdLength;\n const payloadOffset = sequenceOffset + FRAME_SEQUENCE_BYTES;\n if (\n view.length <= payloadOffset ||\n view.length - payloadOffset > DEVICE_PREVIEW_FRAME_MAX_BYTES\n ) {\n return null;\n }\n const jpeg = view.subarray(payloadOffset);\n if (!isJpeg(jpeg)) return null;\n let streamId: string;\n try {\n streamId = new TextDecoder(\"utf-8\", { fatal: true }).decode(\n view.subarray(STREAM_ID_LENGTH_BYTES, STREAM_ID_LENGTH_BYTES + streamIdLength),\n );\n } catch {\n return null;\n }\n const frameSequence = new DataView(\n view.buffer,\n view.byteOffset + sequenceOffset,\n FRAME_SEQUENCE_BYTES,\n ).getUint32(0, true);\n return { streamId, frameSequence, jpeg };\n}\n\n// Relay HTTP response record:\n// [4B JPEG length uint32LE][4B frame sequence uint32LE][JPEG bytes]\n// The browser parser accepts arbitrary HTTP chunk boundaries and can drop superseded records.\nexport const DEVICE_PREVIEW_HTTP_FRAME_HEADER_BYTES = 8;\n\nexport function encodeDevicePreviewHttpFrame(frameSequence: number, jpeg: Uint8Array): Uint8Array {\n if (!Number.isInteger(frameSequence) || frameSequence < 0 || frameSequence > 0xffffffff) {\n throw new RangeError(`frameSequence must be a uint32, got ${frameSequence}`);\n }\n assertJpeg(jpeg);\n const record = new Uint8Array(DEVICE_PREVIEW_HTTP_FRAME_HEADER_BYTES + jpeg.length);\n const header = new DataView(\n record.buffer,\n record.byteOffset,\n DEVICE_PREVIEW_HTTP_FRAME_HEADER_BYTES,\n );\n header.setUint32(0, jpeg.length, true);\n header.setUint32(4, frameSequence, true);\n record.set(jpeg, DEVICE_PREVIEW_HTTP_FRAME_HEADER_BYTES);\n return record;\n}\n\nexport function decodeDevicePreviewHttpFrameHeader(\n view: Uint8Array,\n): DecodedDevicePreviewHttpFrameHeader | null {\n if (view.length < DEVICE_PREVIEW_HTTP_FRAME_HEADER_BYTES) return null;\n const header = new DataView(view.buffer, view.byteOffset, DEVICE_PREVIEW_HTTP_FRAME_HEADER_BYTES);\n const jpegLength = header.getUint32(0, true);\n if (jpegLength === 0 || jpegLength > DEVICE_PREVIEW_FRAME_MAX_BYTES) return null;\n return { jpegLength, frameSequence: header.getUint32(4, true) };\n}\n\n// Dedicated Proxy H.264 packet:\n// [1B zero sentinel][1B version][1B flags][1B streamId byte length][streamId UTF-8]\n// [4B packet sequence uint32LE][2B durationMs uint16LE][H.264 Annex-B bytes]\n//\n// JPEG frame lengths are always positive, so the zero sentinel lets both current stream formats\n// safely share the dedicated Proxy stream WebSocket.\nexport function encodeDevicePreviewH264ProxyPacket(\n streamId: string,\n packet: DevicePreviewH264Packet,\n): Uint8Array {\n const streamIdBytes = new TextEncoder().encode(streamId);\n if (streamIdBytes.length === 0 || streamIdBytes.length > 255) {\n throw new RangeError(`streamId byte length must be 1-255, got ${streamIdBytes.length}`);\n }\n assertPacketSequence(packet.packetSequence);\n assertPacketDuration(packet.durationMs);\n assertAnnexB(packet.annexB);\n\n const sequenceOffset = H264_PROXY_STREAM_ID_OFFSET + streamIdBytes.length;\n const durationOffset = sequenceOffset + FRAME_SEQUENCE_BYTES;\n const payloadOffset = durationOffset + H264_PACKET_DURATION_BYTES;\n const encoded = new Uint8Array(payloadOffset + packet.annexB.length);\n encoded[0] = DEVICE_PREVIEW_H264_PACKET_SENTINEL;\n encoded[1] = DEVICE_PREVIEW_H264_PACKET_VERSION;\n encoded[2] = h264PacketFlags(packet);\n encoded[H264_PROXY_STREAM_ID_LENGTH_OFFSET] = streamIdBytes.length;\n encoded.set(streamIdBytes, H264_PROXY_STREAM_ID_OFFSET);\n const header = new DataView(\n encoded.buffer,\n encoded.byteOffset + sequenceOffset,\n FRAME_SEQUENCE_BYTES + H264_PACKET_DURATION_BYTES,\n );\n header.setUint32(0, packet.packetSequence, true);\n header.setUint16(FRAME_SEQUENCE_BYTES, packet.durationMs, true);\n encoded.set(packet.annexB, payloadOffset);\n return encoded;\n}\n\nexport function decodeDevicePreviewH264ProxyPacket(\n view: Uint8Array,\n): DecodedDevicePreviewH264ProxyPacket | null {\n if (view.length < DEVICE_PREVIEW_H264_PROXY_PACKET_FIXED_HEADER_BYTES + 1) return null;\n if (\n view[0] !== DEVICE_PREVIEW_H264_PACKET_SENTINEL ||\n view[1] !== DEVICE_PREVIEW_H264_PACKET_VERSION\n ) {\n return null;\n }\n const flags = decodeH264PacketFlags(view[2]!);\n if (!flags) return null;\n const streamIdLength = view[H264_PROXY_STREAM_ID_LENGTH_OFFSET]!;\n if (streamIdLength === 0) return null;\n const sequenceOffset = H264_PROXY_STREAM_ID_OFFSET + streamIdLength;\n const durationOffset = sequenceOffset + FRAME_SEQUENCE_BYTES;\n const payloadOffset = durationOffset + H264_PACKET_DURATION_BYTES;\n if (\n view.length <= payloadOffset ||\n view.length - payloadOffset > DEVICE_PREVIEW_FRAME_MAX_BYTES\n ) {\n return null;\n }\n\n let streamId: string;\n try {\n streamId = new TextDecoder(\"utf-8\", { fatal: true }).decode(\n view.subarray(H264_PROXY_STREAM_ID_OFFSET, sequenceOffset),\n );\n } catch {\n return null;\n }\n if (!streamId) return null;\n const annexB = view.subarray(payloadOffset);\n if (!isAnnexB(annexB)) return null;\n const header = new DataView(\n view.buffer,\n view.byteOffset + sequenceOffset,\n FRAME_SEQUENCE_BYTES + H264_PACKET_DURATION_BYTES,\n );\n return {\n streamId,\n packetSequence: header.getUint32(0, true),\n ...flags,\n durationMs: header.getUint16(FRAME_SEQUENCE_BYTES, true),\n annexB,\n };\n}\n\n// Relay HTTP H.264 record:\n// [1B zero sentinel][1B version][1B flags][4B payload length uint32LE]\n// [4B packet sequence uint32LE][2B durationMs uint16LE][H.264 Annex-B bytes]\nexport function encodeDevicePreviewH264HttpPacket(packet: DevicePreviewH264Packet): Uint8Array {\n assertPacketSequence(packet.packetSequence);\n assertPacketDuration(packet.durationMs);\n assertAnnexB(packet.annexB);\n\n const encoded = new Uint8Array(\n DEVICE_PREVIEW_H264_HTTP_PACKET_HEADER_BYTES + packet.annexB.length,\n );\n encoded[0] = DEVICE_PREVIEW_H264_PACKET_SENTINEL;\n encoded[1] = DEVICE_PREVIEW_H264_PACKET_VERSION;\n encoded[2] = h264PacketFlags(packet);\n const header = new DataView(\n encoded.buffer,\n encoded.byteOffset + H264_HTTP_PAYLOAD_LENGTH_OFFSET,\n H264_PACKET_PAYLOAD_LENGTH_BYTES + FRAME_SEQUENCE_BYTES + H264_PACKET_DURATION_BYTES,\n );\n header.setUint32(0, packet.annexB.length, true);\n header.setUint32(H264_PACKET_PAYLOAD_LENGTH_BYTES, packet.packetSequence, true);\n header.setUint16(\n H264_PACKET_PAYLOAD_LENGTH_BYTES + FRAME_SEQUENCE_BYTES,\n packet.durationMs,\n true,\n );\n encoded.set(packet.annexB, DEVICE_PREVIEW_H264_HTTP_PACKET_HEADER_BYTES);\n return encoded;\n}\n\nexport function decodeDevicePreviewH264HttpPacketHeader(\n view: Uint8Array,\n): DecodedDevicePreviewH264HttpPacketHeader | null {\n if (view.length < DEVICE_PREVIEW_H264_HTTP_PACKET_HEADER_BYTES) return null;\n if (\n view[0] !== DEVICE_PREVIEW_H264_PACKET_SENTINEL ||\n view[1] !== DEVICE_PREVIEW_H264_PACKET_VERSION\n ) {\n return null;\n }\n const flags = decodeH264PacketFlags(view[2]!);\n if (!flags) return null;\n const header = new DataView(\n view.buffer,\n view.byteOffset + H264_HTTP_PAYLOAD_LENGTH_OFFSET,\n H264_PACKET_PAYLOAD_LENGTH_BYTES + FRAME_SEQUENCE_BYTES + H264_PACKET_DURATION_BYTES,\n );\n const annexBLength = header.getUint32(0, true);\n if (annexBLength === 0 || annexBLength > DEVICE_PREVIEW_FRAME_MAX_BYTES) return null;\n return {\n annexBLength,\n packetSequence: header.getUint32(H264_PACKET_PAYLOAD_LENGTH_BYTES, true),\n ...flags,\n durationMs: header.getUint16(H264_PACKET_PAYLOAD_LENGTH_BYTES + FRAME_SEQUENCE_BYTES, true),\n };\n}\n","const MU_LAW_BIAS = 0x84;\nconst MU_LAW_CLIP = 32635;\n\nfunction encodeSample(sampleValue: number): number {\n let sample = sampleValue;\n const sign = sample < 0 ? 0x80 : 0;\n if (sample < 0) sample = -sample;\n sample = Math.min(sample, MU_LAW_CLIP) + MU_LAW_BIAS;\n\n let exponent = 7;\n for (let mask = 0x4000; exponent > 0 && (sample & mask) === 0; mask >>= 1) {\n exponent -= 1;\n }\n const mantissa = (sample >> (exponent + 3)) & 0x0f;\n return ~(sign | (exponent << 4) | mantissa) & 0xff;\n}\n\nfunction decodeSample(encodedValue: number): number {\n const value = ~encodedValue & 0xff;\n const sign = value & 0x80;\n const exponent = (value >> 4) & 0x07;\n const mantissa = value & 0x0f;\n const magnitude = ((mantissa << 3) + MU_LAW_BIAS) * 2 ** exponent - MU_LAW_BIAS;\n return sign ? -magnitude : magnitude;\n}\n\nexport function encodePcm16ToMuLaw(pcm: Uint8Array): Uint8Array {\n const sampleCount = Math.floor(pcm.byteLength / 2);\n const encoded = new Uint8Array(sampleCount);\n const view = new DataView(pcm.buffer, pcm.byteOffset, pcm.byteLength);\n for (let index = 0; index < sampleCount; index += 1) {\n encoded[index] = encodeSample(view.getInt16(index * 2, true));\n }\n return encoded;\n}\n\nexport function decodeMuLawToPcm16(encoded: Uint8Array): Uint8Array {\n const pcm = new Uint8Array(encoded.byteLength * 2);\n const view = new DataView(pcm.buffer);\n for (let index = 0; index < encoded.byteLength; index += 1) {\n view.setInt16(index * 2, decodeSample(encoded[index] ?? 0xff), true);\n }\n return pcm;\n}\n","// 有限状态机 helper\n//\n// 提供显式转换表的小型 FSM,区分两类调用模式:\n// - transitionTo(throw):同步确定性流程里调用,非法转移代表 bug,立即暴露\n// - tryTransitionTo(bool):异步事件回调里调用,非法转移可能是吸收态残余事件,调用方按\n// isInAbsorbingState() 分级日志\n//\n// 吸收态采用传递闭包定义:终态(transitions=[])或所有出边都指向吸收态的状态都算吸收。\n// 这样 SessionState.ERROR (→[TERMINATED]) 和 RelayConnectionState.CLOSED ([]) 都被\n// 自动识别为吸收态,不用在 caller 里硬编码状态名。\n//\n// onTransition/onRejected 仅做日志/观测,不应 throw。\n\ninterface FSMDef<S extends string> {\n initial: S;\n // from-state → 允许转入的 to-state 列表;终态对应空数组\n transitions: Record<S, readonly S[]>;\n // 合法转换发生后触发,典型用法是结构化日志\n onTransition?: (from: S, to: S) => void;\n // tryTransitionTo 非法转移时触发;isAbsorbing 指示 from 是否吸收态(晚到残余 vs. 真非法)\n onRejected?: (from: S, to: S, isAbsorbing: boolean) => void;\n}\n\ninterface FSM<S extends string> {\n current(): S;\n is(state: S): boolean;\n isIn(states: readonly S[]): boolean;\n canTransitionTo(to: S): boolean;\n // 非法转换抛 Error;同步流程里当 assert 用\n transitionTo(to: S): void;\n // 非法转换返回 false,不抛;异步回调里用,配合 isInAbsorbingState 分级日志\n tryTransitionTo(to: S): boolean;\n // 当前是否在吸收态(传递闭包)\n isInAbsorbingState(): boolean;\n}\n\n// 计算吸收态集合:终态 + 所有出边都指向吸收态的状态,迭代至不动点\nfunction computeAbsorbingSet<S extends string>(transitions: Record<S, readonly S[]>): Set<S> {\n const absorbing = new Set<S>();\n const entries = Object.entries(transitions) as Array<[S, readonly S[]]>;\n for (const [s, outs] of entries) {\n if (outs.length === 0) absorbing.add(s);\n }\n let changed = true;\n while (changed) {\n changed = false;\n for (const [s, outs] of entries) {\n if (absorbing.has(s)) continue;\n if (outs.length > 0 && outs.every((t) => absorbing.has(t))) {\n absorbing.add(s);\n changed = true;\n }\n }\n }\n return absorbing;\n}\n\nexport function createFSM<S extends string>(def: FSMDef<S>): FSM<S> {\n let state = def.initial;\n const absorbing = computeAbsorbingSet(def.transitions);\n const tryTransitionTo = (to: S): boolean => {\n const allowed = def.transitions[state];\n if (!allowed?.includes(to)) {\n def.onRejected?.(state, to, absorbing.has(state));\n return false;\n }\n const from = state;\n state = to;\n def.onTransition?.(from, to);\n return true;\n };\n return {\n current: () => state,\n is: (s) => state === s,\n isIn: (ss) => ss.includes(state),\n canTransitionTo: (to) => def.transitions[state]?.includes(to) ?? false,\n transitionTo: (to) => {\n if (!tryTransitionTo(to)) {\n throw new Error(`Invalid FSM transition: ${state} -> ${to}`);\n }\n },\n tryTransitionTo,\n isInAbsorbingState: () => absorbing.has(state),\n };\n}\n\n// 无内部 state 的 FSM 视图,供 state 存在外部(如 SessionInfo、DB 行)的 per-instance 场景使用。\n// 调用方自行传入 from,canTransition 校验;吸收态判定通过 isAbsorbing(state) 提供。\ninterface StatelessFSM<S extends string> {\n canTransition(from: S, to: S): boolean;\n isAbsorbing(state: S): boolean;\n}\n\nexport function defineFSM<S extends string>(transitions: Record<S, readonly S[]>): StatelessFSM<S> {\n const absorbing = computeAbsorbingSet(transitions);\n return {\n canTransition: (from, to) => transitions[from]?.includes(to) ?? false,\n isAbsorbing: (state) => absorbing.has(state),\n };\n}\n","import { WebSocket } from \"ws\";\nimport { defineFSM } from \"@dev-anywhere/shared\";\nimport { nanoid } from \"nanoid\";\n\n// 显式代理连接状态,取代 ws null 检查\ntype ProxyConnectionState = \"online\" | \"offline\";\n\n// 显式客户端连接状态,跟踪注册和绑定\ntype ClientConnectionState = \"registered\" | \"bound\";\n\ntype RemoveOfflineProxyResult = \"removed\" | \"not_found\" | \"online\";\n\n// proxy 连接 FSM: 仅 online <-> offline 双向流转。registerProxy 走 reconnect 路径直接写\n// online (相当于 offline -> online), transitionProxy 走 close 路径走 online -> offline。\n// 同状态停留 (online -> online / offline -> offline) 视为非法, 由 canTransition 拦下。\nconst proxyConnectionFSM = defineFSM<ProxyConnectionState>({\n online: [\"offline\"],\n offline: [\"online\"],\n});\n\n// 代理连接状态,跟踪 ws、会话集合、离线时间、显示名称\ninterface ProxyState {\n ws: WebSocket | null;\n connectionState: ProxyConnectionState;\n sessions: Set<string>;\n disconnectedAt: number | null;\n name?: string;\n osName?: string;\n version: string;\n}\n\n// 客户端绑定状态,通过 clientId 而非 WebSocket 引用标识\ninterface ClientBinding {\n proxyId: string;\n bindingId: string;\n ws: WebSocket | null;\n connectionState: ClientConnectionState;\n}\n\ntype BoundClientSocket = WebSocket & {\n boundProxyId?: string;\n bindingId?: string;\n};\n\ninterface ClientConnectionMetadata {\n clientId?: string;\n connectedAt: number;\n userAgent?: string;\n platform?: string;\n maxTouchPoints?: number;\n browserName?: string;\n osName?: string;\n deviceKind?: \"desktop\" | \"tablet\" | \"phone\" | \"unknown\";\n remoteAddress?: string;\n}\n\n// 代理注册、客户端绑定、宽限期管理\nexport class RelayRegistry {\n private proxyStates = new Map<string, ProxyState>();\n private clientBindings = new Map<string, ClientBinding>();\n private connectedClients = new Map<WebSocket, ClientConnectionMetadata>();\n\n registerProxy(\n proxyId: string,\n ws: WebSocket,\n version: string,\n name?: string,\n osName?: string,\n ): \"new\" | \"reconnected\" {\n const existing = this.proxyStates.get(proxyId);\n if (existing) {\n // 如果旧连接还活着,先终止\n if (existing.ws && existing.ws.readyState === WebSocket.OPEN) {\n existing.ws.terminate();\n }\n existing.ws = ws;\n existing.connectionState = \"online\";\n existing.disconnectedAt = null;\n if (name !== undefined) existing.name = name;\n existing.osName = osName;\n existing.version = version;\n return \"reconnected\";\n }\n\n this.proxyStates.set(proxyId, {\n ws,\n connectionState: \"online\",\n sessions: new Set(),\n disconnectedAt: null,\n name,\n osName,\n version,\n });\n return \"new\";\n }\n\n // 显式状态转换,校验 from 状态匹配后更新 connectionState\n transitionProxy(proxyId: string, from: ProxyConnectionState, to: ProxyConnectionState): void {\n if (!proxyConnectionFSM.canTransition(from, to)) {\n throw new Error(`Invalid proxy transition: ${from} -> ${to}`);\n }\n const state = this.proxyStates.get(proxyId);\n if (!state) {\n throw new Error(`Proxy not found: ${proxyId}`);\n }\n if (state.connectionState !== from) {\n throw new Error(\n `Proxy ${proxyId} state mismatch: expected ${from}, actual ${state.connectionState}`,\n );\n }\n state.connectionState = to;\n if (to === \"offline\") {\n state.ws = null;\n state.disconnectedAt = Date.now();\n }\n }\n\n getProxyConnectionState(proxyId: string): ProxyConnectionState | undefined {\n return this.proxyStates.get(proxyId)?.connectionState;\n }\n\n getClientConnectionState(clientId: string): ClientConnectionState | undefined {\n return this.clientBindings.get(clientId)?.connectionState;\n }\n\n // 彻底清理 proxy 状态和客户端绑定\n cleanupProxy(proxyId: string): void {\n const state = this.proxyStates.get(proxyId);\n if (!state) return;\n\n // 解绑所有绑定到该 proxy 的客户端\n for (const [clientId, binding] of this.clientBindings) {\n if (binding.proxyId === proxyId) {\n if (binding.ws) this.clearSocketBinding(binding.ws);\n this.clientBindings.delete(clientId);\n }\n }\n\n // ClientSocket 还单独缓存了 boundProxyId 供消息热路径路由。只删 clientBindings 会让\n // 活跃/重复 tab 残留旧 ID,并在同 ID 的 Proxy 日后重新注册时绕过重新选择直接路由。\n for (const ws of this.connectedClients.keys()) {\n const clientWs = ws as BoundClientSocket;\n if (clientWs.boundProxyId === proxyId) {\n delete clientWs.boundProxyId;\n delete clientWs.bindingId;\n }\n }\n\n this.proxyStates.delete(proxyId);\n }\n\n unregisterProxy(proxyId: string): void {\n this.cleanupProxy(proxyId);\n }\n\n // 检查状态与删除必须保持在同一个同步操作内,避免调用方先检查、稍后删除时误删\n // 已经重连上线的开发机。只有显式进入 offline 状态的记录才允许被用户移除。\n removeOfflineProxy(proxyId: string): RemoveOfflineProxyResult {\n const state = this.proxyStates.get(proxyId);\n if (!state) return \"not_found\";\n if (state.connectionState !== \"offline\") return \"online\";\n\n this.cleanupProxy(proxyId);\n return \"removed\";\n }\n\n getProxy(proxyId: string): WebSocket | undefined {\n const state = this.proxyStates.get(proxyId);\n return state?.ws ?? undefined;\n }\n\n isProxyOnline(proxyId: string): boolean {\n const state = this.proxyStates.get(proxyId);\n if (!state || state.connectionState !== \"online\") return false;\n // connectionState 声明在线但 ws 已失效时,记录警告并返回 false\n if (!state.ws || state.ws.readyState !== WebSocket.OPEN) return false;\n return true;\n }\n\n // proxy 是否存在(含宽限期中的)\n hasProxy(proxyId: string): boolean {\n return this.proxyStates.has(proxyId);\n }\n\n listProxies(): string[] {\n return Array.from(this.proxyStates.keys());\n }\n\n // 返回 proxyId、name、online 的列表,用于 proxy_list_response\n listProxiesWithName(): Array<{\n proxyId: string;\n name?: string;\n osName?: string;\n version: string;\n online: boolean;\n }> {\n return Array.from(this.proxyStates.entries()).map(([proxyId, state]) => ({\n proxyId,\n ...(state.name !== undefined ? { name: state.name } : {}),\n ...(state.osName !== undefined ? { osName: state.osName } : {}),\n version: state.version,\n online: state.connectionState === \"online\",\n }));\n }\n\n getProxyName(proxyId: string): string | undefined {\n return this.proxyStates.get(proxyId)?.name;\n }\n\n // 将 sessionId 关联到 proxy\n addSessionToProxy(proxyId: string, sessionId: string): void {\n const state = this.proxyStates.get(proxyId);\n if (state) {\n state.sessions.add(sessionId);\n }\n }\n\n setSessionsForProxy(proxyId: string, sessionIds: readonly string[]): void {\n const state = this.proxyStates.get(proxyId);\n if (state) {\n state.sessions = new Set(sessionIds);\n }\n }\n\n // 通过 sessionId 反查所属 proxyId\n getProxyForSession(sessionId: string): string | undefined {\n for (const [proxyId, state] of this.proxyStates) {\n if (state.sessions.has(sessionId)) {\n return proxyId;\n }\n }\n return undefined;\n }\n\n // 获取 proxy 关联的所有 sessionId\n getSessionsForProxy(proxyId: string): string[] {\n const state = this.proxyStates.get(proxyId);\n return state ? Array.from(state.sessions) : [];\n }\n\n // clientId 绑定方式\n bindClientById(clientId: string, proxyId: string, ws: WebSocket): string | undefined {\n if (!this.proxyStates.has(proxyId)) {\n return undefined;\n }\n return this.installClientBinding(clientId, proxyId, ws).bindingId;\n }\n\n restoreClientBinding(\n clientId: string,\n ws: WebSocket,\n ): { proxyId: string; bindingId: string } | undefined {\n const binding = this.clientBindings.get(clientId);\n if (!binding) return undefined;\n const restored = this.installClientBinding(clientId, binding.proxyId, ws);\n return { proxyId: restored.proxyId, bindingId: restored.bindingId };\n }\n\n // 断开客户端 WebSocket 但保留绑定关系,重连时可恢复\n unbindClientById(clientId: string): void {\n const binding = this.clientBindings.get(clientId);\n if (binding) {\n if (binding.ws) this.clearSocketBinding(binding.ws);\n binding.ws = null;\n }\n }\n\n // 连接关闭只能释放自己持有的绑定。旧连接的 close 可能晚于新连接注册,\n // 此时不能把已经切换到新 WebSocket 的绑定清空。\n unbindClientSocket(clientId: string, ws: WebSocket): boolean {\n const binding = this.clientBindings.get(clientId);\n if (!binding || binding.ws !== ws) return false;\n this.clearSocketBinding(ws);\n binding.ws = null;\n return true;\n }\n\n getClientBinding(clientId: string): ClientBinding | undefined {\n return this.clientBindings.get(clientId);\n }\n\n isCurrentClientBinding(\n clientId: string | undefined,\n ws: WebSocket,\n scope: { proxyId: string; bindingId: string },\n ): boolean {\n if (!clientId) return false;\n const socket = ws as BoundClientSocket;\n const binding = this.clientBindings.get(clientId);\n return (\n binding?.ws === ws &&\n binding.proxyId === scope.proxyId &&\n binding.bindingId === scope.bindingId &&\n socket.boundProxyId === scope.proxyId &&\n socket.bindingId === scope.bindingId\n );\n }\n\n private installClientBinding(clientId: string, proxyId: string, ws: WebSocket): ClientBinding {\n const previous = this.clientBindings.get(clientId);\n if (previous?.ws) this.clearSocketBinding(previous.ws);\n\n const binding: ClientBinding = {\n proxyId,\n bindingId: nanoid(),\n ws,\n connectionState: \"bound\",\n };\n this.clientBindings.set(clientId, binding);\n const socket = ws as BoundClientSocket;\n socket.boundProxyId = proxyId;\n socket.bindingId = binding.bindingId;\n return binding;\n }\n\n private clearSocketBinding(ws: WebSocket): void {\n const socket = ws as BoundClientSocket;\n delete socket.boundProxyId;\n delete socket.bindingId;\n }\n\n // 获取绑定到指定 proxy 的所有活跃客户端 WebSocket\n getClientsForProxy(proxyId: string): WebSocket[] {\n const clients: WebSocket[] = [];\n for (const [, binding] of this.clientBindings) {\n if (binding.proxyId === proxyId && binding.ws && binding.ws.readyState === WebSocket.OPEN) {\n clients.push(binding.ws);\n }\n }\n return clients;\n }\n\n countClients(): number {\n // 计数依据:ws 还存活且处于 OPEN。仅 `if (binding.ws)` 不够:close handler 漏调\n // unbindClientById 时 ws 对象残留,会让 /status 永久报告虚高 clientCount。\n let count = 0;\n for (const [, binding] of this.clientBindings) {\n if (binding.ws && binding.ws.readyState === WebSocket.OPEN) count++;\n }\n return count;\n }\n\n addClientWs(\n ws: WebSocket,\n metadata: Partial<Omit<ClientConnectionMetadata, \"connectedAt\">> & {\n connectedAt?: number;\n } = {},\n ): void {\n this.connectedClients.set(ws, {\n connectedAt: metadata.connectedAt ?? Date.now(),\n ...(metadata.clientId !== undefined ? { clientId: metadata.clientId } : {}),\n ...(metadata.userAgent !== undefined ? { userAgent: metadata.userAgent } : {}),\n ...(metadata.platform !== undefined ? { platform: metadata.platform } : {}),\n ...(metadata.maxTouchPoints !== undefined ? { maxTouchPoints: metadata.maxTouchPoints } : {}),\n ...(metadata.browserName !== undefined ? { browserName: metadata.browserName } : {}),\n ...(metadata.osName !== undefined ? { osName: metadata.osName } : {}),\n ...(metadata.deviceKind !== undefined ? { deviceKind: metadata.deviceKind } : {}),\n ...(metadata.remoteAddress !== undefined ? { remoteAddress: metadata.remoteAddress } : {}),\n });\n }\n\n updateConnectedClientId(ws: WebSocket, clientId: string): void {\n const metadata = this.connectedClients.get(ws);\n if (metadata) {\n metadata.clientId = clientId;\n return;\n }\n this.addClientWs(ws, { clientId });\n }\n\n updateConnectedClientMetadata(\n ws: WebSocket,\n metadata: Partial<Omit<ClientConnectionMetadata, \"connectedAt\">>,\n ): void {\n const current = this.connectedClients.get(ws);\n if (!current) {\n this.addClientWs(ws, metadata);\n return;\n }\n if (metadata.clientId !== undefined) current.clientId = metadata.clientId;\n if (metadata.userAgent !== undefined) current.userAgent = metadata.userAgent;\n if (metadata.platform !== undefined) current.platform = metadata.platform;\n if (metadata.maxTouchPoints !== undefined) current.maxTouchPoints = metadata.maxTouchPoints;\n if (metadata.browserName !== undefined) current.browserName = metadata.browserName;\n if (metadata.osName !== undefined) current.osName = metadata.osName;\n if (metadata.deviceKind !== undefined) current.deviceKind = metadata.deviceKind;\n if (metadata.remoteAddress !== undefined) current.remoteAddress = metadata.remoteAddress;\n }\n\n removeClientWs(ws: WebSocket): void {\n this.connectedClients.delete(ws);\n }\n\n getAllClientWs(): WebSocket[] {\n const clients: WebSocket[] = [];\n for (const [ws, metadata] of this.connectedClients) {\n // Raw /client sockets are tracked immediately so they can be inspected and cleaned up, but\n // they must not receive business broadcasts before client_register has completed. The\n // registration response is the admission boundary observed by Web clients.\n if (metadata.clientId && ws.readyState === WebSocket.OPEN) {\n clients.push(ws);\n }\n }\n return clients;\n }\n\n getConnectedClientSockets(clientId: string): WebSocket[] {\n const sockets: WebSocket[] = [];\n for (const [ws, metadata] of this.connectedClients) {\n if (metadata.clientId === clientId && ws.readyState === WebSocket.OPEN) {\n sockets.push(ws);\n }\n }\n return sockets;\n }\n\n // 获取单个 proxy 的详细状态信息\n getProxyDetail(proxyId: string):\n | {\n proxyId: string;\n name?: string;\n online: boolean;\n connectionState: ProxyConnectionState;\n sessions: string[];\n disconnectedAt: number | null;\n }\n | undefined {\n const state = this.proxyStates.get(proxyId);\n if (!state) return undefined;\n return {\n proxyId,\n ...(state.name !== undefined ? { name: state.name } : {}),\n online: state.connectionState === \"online\",\n connectionState: state.connectionState,\n sessions: Array.from(state.sessions),\n disconnectedAt: state.disconnectedAt,\n };\n }\n\n // 获取所有客户端绑定的详细信息\n getClientDetails(): Array<{\n clientId: string;\n proxyId: string;\n online: boolean;\n connectionState: ClientConnectionState;\n }> {\n const details: Array<{\n clientId: string;\n proxyId: string;\n online: boolean;\n connectionState: ClientConnectionState;\n }> = [];\n for (const [clientId, binding] of this.clientBindings) {\n details.push({\n clientId,\n proxyId: binding.proxyId,\n online:\n binding.ws !== null &&\n binding.ws !== undefined &&\n binding.ws.readyState === WebSocket.OPEN,\n connectionState: binding.connectionState,\n });\n }\n return details;\n }\n\n getConnectedClientDetails(currentClientId?: string): Array<{\n clientId: string;\n proxyId?: string;\n connectedAt: number;\n current?: boolean;\n userAgent?: string;\n platform?: string;\n maxTouchPoints?: number;\n browserName: string;\n osName: string;\n deviceKind: \"desktop\" | \"tablet\" | \"phone\" | \"unknown\";\n remoteAddress?: string;\n }> {\n const details: Array<{\n clientId: string;\n proxyId?: string;\n connectedAt: number;\n current?: boolean;\n userAgent?: string;\n platform?: string;\n maxTouchPoints?: number;\n browserName: string;\n osName: string;\n deviceKind: \"desktop\" | \"tablet\" | \"phone\" | \"unknown\";\n remoteAddress?: string;\n }> = [];\n for (const [ws, metadata] of this.connectedClients) {\n if (ws.readyState !== WebSocket.OPEN || !metadata.clientId) continue;\n if (!metadata.browserName || !metadata.osName || !metadata.deviceKind) continue;\n const binding = this.clientBindings.get(metadata.clientId);\n details.push({\n clientId: metadata.clientId,\n ...(binding?.proxyId !== undefined ? { proxyId: binding.proxyId } : {}),\n connectedAt: metadata.connectedAt,\n ...(metadata.clientId === currentClientId ? { current: true } : {}),\n ...(metadata.userAgent !== undefined ? { userAgent: metadata.userAgent } : {}),\n ...(metadata.platform !== undefined ? { platform: metadata.platform } : {}),\n ...(metadata.maxTouchPoints !== undefined\n ? { maxTouchPoints: metadata.maxTouchPoints }\n : {}),\n browserName: metadata.browserName,\n osName: metadata.osName,\n deviceKind: metadata.deviceKind,\n ...(metadata.remoteAddress !== undefined ? { remoteAddress: metadata.remoteAddress } : {}),\n });\n }\n return details;\n }\n}\n","import { Router } from \"express\";\nimport {\n PROXY_UPGRADE_BOOTSTRAP_VERSION,\n RELAY_CONTROL_PROTOCOL_VERSION,\n} from \"@dev-anywhere/shared\";\nimport type { RelayRegistry } from \"./registry.js\";\nimport { RELAY_VERSION } from \"./version.js\";\n\ninterface HealthRouterOptions {\n proxyTokenRequired?: boolean;\n clientTokenRequired?: boolean;\n validateClientToken?: (token: string | null) => boolean;\n validateProxyToken?: (token: string | null) => boolean;\n // proxyToken 验证通过且 client token 已配置时返回当前值;否则返回 null。\n getClientToken?: () => string | null;\n}\n\nfunction bearerToken(authHeader: string | undefined): string | null {\n const match = /^Bearer\\s+(.+)$/i.exec(authHeader ?? \"\");\n return match?.[1] ?? null;\n}\n\n// 健康检查和状态查询路由\nexport function healthRouter(registry: RelayRegistry, options: HealthRouterOptions = {}): Router {\n const router = Router();\n const proxyTokenRequired = options.proxyTokenRequired ?? false;\n const clientTokenRequired = options.clientTokenRequired ?? false;\n\n router.get(\"/health\", (_req, res) => {\n res.setHeader(\"Cache-Control\", \"no-store\");\n res.json({\n status: \"ok\",\n version: RELAY_VERSION,\n controlProtocolVersion: RELAY_CONTROL_PROTOCOL_VERSION,\n uptime: process.uptime(),\n auth: {\n proxyTokenRequired,\n clientTokenRequired,\n },\n });\n });\n\n router.get(\"/api/auth/client\", (req, res) => {\n if (!clientTokenRequired) {\n res.status(204).end();\n return;\n }\n const token = bearerToken(req.get(\"authorization\"));\n if (options.validateClientToken?.(token)) {\n res.status(204).end();\n return;\n }\n res.status(401).json({ error: \"invalid_client_token\" });\n });\n\n // 已认证 proxy(凭 proxyToken)查询当前生效的 client token,避免运维者必须 ssh 上来读 .env。\n // 行为:proxy token 关闭时直接 401(防止开放 relay 公开 token);proxy token 不匹配 401;\n // 校验通过且 client token 已配置返回 { clientToken };client token 未配置返回 204。\n router.get(\"/api/admin/client-token\", (req, res) => {\n if (!proxyTokenRequired) {\n res.status(401).json({ error: \"proxy_token_required\" });\n return;\n }\n const token = bearerToken(req.get(\"authorization\"));\n if (!options.validateProxyToken?.(token)) {\n res.status(401).json({ error: \"invalid_proxy_token\" });\n return;\n }\n const clientToken = options.getClientToken?.() ?? null;\n if (!clientToken) {\n res.status(204).end();\n return;\n }\n res.json({ clientToken });\n });\n\n // proxyToken 配置时需要 Bearer 校验,否则放行(dev 模式)。\n // /api/status、/api/proxies、/api/clients 暴露拓扑/绑定信息,公网 relay 必须鉴权防遍历探测。\n function requireProxyTokenIfConfigured(\n req: import(\"express\").Request,\n res: import(\"express\").Response,\n ): boolean {\n if (!proxyTokenRequired) return true;\n const token = bearerToken(req.get(\"authorization\"));\n if (options.validateProxyToken?.(token)) return true;\n res.status(401).json({ error: \"invalid_proxy_token\" });\n return false;\n }\n\n router.get(\"/api/proxy-upgrade-bootstrap\", (req, res) => {\n if (!requireProxyTokenIfConfigured(req, res)) return;\n res.setHeader(\"Cache-Control\", \"no-store\");\n res.json({\n bootstrapVersion: PROXY_UPGRADE_BOOTSTRAP_VERSION,\n relayVersion: RELAY_VERSION,\n controlProtocolVersion: RELAY_CONTROL_PROTOCOL_VERSION,\n });\n });\n\n router.get(\"/status\", (_req, res) => {\n res.json({\n version: RELAY_VERSION,\n proxyCount: registry.listProxies().length,\n clientCount: registry.countClients(),\n uptime: process.uptime(),\n });\n });\n\n // 连接总览:proxy/client 计数、绑定关系\n router.get(\"/api/status\", (req, res) => {\n if (!requireProxyTokenIfConfigured(req, res)) return;\n res.json({\n version: RELAY_VERSION,\n proxyCount: registry.listProxies().length,\n clientCount: registry.countClients(),\n uptime: process.uptime(),\n bindings: registry.getClientDetails(),\n });\n });\n\n // 逐 proxy 详情:id、名称、在线状态、会话列表、离线时间\n router.get(\"/api/proxies\", (req, res) => {\n if (!requireProxyTokenIfConfigured(req, res)) return;\n const proxyIds = registry.listProxies();\n const details = proxyIds\n .map((id) => registry.getProxyDetail(id))\n .filter((d) => d !== undefined);\n res.json(details);\n });\n\n // 逐客户端详情:clientId、绑定的 proxyId、在线状态\n router.get(\"/api/clients\", (req, res) => {\n if (!requireProxyTokenIfConfigured(req, res)) return;\n res.json(registry.getClientDetails());\n });\n\n return router;\n}\n","import { readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\ninterface PackageInfo {\n version?: string;\n}\n\nfunction readRelayVersion(): string {\n const packageJsonPath = join(dirname(fileURLToPath(import.meta.url)), \"..\", \"package.json\");\n const pkg = JSON.parse(readFileSync(packageJsonPath, \"utf-8\")) as PackageInfo;\n return pkg.version ?? \"unknown\";\n}\n\nexport const RELAY_VERSION = readRelayVersion();\n","import { WebSocket } from \"ws\";\nimport {\n compareProxyRelayProtocolVersions,\n isProxyToClientRelayControlType,\n ProxyProtocolAdmissionDirection,\n RELAY_BINARY_FRAME_MAX_BYTES,\n RELAY_CONTROL_PROTOCOL_VERSION,\n RelayErrorCode,\n RelayCloseCode,\n RELAY_JSON_MESSAGE_MAX_BYTES,\n serializeControl,\n type ProxyProtocolRejectDirection,\n type RelayControlMessage,\n} from \"@dev-anywhere/shared\";\nimport type { Logger } from \"@dev-anywhere/shared/logger\";\nimport type { RelayRegistry } from \"../registry.js\";\nimport { parseMessage, routeProxyMessage } from \"../router.js\";\nimport type { RelayChaos } from \"../chaos.js\";\nimport { completeRelayProxyLatencyProbe } from \"../latency-probes.js\";\nimport type { RemoteFileBridge } from \"../remote-file-bridge.js\";\nimport type { PtySnapshotRouteRegistry } from \"../pty-snapshot-route-registry.js\";\nimport type { SessionHistoryRouteRegistry } from \"../session-history-route-registry.js\";\nimport {\n isWebPreviewResponseMessage,\n type WebPreviewRouteRegistry,\n} from \"../web-preview-route-registry.js\";\nimport { rewriteForwardedControl } from \"../forwarded-control.js\";\nimport { RELAY_VERSION } from \"../version.js\";\nimport type { DevicePreviewBridge } from \"../device-preview-bridge.js\";\nimport {\n parseProxyUpgradeBootstrapRequest,\n sendProxyUpgradeBootstrapResponse,\n} from \"../proxy-upgrade-bootstrap.js\";\n\n// 扩展 WebSocket 实例存储代理元数据\ninterface ProxySocket extends WebSocket {\n isAlive: boolean;\n proxyId?: string;\n admissionPhase: \"awaiting\" | \"ready\" | \"quarantined\" | \"rejected\";\n}\n\ntype BoundClientSocket = WebSocket & {\n clientId?: string;\n boundProxyId?: string;\n bindingId?: string;\n};\n\nconst PREVIEW_EVENT_TYPES = new Set([\n \"preview_state_event\",\n \"preview_removed_event\",\n \"device_preview_state_event\",\n \"device_preview_removed_event\",\n]);\nconst PREVIEW_PUSH_TYPES = new Set([\n \"preview_state_push\",\n \"preview_removed_push\",\n \"device_preview_state_push\",\n \"device_preview_removed_push\",\n]);\nconst DEFAULT_PROXY_ADMISSION_TIMEOUT_MS = 10_000;\n// A peer which did not finish registration may retry through its ordinary backoff. This is not\n// the permanent protocol-rejection signal.\nconst RETRYABLE_PROXY_ADMISSION_TIMEOUT_CLOSE_CODE = 1013;\n\ntype PreviewEventMessage = Extract<\n RelayControlMessage,\n {\n type:\n | \"preview_state_event\"\n | \"preview_removed_event\"\n | \"device_preview_state_event\"\n | \"device_preview_removed_event\";\n }\n>;\n\nfunction isPreviewEventMessage(message: RelayControlMessage): message is PreviewEventMessage {\n return PREVIEW_EVENT_TYPES.has(message.type);\n}\n\nfunction isPreviewPushType(type: string): boolean {\n return PREVIEW_PUSH_TYPES.has(type);\n}\n\nfunction previewPushType(event: PreviewEventMessage): RelayControlMessage[\"type\"] {\n switch (event.type) {\n case \"preview_state_event\":\n return \"preview_state_push\";\n case \"preview_removed_event\":\n return \"preview_removed_push\";\n case \"device_preview_state_event\":\n return \"device_preview_state_push\";\n case \"device_preview_removed_event\":\n return \"device_preview_removed_push\";\n }\n}\n\nfunction broadcastPreviewEvent(\n proxyId: string,\n sourceProxyWs: WebSocket,\n event: PreviewEventMessage,\n raw: string,\n registry: RelayRegistry,\n chaos?: RelayChaos,\n): number {\n let delivered = 0;\n for (const rawClientWs of registry.getClientsForProxy(proxyId)) {\n const clientWs = rawClientWs as BoundClientSocket;\n if (!clientWs.clientId || !clientWs.bindingId) continue;\n const scope = { proxyId, bindingId: clientWs.bindingId };\n const isCurrentRoute = (): boolean =>\n registry.getProxy(proxyId) === sourceProxyWs &&\n registry.isCurrentClientBinding(clientWs.clientId, clientWs, scope);\n if (!isCurrentRoute()) continue;\n\n const type = previewPushType(event);\n const push = rewriteForwardedControl(raw, { type, scope });\n if (chaos) {\n chaos.send(clientWs, push, {\n direction: \"proxy_to_client\",\n type,\n guard: isCurrentRoute,\n });\n } else if (isCurrentRoute() && clientWs.readyState === WebSocket.OPEN) {\n clientWs.send(push);\n }\n delivered += 1;\n }\n return delivered;\n}\n\n// 通知绑定到指定 proxy 的所有客户端 proxy 已离线\nfunction notifyClientsProxyOffline(\n proxyId: string,\n registry: RelayRegistry,\n logger: Logger,\n chaos?: RelayChaos,\n): void {\n const clients = registry.getClientsForProxy(proxyId);\n const msg = JSON.stringify({ type: \"proxy_offline\", proxyId });\n for (const clientWs of clients) {\n if (chaos) chaos.send(clientWs, msg, { direction: \"proxy_to_client\", type: \"proxy_offline\" });\n else clientWs.send(msg);\n }\n logger.info({ proxyId, clientCount: clients.length }, \"Notified clients of proxy offline\");\n}\n\n// 通知绑定到指定 proxy 的所有客户端 proxy 已上线\nfunction notifyClientsProxyOnline(\n proxyId: string,\n registry: RelayRegistry,\n logger: Logger,\n chaos?: RelayChaos,\n): void {\n const clients = registry.getClientsForProxy(proxyId);\n const msg = JSON.stringify({ type: \"proxy_online\", proxyId });\n for (const clientWs of clients) {\n if (chaos) chaos.send(clientWs, msg, { direction: \"proxy_to_client\", type: \"proxy_online\" });\n else clientWs.send(msg);\n }\n logger.info({ proxyId, clientCount: clients.length }, \"Notified clients of proxy online\");\n}\n\n// proxy 上线或下线时,将最新的 proxy 列表推送给所有已连接的 client。\n// 复用 proxy_list_response 消息类型,client 端已有对应处理逻辑,无需额外适配。\nfunction broadcastProxyList(registry: RelayRegistry, chaos?: RelayChaos): void {\n const proxies = registry.listProxiesWithName().map((p) => ({\n ...p,\n sessions: registry.getSessionsForProxy(p.proxyId),\n }));\n const msg = JSON.stringify({ type: \"proxy_list_response\", proxies });\n for (const clientWs of registry.getAllClientWs()) {\n if (chaos)\n chaos.send(clientWs, msg, { direction: \"proxy_to_client\", type: \"proxy_list_response\" });\n else clientWs.send(msg);\n }\n}\n\nfunction rejectNotRegistered(ws: ProxySocket): void {\n ws.send(\n JSON.stringify({\n type: \"relay_error\",\n code: RelayErrorCode.NOT_REGISTERED,\n message: \"Proxy must register before sending messages\",\n }),\n );\n}\n\nfunction closeRejectedProxyProtocol(\n ws: ProxySocket,\n direction: ProxyProtocolRejectDirection = ProxyProtocolAdmissionDirection.PROTOCOL_MISMATCH,\n): void {\n if (ws.admissionPhase === \"rejected\") return;\n ws.admissionPhase = \"rejected\";\n ws.close(RelayCloseCode.PROXY_PROTOCOL_REJECTED, direction);\n}\n\nfunction classifyInitialProxyProtocol(raw: string): ProxyProtocolRejectDirection | null {\n let value: unknown;\n try {\n value = JSON.parse(raw);\n } catch {\n return ProxyProtocolAdmissionDirection.PROTOCOL_MISMATCH;\n }\n if (\n !value ||\n typeof value !== \"object\" ||\n (value as { type?: unknown }).type !== \"proxy_register\"\n ) {\n return ProxyProtocolAdmissionDirection.PROTOCOL_MISMATCH;\n }\n const direction = compareProxyRelayProtocolVersions(\n (value as { protocolVersion?: unknown }).protocolVersion,\n RELAY_CONTROL_PROTOCOL_VERSION,\n );\n return direction === ProxyProtocolAdmissionDirection.COMPATIBLE ? null : direction;\n}\n\nfunction isCurrentProxySocket(ws: ProxySocket, registry: RelayRegistry): boolean {\n return ws.proxyId !== undefined && registry.getProxy(ws.proxyId) === ws;\n}\n\n// 处理代理端 WebSocket 连接生命周期\nexport function handleProxyConnection(\n ws: WebSocket,\n registry: RelayRegistry,\n logger: Logger,\n ptySnapshotRoutes: PtySnapshotRouteRegistry,\n sessionHistoryRoutes: SessionHistoryRouteRegistry,\n webPreviewRoutes: WebPreviewRouteRegistry,\n devicePreviewBridge: DevicePreviewBridge,\n chaos?: RelayChaos,\n remoteFileBridge?: RemoteFileBridge,\n proxyAdmissionTimeoutMs = DEFAULT_PROXY_ADMISSION_TIMEOUT_MS,\n): void {\n const proxyWs = ws as ProxySocket;\n proxyWs.isAlive = true;\n proxyWs.admissionPhase = \"awaiting\";\n let registrationCompleted = false;\n let initialFrameReceived = false;\n const effectiveAdmissionTimeoutMs =\n Number.isSafeInteger(proxyAdmissionTimeoutMs) && proxyAdmissionTimeoutMs > 0\n ? proxyAdmissionTimeoutMs\n : DEFAULT_PROXY_ADMISSION_TIMEOUT_MS;\n let admissionTimeout: ReturnType<typeof setTimeout> | null = setTimeout(() => {\n admissionTimeout = null;\n if (proxyWs.admissionPhase !== \"awaiting\" || proxyWs.readyState !== WebSocket.OPEN) return;\n proxyWs.admissionPhase = \"rejected\";\n logger.warn({ timeoutMs: effectiveAdmissionTimeoutMs }, \"Proxy registration timed out\");\n proxyWs.close(RETRYABLE_PROXY_ADMISSION_TIMEOUT_CLOSE_CODE, \"proxy registration timeout\");\n }, effectiveAdmissionTimeoutMs);\n admissionTimeout.unref?.();\n const clearAdmissionTimeout = (): void => {\n if (!admissionTimeout) return;\n clearTimeout(admissionTimeout);\n admissionTimeout = null;\n };\n\n proxyWs.on(\"pong\", () => {\n proxyWs.isAlive = true;\n });\n\n proxyWs.on(\"message\", (data: Buffer, isBinary: boolean) => {\n // Once the version-only bootstrap starts, this socket can never enter the application\n // protocol. In particular, queued traffic flushed by the source build is discarded.\n if (proxyWs.admissionPhase === \"quarantined\" || proxyWs.admissionPhase === \"rejected\") return;\n const isInitialFrame = !initialFrameReceived;\n initialFrameReceived = true;\n\n // Binary frames are pass-through; relay only reads the sessionId prefix for routing.\n if (isBinary) {\n if (!proxyWs.proxyId) {\n closeRejectedProxyProtocol(proxyWs, ProxyProtocolAdmissionDirection.PROTOCOL_MISMATCH);\n return;\n }\n if (!isCurrentProxySocket(proxyWs, registry)) {\n logger.debug(\n { proxyId: proxyWs.proxyId },\n \"Binary frame from superseded Proxy socket dropped\",\n );\n return;\n }\n if (data.length < 2 || data.length > RELAY_BINARY_FRAME_MAX_BYTES) {\n logger.warn({ size: data.length }, \"Binary frame rejected: invalid size\");\n return;\n }\n if (proxyWs.proxyId && remoteFileBridge?.handleProxyBinary(proxyWs.proxyId, data)) {\n return;\n }\n const sessionIdLen = data[0];\n if (sessionIdLen === 0 || sessionIdLen > 255 || data.length < 1 + sessionIdLen) {\n logger.warn(\n { sessionIdLen, dataLen: data.length },\n \"Binary frame rejected: malformed sessionId prefix\",\n );\n return;\n }\n if (!proxyWs.proxyId) {\n logger.warn(\"Binary frame from unregistered proxy, dropped\");\n return;\n }\n\n // Forward the original buffer, including the sessionId prefix, so clients receive exact PTY bytes.\n const clients = registry.getClientsForProxy(proxyWs.proxyId);\n for (const clientWs of clients) {\n if (clientWs.readyState === WebSocket.OPEN) {\n clientWs.send(data, { binary: true, compress: false });\n }\n }\n return;\n }\n\n if (data.length > RELAY_JSON_MESSAGE_MAX_BYTES) {\n logger.warn(\n { size: data.length, proxyId: proxyWs.proxyId },\n \"JSON message rejected: exceeds max size\",\n );\n if (!proxyWs.proxyId) {\n closeRejectedProxyProtocol(proxyWs, ProxyProtocolAdmissionDirection.PROTOCOL_MISMATCH);\n }\n return;\n }\n\n const raw = data.toString();\n const upgradeBootstrap = isInitialFrame\n ? parseProxyUpgradeBootstrapRequest(raw, RELAY_VERSION)\n : null;\n if (upgradeBootstrap) {\n proxyWs.admissionPhase = \"quarantined\";\n clearAdmissionTimeout();\n logger.info(\n {\n proxyId: upgradeBootstrap.proxyId,\n proxyVersion: upgradeBootstrap.proxyVersion,\n relayVersion: RELAY_VERSION,\n },\n \"Proxy upgrade bootstrap sent\",\n );\n sendProxyUpgradeBootstrapResponse(proxyWs, RELAY_VERSION);\n return;\n }\n\n if (isInitialFrame) {\n const rejection = classifyInitialProxyProtocol(raw);\n if (rejection) {\n logger.warn({ direction: rejection }, \"Proxy control protocol rejected before admission\");\n closeRejectedProxyProtocol(proxyWs, rejection);\n return;\n }\n }\n const result = parseMessage(raw);\n\n if (result.kind === \"control\" && result.message.type === \"proxy_register\") {\n if (registrationCompleted) {\n logger.warn(\n { proxyId: proxyWs.proxyId, requestedProxyId: result.message.proxyId },\n \"Repeated Proxy registration on the same socket rejected\",\n );\n closeRejectedProxyProtocol(proxyWs, ProxyProtocolAdmissionDirection.PROTOCOL_MISMATCH);\n return;\n }\n const { proxyId, name, osName, proxyVersion } = result.message;\n proxyWs.admissionPhase = \"ready\";\n clearAdmissionTimeout();\n const status = registry.registerProxy(proxyId, proxyWs, proxyVersion, name, osName);\n proxyWs.proxyId = proxyId;\n registrationCompleted = true;\n const connectionId = devicePreviewBridge.registerProxyConnection(proxyId, proxyWs);\n if (status === \"reconnected\") {\n ptySnapshotRoutes.clearProxy(proxyId);\n sessionHistoryRoutes.clearProxy(proxyId);\n webPreviewRoutes.clearProxy(proxyId);\n }\n logger.info({ proxyId, proxyVersion, status }, \"Proxy registered\");\n\n proxyWs.send(\n serializeControl({\n type: \"proxy_register_response\",\n protocolVersion: RELAY_CONTROL_PROTOCOL_VERSION,\n status,\n relayVersion: RELAY_VERSION,\n connectionId,\n }),\n );\n\n if (status === \"reconnected\") {\n notifyClientsProxyOnline(proxyId, registry, logger, chaos);\n }\n\n broadcastProxyList(registry, chaos);\n return;\n }\n\n if (!proxyWs.proxyId) {\n // Pre-admission failures have exactly one authority: the stable close code and reason.\n // A versioned relay_error cannot be trusted by the peer that just failed admission.\n closeRejectedProxyProtocol(proxyWs, ProxyProtocolAdmissionDirection.PROTOCOL_MISMATCH);\n return;\n }\n\n if (!isCurrentProxySocket(proxyWs, registry)) {\n logger.debug(\n { proxyId: proxyWs.proxyId, kind: result.kind },\n \"Message from superseded Proxy socket dropped\",\n );\n return;\n }\n\n if (result.kind === \"control\" && result.message.type === \"proxy_disconnect\") {\n if (proxyWs.proxyId) {\n ptySnapshotRoutes.clearProxy(proxyWs.proxyId);\n sessionHistoryRoutes.clearProxy(proxyWs.proxyId);\n webPreviewRoutes.clearProxy(proxyWs.proxyId);\n devicePreviewBridge.clearProxy(proxyWs.proxyId);\n notifyClientsProxyOffline(proxyWs.proxyId, registry, logger, chaos);\n registry.unregisterProxy(proxyWs.proxyId);\n logger.info(\n { proxyId: proxyWs.proxyId },\n \"Proxy gracefully disconnected, resources cleaned\",\n );\n proxyWs.proxyId = undefined;\n broadcastProxyList(registry, chaos);\n }\n return;\n }\n\n // proxy 重连后同步 session 列表,relay 据此建立 proxy-session 关联。\n if (result.kind === \"control\" && result.message.type === \"session_sync\") {\n if (!proxyWs.proxyId) return;\n const { sessions } = result.message;\n registry.setSessionsForProxy(\n proxyWs.proxyId,\n sessions.map((s) => s.id),\n );\n logger.info({ proxyId: proxyWs.proxyId, count: sessions.length }, \"Session sync received\");\n return;\n }\n\n if (result.kind === \"control\" && result.message.type === \"latency_relay_proxy_pong\") {\n if (!proxyWs.proxyId) {\n rejectNotRegistered(proxyWs);\n return;\n }\n const completed = completeRelayProxyLatencyProbe({\n proxyId: proxyWs.proxyId,\n requestId: result.message.requestId,\n logger,\n });\n if (!completed) {\n logger.debug(\n { proxyId: proxyWs.proxyId, requestId: result.message.requestId },\n \"Unmatched relay-proxy latency pong ignored\",\n );\n }\n return;\n }\n\n // proxy 发给 client 的控制消息:直接转发给绑定的客户端,不进 session buffer\n if (result.kind === \"control\") {\n if (isPreviewEventMessage(result.message) || isPreviewPushType(result.message.type)) {\n if (!proxyWs.proxyId) {\n rejectNotRegistered(proxyWs);\n return;\n }\n if (registry.getProxy(proxyWs.proxyId) !== proxyWs) {\n logger.debug(\n { proxyId: proxyWs.proxyId, type: result.message.type },\n \"Preview push from superseded Proxy socket dropped\",\n );\n return;\n }\n if (isPreviewPushType(result.message.type)) {\n logger.warn(\n { proxyId: proxyWs.proxyId, type: result.message.type },\n \"Relay-scoped Preview push sent by Proxy was dropped\",\n );\n return;\n }\n if (!isPreviewEventMessage(result.message)) return;\n if (result.message.type === \"device_preview_removed_event\") {\n devicePreviewBridge.handlePreviewRemovedEvent(\n proxyWs.proxyId,\n proxyWs,\n result.message.previewId,\n );\n }\n const clientCount = broadcastPreviewEvent(\n proxyWs.proxyId,\n proxyWs,\n result.message,\n raw,\n registry,\n chaos,\n );\n logger.info(\n { proxyId: proxyWs.proxyId, type: result.message.type, clientCount },\n \"Forwarded scoped Preview event to clients\",\n );\n return;\n }\n // Device Preview has a Relay-owned management/data plane. Consume every device message\n // here so none can accidentally enter the generic Proxy-to-client broadcast path.\n if (result.message.type.startsWith(\"device_preview_\")) {\n if (!proxyWs.proxyId) {\n rejectNotRegistered(proxyWs);\n return;\n }\n devicePreviewBridge.handleProxyControl(proxyWs.proxyId, proxyWs, result.message, raw);\n return;\n }\n if (proxyWs.proxyId && result.message.type === \"remote_file_stream_response\") {\n remoteFileBridge?.handleProxyControl(proxyWs.proxyId, result.message);\n return;\n }\n if (proxyWs.proxyId && result.message.type === \"remote_file_metadata_response\") {\n remoteFileBridge?.handleProxyControl(proxyWs.proxyId, result.message);\n return;\n }\n if (proxyWs.proxyId && result.message.type === \"remote_file_stream_complete\") {\n remoteFileBridge?.handleProxyControl(proxyWs.proxyId, result.message);\n return;\n }\n if (proxyWs.proxyId && result.message.type === \"remote_file_upload_stream_response\") {\n remoteFileBridge?.handleProxyControl(proxyWs.proxyId, result.message);\n return;\n }\n if (proxyWs.proxyId && result.message.type === \"session_snapshot\") {\n const route = ptySnapshotRoutes.resolve(\n proxyWs.proxyId,\n result.message.sessionId,\n result.message.requestId,\n proxyWs,\n );\n if (route.kind === \"matched\" && route.clientWs.readyState === WebSocket.OPEN) {\n if (chaos) {\n chaos.send(route.clientWs, raw, {\n direction: \"proxy_to_client\",\n type: result.message.type,\n });\n } else {\n route.clientWs.send(raw);\n }\n return;\n }\n\n logger.debug(\n {\n proxyId: proxyWs.proxyId,\n sessionId: result.message.sessionId,\n requestId: result.message.requestId,\n route: route.kind,\n },\n \"Unmatched PTY snapshot dropped\",\n );\n return;\n }\n if (result.message.type === \"session_history_response\") {\n if (!proxyWs.proxyId) {\n rejectNotRegistered(proxyWs);\n return;\n }\n const route = sessionHistoryRoutes.resolve(\n proxyWs.proxyId,\n result.message.requestId,\n proxyWs,\n );\n if (route.kind === \"matched\") {\n let delivered = 0;\n for (const target of route.targets) {\n if (target.clientWs.readyState !== WebSocket.OPEN) continue;\n const response = rewriteForwardedControl(raw, {\n type: result.message.type,\n requestId: target.requestId,\n });\n if (chaos) {\n chaos.send(target.clientWs, response, {\n direction: \"proxy_to_client\",\n type: result.message.type,\n });\n } else {\n target.clientWs.send(response);\n }\n delivered += 1;\n }\n logger.debug(\n {\n proxyId: proxyWs.proxyId,\n upstreamRequestId: result.message.requestId,\n waiterCount: route.targets.length,\n delivered,\n success: result.message.success,\n },\n \"Session history response fanned out\",\n );\n return;\n }\n\n logger.debug(\n {\n proxyId: proxyWs.proxyId,\n requestId: result.message.requestId,\n route: route.kind,\n },\n \"Unmatched session history response dropped\",\n );\n return;\n }\n if (isWebPreviewResponseMessage(result.message)) {\n if (!proxyWs.proxyId) {\n rejectNotRegistered(proxyWs);\n return;\n }\n const route = webPreviewRoutes.resolve(\n proxyWs.proxyId,\n result.message.requestId,\n result.message.type,\n proxyWs,\n );\n if (route.kind === \"matched\") {\n const isCurrentRoute = (): boolean =>\n registry.getProxy(proxyWs.proxyId!) === proxyWs &&\n registry.isCurrentClientBinding(route.clientId, route.clientWs, route.scope);\n if (route.clientWs.readyState !== WebSocket.OPEN || !isCurrentRoute()) {\n logger.debug(\n {\n proxyId: proxyWs.proxyId,\n requestId: result.message.requestId,\n type: result.message.type,\n },\n \"Web Preview response for stale client binding dropped\",\n );\n return;\n }\n const responseRaw = rewriteForwardedControl(raw, {\n type: result.message.type,\n requestId: route.clientRequestId,\n scope: route.scope,\n });\n if (chaos) {\n chaos.send(route.clientWs, responseRaw, {\n direction: \"proxy_to_client\",\n type: result.message.type,\n guard: isCurrentRoute,\n });\n } else if (isCurrentRoute()) {\n route.clientWs.send(responseRaw);\n }\n return;\n }\n\n logger.debug(\n {\n proxyId: proxyWs.proxyId,\n requestId: result.message.requestId,\n type: result.message.type,\n route: route.kind,\n ...(route.kind === \"response_type_mismatch\"\n ? { expectedResponseType: route.expectedResponseType }\n : {}),\n },\n \"Unmatched Web Preview response dropped\",\n );\n return;\n }\n if (isProxyToClientRelayControlType(result.message.type)) {\n if (!proxyWs.proxyId) {\n rejectNotRegistered(proxyWs);\n return;\n }\n const clients = registry.getClientsForProxy(proxyWs.proxyId);\n for (const clientWs of clients) {\n if (clientWs.readyState === WebSocket.OPEN) {\n if (chaos) {\n chaos.send(clientWs, raw, {\n direction: \"proxy_to_client\",\n type: result.message.type,\n });\n } else {\n clientWs.send(raw);\n }\n }\n }\n logger.info(\n { proxyId: proxyWs.proxyId, type: result.message.type, clientCount: clients.length },\n \"Forwarded control message from proxy to clients\",\n );\n return;\n }\n // 其他控制消息代理端不应发送\n logger.warn({ type: result.message.type }, \"Unexpected control message from proxy\");\n return;\n }\n\n if (result.kind === \"envelope\") {\n if (!proxyWs.proxyId) {\n rejectNotRegistered(proxyWs);\n return;\n }\n routeProxyMessage(raw, proxyWs.proxyId, registry, logger, chaos);\n return;\n }\n\n if (result.kind === \"invalid\") {\n logger.error({ error: result.error, raw: raw.slice(0, 200) }, \"Invalid message from proxy\");\n proxyWs.send(\n JSON.stringify({\n type: \"relay_error\",\n code: RelayErrorCode.INVALID_MESSAGE,\n message: `${result.error} | raw: ${raw.slice(0, 200)}`,\n }),\n );\n return;\n }\n });\n\n proxyWs.on(\"close\", (code: number, reason: Buffer) => {\n clearAdmissionTimeout();\n if (!proxyWs.proxyId) return;\n const closeMeta = { code, reason: reason.toString() || undefined };\n // 同 proxyId 重连场景:registerProxy 会 terminate 旧 ws、把 registry 指向新 ws,\n // 旧 ws 的 close 异步触发到达这里时,registry.getProxy(proxyId) 已是新 ws 实例。\n // 此时若仍执行 transitionProxy(\"online\", \"offline\"),会把新连接的状态翻回离线并广播一次假离线。\n // 仅当 registry 当前持有的 ws 仍是我们自己(或 entry 已被 proxy_disconnect 清掉)时才走离线流程。\n const current = registry.getProxy(proxyWs.proxyId);\n if (current && current !== proxyWs) {\n logger.info(\n { proxyId: proxyWs.proxyId, ...closeMeta },\n \"Old proxy ws closed after being superseded by reconnect, skipping offline transition\",\n );\n return;\n }\n ptySnapshotRoutes.clearProxy(proxyWs.proxyId);\n sessionHistoryRoutes.clearProxy(proxyWs.proxyId);\n webPreviewRoutes.clearProxy(proxyWs.proxyId);\n devicePreviewBridge.clearProxy(proxyWs.proxyId);\n notifyClientsProxyOffline(proxyWs.proxyId, registry, logger, chaos);\n try {\n registry.transitionProxy(proxyWs.proxyId, \"online\", \"offline\");\n } catch (err) {\n // 期望路径: proxy_disconnect 已清理 entry, 或 entry 已 offline——transitionProxy 抛\n // \"Proxy not found\" / state mismatch。debug 级别记录 err 以便真有 FSM bug 时能定位。\n logger.debug(\n { proxyId: proxyWs.proxyId, err: String(err) },\n \"transitionProxy on close skipped\",\n );\n }\n logger.info(\n { proxyId: proxyWs.proxyId, ...closeMeta },\n \"Proxy disconnected, state preserved for reconnect\",\n );\n broadcastProxyList(registry, chaos);\n });\n\n proxyWs.on(\"error\", (err) => {\n logger.error({ err, proxyId: proxyWs.proxyId }, \"Proxy WebSocket error\");\n });\n}\n","import { MessageEnvelopeSchema, RelayControlSchema, RelayErrorCode } from \"@dev-anywhere/shared\";\nimport type { RelayControlMessage } from \"@dev-anywhere/shared\";\nimport type { MessageEnvelope } from \"@dev-anywhere/shared\";\nimport { WebSocket } from \"ws\";\nimport type { Logger } from \"@dev-anywhere/shared/logger\";\nimport type { RelayRegistry } from \"./registry.js\";\nimport type { RelayChaos } from \"./chaos.js\";\n\n// 消息解析结果:控制消息、信封消息或无效消息\ntype ParseResult =\n | { kind: \"control\"; message: RelayControlMessage }\n | { kind: \"envelope\"; message: MessageEnvelope; raw: string }\n | { kind: \"invalid\"; error: string };\n\n// 解析 WebSocket 消息,按优先级尝试 RelayControl 和 MessageEnvelope\nexport function parseMessage(data: string): ParseResult {\n let parsed: unknown;\n try {\n parsed = JSON.parse(data);\n } catch {\n return { kind: \"invalid\", error: \"Invalid JSON\" };\n }\n\n const envelopeResult = MessageEnvelopeSchema.safeParse(parsed);\n if (envelopeResult.success) {\n return { kind: \"envelope\", message: envelopeResult.data, raw: data };\n }\n\n const controlResult = RelayControlSchema.safeParse(parsed);\n if (controlResult.success) {\n return { kind: \"control\", message: controlResult.data };\n }\n\n return { kind: \"invalid\", error: \"Message matches neither RelayControl nor MessageEnvelope\" };\n}\n\n// 从 raw JSON 抓 requestId, 用来给 invalid message 拼回 relay_error 时填充——这样\n// client waitForMessage 能用 requestId 立即拒对应的 pending Promise, 不必等 timeout。\nfunction extractRequestIdFromRaw(raw: string): string | undefined {\n try {\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\" && typeof parsed.requestId === \"string\") {\n return parsed.requestId;\n }\n } catch {\n // raw 不是合法 JSON, 直接没 requestId\n }\n return undefined;\n}\n\n// 将 proxy 发来的 MessageEnvelope 转发给绑定的 client\n// relay 无状态,不缓冲消息,直接透传\nexport function routeProxyMessage(\n raw: string,\n proxyId: string,\n registry: RelayRegistry,\n logger: Logger,\n chaos?: RelayChaos,\n): void {\n const result = parseMessage(raw);\n\n if (result.kind === \"invalid\") {\n logger.warn({ proxyId, error: result.error }, \"Invalid message from proxy\");\n return;\n }\n\n if (result.kind === \"control\") {\n logger.warn({ proxyId }, \"Control message in routeProxyMessage, should be handled by handler\");\n return;\n }\n\n const { message } = result;\n\n // session-scoped envelope 在 proxy 与 sessionId 间建立关联; 全局广播 (session_list /\n // heartbeat / auth / sync_*) 没有 sessionId, 直接广播给所有 client。\n if (typeof message.sessionId === \"string\") {\n registry.addSessionToProxy(proxyId, message.sessionId);\n }\n\n // 转发给所有绑定的客户端\n const clients = registry.getClientsForProxy(proxyId);\n for (const clientWs of clients) {\n if (clientWs.readyState === WebSocket.OPEN) {\n if (chaos) chaos.send(clientWs, raw, { direction: \"proxy_to_client\", type: message.type });\n else clientWs.send(raw);\n }\n }\n}\n\n// 将 client 发来的 MessageEnvelope 转发给绑定的 proxy\n// proxyId 由调用方从 clientId 绑定中解析后传入\nexport function routeClientMessage(\n raw: string,\n proxyId: string,\n clientWs: WebSocket,\n registry: RelayRegistry,\n logger: Logger,\n chaos?: RelayChaos,\n): void {\n const result = parseMessage(raw);\n\n if (result.kind === \"invalid\") {\n logger.warn({ error: result.error }, \"Invalid message from client\");\n // 把拒绝原因带 requestId 发回 client, 让 waitForMessage 立刻拒 pending Promise。\n // 不发回的话, 调用方只看到 \"上传超时\" / \"请求超时\" 这种泛用 timeout, 不知道\n // 实际是 schema 不认。常见触发场景: 客户端有新协议, relay 在旧 build 上还没认。\n const requestId = extractRequestIdFromRaw(raw);\n clientWs.send(\n JSON.stringify({\n type: \"relay_error\",\n code: RelayErrorCode.INVALID_MESSAGE,\n message: result.error,\n ...(requestId ? { requestId } : {}),\n }),\n );\n return;\n }\n\n if (result.kind === \"control\") {\n logger.warn(\"Control message in routeClientMessage, should be handled by handler\");\n return;\n }\n\n const proxyWs = registry.getProxy(proxyId);\n if (!proxyWs || proxyWs.readyState !== WebSocket.OPEN) {\n clientWs.send(\n JSON.stringify({\n type: \"relay_error\",\n code: RelayErrorCode.PROXY_OFFLINE,\n message: `Proxy ${proxyId} is not available`,\n }),\n );\n return;\n }\n\n if (chaos) chaos.send(proxyWs, raw, { direction: \"client_to_proxy\", type: result.message.type });\n else proxyWs.send(raw);\n}\n","import { performance } from \"node:perf_hooks\";\nimport { WebSocket } from \"ws\";\nimport { serializeControl, type ControlMessage } from \"@dev-anywhere/shared\";\nimport type { Logger } from \"@dev-anywhere/shared/logger\";\nimport type { RelayChaos } from \"./chaos.js\";\n\nconst DEFAULT_RELAY_PROXY_PROBE_TIMEOUT_MS = 3_000;\n\ninterface RelayProxyProbe {\n proxyId: string;\n requestId: string;\n clientWs: WebSocket;\n startedAt: number;\n timer: ReturnType<typeof setTimeout>;\n chaos?: RelayChaos;\n}\n\nconst pendingRelayProxyProbes = new Map<string, RelayProxyProbe>();\n\nfunction keyFor(proxyId: string, requestId: string): string {\n return `${proxyId}:${requestId}`;\n}\n\nfunction sendClientResponse(\n clientWs: WebSocket,\n response: ControlMessage<\"latency_relay_proxy_response\">,\n chaos?: RelayChaos,\n): void {\n if (clientWs.readyState !== WebSocket.OPEN) return;\n const raw = serializeControl(response);\n if (chaos) {\n chaos.send(clientWs, raw, {\n direction: \"proxy_to_client\",\n type: \"latency_relay_proxy_response\",\n });\n return;\n }\n clientWs.send(raw);\n}\n\nexport function startRelayProxyLatencyProbe({\n requestId,\n proxyId,\n proxyWs,\n clientWs,\n logger,\n chaos,\n timeoutMs = DEFAULT_RELAY_PROXY_PROBE_TIMEOUT_MS,\n}: {\n requestId: string;\n proxyId: string;\n proxyWs: WebSocket;\n clientWs: WebSocket;\n logger: Logger;\n chaos?: RelayChaos;\n timeoutMs?: number;\n}): void {\n const key = keyFor(proxyId, requestId);\n const existing = pendingRelayProxyProbes.get(key);\n if (existing) {\n clearTimeout(existing.timer);\n pendingRelayProxyProbes.delete(key);\n }\n\n const startedAt = performance.now();\n const timer = setTimeout(() => {\n pendingRelayProxyProbes.delete(key);\n sendClientResponse(\n clientWs,\n {\n type: \"latency_relay_proxy_response\",\n requestId,\n success: false,\n error: \"Relay 到开发机测速超时\",\n },\n chaos,\n );\n logger.warn({ proxyId, requestId }, \"Relay-proxy latency probe timed out\");\n }, timeoutMs);\n\n pendingRelayProxyProbes.set(key, {\n proxyId,\n requestId,\n clientWs,\n startedAt,\n timer,\n chaos,\n });\n\n const raw = serializeControl({\n type: \"latency_relay_proxy_ping\",\n requestId,\n relayNow: Date.now(),\n });\n if (chaos) {\n chaos.send(proxyWs, raw, { direction: \"client_to_proxy\", type: \"latency_relay_proxy_ping\" });\n return;\n }\n proxyWs.send(raw);\n}\n\nexport function completeRelayProxyLatencyProbe({\n proxyId,\n requestId,\n logger,\n}: {\n proxyId: string;\n requestId: string;\n logger: Logger;\n}): boolean {\n const key = keyFor(proxyId, requestId);\n const pending = pendingRelayProxyProbes.get(key);\n if (!pending) return false;\n\n pendingRelayProxyProbes.delete(key);\n clearTimeout(pending.timer);\n const rttMs = performance.now() - pending.startedAt;\n\n sendClientResponse(\n pending.clientWs,\n {\n type: \"latency_relay_proxy_response\",\n requestId,\n success: true,\n rttMs,\n },\n pending.chaos,\n );\n logger.debug({ proxyId, requestId, rttMs }, \"Relay-proxy latency probe completed\");\n return true;\n}\n","import { nanoid } from \"nanoid\";\nimport type { WebSocket } from \"ws\";\nimport type { PreviewScope } from \"@dev-anywhere/shared\";\n\nconst DEFAULT_MAX_ENTRIES = 4_096;\nconst DEFAULT_MAX_PENDING_PER_CLIENT = 64;\nconst DEFAULT_PENDING_TTL_MS = 60_000;\nconst DEFAULT_TOMBSTONE_TTL_MS = 60_000;\n\ntype PendingRoute<ResponseType extends string> = {\n state: \"pending\";\n proxyId: string;\n proxyWs: WebSocket;\n clientWs: WebSocket;\n clientId: string;\n scope: PreviewScope;\n clientRequestId: string;\n expectedResponseType: ResponseType;\n expiresAt: number;\n timer: ReturnType<typeof setTimeout>;\n};\n\ntype TombstoneRoute = {\n state: \"tombstone\";\n proxyId: string;\n expiresAt: number;\n timer: ReturnType<typeof setTimeout>;\n};\n\ntype Route<ResponseType extends string> = PendingRoute<ResponseType> | TombstoneRoute;\n\ntype PreviewRouteRegistration =\n | { kind: \"registered\"; upstreamRequestId: string }\n | { kind: \"client_capacity_exceeded\" }\n | { kind: \"capacity_exceeded\" };\n\ntype PreviewRouteResolution<ResponseType extends string> =\n | {\n kind: \"matched\";\n clientWs: WebSocket;\n clientId: string;\n clientRequestId: string;\n scope: PreviewScope;\n }\n | { kind: \"response_type_mismatch\"; expectedResponseType: ResponseType }\n | { kind: \"stale_proxy\" }\n | { kind: \"tombstone\" }\n | { kind: \"unmatched\" };\n\nexport interface PreviewRouteRegistryOptions {\n maxEntries?: number;\n maxPendingPerClient?: number;\n pendingTtlMs?: number;\n tombstoneTtlMs?: number;\n now?: () => number;\n upstreamRequestIdFactory?: () => string;\n}\n\ninterface PreviewRouteRegistryConfig {\n label: string;\n requestIdPrefix: string;\n}\n\nfunction routeKey(proxyId: string, upstreamRequestId: string): string {\n return JSON.stringify([proxyId, upstreamRequestId]);\n}\n\ntype BoundClientSocket = WebSocket & {\n clientId?: string;\n boundProxyId?: string;\n bindingId?: string;\n};\n\n/**\n * Correlates a request with the exact browser and Proxy sockets that carried it. Request IDs are\n * rewritten before crossing the Relay so equal IDs from different browsers cannot collide.\n * Completed, abandoned, and expired routes become short-lived tombstones so late responses cannot\n * fall through to a broadcast path.\n */\nexport class PreviewRouteRegistry<ResponseType extends string> {\n private readonly routes = new Map<string, Route<ResponseType>>();\n private readonly maxEntries: number;\n private readonly maxPendingPerClient: number;\n private readonly pendingTtlMs: number;\n private readonly tombstoneTtlMs: number;\n private readonly now: () => number;\n private readonly upstreamRequestIdFactory: () => string;\n private upstreamRequestSequence = 0;\n\n constructor(\n private readonly config: PreviewRouteRegistryConfig,\n options: PreviewRouteRegistryOptions = {},\n ) {\n this.maxEntries = Math.max(1, options.maxEntries ?? DEFAULT_MAX_ENTRIES);\n this.maxPendingPerClient = Math.max(\n 1,\n options.maxPendingPerClient ?? DEFAULT_MAX_PENDING_PER_CLIENT,\n );\n this.pendingTtlMs = Math.max(1, options.pendingTtlMs ?? DEFAULT_PENDING_TTL_MS);\n this.tombstoneTtlMs = Math.max(1, options.tombstoneTtlMs ?? DEFAULT_TOMBSTONE_TTL_MS);\n this.now = options.now ?? Date.now;\n this.upstreamRequestIdFactory =\n options.upstreamRequestIdFactory ??\n (() => {\n this.upstreamRequestSequence += 1;\n return `${config.requestIdPrefix}-${this.upstreamRequestSequence.toString(36)}-${nanoid(12)}`;\n });\n }\n\n register(\n proxyId: string,\n clientRequestId: string,\n expectedResponseType: ResponseType,\n clientWs: WebSocket,\n proxyWs: WebSocket,\n ): PreviewRouteRegistration {\n const now = this.now();\n this.pruneExpired(now);\n const boundClient = clientWs as BoundClientSocket;\n if (!boundClient.clientId || boundClient.boundProxyId !== proxyId || !boundClient.bindingId) {\n throw new Error(`${this.config.label} route requires an exact client binding`);\n }\n\n let pendingForClient = 0;\n for (const route of this.routes.values()) {\n if (route.state !== \"pending\" || route.clientWs !== clientWs) continue;\n pendingForClient += 1;\n if (pendingForClient >= this.maxPendingPerClient) {\n return { kind: \"client_capacity_exceeded\" };\n }\n }\n\n if (this.routes.size >= this.maxEntries && !this.evictOldestTombstone()) {\n return { kind: \"capacity_exceeded\" };\n }\n\n const upstreamRequestId = this.createUniqueUpstreamRequestId(proxyId);\n const key = routeKey(proxyId, upstreamRequestId);\n const expiresAt = now + this.pendingTtlMs;\n const timer = setTimeout(() => {\n if (this.routes.get(key) === route) this.setTombstone(key, proxyId, this.now());\n }, this.pendingTtlMs);\n timer.unref?.();\n const route: PendingRoute<ResponseType> = {\n state: \"pending\",\n proxyId,\n proxyWs,\n clientWs,\n clientId: boundClient.clientId,\n clientRequestId,\n scope: { proxyId, bindingId: boundClient.bindingId },\n expectedResponseType,\n expiresAt,\n timer,\n };\n this.routes.set(key, route);\n return { kind: \"registered\", upstreamRequestId };\n }\n\n resolve(\n proxyId: string,\n upstreamRequestId: string,\n responseType: ResponseType,\n proxyWs: WebSocket,\n ): PreviewRouteResolution<ResponseType> {\n const now = this.now();\n this.pruneExpired(now);\n const key = routeKey(proxyId, upstreamRequestId);\n const route = this.routes.get(key);\n if (!route) return { kind: \"unmatched\" };\n if (route.state === \"tombstone\") return { kind: \"tombstone\" };\n if (route.proxyWs !== proxyWs) return { kind: \"stale_proxy\" };\n if (route.expectedResponseType !== responseType) {\n return { kind: \"response_type_mismatch\", expectedResponseType: route.expectedResponseType };\n }\n\n const result = {\n clientWs: route.clientWs,\n clientId: route.clientId,\n clientRequestId: route.clientRequestId,\n scope: route.scope,\n };\n this.setTombstone(key, proxyId, now);\n return { kind: \"matched\", ...result };\n }\n\n abandonSocket(clientWs: WebSocket): void {\n const now = this.now();\n this.pruneExpired(now);\n for (const [key, route] of this.routes) {\n if (route.state === \"pending\" && route.clientWs === clientWs) {\n this.setTombstone(key, route.proxyId, now);\n }\n }\n }\n\n clearProxy(proxyId: string): void {\n for (const [key, route] of this.routes) {\n if (route.proxyId === proxyId) this.deleteRoute(key, route);\n }\n }\n\n dispose(): void {\n for (const [key, route] of this.routes) this.deleteRoute(key, route);\n }\n\n private createUniqueUpstreamRequestId(proxyId: string): string {\n for (let attempt = 0; attempt < 16; attempt += 1) {\n const candidate = this.upstreamRequestIdFactory();\n if (!this.routes.has(routeKey(proxyId, candidate))) return candidate;\n }\n throw new Error(`Unable to allocate a unique ${this.config.label} requestId`);\n }\n\n private setTombstone(key: string, proxyId: string, now: number): void {\n const current = this.routes.get(key);\n if (current) clearTimeout(current.timer);\n const expiresAt = now + this.tombstoneTtlMs;\n const timer = setTimeout(() => {\n if (this.routes.get(key) === route) this.routes.delete(key);\n }, this.tombstoneTtlMs);\n timer.unref?.();\n const route: TombstoneRoute = { state: \"tombstone\", proxyId, expiresAt, timer };\n this.routes.set(key, route);\n }\n\n private deleteRoute(key: string, route: Route<ResponseType>): void {\n clearTimeout(route.timer);\n this.routes.delete(key);\n }\n\n private evictOldestTombstone(): boolean {\n let candidate: [string, TombstoneRoute] | undefined;\n for (const [key, route] of this.routes) {\n if (route.state !== \"tombstone\") continue;\n if (!candidate || route.expiresAt < candidate[1].expiresAt) candidate = [key, route];\n }\n if (!candidate) return false;\n this.deleteRoute(candidate[0], candidate[1]);\n return true;\n }\n\n private pruneExpired(now: number): void {\n for (const [key, route] of this.routes) {\n if (route.expiresAt <= now) this.deleteRoute(key, route);\n }\n }\n}\n","import type { RelayControlMessage } from \"@dev-anywhere/shared\";\nimport {\n PreviewRouteRegistry,\n type PreviewRouteRegistryOptions,\n} from \"./preview-route-registry.js\";\n\nexport const webPreviewResponseByRequest = {\n preview_capability_request: \"preview_capability_response\",\n preview_static_inspect_request: \"preview_static_inspect_response\",\n preview_create_request: \"preview_create_response\",\n preview_list_request: \"preview_list_response\",\n preview_rename_request: \"preview_rename_response\",\n preview_reconnect_request: \"preview_reconnect_response\",\n preview_close_request: \"preview_close_response\",\n} as const;\n\nexport type WebPreviewRequestType = keyof typeof webPreviewResponseByRequest;\nexport type WebPreviewResponseType = (typeof webPreviewResponseByRequest)[WebPreviewRequestType];\nexport type WebPreviewRequestMessage = Extract<\n RelayControlMessage,\n { type: WebPreviewRequestType }\n>;\nexport type WebPreviewResponseMessage = Extract<\n RelayControlMessage,\n { type: WebPreviewResponseType }\n>;\nconst requestTypes = new Set<string>(Object.keys(webPreviewResponseByRequest));\nconst responseTypes = new Set<string>(Object.values(webPreviewResponseByRequest));\n\nexport function isWebPreviewRequestMessage(\n message: RelayControlMessage,\n): message is WebPreviewRequestMessage {\n return requestTypes.has(message.type);\n}\n\nexport function isWebPreviewResponseMessage(\n message: RelayControlMessage,\n): message is WebPreviewResponseMessage {\n return responseTypes.has(message.type);\n}\n\nexport class WebPreviewRouteRegistry extends PreviewRouteRegistry<WebPreviewResponseType> {\n constructor(options: PreviewRouteRegistryOptions = {}) {\n super({ label: \"Web Preview\", requestIdPrefix: \"relay-preview\" }, options);\n }\n}\n","import type { PreviewScope, RelayControlMessage } from \"@dev-anywhere/shared\";\n\n/** Preserve response data after validation while replacing Relay-owned routing fields. */\nexport function rewriteForwardedControl(\n validatedRaw: string,\n relayFields: {\n type: RelayControlMessage[\"type\"];\n requestId?: string;\n scope?: PreviewScope;\n },\n): string {\n const message = JSON.parse(validatedRaw) as Record<string, unknown>;\n // Responses without a request ID or scope must not inherit either from unknown metadata.\n delete message.requestId;\n delete message.scope;\n return JSON.stringify({ ...message, ...relayFields });\n}\n","import { IdSchema } from \"@dev-anywhere/shared\";\nimport type { WebSocket } from \"ws\";\nimport { z } from \"zod\";\n\nconst UPGRADE_BOOTSTRAP_SOURCE_VERSION = \"0.8.1\";\nconst STABLE_VERSION_RE = /^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)$/;\n\nconst ProxyUpgradeBootstrapRequestSchema = z\n .object({\n type: z.literal(\"proxy_register\"),\n proxyId: IdSchema,\n name: z.string().optional(),\n proxyVersion: z.literal(UPGRADE_BOOTSTRAP_SOURCE_VERSION),\n })\n .strict();\n\ntype ProxyUpgradeBootstrapRequest = z.infer<typeof ProxyUpgradeBootstrapRequestSchema>;\n\nfunction parseStableVersion(value: string): readonly [number, number, number] | null {\n const match = STABLE_VERSION_RE.exec(value);\n if (!match) return null;\n const parts = [Number(match[1]), Number(match[2]), Number(match[3])] as const;\n return parts.every(Number.isSafeInteger) ? parts : null;\n}\n\nfunction isLowerStableVersion(source: string, target: string): boolean {\n const left = parseStableVersion(source);\n const right = parseStableVersion(target);\n if (!left || !right) return false;\n for (let index = 0; index < left.length; index += 1) {\n if (left[index] !== right[index]) return left[index] < right[index];\n }\n return false;\n}\n\n// This is deliberately outside RelayControlSchema: the current control schema remains the only\n// way to register and exchange application traffic. This narrow bootstrap can only tell the\n// released source build which exact Relay package version it should install.\nexport function parseProxyUpgradeBootstrapRequest(\n raw: string,\n relayVersion: string,\n): ProxyUpgradeBootstrapRequest | null {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return null;\n }\n\n const request = ProxyUpgradeBootstrapRequestSchema.safeParse(parsed);\n if (!request.success) return null;\n if (!isLowerStableVersion(request.data.proxyVersion, relayVersion)) return null;\n return request.data;\n}\n\nexport function sendProxyUpgradeBootstrapResponse(ws: WebSocket, relayVersion: string): void {\n // Keep the authenticated socket open in its caller-owned quarantine until the updater replaces\n // the source daemon. Closing here would reset that daemon's reconnect counter after every\n // response and create a tight reconnect loop when automatic updates are disabled or unavailable.\n ws.send(\n JSON.stringify({\n type: \"proxy_register_response\",\n status: \"new\",\n relayVersion,\n }),\n (error) => {\n if (error) ws.terminate();\n },\n );\n}\n","import { WebSocket } from \"ws\";\nimport {\n ControlErrorCode,\n isClientToProxyRelayControlType,\n RELAY_CONTROL_PROTOCOL_VERSION,\n RelayCloseCode,\n RelayErrorCode,\n RelayProtocolRejectReason,\n type RelayProtocolRejectReasonType,\n RELAY_JSON_MESSAGE_MAX_BYTES,\n serializeControl,\n type ControlErrorCodeType,\n type PreviewScope,\n type RelayControlMessage,\n} from \"@dev-anywhere/shared\";\nimport type { Logger } from \"@dev-anywhere/shared/logger\";\nimport type { RelayRegistry } from \"../registry.js\";\nimport { parseMessage, routeClientMessage } from \"../router.js\";\nimport type { RelayChaos } from \"../chaos.js\";\nimport { handleVoiceConfigControl } from \"../voice/client-controls.js\";\nimport type { VoiceConfigStore } from \"../voice/config-store.js\";\nimport type { VoiceProviderRegistry } from \"../voice/provider.js\";\nimport { startRelayProxyLatencyProbe } from \"../latency-probes.js\";\nimport type { RemoteFileBridge } from \"../remote-file-bridge.js\";\nimport type { PtySnapshotRouteRegistry } from \"../pty-snapshot-route-registry.js\";\nimport type { SessionHistoryRouteRegistry } from \"../session-history-route-registry.js\";\nimport {\n isWebPreviewRequestMessage,\n webPreviewResponseByRequest,\n type WebPreviewRequestMessage,\n type WebPreviewRouteRegistry,\n} from \"../web-preview-route-registry.js\";\nimport type { DevicePreviewBridge } from \"../device-preview-bridge.js\";\nimport { isDevicePreviewRequestMessage } from \"../device-preview-route-registry.js\";\nimport {\n classifyClientRegistrationProtocol,\n inspectClientRegistrationAdmission,\n} from \"../client-registration-admission.js\";\n\n// 扩展 WebSocket 实例存储客户端元数据\ninterface ClientSocket extends WebSocket {\n isAlive: boolean;\n admissionPhase: \"awaiting\" | \"ready\" | \"rejected\";\n clientId?: string;\n boundProxyId?: string;\n bindingId?: string;\n}\n\ninterface ClientConnectionInfo {\n userAgent?: string;\n remoteAddress?: string;\n}\n\ninterface ClientRegisterInfo {\n protocolVersion: number;\n clientId: string;\n userAgent?: string;\n platform?: string;\n maxTouchPoints?: number;\n browserName: string;\n osName: string;\n deviceKind: \"desktop\" | \"tablet\" | \"phone\" | \"unknown\";\n}\n\nconst DEFAULT_CLIENT_ADMISSION_TIMEOUT_MS = 10_000;\n// 1013 (Try Again Later) deliberately remains outside the permanent protocol-rejection codes.\n// A client which merely failed to finish registration in time should use its ordinary backoff.\nconst RETRYABLE_CLIENT_ADMISSION_TIMEOUT_CLOSE_CODE = 1013;\n\n// 处理 client_register 消息:三种状态 restored / proxy_offline / new。\n// relay 不缓存输出;恢复由 proxy 重新推送 session_list/agent_status/snapshot 等状态。\nfunction handleClientRegister(\n registration: ClientRegisterInfo,\n clientWs: ClientSocket,\n registry: RelayRegistry,\n logger: Logger,\n webPreviewRoutes: WebPreviewRouteRegistry,\n devicePreviewBridge: DevicePreviewBridge,\n): void {\n const { clientId } = registration;\n if (clientWs.clientId && clientWs.clientId !== clientId) {\n webPreviewRoutes.abandonSocket(clientWs);\n devicePreviewBridge.abandonClientSocket(clientWs);\n registry.unbindClientSocket(clientWs.clientId, clientWs);\n }\n clientWs.clientId = clientId;\n registry.updateConnectedClientMetadata(clientWs, {\n clientId,\n ...(registration.userAgent !== undefined ? { userAgent: registration.userAgent } : {}),\n ...(registration.platform !== undefined ? { platform: registration.platform } : {}),\n ...(registration.maxTouchPoints !== undefined\n ? { maxTouchPoints: registration.maxTouchPoints }\n : {}),\n browserName: registration.browserName,\n osName: registration.osName,\n deviceKind: registration.deviceKind,\n });\n\n const binding = registry.getClientBinding(clientId);\n\n if (!binding) {\n clientWs.send(\n serializeControl({\n type: \"client_register_response\",\n protocolVersion: RELAY_CONTROL_PROTOCOL_VERSION,\n status: \"new\",\n }),\n );\n logger.info({ clientId, status: \"new\" }, \"Client registered\");\n return;\n }\n\n const previousWs = binding.ws;\n if (previousWs) {\n // Registering an existing clientId always creates a new binding generation. Pending Preview\n // responses and private streams belong to the superseded generation, even when the same\n // physical WebSocket sends client_register again.\n webPreviewRoutes.abandonSocket(previousWs);\n devicePreviewBridge.abandonClientSocket(previousWs);\n }\n const restored = registry.restoreClientBinding(clientId, clientWs);\n if (!restored) {\n throw new Error(`Client binding disappeared while restoring ${clientId}`);\n }\n const { proxyId, bindingId } = restored;\n\n if (!registry.isProxyOnline(proxyId)) {\n clientWs.send(\n serializeControl({\n type: \"client_register_response\",\n protocolVersion: RELAY_CONTROL_PROTOCOL_VERSION,\n status: \"proxy_offline\",\n proxyId,\n bindingId,\n }),\n );\n logger.info({ clientId, proxyId, status: \"proxy_offline\" }, \"Client registered\");\n return;\n }\n\n // proxy 在线,恢复绑定(relay 无状态,不做增量回放)\n clientWs.send(\n serializeControl({\n type: \"client_register_response\",\n protocolVersion: RELAY_CONTROL_PROTOCOL_VERSION,\n status: \"restored\",\n proxyId,\n bindingId,\n }),\n );\n\n logger.info({ clientId, proxyId, status: \"restored\" }, \"Client registered\");\n}\n\nfunction handleRelayClientListRequest(\n clientWs: ClientSocket,\n registry: RelayRegistry,\n requestId: string | undefined,\n): void {\n clientWs.send(\n JSON.stringify({\n type: \"relay_client_list_response\",\n requestId,\n clients: registry.getConnectedClientDetails(clientWs.clientId),\n }),\n );\n}\n\nfunction proxyListResponse(registry: RelayRegistry): string {\n const proxies = registry.listProxiesWithName().map((proxy) => ({\n ...proxy,\n sessions: registry.getSessionsForProxy(proxy.proxyId),\n }));\n return serializeControl({ type: \"proxy_list_response\", proxies });\n}\n\nfunction broadcastProxyList(registry: RelayRegistry, chaos?: RelayChaos): void {\n const response = proxyListResponse(registry);\n for (const target of registry.getAllClientWs()) {\n if (chaos) {\n chaos.send(target, response, {\n direction: \"proxy_to_client\",\n type: \"proxy_list_response\",\n });\n } else {\n target.send(response);\n }\n }\n}\n\nfunction broadcastProxyRemoved(proxyId: string, registry: RelayRegistry, chaos?: RelayChaos): void {\n const notification = serializeControl({ type: \"proxy_removed\", proxyId });\n for (const target of registry.getAllClientWs()) {\n if (chaos) {\n chaos.send(target, notification, {\n direction: \"proxy_to_client\",\n type: \"proxy_removed\",\n });\n } else {\n target.send(notification);\n }\n }\n}\n\nfunction sendProxyRemoveResponse(\n clientWs: ClientSocket,\n response: {\n requestId: string;\n proxyId: string;\n success: boolean;\n errorCode?: ControlErrorCodeType;\n error?: string;\n },\n chaos?: RelayChaos,\n): void {\n const raw = serializeControl({ type: \"proxy_remove_response\", ...response });\n if (chaos) {\n chaos.send(clientWs, raw, {\n direction: \"proxy_to_client\",\n type: \"proxy_remove_response\",\n });\n } else {\n clientWs.send(raw);\n }\n}\n\nfunction handleProxyRemove(\n clientWs: ClientSocket,\n registry: RelayRegistry,\n logger: Logger,\n ptySnapshotRoutes: PtySnapshotRouteRegistry,\n sessionHistoryRoutes: SessionHistoryRouteRegistry,\n webPreviewRoutes: WebPreviewRouteRegistry,\n remoteFileBridge: RemoteFileBridge | undefined,\n devicePreviewBridge: DevicePreviewBridge,\n requestId: string,\n proxyId: string,\n chaos?: RelayChaos,\n): void {\n const result = registry.removeOfflineProxy(proxyId);\n if (result === \"not_found\") {\n sendProxyRemoveResponse(\n clientWs,\n {\n requestId,\n proxyId,\n success: false,\n errorCode: ControlErrorCode.PROXY_NOT_FOUND,\n error: `开发机 ${proxyId} 不存在`,\n },\n chaos,\n );\n return;\n }\n if (result === \"online\") {\n sendProxyRemoveResponse(\n clientWs,\n {\n requestId,\n proxyId,\n success: false,\n errorCode: ControlErrorCode.PROXY_ONLINE,\n error: `开发机 ${proxyId} 仍在线,无法删除`,\n },\n chaos,\n );\n return;\n }\n\n ptySnapshotRoutes.clearProxy(proxyId);\n sessionHistoryRoutes.clearProxy(proxyId);\n webPreviewRoutes.clearProxy(proxyId);\n try {\n remoteFileBridge?.revokeProxy(proxyId);\n } catch (err) {\n // Proxy record and its routing bindings are already gone. A cleanup-side failure must not\n // strand the request without an ACK; revokeProxy deletes persistent tokens before touching\n // active HTTP responses, so old URLs remain unusable even on this exceptional path.\n logger.error({ err, proxyId }, \"Failed to finish remote file cleanup for removed proxy\");\n }\n try {\n devicePreviewBridge.revokeProxy(proxyId);\n } catch (err) {\n logger.error({ err, proxyId }, \"Failed to finish Device Preview cleanup for removed proxy\");\n }\n\n // cleanupProxy 会清掉发起者原有的 proxy binding;因此 ACK 必须直接写回当前\n // client WebSocket,不能再通过 binding 反查目标,否则删除自己的离线绑定时会丢响应。\n sendProxyRemoveResponse(clientWs, { requestId, proxyId, success: true }, chaos);\n broadcastProxyRemoved(proxyId, registry, chaos);\n broadcastProxyList(registry, chaos);\n logger.info({ proxyId, clientId: clientWs.clientId }, \"Offline proxy removed by client\");\n}\n\nfunction handleRelayClientKick(\n clientWs: ClientSocket,\n registry: RelayRegistry,\n logger: Logger,\n requestId: string,\n targetClientId: string,\n): void {\n if (targetClientId === clientWs.clientId) {\n clientWs.send(\n JSON.stringify({\n type: \"relay_client_kick_response\",\n requestId,\n clientId: targetClientId,\n success: false,\n errorCode: ControlErrorCode.UNKNOWN,\n error: \"不能断开当前客户端\",\n }),\n );\n return;\n }\n\n const targets = registry.getConnectedClientSockets(targetClientId);\n if (targets.length === 0) {\n clientWs.send(\n JSON.stringify({\n type: \"relay_client_kick_response\",\n requestId,\n clientId: targetClientId,\n success: false,\n errorCode: ControlErrorCode.UNKNOWN,\n error: \"客户端不在线\",\n }),\n );\n return;\n }\n\n const kickedMessage = JSON.stringify({\n type: \"relay_client_kicked\",\n reason: \"由客户端管理断开\",\n });\n for (const target of targets) {\n try {\n target.send(kickedMessage);\n target.close(RelayCloseCode.CLIENT_KICKED, \"client kicked\");\n } catch (err) {\n logger.warn({ err, clientId: targetClientId }, \"Failed to close kicked client\");\n target.terminate();\n } finally {\n registry.removeClientWs(target);\n registry.unbindClientById(targetClientId);\n }\n }\n\n clientWs.send(\n JSON.stringify({\n type: \"relay_client_kick_response\",\n requestId,\n clientId: targetClientId,\n success: true,\n }),\n );\n logger.info(\n { byClientId: clientWs.clientId, targetClientId, targetCount: targets.length },\n \"Relay client kicked\",\n );\n}\n\nfunction rejectNotBound(ws: ClientSocket, requestId?: string): void {\n ws.send(\n JSON.stringify({\n type: \"relay_error\",\n ...(requestId !== undefined ? { requestId } : {}),\n code: RelayErrorCode.NOT_BOUND,\n message: \"Client is not bound to any proxy\",\n }),\n );\n}\n\nfunction rejectNotRegistered(ws: ClientSocket, requestId: string | undefined): void {\n ws.send(\n JSON.stringify({\n type: \"relay_error\",\n requestId,\n code: RelayErrorCode.NOT_REGISTERED,\n message: \"Client must register first\",\n }),\n );\n}\n\nfunction rejectStaleBinding(ws: ClientSocket, requestId?: string): void {\n ws.send(\n JSON.stringify({\n type: \"relay_error\",\n ...(requestId ? { requestId } : {}),\n code: RelayErrorCode.STALE_BINDING,\n message: \"Preview request used a stale client binding\",\n }),\n );\n}\n\nfunction rejectStaleDevicePreviewInput(\n ws: ClientSocket,\n message: Extract<RelayControlMessage, { type: \"device_preview_input\" }>,\n): void {\n ws.send(\n serializeControl({\n type: \"device_preview_input_ack\",\n scope: message.scope,\n leaseId: message.leaseId,\n inputSeq: message.inputSeq,\n success: false,\n error: \"Preview request used a stale client binding\",\n errorCode: ControlErrorCode.CONTROL_LEASE_INVALID,\n }),\n );\n}\n\nfunction sendWebPreviewFailure(\n ws: ClientSocket,\n message: WebPreviewRequestMessage,\n error: string,\n errorCode: ControlErrorCodeType,\n): boolean {\n switch (message.type) {\n case \"preview_capability_request\":\n ws.send(\n serializeControl({\n type: \"preview_capability_response\",\n requestId: message.requestId,\n scope: message.scope,\n success: false,\n error,\n errorCode,\n }),\n );\n return true;\n case \"preview_static_inspect_request\":\n ws.send(\n serializeControl({\n type: \"preview_static_inspect_response\",\n requestId: message.requestId,\n scope: message.scope,\n success: false,\n error,\n errorCode,\n }),\n );\n return true;\n case \"preview_create_request\":\n ws.send(\n serializeControl({\n type: \"preview_create_response\",\n requestId: message.requestId,\n scope: message.scope,\n operationId: message.operationId,\n accepted: false,\n error,\n errorCode,\n }),\n );\n return true;\n case \"preview_rename_request\":\n ws.send(\n serializeControl({\n type: \"preview_rename_response\",\n requestId: message.requestId,\n scope: message.scope,\n operationId: message.operationId,\n previewId: message.previewId,\n success: false,\n error,\n errorCode,\n }),\n );\n return true;\n case \"preview_reconnect_request\":\n ws.send(\n serializeControl({\n type: \"preview_reconnect_response\",\n requestId: message.requestId,\n scope: message.scope,\n operationId: message.operationId,\n previewId: message.previewId,\n success: false,\n error,\n errorCode,\n }),\n );\n return true;\n case \"preview_close_request\":\n ws.send(\n serializeControl({\n type: \"preview_close_response\",\n requestId: message.requestId,\n scope: message.scope,\n operationId: message.operationId,\n previewId: message.previewId,\n success: false,\n error,\n errorCode,\n }),\n );\n return true;\n case \"preview_list_request\":\n return false;\n }\n}\n\nfunction validatePreviewScope(\n ws: ClientSocket,\n registry: RelayRegistry,\n requestId: string | undefined,\n scope: PreviewScope,\n): boolean {\n if (registry.isCurrentClientBinding(ws.clientId, ws, scope)) return true;\n rejectStaleBinding(ws, requestId);\n return false;\n}\n\nfunction closeRejectedClientProtocol(\n ws: ClientSocket,\n reason: RelayProtocolRejectReasonType = RelayProtocolRejectReason.PROTOCOL_MISMATCH,\n): void {\n if (!beginClientRejection(ws)) return;\n ws.close(RelayCloseCode.CLIENT_PROTOCOL_REJECTED, reason);\n}\n\nfunction beginClientRejection(ws: ClientSocket): boolean {\n if (ws.admissionPhase === \"rejected\") return false;\n ws.admissionPhase = \"rejected\";\n return ws.readyState !== WebSocket.CLOSING && ws.readyState !== WebSocket.CLOSED;\n}\n\nfunction closeUnversionedClientProtocol(ws: ClientSocket): void {\n // 4401 is the permanent-disconnect signal understood by clients from before the versioned\n // registration handshake. Sending it here is an admission-level tombstone only: the Relay does\n // not accept or translate the obsolete business protocol.\n if (!beginClientRejection(ws)) return;\n ws.send(\n JSON.stringify({\n type: \"relay_client_kicked\",\n reason: \"页面版本已更新,请刷新\",\n }),\n );\n ws.close(RelayCloseCode.CLIENT_KICKED, \"client refresh required\");\n}\n\nfunction rejectVersionedClientProtocol(\n ws: ClientSocket,\n clientProtocolVersion: unknown,\n reason: RelayProtocolRejectReasonType,\n clientId: string | undefined,\n logger: Logger,\n): void {\n logger.warn(\n {\n ...(clientId !== undefined ? { clientId } : {}),\n clientProtocolVersion,\n relayProtocolVersion: RELAY_CONTROL_PROTOCOL_VERSION,\n reason,\n },\n \"Client control protocol rejected at admission\",\n );\n closeRejectedClientProtocol(ws, reason);\n}\n\nfunction rejectProxySelect(ws: ClientSocket, requestId: string | undefined, proxyId: string): void {\n ws.send(\n serializeControl({\n type: \"proxy_select_response\",\n requestId,\n success: false,\n errorCode: ControlErrorCode.PROXY_OFFLINE,\n error: `Proxy not online: ${proxyId}`,\n }),\n );\n}\n\nfunction sendRelayProxyProbeFailure(\n ws: ClientSocket,\n requestId: string,\n error: string,\n chaos?: RelayChaos,\n): void {\n const response = serializeControl({\n type: \"latency_relay_proxy_response\",\n requestId,\n success: false,\n error,\n });\n if (chaos) {\n chaos.send(ws, response, {\n direction: \"proxy_to_client\",\n type: \"latency_relay_proxy_response\",\n });\n return;\n }\n ws.send(response);\n}\n\nfunction sendRemoteFileUrlFailure(\n ws: ClientSocket,\n requestId: string,\n sessionId: string,\n error: string,\n errorCode: ControlErrorCodeType = ControlErrorCode.UNKNOWN,\n): void {\n ws.send(\n serializeControl({\n type: \"remote_file_url_response\",\n requestId,\n sessionId,\n success: false,\n error,\n errorCode,\n }),\n );\n}\n\nfunction sendRemoteFileUploadUrlFailure(\n ws: ClientSocket,\n requestId: string,\n sessionId: string,\n error: string,\n errorCode: ControlErrorCodeType = ControlErrorCode.UNKNOWN,\n): void {\n ws.send(\n serializeControl({\n type: \"remote_file_upload_url_response\",\n requestId,\n sessionId,\n success: false,\n error,\n errorCode,\n }),\n );\n}\n\n// 处理远程客户端 WebSocket 连接生命周期\nexport function handleClientConnection(\n ws: WebSocket,\n registry: RelayRegistry,\n logger: Logger,\n ptySnapshotRoutes: PtySnapshotRouteRegistry,\n sessionHistoryRoutes: SessionHistoryRouteRegistry,\n webPreviewRoutes: WebPreviewRouteRegistry,\n devicePreviewBridge: DevicePreviewBridge,\n chaos?: RelayChaos,\n voiceConfigStore?: VoiceConfigStore,\n voiceProviders?: VoiceProviderRegistry,\n remoteFileBridge?: RemoteFileBridge,\n connectionInfo: ClientConnectionInfo = {},\n clientAdmissionTimeoutMs = DEFAULT_CLIENT_ADMISSION_TIMEOUT_MS,\n): void {\n const clientWs = ws as ClientSocket;\n clientWs.isAlive = true;\n clientWs.admissionPhase = \"awaiting\";\n registry.addClientWs(clientWs, connectionInfo);\n\n const effectiveAdmissionTimeoutMs =\n Number.isSafeInteger(clientAdmissionTimeoutMs) && clientAdmissionTimeoutMs > 0\n ? clientAdmissionTimeoutMs\n : DEFAULT_CLIENT_ADMISSION_TIMEOUT_MS;\n let admissionTimeout: ReturnType<typeof setTimeout> | null = setTimeout(() => {\n admissionTimeout = null;\n if (clientWs.admissionPhase !== \"awaiting\" || clientWs.readyState !== WebSocket.OPEN) return;\n if (!beginClientRejection(clientWs)) return;\n logger.warn(\n { timeoutMs: effectiveAdmissionTimeoutMs, remoteAddress: connectionInfo.remoteAddress },\n \"Client registration timed out\",\n );\n clientWs.close(RETRYABLE_CLIENT_ADMISSION_TIMEOUT_CLOSE_CODE, \"client registration timeout\");\n }, effectiveAdmissionTimeoutMs);\n admissionTimeout.unref?.();\n const clearAdmissionTimeout = (): void => {\n if (!admissionTimeout) return;\n clearTimeout(admissionTimeout);\n admissionTimeout = null;\n };\n\n clientWs.on(\"pong\", () => {\n clientWs.isAlive = true;\n });\n\n clientWs.on(\"message\", (data: Buffer, isBinary: boolean) => {\n if (clientWs.admissionPhase === \"rejected\") return;\n // Clients only send JSON control/envelope messages; binary frames from clients are ignored.\n if (isBinary) {\n if (!clientWs.clientId) closeRejectedClientProtocol(clientWs);\n return;\n }\n\n if (data.length > RELAY_JSON_MESSAGE_MAX_BYTES) {\n logger.warn(\n { size: data.length, clientId: clientWs.clientId },\n \"JSON message rejected: exceeds max size\",\n );\n if (!clientWs.clientId) closeRejectedClientProtocol(clientWs);\n return;\n }\n\n const raw = data.toString();\n const registrationAdmission = inspectClientRegistrationAdmission(raw);\n if (registrationAdmission.kind === \"unversioned_client_registration\") {\n logger.warn(\n {\n ...(registrationAdmission.clientId !== undefined\n ? { clientId: registrationAdmission.clientId }\n : {}),\n },\n \"Unversioned client registration rejected\",\n );\n closeUnversionedClientProtocol(clientWs);\n return;\n }\n if (registrationAdmission.kind === \"versioned_client_registration\") {\n const registrationProtocolIssue = classifyClientRegistrationProtocol(\n registrationAdmission.protocolVersion,\n );\n if (registrationProtocolIssue) {\n rejectVersionedClientProtocol(\n clientWs,\n registrationAdmission.protocolVersion,\n registrationProtocolIssue,\n registrationAdmission.clientId,\n logger,\n );\n return;\n }\n }\n\n const result = parseMessage(raw);\n\n if (result.kind === \"control\") {\n const msg = result.message;\n logger.info(\n { type: msg.type, clientId: clientWs.clientId, bound: clientWs.boundProxyId },\n \"Client message received\",\n );\n\n if (msg.type === \"client_register\") {\n handleClientRegister(\n msg,\n clientWs,\n registry,\n logger,\n webPreviewRoutes,\n devicePreviewBridge,\n );\n clientWs.admissionPhase = \"ready\";\n clearAdmissionTimeout();\n return;\n }\n\n if (!clientWs.clientId) {\n const requestId =\n \"requestId\" in msg && typeof msg.requestId === \"string\" ? msg.requestId : undefined;\n rejectNotRegistered(clientWs, requestId);\n closeRejectedClientProtocol(clientWs);\n return;\n }\n\n if (msg.type === \"relay_client_list_request\") {\n handleRelayClientListRequest(clientWs, registry, msg.requestId);\n return;\n }\n\n if (msg.type === \"relay_client_kick\") {\n handleRelayClientKick(clientWs, registry, logger, msg.requestId, msg.clientId);\n return;\n }\n\n if (msg.type === \"proxy_remove\") {\n if (!clientWs.clientId) {\n rejectNotRegistered(clientWs, msg.requestId);\n closeRejectedClientProtocol(clientWs);\n return;\n }\n handleProxyRemove(\n clientWs,\n registry,\n logger,\n ptySnapshotRoutes,\n sessionHistoryRoutes,\n webPreviewRoutes,\n remoteFileBridge,\n devicePreviewBridge,\n msg.requestId,\n msg.proxyId,\n chaos,\n );\n return;\n }\n\n const isScopedDevicePreviewMessage =\n isDevicePreviewRequestMessage(msg) ||\n msg.type === \"device_preview_stream_url_request\" ||\n msg.type === \"device_preview_input\" ||\n msg.type === \"device_preview_control_claim_request\";\n if (isScopedDevicePreviewMessage) {\n if (\n msg.type === \"device_preview_input\" &&\n !registry.isCurrentClientBinding(clientWs.clientId, clientWs, msg.scope)\n ) {\n rejectStaleDevicePreviewInput(clientWs, msg);\n return;\n }\n const requestId = msg.type === \"device_preview_input\" ? undefined : msg.requestId;\n if (!validatePreviewScope(clientWs, registry, requestId, msg.scope)) return;\n devicePreviewBridge.handleClientControl(clientWs, msg);\n return;\n }\n\n if (msg.type === \"remote_file_url_request\") {\n if (!remoteFileBridge) {\n sendRemoteFileUrlFailure(clientWs, msg.requestId, msg.sessionId, \"文件流服务不可用\");\n return;\n }\n if (!clientWs.clientId) {\n sendRemoteFileUrlFailure(\n clientWs,\n msg.requestId,\n msg.sessionId,\n \"客户端未注册\",\n ControlErrorCode.UNKNOWN,\n );\n return;\n }\n const targetProxyId = clientWs.boundProxyId;\n if (!targetProxyId || !registry.isProxyOnline(targetProxyId)) {\n sendRemoteFileUrlFailure(\n clientWs,\n msg.requestId,\n msg.sessionId,\n \"当前未连接开发机\",\n ControlErrorCode.PROXY_OFFLINE,\n );\n return;\n }\n const ownerProxyId = registry.getProxyForSession(msg.sessionId);\n if (ownerProxyId && ownerProxyId !== targetProxyId) {\n sendRemoteFileUrlFailure(\n clientWs,\n msg.requestId,\n msg.sessionId,\n \"会话不属于当前开发机\",\n ControlErrorCode.SESSION_NOT_FOUND,\n );\n return;\n }\n void remoteFileBridge\n .createUrl({\n clientId: clientWs.clientId,\n proxyId: targetProxyId,\n sessionId: msg.sessionId,\n path: msg.path,\n disposition: msg.disposition,\n })\n .then((result) => {\n if (clientWs.readyState !== WebSocket.OPEN) return;\n if (!result.success) {\n sendRemoteFileUrlFailure(\n clientWs,\n msg.requestId,\n msg.sessionId,\n result.error,\n result.errorCode,\n );\n return;\n }\n clientWs.send(\n serializeControl({\n type: \"remote_file_url_response\",\n requestId: msg.requestId,\n sessionId: msg.sessionId,\n path: result.path,\n success: true,\n url: result.url,\n expiresAt: result.expiresAt,\n }),\n );\n })\n .catch((err: unknown) => {\n if (clientWs.readyState !== WebSocket.OPEN) return;\n sendRemoteFileUrlFailure(\n clientWs,\n msg.requestId,\n msg.sessionId,\n err instanceof Error ? err.message : String(err),\n );\n });\n return;\n }\n\n if (msg.type === \"remote_file_upload_url_request\") {\n if (!remoteFileBridge) {\n sendRemoteFileUploadUrlFailure(clientWs, msg.requestId, msg.sessionId, \"上传服务不可用\");\n return;\n }\n if (!clientWs.clientId) {\n sendRemoteFileUploadUrlFailure(clientWs, msg.requestId, msg.sessionId, \"客户端未注册\");\n return;\n }\n const targetProxyId = clientWs.boundProxyId;\n if (!targetProxyId || !registry.isProxyOnline(targetProxyId)) {\n sendRemoteFileUploadUrlFailure(\n clientWs,\n msg.requestId,\n msg.sessionId,\n \"当前未连接开发机\",\n ControlErrorCode.PROXY_OFFLINE,\n );\n return;\n }\n const ownerProxyId = registry.getProxyForSession(msg.sessionId);\n if (ownerProxyId && ownerProxyId !== targetProxyId) {\n sendRemoteFileUploadUrlFailure(\n clientWs,\n msg.requestId,\n msg.sessionId,\n \"会话不属于当前开发机\",\n ControlErrorCode.SESSION_NOT_FOUND,\n );\n return;\n }\n const { uploadUrl, expiresAt } = remoteFileBridge.createUploadUrl({\n clientId: clientWs.clientId,\n proxyId: targetProxyId,\n sessionId: msg.sessionId,\n kind: msg.kind,\n fileName: msg.fileName,\n mimeType: msg.mimeType,\n size: msg.size,\n });\n clientWs.send(\n serializeControl({\n type: \"remote_file_upload_url_response\",\n requestId: msg.requestId,\n sessionId: msg.sessionId,\n success: true,\n uploadUrl,\n expiresAt,\n }),\n );\n return;\n }\n\n if (msg.type === \"proxy_list_request\") {\n const proxies = registry.listProxiesWithName().map((proxy) => ({\n ...proxy,\n sessions: registry.getSessionsForProxy(proxy.proxyId),\n }));\n const response = serializeControl({\n type: \"proxy_list_response\",\n ...(msg.requestId !== undefined ? { requestId: msg.requestId } : {}),\n proxies,\n });\n if (chaos) {\n chaos.send(clientWs, response, {\n direction: \"proxy_to_client\",\n type: \"proxy_list_response\",\n });\n } else {\n clientWs.send(response);\n }\n return;\n }\n\n if (msg.type === \"latency_web_relay_ping\") {\n const response = serializeControl({\n type: \"latency_web_relay_pong\",\n requestId: msg.requestId,\n relayNow: Date.now(),\n });\n if (chaos) {\n chaos.send(clientWs, response, {\n direction: \"proxy_to_client\",\n type: \"latency_web_relay_pong\",\n });\n } else {\n clientWs.send(response);\n }\n return;\n }\n\n if (msg.type === \"latency_relay_proxy_request\") {\n const targetProxyId = clientWs.boundProxyId;\n if (!targetProxyId) {\n sendRelayProxyProbeFailure(clientWs, msg.requestId, \"当前未连接开发机\", chaos);\n return;\n }\n const proxyWs = registry.getProxy(targetProxyId);\n if (!proxyWs || proxyWs.readyState !== WebSocket.OPEN) {\n sendRelayProxyProbeFailure(\n clientWs,\n msg.requestId,\n `开发机 ${targetProxyId} 不在线`,\n chaos,\n );\n return;\n }\n startRelayProxyLatencyProbe({\n requestId: msg.requestId,\n proxyId: targetProxyId,\n proxyWs,\n clientWs,\n logger,\n chaos,\n });\n return;\n }\n\n if (\n voiceConfigStore &&\n handleVoiceConfigControl(msg, clientWs, voiceConfigStore, logger, voiceProviders)\n ) {\n return;\n }\n\n if (isWebPreviewRequestMessage(msg)) {\n if (!validatePreviewScope(clientWs, registry, msg.requestId, msg.scope)) {\n return;\n }\n const targetProxyId = clientWs.boundProxyId;\n if (!targetProxyId) {\n if (\n !sendWebPreviewFailure(\n clientWs,\n msg,\n \"当前未连接开发机\",\n ControlErrorCode.PROXY_OFFLINE,\n )\n ) {\n rejectNotBound(clientWs, msg.requestId);\n }\n return;\n }\n const proxyWs = registry.getProxy(targetProxyId);\n if (!proxyWs || proxyWs.readyState !== WebSocket.OPEN) {\n if (\n !sendWebPreviewFailure(\n clientWs,\n msg,\n `开发机 ${targetProxyId} 不在线`,\n ControlErrorCode.PROXY_OFFLINE,\n )\n ) {\n clientWs.send(\n JSON.stringify({\n type: \"relay_error\",\n requestId: msg.requestId,\n code: RelayErrorCode.PROXY_OFFLINE,\n message: `Proxy ${targetProxyId} is not available`,\n }),\n );\n }\n return;\n }\n\n let registration: ReturnType<WebPreviewRouteRegistry[\"register\"]>;\n try {\n registration = webPreviewRoutes.register(\n targetProxyId,\n msg.requestId,\n webPreviewResponseByRequest[msg.type],\n clientWs,\n proxyWs,\n );\n } catch (error) {\n logger.error(\n { proxyId: targetProxyId, type: msg.type, error },\n \"Could not allocate Web Preview management route\",\n );\n if (\n !sendWebPreviewFailure(\n clientWs,\n msg,\n \"暂时无法处理网页预览请求\",\n ControlErrorCode.UNKNOWN,\n )\n ) {\n clientWs.send(\n JSON.stringify({\n type: \"relay_error\",\n requestId: msg.requestId,\n code: RelayErrorCode.INVALID_MESSAGE,\n message: \"Could not allocate Web Preview request\",\n }),\n );\n }\n return;\n }\n if (registration.kind !== \"registered\") {\n const message =\n registration.kind === \"client_capacity_exceeded\"\n ? \"当前客户端有过多待处理的网页预览请求\"\n : \"网页预览请求过多\";\n if (!sendWebPreviewFailure(clientWs, msg, message, ControlErrorCode.RATE_LIMITED)) {\n clientWs.send(\n JSON.stringify({\n type: \"relay_error\",\n requestId: msg.requestId,\n code: RelayErrorCode.INVALID_MESSAGE,\n message,\n }),\n );\n }\n return;\n }\n\n const upstreamRequest = {\n ...msg,\n requestId: registration.upstreamRequestId,\n } as WebPreviewRequestMessage;\n const upstreamRaw = serializeControl(upstreamRequest);\n const requestRouteStillCurrent = (): boolean =>\n clientWs.readyState === WebSocket.OPEN &&\n proxyWs.readyState === WebSocket.OPEN &&\n registry.getProxy(targetProxyId) === proxyWs &&\n registry.isCurrentClientBinding(clientWs.clientId, clientWs, msg.scope);\n if (!requestRouteStillCurrent()) return;\n if (chaos) {\n chaos.send(proxyWs, upstreamRaw, {\n direction: \"client_to_proxy\",\n type: msg.type,\n guard: requestRouteStillCurrent,\n });\n } else if (requestRouteStillCurrent()) {\n proxyWs.send(upstreamRaw);\n }\n return;\n }\n\n // client → proxy 透传:relay 不处理内容,直接转发给绑定的 proxy。\n // 路由 key 永远是 clientWs.boundProxyId, 不能被消息字段里 client 自填的 proxyId 覆盖\n // (那条路径让绑到 p1 的 client 通过 dir_list_request{proxyId:\"p2\"} 读到别的 proxy 的目录)。\n if (isClientToProxyRelayControlType(msg.type)) {\n const targetProxyId = clientWs.boundProxyId;\n if (!targetProxyId) {\n rejectNotBound(clientWs);\n return;\n }\n const proxyWs = registry.getProxy(targetProxyId);\n if (proxyWs && proxyWs.readyState === WebSocket.OPEN) {\n if (msg.type === \"session_history_request\") {\n const registration = sessionHistoryRoutes.register(\n targetProxyId,\n msg.requestId,\n clientWs,\n proxyWs,\n );\n if (registration.kind === \"duplicate\") {\n logger.debug(\n { proxyId: targetProxyId, requestId: msg.requestId },\n \"Duplicate session history request suppressed\",\n );\n return;\n }\n if (registration.kind === \"joined\") {\n logger.debug(\n {\n proxyId: targetProxyId,\n requestId: msg.requestId,\n upstreamRequestId: registration.upstreamRequestId,\n },\n \"Session history request joined active upstream flight\",\n );\n return;\n }\n if (registration.kind !== \"leader\") {\n logger.warn(\n { proxyId: targetProxyId, requestId: msg.requestId, registration },\n \"Session history response route rejected\",\n );\n clientWs.send(\n JSON.stringify({\n type: \"relay_error\",\n requestId: msg.requestId,\n code: RelayErrorCode.INVALID_MESSAGE,\n message:\n registration.kind === \"collision\"\n ? \"Session history requestId is already in use\"\n : \"Too many pending session history requests\",\n }),\n );\n return;\n }\n const upstreamRequest = serializeControl({\n type: \"session_history_request\",\n requestId: registration.upstreamRequestId,\n });\n if (chaos) {\n chaos.send(proxyWs, upstreamRequest, {\n direction: \"client_to_proxy\",\n type: msg.type,\n });\n } else {\n proxyWs.send(upstreamRequest);\n }\n return;\n }\n if (msg.type === \"session_subscribe\") {\n const registration = ptySnapshotRoutes.register(\n targetProxyId,\n msg.sessionId,\n msg.requestId,\n clientWs,\n proxyWs,\n );\n if (registration === \"duplicate\") {\n logger.debug(\n { proxyId: targetProxyId, sessionId: msg.sessionId, requestId: msg.requestId },\n \"Duplicate PTY snapshot subscribe suppressed\",\n );\n return;\n }\n if (registration !== \"registered\" && registration !== \"retry_due\") {\n logger.warn(\n {\n proxyId: targetProxyId,\n sessionId: msg.sessionId,\n requestId: msg.requestId,\n registration,\n },\n \"PTY snapshot subscribe route rejected\",\n );\n clientWs.send(\n JSON.stringify({\n type: \"relay_error\",\n requestId: msg.requestId,\n code: RelayErrorCode.INVALID_MESSAGE,\n message:\n registration === \"collision\"\n ? \"PTY snapshot requestId is already in use\"\n : \"Too many pending PTY snapshot requests\",\n }),\n );\n return;\n }\n if (registration === \"retry_due\") {\n logger.debug(\n { proxyId: targetProxyId, sessionId: msg.sessionId, requestId: msg.requestId },\n \"Retrying unanswered PTY snapshot subscribe\",\n );\n }\n }\n if (chaos) chaos.send(proxyWs, raw, { direction: \"client_to_proxy\", type: msg.type });\n else proxyWs.send(raw);\n } else {\n clientWs.send(\n JSON.stringify({\n type: \"relay_error\",\n code: RelayErrorCode.PROXY_OFFLINE,\n message: `Proxy ${targetProxyId} is not available`,\n }),\n );\n }\n return;\n }\n\n if (msg.type === \"proxy_select\") {\n if (!clientWs.clientId) {\n rejectNotRegistered(clientWs, msg.requestId);\n closeRejectedClientProtocol(clientWs);\n return;\n }\n if (!registry.isProxyOnline(msg.proxyId)) {\n rejectProxySelect(clientWs, msg.requestId, msg.proxyId);\n return;\n }\n const bindingId = registry.bindClientById(clientWs.clientId, msg.proxyId, clientWs);\n if (!bindingId) {\n rejectProxySelect(clientWs, msg.requestId, msg.proxyId);\n return;\n }\n // Every successful selection installs a new binding generation, including re-selecting\n // the same Proxy. Any in-flight Preview work belongs to the previous generation.\n webPreviewRoutes.abandonSocket(clientWs);\n devicePreviewBridge.abandonClientSocket(clientWs);\n const response = serializeControl({\n type: \"proxy_select_response\",\n requestId: msg.requestId,\n success: true,\n proxyId: msg.proxyId,\n bindingId,\n });\n const selectedScope = { proxyId: msg.proxyId, bindingId };\n const selectionStillCurrent = (): boolean =>\n registry.isCurrentClientBinding(clientWs.clientId, clientWs, selectedScope);\n if (chaos) {\n chaos.send(clientWs, response, {\n direction: \"proxy_to_client\",\n type: \"proxy_select_response\",\n guard: selectionStillCurrent,\n });\n } else if (selectionStillCurrent()) {\n clientWs.send(response);\n }\n logger.info({ proxyId: msg.proxyId, clientId: clientWs.clientId }, \"Client bound to proxy\");\n return;\n }\n\n clientWs.send(\n JSON.stringify({\n type: \"relay_error\",\n code: RelayErrorCode.UNSUPPORTED,\n message: `Unsupported control message: ${msg.type}`,\n }),\n );\n return;\n }\n\n if (result.kind === \"envelope\") {\n if (!clientWs.clientId) {\n rejectNotRegistered(clientWs, undefined);\n closeRejectedClientProtocol(clientWs);\n return;\n }\n if (!clientWs.boundProxyId) {\n rejectNotBound(clientWs);\n return;\n }\n routeClientMessage(raw, clientWs.boundProxyId, clientWs, registry, logger, chaos);\n return;\n }\n\n const isRegistrationAttempt = registrationAdmission.kind !== \"not_client_registration\";\n const logContext = {\n error: result.error,\n raw: raw.slice(0, 200),\n ...(registrationAdmission.kind !== \"not_client_registration\" &&\n registrationAdmission.clientId !== undefined\n ? { clientId: registrationAdmission.clientId }\n : {}),\n };\n logger.error(logContext, \"Invalid message from client\");\n clientWs.send(\n JSON.stringify({\n type: \"relay_error\",\n code: RelayErrorCode.INVALID_MESSAGE,\n message: `${result.error} | raw: ${raw.slice(0, 200)}`,\n }),\n );\n if (isRegistrationAttempt || !clientWs.clientId) {\n closeRejectedClientProtocol(clientWs);\n }\n });\n\n clientWs.on(\"close\", (code: number, reason: Buffer) => {\n clearAdmissionTimeout();\n clientWs.admissionPhase = \"rejected\";\n ptySnapshotRoutes.abandonSocket(clientWs);\n sessionHistoryRoutes.abandonSocket(clientWs);\n webPreviewRoutes.abandonSocket(clientWs);\n devicePreviewBridge.abandonClientSocket(clientWs);\n registry.removeClientWs(clientWs);\n // 清掉 binding.ws 引用:保留绑定关系(重连时还能恢复 proxyId 关联),但释放对已关闭 ws 对象的强引用,\n // 避免高频重连下 clientBindings Map 长期持有死 ws 对象阻止 GC,同时让 countClients 数字不再虚高。\n if (clientWs.clientId) {\n registry.unbindClientSocket(clientWs.clientId, clientWs);\n }\n logger.info(\n {\n clientId: clientWs.clientId,\n boundProxyId: clientWs.boundProxyId,\n code,\n reason: reason.toString() || undefined,\n },\n \"Client disconnected\",\n );\n });\n\n clientWs.on(\"error\", (err) => {\n logger.error({ err }, \"Client WebSocket error\");\n });\n}\n","import { EventEmitter } from \"node:events\";\nimport { nanoid } from \"nanoid\";\nimport { WebSocket } from \"ws\";\nimport { bailianRealtimeUrl, type BailianRegion } from \"./bailian-endpoints.js\";\n\ntype SocketOptions = { headers?: Record<string, string> };\ntype ProviderSocket = EventEmitter & {\n readyState: number;\n send: (data: string | Buffer) => void;\n close: (code?: number, reason?: string) => void;\n};\n\ntype BailianAsrSocketFactory = (url: string, options: SocketOptions) => ProviderSocket;\n\nexport interface BailianAsrConfig {\n apiKey: string;\n region: BailianRegion;\n model: string;\n sampleRate: number;\n language: string;\n}\n\nexport interface BailianAsrClient {\n on(event: \"ready\", handler: () => void): this;\n on(event: \"partial\" | \"final\", handler: (text: string) => void): this;\n on(event: \"error\", handler: (error: Error) => void): this;\n on(event: \"closed\", handler: (code?: number, reason?: string) => void): this;\n sendPcm(chunk: Buffer): void;\n stop(): void;\n close(): void;\n}\n\ninterface BailianAsrClientOptions {\n socketFactory?: BailianAsrSocketFactory;\n eventIdFactory?: () => string;\n}\n\nconst OPEN = 1;\nconst END_OF_SPEECH_SILENCE_MS = 1200;\n// Voice Pilot already uses an aggressive client-side VAD. Keep the provider-side\n// gate less sensitive so sustained household noise is not transcribed as speech.\nconst NOISE_RESISTANT_SERVER_VAD_THRESHOLD = 0.8;\n\nfunction defaultSocketFactory(url: string, options: SocketOptions): ProviderSocket {\n return new WebSocket(url, options) as ProviderSocket;\n}\n\nfunction extractRealtimePreview(payload: unknown): string | null {\n if (!payload || typeof payload !== \"object\") return null;\n const record = payload as Record<string, unknown>;\n if (typeof record.text === \"string\" || typeof record.stash === \"string\") {\n const text = typeof record.text === \"string\" ? record.text : \"\";\n const stash = typeof record.stash === \"string\" ? record.stash : \"\";\n const preview = `${text}${stash}`;\n return preview.length > 0 ? preview : null;\n }\n const candidates = [\n record.text,\n record.transcript,\n record.delta,\n record.output &&\n typeof record.output === \"object\" &&\n (record.output as Record<string, unknown>).text,\n ];\n for (const candidate of candidates) {\n if (typeof candidate === \"string\" && candidate.length > 0) return candidate;\n }\n return null;\n}\n\nfunction extractFinalText(payload: unknown): string | null {\n if (!payload || typeof payload !== \"object\") return null;\n const record = payload as Record<string, unknown>;\n const candidates = [\n record.transcript,\n record.text,\n record.output &&\n typeof record.output === \"object\" &&\n (record.output as Record<string, unknown>).text,\n ];\n for (const candidate of candidates) {\n if (typeof candidate === \"string\" && candidate.length > 0) return candidate;\n }\n return null;\n}\n\nfunction extractError(payload: unknown): Error {\n if (!payload || typeof payload !== \"object\") return new Error(\"Bailian ASR error\");\n const record = payload as Record<string, unknown>;\n const nested = record.error && typeof record.error === \"object\" ? record.error : null;\n let message = \"Bailian ASR error\";\n if (nested && typeof (nested as Record<string, unknown>).message === \"string\") {\n message = (nested as Record<string, string>).message;\n } else if (typeof record.message === \"string\") {\n message = record.message;\n }\n return new Error(message);\n}\n\nclass BailianAsrClientImpl extends EventEmitter implements BailianAsrClient {\n private socket: ProviderSocket;\n private isOpen = false;\n private isReady = false;\n private hasFinalTranscript = false;\n private pending: string[] = [];\n\n constructor(\n private readonly config: BailianAsrConfig,\n socketFactory: BailianAsrSocketFactory,\n private readonly eventIdFactory: () => string,\n ) {\n super();\n this.socket = socketFactory(bailianRealtimeUrl(config.region, config.model), {\n headers: {\n Authorization: `bearer ${config.apiKey}`,\n \"OpenAI-Beta\": \"realtime=v1\",\n },\n });\n this.socket.on(\"open\", () => this.handleOpen());\n this.socket.on(\"message\", (data: unknown) => this.handleMessage(data));\n this.socket.on(\"error\", (err: unknown) =>\n this.emit(\"error\", err instanceof Error ? err : new Error(String(err))),\n );\n this.socket.on(\"close\", (code?: number, reason?: Buffer) =>\n this.emit(\"closed\", code, reason?.toString(\"utf8\")),\n );\n }\n\n sendPcm(chunk: Buffer): void {\n this.sendWhenReady({\n event_id: this.eventIdFactory(),\n type: \"input_audio_buffer.append\",\n audio: chunk.toString(\"base64\"),\n });\n }\n\n stop(): void {\n this.sendWhenReady({\n event_id: this.eventIdFactory(),\n type: \"session.finish\",\n });\n }\n\n close(): void {\n this.socket.close();\n }\n\n private handleOpen(): void {\n this.isOpen = true;\n this.sendNow({\n event_id: this.eventIdFactory(),\n type: \"session.update\",\n session: {\n modalities: [\"text\"],\n input_audio_format: \"pcm\",\n sample_rate: this.config.sampleRate,\n input_audio_transcription: {\n language: this.config.language,\n },\n turn_detection: {\n type: \"server_vad\",\n threshold: NOISE_RESISTANT_SERVER_VAD_THRESHOLD,\n silence_duration_ms: END_OF_SPEECH_SILENCE_MS,\n },\n },\n });\n }\n\n private handleMessage(data: unknown): void {\n const text =\n typeof data === \"string\" ? data : Buffer.isBuffer(data) ? data.toString(\"utf8\") : \"\";\n if (!text) return;\n let payload: unknown;\n try {\n payload = JSON.parse(text);\n } catch {\n return;\n }\n const record = payload as { type?: unknown };\n const type = typeof record.type === \"string\" ? record.type : \"\";\n if (type.includes(\"error\")) {\n this.emit(\"error\", extractError(payload));\n return;\n }\n if (type === \"conversation.item.input_audio_transcription.failed\") {\n this.emit(\"error\", extractError(payload));\n return;\n }\n if (type === \"session.updated\") {\n this.isReady = true;\n this.emit(\"ready\");\n this.flushPending();\n return;\n }\n if (type === \"conversation.item.input_audio_transcription.text\") {\n const preview = extractRealtimePreview(payload);\n if (preview) this.emit(\"partial\", preview);\n return;\n }\n if (type === \"conversation.item.input_audio_transcription.completed\") {\n const transcript = extractFinalText(payload);\n if (transcript) {\n this.hasFinalTranscript = true;\n this.emit(\"final\", transcript);\n }\n return;\n }\n if (type === \"session.finished\") {\n const transcript = extractFinalText(payload);\n if (transcript && !this.hasFinalTranscript) {\n this.hasFinalTranscript = true;\n this.emit(\"final\", transcript);\n }\n this.socket.close(1000, \"session-finished\");\n }\n }\n\n private sendWhenReady(payload: unknown): void {\n const message = JSON.stringify(payload);\n if ((this.isOpen || this.socket.readyState === OPEN) && this.isReady) {\n this.socket.send(message);\n return;\n }\n this.pending.push(message);\n }\n\n private sendNow(payload: unknown): void {\n this.socket.send(JSON.stringify(payload));\n }\n\n private flushPending(): void {\n for (const message of this.pending) {\n this.socket.send(message);\n }\n this.pending = [];\n }\n}\n\nexport function createBailianAsrClient(\n config: BailianAsrConfig,\n options: BailianAsrClientOptions = {},\n): BailianAsrClient {\n return new BailianAsrClientImpl(\n config,\n options.socketFactory ?? defaultSocketFactory,\n options.eventIdFactory ?? (() => `event_${nanoid()}`),\n );\n}\n","export type BailianRegion = \"cn\" | \"intl\";\n\nconst BAILIAN_HOSTS: Record<BailianRegion, string> = {\n cn: \"wss://dashscope.aliyuncs.com\",\n intl: \"wss://dashscope-intl.aliyuncs.com\",\n};\n\nexport function bailianRealtimeUrl(region: BailianRegion, model?: string): string {\n const url = `${BAILIAN_HOSTS[region]}/api-ws/v1/realtime`;\n return model ? `${url}?model=${encodeURIComponent(model)}` : url;\n}\n\nexport function bailianInferenceUrl(region: BailianRegion): string {\n return `${BAILIAN_HOSTS[region]}/api-ws/v1/inference`;\n}\n","import { EventEmitter } from \"node:events\";\nimport { nanoid } from \"nanoid\";\nimport { WebSocket } from \"ws\";\nimport { bailianInferenceUrl, type BailianRegion } from \"./bailian-endpoints.js\";\n\ntype SocketOptions = { headers?: Record<string, string> };\ntype ProviderSocket = EventEmitter & {\n readyState: number;\n send: (data: string | Buffer) => void;\n close: (code?: number, reason?: string) => void;\n};\n\ntype BailianTtsSocketFactory = (url: string, options: SocketOptions) => ProviderSocket;\n\nexport interface BailianTtsConfig {\n apiKey: string;\n region: BailianRegion;\n model: string;\n voice: string;\n sampleRate: number;\n}\n\nexport interface BailianTtsClient {\n on(event: \"started\" | \"finished\", handler: () => void): this;\n on(event: \"audio\", handler: (chunk: Buffer) => void): this;\n on(event: \"error\", handler: (error: Error) => void): this;\n on(event: \"closed\", handler: (code?: number, reason?: string) => void): this;\n speak(text: string): void;\n close(): void;\n}\n\ninterface BailianTtsClientOptions {\n socketFactory?: BailianTtsSocketFactory;\n taskIdFactory?: () => string;\n}\n\nconst OPEN = 1;\n\nfunction defaultSocketFactory(url: string, options: SocketOptions): ProviderSocket {\n return new WebSocket(url, options) as ProviderSocket;\n}\n\nfunction errorFromPayload(payload: unknown): Error {\n if (!payload || typeof payload !== \"object\") return new Error(\"Bailian TTS error\");\n const record = payload as Record<string, unknown>;\n const header = record.header && typeof record.header === \"object\" ? record.header : null;\n let message = \"Bailian TTS error\";\n if (header && typeof (header as Record<string, unknown>).error_message === \"string\") {\n message = (header as Record<string, string>).error_message;\n } else if (typeof record.message === \"string\") {\n message = record.message;\n }\n return new Error(message);\n}\n\nfunction eventFromPayload(payload: unknown): string {\n if (!payload || typeof payload !== \"object\") return \"\";\n const record = payload as Record<string, unknown>;\n const header = record.header && typeof record.header === \"object\" ? record.header : null;\n const event = header ? (header as Record<string, unknown>).event : undefined;\n return typeof event === \"string\" ? event : \"\";\n}\n\nclass BailianTtsClientImpl extends EventEmitter implements BailianTtsClient {\n private socket: ProviderSocket;\n private isOpen = false;\n private current: { taskId: string; text: string } | null = null;\n\n constructor(\n private readonly config: BailianTtsConfig,\n socketFactory: BailianTtsSocketFactory,\n private readonly taskIdFactory: () => string,\n ) {\n super();\n this.socket = socketFactory(bailianInferenceUrl(config.region), {\n headers: { Authorization: `bearer ${config.apiKey}` },\n });\n this.socket.on(\"open\", () => this.handleOpen());\n this.socket.on(\"message\", (data: unknown, isBinary?: boolean) =>\n this.handleMessage(data, isBinary),\n );\n this.socket.on(\"error\", (err: unknown) =>\n this.emit(\"error\", err instanceof Error ? err : new Error(String(err))),\n );\n this.socket.on(\"close\", (code?: number, reason?: Buffer) =>\n this.emit(\"closed\", code, reason?.toString(\"utf8\")),\n );\n }\n\n speak(text: string): void {\n if (this.current) {\n throw new Error(\"Bailian TTS is already speaking\");\n }\n this.current = { taskId: this.taskIdFactory(), text };\n if (this.isOpen || this.socket.readyState === OPEN) {\n this.sendRunTask();\n }\n }\n\n close(): void {\n this.socket.close();\n }\n\n private handleOpen(): void {\n this.isOpen = true;\n if (this.current) this.sendRunTask();\n }\n\n private handleMessage(data: unknown, isBinary = false): void {\n const text = this.tryDecodeText(data, isBinary);\n if (!text) {\n const chunk = Buffer.isBuffer(data) ? data : Buffer.from(data as ArrayBuffer);\n this.emit(\"audio\", chunk);\n return;\n }\n let payload: unknown;\n try {\n payload = JSON.parse(text);\n } catch {\n const chunk = Buffer.isBuffer(data) ? data : Buffer.from(text);\n this.emit(\"audio\", chunk);\n return;\n }\n\n const event = eventFromPayload(payload);\n if (event === \"task-started\") {\n this.emit(\"started\");\n this.sendTextAndFinish();\n return;\n }\n if (event === \"task-finished\") {\n this.emit(\"finished\");\n this.current = null;\n return;\n }\n if (event === \"task-failed\" || event === \"task-error\") {\n this.emit(\"error\", errorFromPayload(payload));\n this.current = null;\n }\n }\n\n private tryDecodeText(data: unknown, isBinary: boolean): string | null {\n if (typeof data === \"string\") return data;\n if (isBinary) return null;\n if (Buffer.isBuffer(data)) return data.toString(\"utf8\");\n return null;\n }\n\n private sendRunTask(): void {\n if (!this.current) return;\n this.socket.send(\n JSON.stringify({\n header: {\n action: \"run-task\",\n task_id: this.current.taskId,\n streaming: \"duplex\",\n },\n payload: {\n task_group: \"audio\",\n task: \"tts\",\n function: \"SpeechSynthesizer\",\n model: this.config.model,\n input: {},\n parameters: {\n text_type: \"PlainText\",\n voice: this.config.voice,\n format: \"pcm\",\n sample_rate: this.config.sampleRate,\n },\n },\n }),\n );\n }\n\n private sendTextAndFinish(): void {\n if (!this.current) return;\n this.socket.send(\n JSON.stringify({\n header: { action: \"continue-task\", task_id: this.current.taskId },\n payload: { input: { text: this.current.text } },\n }),\n );\n this.socket.send(\n JSON.stringify({\n header: { action: \"finish-task\", task_id: this.current.taskId },\n payload: { input: {} },\n }),\n );\n }\n}\n\nexport function createBailianTtsClient(\n config: BailianTtsConfig,\n options: BailianTtsClientOptions = {},\n): BailianTtsClient {\n return new BailianTtsClientImpl(\n config,\n options.socketFactory ?? defaultSocketFactory,\n options.taskIdFactory ?? (() => nanoid()),\n );\n}\n","import waveResampler from \"wave-resampler\";\n\nconst RESAMPLE_DETAILS = {\n method: \"sinc\",\n LPF: true,\n LPFType: \"FIR\",\n} as const;\n\nexport function resampleMonoPcmS16le(\n audio: Buffer,\n inputSampleRate: number,\n outputSampleRate: number,\n): Buffer {\n if (audio.byteLength % 2 !== 0) {\n throw new Error(\"PCM 音频数据长度无效\");\n }\n if (!validSampleRate(inputSampleRate) || !validSampleRate(outputSampleRate)) {\n throw new Error(\"PCM 音频采样率无效\");\n }\n if (inputSampleRate === outputSampleRate) return Buffer.from(audio);\n\n const input = new Int16Array(audio.byteLength / 2);\n for (let index = 0; index < input.length; index += 1) {\n input[index] = audio.readInt16LE(index * 2);\n }\n\n const samples = waveResampler.resample(\n input,\n inputSampleRate,\n outputSampleRate,\n RESAMPLE_DETAILS,\n );\n const output = Buffer.alloc(samples.length * 2);\n for (let index = 0; index < samples.length; index += 1) {\n const sample = samples[index];\n if (typeof sample !== \"number\" || !Number.isFinite(sample)) {\n throw new Error(\"PCM 音频重采样失败\");\n }\n output.writeInt16LE(Math.max(-32768, Math.min(32767, Math.round(sample))), index * 2);\n }\n return output;\n}\n\nfunction validSampleRate(sampleRate: number): boolean {\n return Number.isSafeInteger(sampleRate) && sampleRate > 0;\n}\n","import type { VoiceConfigUpdate } from \"@dev-anywhere/shared\";\nimport {\n createBailianAsrClient,\n type BailianAsrClient,\n type BailianAsrConfig,\n} from \"./bailian-asr.js\";\nimport {\n createBailianTtsClient,\n type BailianTtsClient,\n type BailianTtsConfig,\n} from \"./bailian-tts.js\";\nimport type { StoredVoiceConfig } from \"./config-store.js\";\nimport { resampleMonoPcmS16le } from \"./pcm-resample.js\";\n\nexport interface VoiceConfigTestResult {\n audio?: Buffer;\n sampleRate?: number;\n transcript?: string;\n}\n\nexport interface VoiceConfigTester {\n test: (config: StoredVoiceConfig) => Promise<VoiceConfigTestResult>;\n}\n\ninterface BailianVoiceConfigTesterOptions {\n ttsClientFactory?: (config: BailianTtsConfig) => BailianTtsClient;\n asrClientFactory?: (config: BailianAsrConfig) => BailianAsrClient;\n sampleText?: string;\n timeoutMs?: number;\n}\n\nconst TTS_TEST_SAMPLE_RATE = 24000;\nconst ASR_TEST_SAMPLE_RATE = 16000;\nconst ASR_TEST_CHUNK_BYTES = 3200;\nconst ASR_TEST_CHUNK_INTERVAL_MS = 100;\n\nexport function mergeVoiceConfigForTest(\n current: StoredVoiceConfig,\n update?: VoiceConfigUpdate,\n): StoredVoiceConfig {\n return {\n ...current,\n provider: \"aliyun-bailian\",\n ...(update?.clearApiKey ? { apiKey: undefined } : {}),\n ...(update?.apiKey ? { apiKey: update.apiKey } : {}),\n ...(update?.region ? { region: update.region } : {}),\n ...(update?.asrModel ? { asrModel: update.asrModel } : {}),\n ...(update?.ttsModel ? { ttsModel: update.ttsModel } : {}),\n ...(update?.ttsVoice ? { ttsVoice: update.ttsVoice } : {}),\n ...(update?.turnIdleSeconds ? { turnIdleSeconds: update.turnIdleSeconds } : {}),\n };\n}\n\nexport function createBailianVoiceConfigTester(\n options: BailianVoiceConfigTesterOptions = {},\n): VoiceConfigTester {\n const ttsClientFactory = options.ttsClientFactory ?? createBailianTtsClient;\n const asrClientFactory = options.asrClientFactory ?? createBailianAsrClient;\n const sampleText = options.sampleText ?? \"语音助手测试\";\n const timeoutMs = options.timeoutMs ?? 8000;\n\n return {\n async test(config) {\n if (!config.apiKey) {\n return Promise.reject(new Error(\"请先填写阿里云百炼 API Key\"));\n }\n const audio = await synthesizeTestAudio({\n config,\n sampleText,\n timeoutMs,\n clientFactory: ttsClientFactory,\n });\n const recognitionAudio = resampleMonoPcmS16le(\n audio,\n TTS_TEST_SAMPLE_RATE,\n ASR_TEST_SAMPLE_RATE,\n );\n const transcript = await recognizeTestAudio({\n config,\n audio: recognitionAudio,\n sampleText,\n timeoutMs,\n clientFactory: asrClientFactory,\n });\n return { audio, sampleRate: TTS_TEST_SAMPLE_RATE, transcript };\n },\n };\n}\n\nfunction synthesizeTestAudio(options: {\n config: StoredVoiceConfig;\n sampleText: string;\n timeoutMs: number;\n clientFactory: (config: BailianTtsConfig) => BailianTtsClient;\n}): Promise<Buffer> {\n const { config, sampleText, timeoutMs, clientFactory } = options;\n const client = clientFactory({\n apiKey: config.apiKey!,\n region: config.region,\n model: config.ttsModel,\n voice: config.ttsVoice,\n sampleRate: TTS_TEST_SAMPLE_RATE,\n });\n\n return new Promise<Buffer>((resolve, reject) => {\n let settled = false;\n const chunks: Buffer[] = [];\n const timer = setTimeout(() => {\n settle(new Error(\"TTS 测试超时\"));\n }, timeoutMs);\n\n function settle(error?: Error, audio?: Buffer): void {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n client.close();\n if (error) reject(error);\n else resolve(audio ?? Buffer.alloc(0));\n }\n\n client.on(\"audio\", (chunk) => {\n if (chunk.length > 0) chunks.push(chunk);\n });\n client.on(\"finished\", () => {\n if (chunks.length === 0) {\n settle(new Error(\"TTS 测试没有返回音频\"));\n return;\n }\n settle(undefined, Buffer.concat(chunks));\n });\n client.on(\"error\", (error) => settle(error));\n client.on(\"closed\", () => {\n if (!settled) settle(new Error(\"TTS 测试连接已关闭\"));\n });\n\n try {\n client.speak(sampleText);\n } catch (err) {\n settle(err instanceof Error ? err : new Error(\"TTS 测试启动失败\"));\n }\n });\n}\n\nfunction recognizeTestAudio(options: {\n config: StoredVoiceConfig;\n audio: Buffer;\n sampleText: string;\n timeoutMs: number;\n clientFactory: (config: BailianAsrConfig) => BailianAsrClient;\n}): Promise<string> {\n const { config, audio, sampleText, timeoutMs, clientFactory } = options;\n const client = clientFactory({\n apiKey: config.apiKey!,\n region: config.region,\n model: config.asrModel,\n sampleRate: ASR_TEST_SAMPLE_RATE,\n language: \"zh\",\n });\n\n return new Promise<string>((resolve, reject) => {\n let settled = false;\n let streamTimer: ReturnType<typeof setTimeout> | null = null;\n const timer = setTimeout(() => {\n settle(new Error(\"STT 测试超时\"));\n }, timeoutMs);\n\n function settle(error?: Error, transcript?: string): void {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n if (streamTimer) clearTimeout(streamTimer);\n client.close();\n if (error) reject(error);\n else resolve(transcript ?? \"\");\n }\n\n client.on(\"ready\", () => {\n let offset = 0;\n const sendNextChunk = () => {\n if (settled) return;\n const chunk = audio.subarray(offset, offset + ASR_TEST_CHUNK_BYTES);\n if (chunk.length > 0) {\n client.sendPcm(chunk);\n offset += chunk.length;\n }\n if (offset >= audio.length) {\n client.stop();\n return;\n }\n streamTimer = setTimeout(sendNextChunk, ASR_TEST_CHUNK_INTERVAL_MS);\n };\n sendNextChunk();\n });\n client.on(\"final\", (transcript) => {\n if (matchesExpectedTranscript(transcript, sampleText)) {\n settle(undefined, transcript);\n return;\n }\n settle(new Error(`STT 测试识别结果不匹配:${transcript}`));\n });\n client.on(\"error\", (error) => settle(error));\n client.on(\"closed\", () => {\n if (!settled) settle(new Error(\"STT 测试连接已关闭\"));\n });\n });\n}\n\nfunction matchesExpectedTranscript(actual: string, expected: string): boolean {\n return normalizeTranscript(actual).includes(normalizeTranscript(expected));\n}\n\nfunction normalizeTranscript(text: string): string {\n return text.replace(/[^\\p{Script=Han}a-zA-Z0-9]/gu, \"\").toLowerCase();\n}\n","import { ControlErrorCode, type RelayControlMessage } from \"@dev-anywhere/shared\";\nimport type { Logger } from \"@dev-anywhere/shared/logger\";\nimport type { WebSocket } from \"ws\";\nimport type { VoiceConfigStore } from \"./config-store.js\";\nimport { mergeVoiceConfigForTest } from \"./config-test.js\";\nimport type { VoiceProviderRegistry } from \"./provider.js\";\n\nexport function handleVoiceConfigControl(\n msg: RelayControlMessage,\n ws: WebSocket,\n store: VoiceConfigStore,\n logger: Logger,\n providers?: VoiceProviderRegistry,\n): boolean {\n if (msg.type === \"voice_config_request\") {\n ws.send(\n JSON.stringify({\n type: \"voice_config_response\",\n requestId: msg.requestId,\n config: store.read(),\n }),\n );\n return true;\n }\n\n if (msg.type === \"voice_config_update\") {\n try {\n const config = store.update(msg.config);\n ws.send(\n JSON.stringify({\n type: \"voice_config_update_response\",\n requestId: msg.requestId,\n success: true,\n config,\n }),\n );\n } catch (err) {\n logger.warn({ err }, \"Voice config update failed\");\n ws.send(\n JSON.stringify({\n type: \"voice_config_update_response\",\n requestId: msg.requestId,\n success: false,\n errorCode: ControlErrorCode.UNKNOWN,\n error: err instanceof Error ? err.message : \"Voice config update failed\",\n }),\n );\n }\n return true;\n }\n\n if (msg.type === \"voice_capabilities_request\") {\n if (!providers) {\n ws.send(\n JSON.stringify({\n type: \"voice_capabilities_response\",\n requestId: msg.requestId,\n errorCode: ControlErrorCode.UNKNOWN,\n error: \"Voice capabilities provider is not available\",\n }),\n );\n return true;\n }\n\n const config = { ...store.readSecret(), ...(msg.region ? { region: msg.region } : {}) };\n let provider;\n try {\n provider = providers.current(config);\n } catch (err) {\n logger.warn({ err }, \"Voice capabilities provider resolution failed\");\n ws.send(\n JSON.stringify({\n type: \"voice_capabilities_response\",\n requestId: msg.requestId,\n errorCode: ControlErrorCode.UNKNOWN,\n error: err instanceof Error ? err.message : \"Voice capabilities request failed\",\n }),\n );\n return true;\n }\n\n void provider\n .readCapabilities(config)\n .then((capabilities) => {\n ws.send(\n JSON.stringify({\n type: \"voice_capabilities_response\",\n requestId: msg.requestId,\n capabilities,\n }),\n );\n })\n .catch((err: unknown) => {\n logger.warn({ err }, \"Voice capabilities request failed\");\n ws.send(\n JSON.stringify({\n type: \"voice_capabilities_response\",\n requestId: msg.requestId,\n errorCode: ControlErrorCode.UNKNOWN,\n error: err instanceof Error ? err.message : \"Voice capabilities request failed\",\n }),\n );\n });\n return true;\n }\n\n if (msg.type === \"voice_config_test\") {\n if (!providers) {\n ws.send(\n JSON.stringify({\n type: \"voice_config_test_response\",\n requestId: msg.requestId,\n success: false,\n errorCode: ControlErrorCode.UNKNOWN,\n error: \"Voice config tester is not available\",\n }),\n );\n return true;\n }\n\n const testConfig = mergeVoiceConfigForTest(store.readSecret(), msg.config);\n let provider;\n try {\n provider = providers.current(testConfig);\n } catch (err) {\n logger.warn({ err }, \"Voice config test provider resolution failed\");\n ws.send(\n JSON.stringify({\n type: \"voice_config_test_response\",\n requestId: msg.requestId,\n success: false,\n errorCode: ControlErrorCode.UNKNOWN,\n error: err instanceof Error ? err.message : \"Voice config test failed\",\n }),\n );\n return true;\n }\n\n void provider\n .testConfig(testConfig)\n .then((result) => {\n ws.send(\n JSON.stringify({\n type: \"voice_config_test_response\",\n requestId: msg.requestId,\n success: true,\n ...(result.audio ? { audioBase64: result.audio.toString(\"base64\") } : {}),\n ...(result.sampleRate ? { audioSampleRate: result.sampleRate } : {}),\n ...(result.audio ? { audioEncoding: \"pcm_s16le\" } : {}),\n ...(result.transcript ? { transcript: result.transcript } : {}),\n }),\n );\n })\n .catch((err: unknown) => {\n logger.warn({ err }, \"Voice config test failed\");\n ws.send(\n JSON.stringify({\n type: \"voice_config_test_response\",\n requestId: msg.requestId,\n success: false,\n errorCode: ControlErrorCode.UNKNOWN,\n error: err instanceof Error ? err.message : \"Voice config test failed\",\n }),\n );\n });\n return true;\n }\n\n return false;\n}\n","import type { RelayControlMessage } from \"@dev-anywhere/shared\";\nimport {\n PreviewRouteRegistry,\n type PreviewRouteRegistryOptions,\n} from \"./preview-route-registry.js\";\n\nexport const devicePreviewResponseByRequest = {\n device_preview_capability_request: \"device_preview_capability_response\",\n device_preview_targets_request: \"device_preview_targets_response\",\n device_preview_create_request: \"device_preview_create_response\",\n device_preview_list_request: \"device_preview_list_response\",\n device_preview_rename_request: \"device_preview_rename_response\",\n device_preview_reconnect_request: \"device_preview_reconnect_response\",\n device_preview_close_request: \"device_preview_close_response\",\n} as const;\n\nexport type DevicePreviewRequestType = keyof typeof devicePreviewResponseByRequest;\nexport type DevicePreviewResponseType =\n (typeof devicePreviewResponseByRequest)[DevicePreviewRequestType];\nexport type DevicePreviewRequestMessage = Extract<\n RelayControlMessage,\n { type: DevicePreviewRequestType }\n>;\nexport type DevicePreviewResponseMessage = Extract<\n RelayControlMessage,\n { type: DevicePreviewResponseType }\n>;\nconst requestTypes = new Set<string>(Object.keys(devicePreviewResponseByRequest));\nconst responseTypes = new Set<string>(Object.values(devicePreviewResponseByRequest));\n\nexport function isDevicePreviewRequestMessage(\n message: RelayControlMessage,\n): message is DevicePreviewRequestMessage {\n return requestTypes.has(message.type);\n}\n\nexport function isDevicePreviewResponseMessage(\n message: RelayControlMessage,\n): message is DevicePreviewResponseMessage {\n return responseTypes.has(message.type);\n}\n\nexport class DevicePreviewRouteRegistry extends PreviewRouteRegistry<DevicePreviewResponseType> {\n constructor(options: PreviewRouteRegistryOptions = {}) {\n super({ label: \"Device Preview\", requestIdPrefix: \"relay-device-preview\" }, options);\n }\n}\n","import {\n RELAY_CONTROL_PROTOCOL_VERSION,\n RelayProtocolRejectReason,\n type RelayProtocolRejectReasonType,\n} from \"@dev-anywhere/shared\";\n\nexport type ClientRegistrationAdmission =\n | { kind: \"not_client_registration\" }\n | { kind: \"unversioned_client_registration\"; clientId?: string }\n | {\n kind: \"versioned_client_registration\";\n clientId?: string;\n protocolVersion: unknown;\n };\n\n// Registration is the transport admission boundary. Inspect its small, stable envelope before\n// handing the payload to the versioned business schema so an incompatible client can receive a\n// terminal transport signal instead of entering the ordinary reconnect path.\nexport function inspectClientRegistrationAdmission(raw: string): ClientRegistrationAdmission {\n let value: unknown;\n try {\n value = JSON.parse(raw);\n } catch {\n return { kind: \"not_client_registration\" };\n }\n\n if (value === null || typeof value !== \"object\") {\n return { kind: \"not_client_registration\" };\n }\n const candidate = value as Record<string, unknown>;\n if (candidate.type !== \"client_register\") {\n return { kind: \"not_client_registration\" };\n }\n\n const clientId = typeof candidate.clientId === \"string\" ? candidate.clientId : undefined;\n if (!(\"protocolVersion\" in candidate)) {\n return {\n kind: \"unversioned_client_registration\",\n ...(clientId !== undefined ? { clientId } : {}),\n };\n }\n\n return {\n kind: \"versioned_client_registration\",\n ...(clientId !== undefined ? { clientId } : {}),\n protocolVersion: candidate.protocolVersion,\n };\n}\n\nexport function classifyClientRegistrationProtocol(\n clientVersion: unknown,\n relayVersion: number = RELAY_CONTROL_PROTOCOL_VERSION,\n): RelayProtocolRejectReasonType | null {\n if (\n typeof clientVersion !== \"number\" ||\n !Number.isSafeInteger(clientVersion) ||\n clientVersion <= 0\n ) {\n return RelayProtocolRejectReason.PROTOCOL_MISMATCH;\n }\n if (clientVersion === relayVersion) return null;\n return clientVersion < relayVersion\n ? RelayProtocolRejectReason.PAGE_OUTDATED\n : RelayProtocolRejectReason.SERVICE_OUTDATED;\n}\n","import type { WebSocket, WebSocketServer } from \"ws\";\nimport type { Logger } from \"@dev-anywhere/shared/logger\";\n\ninterface HeartbeatSocket extends WebSocket {\n isAlive?: boolean;\n}\n\ninterface HeartbeatOptions {\n logger?: Pick<Logger, \"warn\">;\n peerType?: string;\n describePeer?: (ws: WebSocket) => Record<string, unknown>;\n}\n\nfunction markAlive(ws: WebSocket): void {\n (ws as HeartbeatSocket).isAlive = true;\n}\n\n// 通用 WebSocket 心跳检测,检测死连接并 terminate\n// terminate 触发 close 事件,后续由各自的 close handler 处理恢复逻辑\nexport function setupHeartbeat(\n wss: WebSocketServer,\n interval = 30000,\n options: HeartbeatOptions = {},\n): NodeJS.Timeout {\n wss.on(\"connection\", (ws) => {\n markAlive(ws);\n ws.on(\"pong\", () => {\n markAlive(ws);\n });\n });\n\n return setInterval(() => {\n for (const ws of wss.clients) {\n const sock = ws as HeartbeatSocket;\n if (sock.isAlive === false) {\n options.logger?.warn(\n {\n peerType: options.peerType,\n ...(options.describePeer?.(ws) ?? {}),\n },\n \"WebSocket heartbeat timeout\",\n );\n sock.terminate();\n continue;\n }\n sock.isAlive = false;\n sock.ping();\n }\n }, interval);\n}\n","import { WebSocket } from \"ws\";\nimport type { Logger } from \"@dev-anywhere/shared/logger\";\n\nexport type RelayChaosDirection = \"client_to_proxy\" | \"proxy_to_client\";\n\nexport interface RelayChaosOptions {\n enabled: boolean;\n delayMs: number;\n duplicate: boolean;\n duplicateDelayMs: number;\n reorder: boolean;\n reorderDelayMs: number;\n types: Set<string> | undefined;\n}\n\nexport interface RelayChaosMeta {\n direction: RelayChaosDirection;\n type: string;\n guard?: () => boolean;\n}\n\nexport interface RelayChaos {\n send(ws: WebSocket, data: string | Buffer, meta: RelayChaosMeta): void;\n}\n\nexport function parseRelayChaosFromEnv(env: NodeJS.ProcessEnv): RelayChaosOptions {\n const enabled = env.DEV_ANYWHERE_RELAY_CHAOS === \"1\";\n const types = env.DEV_ANYWHERE_RELAY_CHAOS_TYPES?.split(\",\")\n .map((type) => type.trim())\n .filter(Boolean);\n\n return {\n enabled,\n delayMs: parseInt(env.DEV_ANYWHERE_RELAY_CHAOS_DELAY_MS ?? \"0\", 10),\n duplicate: env.DEV_ANYWHERE_RELAY_CHAOS_DUPLICATE === \"1\",\n duplicateDelayMs: parseInt(env.DEV_ANYWHERE_RELAY_CHAOS_DUPLICATE_DELAY_MS ?? \"10\", 10),\n reorder: env.DEV_ANYWHERE_RELAY_CHAOS_REORDER === \"1\",\n reorderDelayMs: parseInt(env.DEV_ANYWHERE_RELAY_CHAOS_REORDER_DELAY_MS ?? \"40\", 10),\n types: types && types.length > 0 ? new Set(types) : undefined,\n };\n}\n\nexport function createRelayChaos(options: RelayChaosOptions, logger: Logger): RelayChaos {\n let sequence = 0;\n\n function shouldAffect(meta: RelayChaosMeta): boolean {\n if (!options.enabled) return false;\n if (options.types && !options.types.has(meta.type)) return false;\n return true;\n }\n\n function sendNow(ws: WebSocket, data: string | Buffer, guard?: () => boolean): void {\n if (ws.readyState === WebSocket.OPEN && (!guard || guard())) {\n ws.send(data);\n }\n }\n\n return {\n send(ws, data, meta) {\n if (!shouldAffect(meta)) {\n sendNow(ws, data, meta.guard);\n return;\n }\n\n sequence += 1;\n const reorderDelay = options.reorder && sequence % 2 === 1 ? options.reorderDelayMs : 0;\n const delayMs = Math.max(0, options.delayMs + reorderDelay);\n\n logger.warn(\n { direction: meta.direction, type: meta.type, delayMs, duplicate: options.duplicate },\n \"Relay chaos forwarding message\",\n );\n\n setTimeout(() => sendNow(ws, data, meta.guard), delayMs);\n\n if (options.duplicate) {\n setTimeout(() => sendNow(ws, data, meta.guard), delayMs + options.duplicateDelayMs);\n }\n },\n };\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport {\n VoiceConfigUpdateSchema,\n VoiceProviderConfigSchema,\n type VoiceConfigUpdate,\n type VoiceProviderConfig,\n} from \"@dev-anywhere/shared\";\n\nexport interface StoredVoiceConfig {\n provider: \"aliyun-bailian\";\n apiKey?: string;\n region: \"cn\" | \"intl\";\n asrModel: string;\n ttsModel: string;\n ttsVoice: string;\n turnIdleSeconds: number;\n}\n\ninterface VoiceConfigStoreOptions {\n dataDir?: string;\n defaults?: Partial<Omit<StoredVoiceConfig, \"provider\" | \"apiKey\">>;\n}\n\nexport interface VoiceConfigStore {\n read: () => VoiceProviderConfig;\n update: (update: VoiceConfigUpdate) => VoiceProviderConfig;\n readSecret: () => StoredVoiceConfig;\n}\n\nconst DEFAULT_STORED_CONFIG: StoredVoiceConfig = {\n provider: \"aliyun-bailian\",\n region: \"cn\",\n asrModel: \"qwen3-asr-flash-realtime\",\n ttsModel: \"cosyvoice-v3-flash\",\n ttsVoice: \"longanyang\",\n turnIdleSeconds: 3,\n};\n\nfunction redacted(config: StoredVoiceConfig): VoiceProviderConfig {\n return VoiceProviderConfigSchema.parse({\n provider: config.provider,\n configured: Boolean(config.apiKey),\n region: config.region,\n asrModel: config.asrModel,\n ttsModel: config.ttsModel,\n ttsVoice: config.ttsVoice,\n turnIdleSeconds: config.turnIdleSeconds,\n });\n}\n\nfunction mergeDefaults(defaults: VoiceConfigStoreOptions[\"defaults\"]): StoredVoiceConfig {\n return {\n ...DEFAULT_STORED_CONFIG,\n ...defaults,\n };\n}\n\nfunction parseStoredConfig(raw: unknown, fallback: StoredVoiceConfig): StoredVoiceConfig {\n if (!raw || typeof raw !== \"object\") return fallback;\n const candidate = raw as Partial<StoredVoiceConfig>;\n return {\n ...fallback,\n provider: \"aliyun-bailian\",\n ...(typeof candidate.apiKey === \"string\" && candidate.apiKey.length > 0\n ? { apiKey: candidate.apiKey }\n : { apiKey: undefined }),\n ...(candidate.region === \"cn\" || candidate.region === \"intl\"\n ? { region: candidate.region }\n : {}),\n ...(typeof candidate.asrModel === \"string\" && candidate.asrModel.length > 0\n ? { asrModel: candidate.asrModel }\n : {}),\n ...(typeof candidate.ttsModel === \"string\" && candidate.ttsModel.length > 0\n ? { ttsModel: candidate.ttsModel }\n : {}),\n ...(typeof candidate.ttsVoice === \"string\" && candidate.ttsVoice.length > 0\n ? { ttsVoice: candidate.ttsVoice }\n : {}),\n ...(typeof candidate.turnIdleSeconds === \"number\" &&\n Number.isSafeInteger(candidate.turnIdleSeconds) &&\n candidate.turnIdleSeconds > 0\n ? { turnIdleSeconds: candidate.turnIdleSeconds }\n : {}),\n };\n}\n\nexport function createVoiceConfigStore(options: VoiceConfigStoreOptions = {}): VoiceConfigStore {\n const fallback = mergeDefaults(options.defaults);\n const filePath = options.dataDir ? join(options.dataDir, \"voice-config.json\") : null;\n let memoryConfig: StoredVoiceConfig = fallback;\n\n function load(): StoredVoiceConfig {\n if (!filePath) return memoryConfig;\n if (!existsSync(filePath)) return fallback;\n try {\n return parseStoredConfig(JSON.parse(readFileSync(filePath, \"utf8\")), fallback);\n } catch {\n return fallback;\n }\n }\n\n function save(config: StoredVoiceConfig): void {\n if (!filePath) {\n memoryConfig = config;\n return;\n }\n mkdirSync(dirname(filePath), { recursive: true });\n writeFileSync(filePath, `${JSON.stringify(config, null, 2)}\\n`, { mode: 0o600 });\n }\n\n return {\n read() {\n return redacted(load());\n },\n update(update) {\n const parsed = VoiceConfigUpdateSchema.parse(update);\n const current = load();\n const next: StoredVoiceConfig = {\n ...current,\n provider: \"aliyun-bailian\",\n ...(parsed.clearApiKey ? { apiKey: undefined } : {}),\n ...(parsed.apiKey ? { apiKey: parsed.apiKey } : {}),\n ...(parsed.region ? { region: parsed.region } : {}),\n ...(parsed.asrModel ? { asrModel: parsed.asrModel } : {}),\n ...(parsed.ttsModel ? { ttsModel: parsed.ttsModel } : {}),\n ...(parsed.ttsVoice ? { ttsVoice: parsed.ttsVoice } : {}),\n ...(parsed.turnIdleSeconds ? { turnIdleSeconds: parsed.turnIdleSeconds } : {}),\n };\n save(next);\n return redacted(next);\n },\n readSecret() {\n return load();\n },\n };\n}\n","import { WebSocket, type RawData } from \"ws\";\nimport {\n VoiceAsrClientMessageSchema,\n decodeMuLawToPcm16,\n type VoiceAsrStartMessage,\n} from \"@dev-anywhere/shared\";\nimport type { Logger } from \"@dev-anywhere/shared/logger\";\nimport type { BailianAsrClient, BailianAsrConfig } from \"./bailian-asr.js\";\nimport type { StoredVoiceConfig, VoiceConfigStore } from \"./config-store.js\";\nimport type { VoiceAsrProviderClient, VoiceProviderRegistry } from \"./provider.js\";\n\nexport type VoiceAsrClientFactory = (config: BailianAsrConfig) => BailianAsrClient;\n\ninterface ActiveAsrStats {\n sessionId: string;\n attemptId: string;\n sampleRate: number;\n provider: StoredVoiceConfig[\"provider\"];\n region: StoredVoiceConfig[\"region\"];\n asrModel: string;\n encoding: VoiceAsrStartMessage[\"encoding\"];\n startedAt: number;\n readyAt: number | null;\n firstPcmAt: number | null;\n encodedBytes: number;\n pcmBytes: number;\n pcmChunks: number;\n partialEvents: number;\n finalEvents: number;\n finalChars: number;\n}\n\nfunction sendJson(ws: WebSocket, payload: unknown): void {\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify(payload));\n }\n}\n\nfunction toBuffer(data: RawData): Buffer {\n if (Buffer.isBuffer(data)) return data;\n if (data instanceof ArrayBuffer) return Buffer.from(data);\n return Buffer.concat(data);\n}\n\nfunction parseJson(data: RawData): unknown | null {\n try {\n return JSON.parse(toBuffer(data).toString(\"utf8\"));\n } catch {\n return null;\n }\n}\n\nfunction buildStats(payload: VoiceAsrStartMessage, config: StoredVoiceConfig): ActiveAsrStats {\n return {\n sessionId: payload.sessionId,\n attemptId: payload.attemptId,\n sampleRate: payload.sampleRate,\n provider: config.provider,\n region: config.region,\n asrModel: config.asrModel,\n encoding: payload.encoding,\n startedAt: Date.now(),\n readyAt: null,\n firstPcmAt: null,\n encodedBytes: 0,\n pcmBytes: 0,\n pcmChunks: 0,\n partialEvents: 0,\n finalEvents: 0,\n finalChars: 0,\n };\n}\n\nfunction statsLogFields(stats: ActiveAsrStats): Record<string, unknown> {\n const now = Date.now();\n return {\n sessionId: stats.sessionId,\n attemptId: stats.attemptId,\n sampleRate: stats.sampleRate,\n provider: stats.provider,\n region: stats.region,\n asrModel: stats.asrModel,\n encoding: stats.encoding,\n encodedBytes: stats.encodedBytes,\n pcmBytes: stats.pcmBytes,\n pcmChunks: stats.pcmChunks,\n partialEvents: stats.partialEvents,\n finalEvents: stats.finalEvents,\n finalChars: stats.finalChars,\n durationMs: now - stats.startedAt,\n readyMs: stats.readyAt === null ? null : stats.readyAt - stats.startedAt,\n firstPcmMs: stats.firstPcmAt === null ? null : stats.firstPcmAt - stats.startedAt,\n };\n}\n\nexport function handleVoiceAsrConnection(\n ws: WebSocket,\n store: VoiceConfigStore,\n logger: Logger,\n providers: VoiceProviderRegistry,\n): void {\n let provider: VoiceAsrProviderClient | null = null;\n let activeStats: ActiveAsrStats | null = null;\n\n function isCurrent(\n candidate: VoiceAsrProviderClient,\n stats: ActiveAsrStats,\n event: string,\n ): boolean {\n if (provider === candidate && activeStats === stats) return true;\n logger.debug(\n { attemptId: stats.attemptId, activeAttemptId: activeStats?.attemptId ?? null, event },\n \"Ignored stale Voice ASR provider event\",\n );\n return false;\n }\n\n function detachProvider(reason: string): void {\n const previousProvider = provider;\n const previousStats = activeStats;\n provider = null;\n activeStats = null;\n if (previousStats) {\n logger.info({ ...statsLogFields(previousStats), reason }, \"Voice ASR attempt detached\");\n }\n previousProvider?.close();\n }\n\n function start(payload: VoiceAsrStartMessage): void {\n const config = store.readSecret();\n if (!config.apiKey) {\n sendJson(ws, {\n type: \"error\",\n attemptId: payload.attemptId,\n errorCode: \"not_configured\",\n error: \"Voice provider is not configured\",\n });\n return;\n }\n detachProvider(\"replaced\");\n const stats = buildStats(payload, config);\n let currentProvider: VoiceAsrProviderClient;\n try {\n currentProvider = providers.current(config).createAsrClient(config, {\n sampleRate: stats.sampleRate,\n language: \"zh\",\n });\n } catch (error) {\n logger.warn({ ...statsLogFields(stats), err: error }, \"Voice ASR provider creation failed\");\n sendJson(ws, {\n type: \"error\",\n attemptId: payload.attemptId,\n error: error instanceof Error ? error.message : \"ASR failed\",\n });\n return;\n }\n provider = currentProvider;\n activeStats = stats;\n logger.info(statsLogFields(stats), \"Voice ASR attempt started\");\n currentProvider.on(\"ready\", () => {\n if (!isCurrent(currentProvider, stats, \"ready\")) return;\n stats.readyAt = Date.now();\n logger.info(statsLogFields(stats), \"Voice ASR provider ready\");\n sendJson(ws, { type: \"ready\", attemptId: stats.attemptId });\n });\n currentProvider.on(\"partial\", (text) => {\n if (!isCurrent(currentProvider, stats, \"partial\")) return;\n stats.partialEvents += 1;\n sendJson(ws, { type: \"partial\", attemptId: stats.attemptId, text });\n });\n currentProvider.on(\"final\", (text) => {\n if (!isCurrent(currentProvider, stats, \"final\")) return;\n stats.finalEvents += 1;\n stats.finalChars += text.length;\n sendJson(ws, { type: \"final\", attemptId: stats.attemptId, text });\n });\n currentProvider.on(\"error\", (error) => {\n if (!isCurrent(currentProvider, stats, \"error\")) return;\n logger.warn({ ...statsLogFields(stats), err: error }, \"Voice ASR provider reported an error\");\n sendJson(ws, {\n type: \"error\",\n attemptId: stats.attemptId,\n error: error.message || \"ASR failed\",\n });\n });\n currentProvider.on(\"closed\", (code, reason) => {\n if (!isCurrent(currentProvider, stats, \"closed\")) return;\n provider = null;\n activeStats = null;\n logger.info({ ...statsLogFields(stats), code, reason }, \"Voice ASR provider closed\");\n sendJson(ws, { type: \"closed\", attemptId: stats.attemptId, code, reason });\n });\n }\n\n ws.on(\"message\", (data, isBinary) => {\n if (isBinary) {\n const encodedChunk = toBuffer(data);\n if (provider && activeStats) {\n const pcmChunk =\n activeStats.encoding === \"mulaw\"\n ? Buffer.from(decodeMuLawToPcm16(encodedChunk))\n : encodedChunk;\n if (activeStats.firstPcmAt === null) activeStats.firstPcmAt = Date.now();\n activeStats.encodedBytes += encodedChunk.byteLength;\n activeStats.pcmBytes += pcmChunk.byteLength;\n activeStats.pcmChunks += 1;\n provider.sendPcm(pcmChunk);\n sendJson(ws, {\n type: \"audio_ack\",\n attemptId: activeStats.attemptId,\n encodedBytes: activeStats.encodedBytes,\n pcmBytes: activeStats.pcmBytes,\n chunks: activeStats.pcmChunks,\n });\n }\n return;\n }\n\n const parsed = VoiceAsrClientMessageSchema.safeParse(parseJson(data));\n if (!parsed.success) {\n logger.debug({ issues: parsed.error.issues }, \"Ignored invalid Voice ASR client message\");\n return;\n }\n const payload = parsed.data;\n if (payload.type === \"start\") {\n start(payload);\n return;\n }\n if (payload.type === \"stop\") {\n if (!provider || !activeStats || activeStats.attemptId !== payload.attemptId) {\n logger.debug(\n { attemptId: payload.attemptId, activeAttemptId: activeStats?.attemptId ?? null },\n \"Ignored stale Voice ASR stop\",\n );\n return;\n }\n logger.info(statsLogFields(activeStats), \"Voice ASR stop requested\");\n provider.stop();\n }\n });\n\n ws.on(\"close\", (code, reason) => {\n if (activeStats) {\n logger.info(\n { ...statsLogFields(activeStats), code, reason: reason.toString(\"utf8\") },\n \"Voice ASR client websocket closed\",\n );\n }\n detachProvider(\"client-websocket-closed\");\n });\n ws.on(\"error\", (err) => {\n logger.warn(\n { ...(activeStats ? statsLogFields(activeStats) : {}), err },\n \"Voice ASR websocket error\",\n );\n detachProvider(\"client-websocket-error\");\n });\n}\n","import { WebSocket, type RawData } from \"ws\";\nimport type { Logger } from \"@dev-anywhere/shared/logger\";\nimport type { BailianTtsClient, BailianTtsConfig } from \"./bailian-tts.js\";\nimport type { StoredVoiceConfig, VoiceConfigStore } from \"./config-store.js\";\nimport type { VoiceProviderRegistry, VoiceTtsProviderClient } from \"./provider.js\";\n\nexport type VoiceTtsClientFactory = (config: BailianTtsConfig) => BailianTtsClient;\n\ninterface SpeakMessage {\n type: \"speak\";\n requestId: string;\n text: string;\n}\n\ninterface ActiveTtsStats {\n requestId: string;\n textChars: number;\n provider: StoredVoiceConfig[\"provider\"];\n region: StoredVoiceConfig[\"region\"];\n ttsModel: string;\n ttsVoice: string;\n startedAt: number;\n firstAudioAt: number | null;\n audioBytes: number;\n audioChunks: number;\n}\n\nfunction sendJson(ws: WebSocket, payload: unknown): void {\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify(payload));\n }\n}\n\nfunction parseJson(data: RawData): unknown | null {\n try {\n const buffer = Buffer.isBuffer(data)\n ? data\n : data instanceof ArrayBuffer\n ? Buffer.from(data)\n : Buffer.concat(data);\n return JSON.parse(buffer.toString(\"utf8\"));\n } catch {\n return null;\n }\n}\n\nfunction isSpeakMessage(payload: unknown): payload is SpeakMessage {\n if (!payload || typeof payload !== \"object\") return false;\n const record = payload as Record<string, unknown>;\n return (\n record.type === \"speak\" &&\n typeof record.requestId === \"string\" &&\n typeof record.text === \"string\" &&\n record.text.length > 0\n );\n}\n\nfunction nowMs(): number {\n return Date.now();\n}\n\nfunction buildStats(requestId: string, text: string, config: StoredVoiceConfig): ActiveTtsStats {\n return {\n requestId,\n textChars: text.length,\n provider: config.provider,\n region: config.region,\n ttsModel: config.ttsModel,\n ttsVoice: config.ttsVoice,\n startedAt: nowMs(),\n firstAudioAt: null,\n audioBytes: 0,\n audioChunks: 0,\n };\n}\n\nfunction statsLogFields(stats: ActiveTtsStats): Record<string, unknown> {\n const currentTime = nowMs();\n return {\n requestId: stats.requestId,\n textChars: stats.textChars,\n provider: stats.provider,\n region: stats.region,\n ttsModel: stats.ttsModel,\n ttsVoice: stats.ttsVoice,\n audioBytes: stats.audioBytes,\n audioChunks: stats.audioChunks,\n durationMs: currentTime - stats.startedAt,\n firstAudioMs: stats.firstAudioAt === null ? null : stats.firstAudioAt - stats.startedAt,\n };\n}\n\nfunction closeReasonText(reason: unknown): string {\n if (Buffer.isBuffer(reason)) return reason.toString(\"utf8\");\n return typeof reason === \"string\" ? reason : \"\";\n}\n\nexport function handleVoiceTtsConnection(\n ws: WebSocket,\n store: VoiceConfigStore,\n logger: Logger,\n providers: VoiceProviderRegistry,\n): void {\n let provider: VoiceTtsProviderClient | null = null;\n let providerConfig: StoredVoiceConfig | null = null;\n let activeRequestId: string | null = null;\n let activeStats: ActiveTtsStats | null = null;\n\n function ensureProvider(): { client: VoiceTtsProviderClient; config: StoredVoiceConfig } | null {\n if (provider && providerConfig) return { client: provider, config: providerConfig };\n const config = store.readSecret();\n if (!config.apiKey) {\n sendJson(ws, {\n type: \"error\",\n errorCode: \"not_configured\",\n error: \"Voice provider is not configured\",\n });\n return null;\n }\n provider = providers.current(config).createTtsClient(config, {\n sampleRate: 24000,\n });\n providerConfig = config;\n provider.on(\"started\", () => {\n if (activeStats) logger.info(statsLogFields(activeStats), \"Voice TTS started\");\n sendJson(ws, { type: \"started\", requestId: activeRequestId });\n });\n provider.on(\"audio\", (chunk) => {\n if (activeStats) {\n if (activeStats.firstAudioAt === null) activeStats.firstAudioAt = nowMs();\n activeStats.audioBytes += chunk.byteLength;\n activeStats.audioChunks += 1;\n }\n if (ws.readyState === WebSocket.OPEN) ws.send(chunk);\n });\n provider.on(\"finished\", () => {\n if (activeStats) logger.info(statsLogFields(activeStats), \"Voice TTS finished\");\n sendJson(ws, { type: \"finished\", requestId: activeRequestId });\n activeRequestId = null;\n activeStats = null;\n });\n provider.on(\"error\", (error) => {\n if (activeStats) {\n logger.warn(\n { ...statsLogFields(activeStats), err: error },\n \"Voice TTS provider reported an error\",\n );\n }\n sendJson(ws, {\n type: \"error\",\n requestId: activeRequestId,\n error: error.message || \"TTS failed\",\n });\n activeRequestId = null;\n activeStats = null;\n });\n provider.on(\"closed\", (code, reason) => {\n if (activeStats) {\n logger.warn(\n { ...statsLogFields(activeStats), code, reason },\n \"Voice TTS provider closed before finishing\",\n );\n sendJson(ws, {\n type: \"error\",\n requestId: activeRequestId,\n errorCode: \"provider_closed\",\n error: \"Voice TTS provider closed before finishing\",\n });\n activeRequestId = null;\n activeStats = null;\n } else {\n logger.info({ code, reason }, \"Voice TTS provider closed\");\n provider = null;\n providerConfig = null;\n return;\n }\n sendJson(ws, { type: \"closed\", code, reason });\n provider = null;\n providerConfig = null;\n });\n return { client: provider, config };\n }\n\n ws.on(\"message\", (data) => {\n const payload = parseJson(data);\n if (!isSpeakMessage(payload)) return;\n if (activeRequestId) {\n sendJson(ws, {\n type: \"error\",\n requestId: payload.requestId,\n errorCode: \"busy\",\n error: \"Voice TTS is already speaking\",\n });\n return;\n }\n const ensured = ensureProvider();\n if (!ensured) return;\n const { client, config } = ensured;\n activeRequestId = payload.requestId;\n activeStats = buildStats(payload.requestId, payload.text, config);\n logger.info(statsLogFields(activeStats), \"Voice TTS request received\");\n try {\n client.speak(payload.text);\n } catch (err) {\n if (activeStats) {\n logger.warn(\n { ...statsLogFields(activeStats), err },\n \"Voice TTS request failed before provider accepted it\",\n );\n }\n sendJson(ws, {\n type: \"error\",\n requestId: payload.requestId,\n error: err instanceof Error ? err.message : \"Voice TTS failed\",\n });\n activeRequestId = null;\n activeStats = null;\n }\n });\n\n ws.on(\"close\", (code?: number, reason?: Buffer) => {\n if (activeStats) {\n logger.warn(\n { ...statsLogFields(activeStats), code, reason: closeReasonText(reason) },\n \"Voice TTS client websocket closed before finishing\",\n );\n }\n const currentProvider = provider;\n provider = null;\n providerConfig = null;\n activeRequestId = null;\n activeStats = null;\n currentProvider?.close();\n });\n ws.on(\"error\", (err) => {\n logger.warn({ err }, \"Voice TTS websocket error\");\n provider?.close();\n provider = null;\n providerConfig = null;\n activeRequestId = null;\n activeStats = null;\n });\n}\n","import {\n createBundledBailianVoiceCapabilities,\n type VoiceCapabilities,\n type VoiceOption,\n} from \"@dev-anywhere/shared\";\nimport type { StoredVoiceConfig } from \"./config-store.js\";\n\ntype FetchResponse = {\n ok: boolean;\n json: () => Promise<unknown>;\n};\ntype FetchLike = (\n url: string,\n init?: {\n method?: string;\n headers?: Record<string, string>;\n body?: string;\n },\n) => Promise<FetchResponse>;\n\nexport interface VoiceCapabilitiesProvider {\n read: (config: StoredVoiceConfig) => Promise<VoiceCapabilities>;\n}\n\ninterface BailianVoiceCapabilitiesProviderOptions {\n fetchImpl?: FetchLike;\n now?: () => number;\n}\n\nconst CUSTOMIZATION_ENDPOINTS: Record<StoredVoiceConfig[\"region\"], string> = {\n cn: \"https://dashscope.aliyuncs.com/api/v1/services/audio/tts/customization\",\n intl: \"https://dashscope-intl.aliyuncs.com/api/v1/services/audio/tts/customization\",\n};\n\nfunction modelFromCustomCosyVoiceId(voiceId: string): string | undefined {\n const match = voiceId.match(/^(cosyvoice-v3(?:\\.5)?-(?:flash|plus))-/);\n return match?.[1];\n}\n\nasync function fetchCustomVoices(\n fetchImpl: FetchLike,\n config: StoredVoiceConfig,\n): Promise<VoiceOption[]> {\n if (!config.apiKey) return [];\n const response = await fetchImpl(CUSTOMIZATION_ENDPOINTS[config.region], {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${config.apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n model: \"voice-enrollment\",\n input: {\n action: \"list_voice\",\n page_size: 100,\n page_index: 0,\n },\n }),\n });\n if (!response.ok) return [];\n const payload = response.json() as Promise<{\n output?: {\n voice_list?: Array<{\n voice_id?: string;\n status?: string;\n voice_prompt?: string;\n }>;\n };\n }>;\n const voiceList = (await payload).output?.voice_list ?? [];\n return voiceList\n .filter((voice) => !voice.status || voice.status === \"OK\")\n .flatMap((voice): VoiceOption[] => {\n if (!voice.voice_id) return [];\n const model = modelFromCustomCosyVoiceId(voice.voice_id);\n return [\n {\n value: voice.voice_id,\n label: [voice.voice_id, \"自定义\", voice.voice_prompt].filter(Boolean).join(\" · \"),\n ...(model ? { model } : {}),\n source: \"custom\",\n },\n ];\n });\n}\n\nexport function createBailianVoiceCapabilitiesProvider(\n options: BailianVoiceCapabilitiesProviderOptions = {},\n): VoiceCapabilitiesProvider {\n const fetchImpl = options.fetchImpl ?? (globalThis.fetch as unknown as FetchLike);\n const now = options.now ?? Date.now;\n\n return {\n async read(config) {\n let customVoices: VoiceOption[];\n try {\n customVoices = await fetchCustomVoices(fetchImpl, config);\n } catch {\n customVoices = [];\n }\n\n const bundled = createBundledBailianVoiceCapabilities(now());\n return {\n ...bundled,\n ttsVoices: [...bundled.ttsVoices, ...customVoices],\n };\n },\n };\n}\n","import {\n createBailianAsrClient,\n type BailianAsrClient,\n type BailianAsrConfig,\n} from \"./bailian-asr.js\";\nimport {\n createBailianTtsClient,\n type BailianTtsClient,\n type BailianTtsConfig,\n} from \"./bailian-tts.js\";\nimport {\n createBailianVoiceCapabilitiesProvider,\n type VoiceCapabilitiesProvider,\n} from \"./capabilities.js\";\nimport { createBailianVoiceConfigTester, type VoiceConfigTester } from \"./config-test.js\";\nimport type { StoredVoiceConfig } from \"./config-store.js\";\nimport type { VoiceProviderAdapter } from \"./provider.js\";\n\ninterface BailianVoiceProviderOptions {\n asrClientFactory?: (config: BailianAsrConfig) => BailianAsrClient;\n ttsClientFactory?: (config: BailianTtsConfig) => BailianTtsClient;\n capabilitiesProvider?: VoiceCapabilitiesProvider;\n configTester?: VoiceConfigTester;\n}\n\nfunction requireApiKey(config: StoredVoiceConfig): string {\n if (!config.apiKey) throw new Error(\"Voice provider is not configured\");\n return config.apiKey;\n}\n\nexport function createBailianVoiceProvider(\n options: BailianVoiceProviderOptions = {},\n): VoiceProviderAdapter {\n const asrClientFactory = options.asrClientFactory ?? createBailianAsrClient;\n const ttsClientFactory = options.ttsClientFactory ?? createBailianTtsClient;\n const capabilitiesProvider =\n options.capabilitiesProvider ?? createBailianVoiceCapabilitiesProvider();\n const configTester =\n options.configTester ??\n createBailianVoiceConfigTester({\n asrClientFactory,\n ttsClientFactory,\n });\n\n return {\n id: \"aliyun-bailian\",\n createAsrClient(config, clientOptions) {\n return asrClientFactory({\n apiKey: requireApiKey(config),\n region: config.region,\n model: config.asrModel,\n sampleRate: clientOptions.sampleRate,\n language: clientOptions.language,\n });\n },\n createTtsClient(config, clientOptions) {\n return ttsClientFactory({\n apiKey: requireApiKey(config),\n region: config.region,\n model: config.ttsModel,\n voice: config.ttsVoice,\n sampleRate: clientOptions.sampleRate,\n });\n },\n readCapabilities(config) {\n return capabilitiesProvider.read(config);\n },\n testConfig(config) {\n return configTester.test(config);\n },\n };\n}\n","import type { VoiceCapabilities, VoiceProviderConfig } from \"@dev-anywhere/shared\";\nimport type { StoredVoiceConfig } from \"./config-store.js\";\nimport type { VoiceConfigTestResult } from \"./config-test.js\";\n\nexport type VoiceProviderId = VoiceProviderConfig[\"provider\"];\n\nexport interface VoiceAsrProviderClient {\n on(event: \"ready\", handler: () => void): this;\n on(event: \"partial\" | \"final\", handler: (text: string) => void): this;\n on(event: \"error\", handler: (error: Error) => void): this;\n on(event: \"closed\", handler: (code?: number, reason?: string) => void): this;\n sendPcm(chunk: Buffer): void;\n stop(): void;\n close(): void;\n}\n\nexport interface VoiceTtsProviderClient {\n on(event: \"started\" | \"finished\", handler: () => void): this;\n on(event: \"audio\", handler: (chunk: Buffer) => void): this;\n on(event: \"error\", handler: (error: Error) => void): this;\n on(event: \"closed\", handler: (code?: number, reason?: string) => void): this;\n speak(text: string): void;\n close(): void;\n}\n\nexport interface VoiceAsrProviderOptions {\n sampleRate: number;\n language: string;\n}\n\nexport interface VoiceTtsProviderOptions {\n sampleRate: number;\n}\n\nexport interface VoiceProviderAdapter {\n id: VoiceProviderId;\n createAsrClient: (\n config: StoredVoiceConfig,\n options: VoiceAsrProviderOptions,\n ) => VoiceAsrProviderClient;\n createTtsClient: (\n config: StoredVoiceConfig,\n options: VoiceTtsProviderOptions,\n ) => VoiceTtsProviderClient;\n readCapabilities: (config: StoredVoiceConfig) => Promise<VoiceCapabilities>;\n testConfig: (config: StoredVoiceConfig) => Promise<VoiceConfigTestResult>;\n}\n\nexport interface VoiceProviderRegistry {\n current: (config: StoredVoiceConfig) => VoiceProviderAdapter;\n require: (providerId: string) => VoiceProviderAdapter;\n}\n\nexport function createVoiceProviderRegistry(\n adapters: readonly VoiceProviderAdapter[],\n): VoiceProviderRegistry {\n const byId = new Map<string, VoiceProviderAdapter>();\n for (const adapter of adapters) {\n if (byId.has(adapter.id)) {\n throw new Error(`Duplicate voice provider: ${adapter.id}`);\n }\n byId.set(adapter.id, adapter);\n }\n\n function require(providerId: string): VoiceProviderAdapter {\n const adapter = byId.get(providerId);\n if (!adapter) throw new Error(`Unsupported voice provider: ${providerId}`);\n return adapter;\n }\n\n return {\n current(config) {\n return require(config.provider);\n },\n require,\n };\n}\n","import type { Request, Response } from \"express\";\nimport { nanoid } from \"nanoid\";\nimport { WebSocket } from \"ws\";\nimport {\n ControlErrorCode,\n decodeFileStreamFrame,\n encodeFileStreamFrame,\n serializeControl,\n type ControlMessage,\n} from \"@dev-anywhere/shared\";\nimport type { ControlErrorCode as ControlErrorCodeType } from \"@dev-anywhere/shared\";\nimport type { Logger } from \"@dev-anywhere/shared/logger\";\nimport type { RelayRegistry } from \"./registry.js\";\n\nconst REMOTE_FILE_TOKEN_TTL_MS = 24 * 60 * 60 * 1000;\nconst REMOTE_FILE_METADATA_TIMEOUT_MS = 30 * 1000;\nconst REMOTE_FILE_UPLOAD_RESPONSE_TIMEOUT_MS = 60 * 1000;\n\ntype RemoteFileDisposition = \"inline\" | \"download\";\ntype RemoteFileUploadKind = \"clipboard_image\" | \"file\";\n\ninterface RemoteFileToken {\n token: string;\n clientId: string;\n proxyId: string;\n sessionId: string;\n path: string;\n disposition: RemoteFileDisposition;\n expiresAt: number;\n}\n\ntype RemoteFileUrlResult =\n | { success: true; path: string; url: string; expiresAt: number }\n | { success: false; path: string; error: string; errorCode?: ControlErrorCodeType };\n\ninterface PendingUrlMetadata {\n requestId: string;\n clientId: string;\n proxyId: string;\n sessionId: string;\n path: string;\n disposition: RemoteFileDisposition;\n timer: NodeJS.Timeout;\n resolve: (result: RemoteFileUrlResult) => void;\n}\n\ninterface PendingHttpStream {\n streamId: string;\n token: RemoteFileToken;\n res: Response;\n metadataTimer: NodeJS.Timeout;\n headersSent: boolean;\n finished: boolean;\n}\n\ninterface RemoteFileUploadToken {\n token: string;\n clientId: string;\n proxyId: string;\n sessionId: string;\n kind: RemoteFileUploadKind;\n fileName?: string;\n mimeType: string;\n size?: number;\n expiresAt: number;\n}\n\ninterface PendingHttpUpload {\n uploadId: string;\n token: RemoteFileUploadToken;\n res: Response;\n chunkSeq: number;\n requestEnded: boolean;\n finished: boolean;\n responseTimer: NodeJS.Timeout | null;\n}\n\ninterface RemoteFileBridgeDeps {\n registry: RelayRegistry;\n logger: Logger;\n}\n\nfunction encodeContentDisposition(disposition: RemoteFileDisposition, fileName: string): string {\n const type = disposition === \"download\" ? \"attachment\" : \"inline\";\n const fallback =\n fileName\n .replace(/[^\\x20-\\x7e]/g, \"_\")\n .replace(/[\"\\\\/\\r\\n]/g, \"_\")\n .replace(/_+/g, \"_\")\n .trim() || \"download\";\n const encodedFileName = encodeURIComponent(fileName).replace(\n /['()*]/g,\n (char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`,\n );\n return `${type}; filename=\"${fallback}\"; filename*=UTF-8''${encodedFileName}`;\n}\n\nfunction statusForErrorCode(errorCode?: string): number {\n switch (errorCode) {\n case ControlErrorCode.SESSION_NOT_FOUND:\n case ControlErrorCode.PATH_NOT_FOUND:\n return 404;\n case ControlErrorCode.INVALID_PATH:\n case ControlErrorCode.PATH_NOT_DIRECTORY:\n return 400;\n case ControlErrorCode.PATH_ACCESS_DENIED:\n return 403;\n default:\n return 500;\n }\n}\n\nexport class RemoteFileBridge {\n private readonly tokens = new Map<string, RemoteFileToken>();\n private readonly uploadTokens = new Map<string, RemoteFileUploadToken>();\n private readonly pendingUrlMetadata = new Map<string, PendingUrlMetadata>();\n private readonly pendingStreams = new Map<string, PendingHttpStream>();\n private readonly pendingUploads = new Map<string, PendingHttpUpload>();\n\n constructor(private readonly deps: RemoteFileBridgeDeps) {}\n\n revokeProxy(proxyId: string): void {\n let revokedTokens = 0;\n let rejectedMetadata = 0;\n let failedStreams = 0;\n let failedUploads = 0;\n\n for (const [token, metadata] of this.tokens) {\n if (metadata.proxyId !== proxyId) continue;\n this.tokens.delete(token);\n revokedTokens += 1;\n }\n for (const [token, metadata] of this.uploadTokens) {\n if (metadata.proxyId !== proxyId) continue;\n this.uploadTokens.delete(token);\n revokedTokens += 1;\n }\n for (const [requestId, pending] of this.pendingUrlMetadata) {\n if (pending.proxyId !== proxyId) continue;\n this.pendingUrlMetadata.delete(requestId);\n clearTimeout(pending.timer);\n pending.resolve({\n success: false,\n path: pending.path,\n error: \"开发机已删除\",\n errorCode: ControlErrorCode.PROXY_NOT_FOUND,\n });\n rejectedMetadata += 1;\n }\n for (const [streamId, pending] of this.pendingStreams) {\n if (pending.token.proxyId !== proxyId) continue;\n this.failStream(streamId, 410, \"开发机已删除\", ControlErrorCode.PROXY_NOT_FOUND);\n failedStreams += 1;\n }\n for (const [uploadId, pending] of this.pendingUploads) {\n if (pending.token.proxyId !== proxyId) continue;\n this.failUpload(uploadId, 410, \"开发机已删除\", ControlErrorCode.PROXY_NOT_FOUND);\n failedUploads += 1;\n }\n\n this.deps.logger.info(\n { proxyId, revokedTokens, rejectedMetadata, failedStreams, failedUploads },\n \"Remote file access revoked for removed proxy\",\n );\n }\n\n createUrl(input: {\n clientId: string;\n proxyId: string;\n sessionId: string;\n path: string;\n disposition: RemoteFileDisposition;\n }): Promise<RemoteFileUrlResult> {\n this.cleanupExpiredTokens();\n const proxyWs = this.deps.registry.getProxy(input.proxyId);\n if (!proxyWs || proxyWs.readyState !== WebSocket.OPEN) {\n return Promise.resolve({\n success: false,\n path: input.path,\n error: \"当前未连接开发机\",\n errorCode: ControlErrorCode.PROXY_OFFLINE,\n });\n }\n\n const requestId = nanoid(21);\n return new Promise<RemoteFileUrlResult>((resolve) => {\n const timer = setTimeout(() => {\n this.pendingUrlMetadata.delete(requestId);\n resolve({\n success: false,\n path: input.path,\n error: \"读取文件元数据超时\",\n errorCode: ControlErrorCode.UNKNOWN,\n });\n }, REMOTE_FILE_METADATA_TIMEOUT_MS);\n\n this.pendingUrlMetadata.set(requestId, {\n requestId,\n clientId: input.clientId,\n proxyId: input.proxyId,\n sessionId: input.sessionId,\n path: input.path,\n disposition: input.disposition,\n timer,\n resolve,\n });\n\n proxyWs.send(\n serializeControl({\n type: \"remote_file_metadata_request\",\n requestId,\n sessionId: input.sessionId,\n path: input.path,\n }),\n );\n this.deps.logger.info(\n { requestId, proxyId: input.proxyId, sessionId: input.sessionId, path: input.path },\n \"Remote file URL metadata requested\",\n );\n });\n }\n\n createUploadUrl(input: {\n clientId: string;\n proxyId: string;\n sessionId: string;\n kind: RemoteFileUploadKind;\n fileName?: string;\n mimeType: string;\n size?: number;\n }): { uploadUrl: string; expiresAt: number } {\n this.cleanupExpiredTokens();\n const token = nanoid(32);\n const expiresAt = Date.now() + REMOTE_FILE_TOKEN_TTL_MS;\n this.uploadTokens.set(token, {\n token,\n clientId: input.clientId,\n proxyId: input.proxyId,\n sessionId: input.sessionId,\n kind: input.kind,\n fileName: input.fileName,\n mimeType: input.mimeType,\n size: input.size,\n expiresAt,\n });\n return { uploadUrl: `/api/remote-uploads/${token}`, expiresAt };\n }\n\n handleHttpRequest(req: Request, res: Response): void {\n const tokenValue = req.params.token;\n const token = typeof tokenValue === \"string\" ? this.tokens.get(tokenValue) : undefined;\n if (!token || token.expiresAt <= Date.now()) {\n if (typeof tokenValue === \"string\") this.tokens.delete(tokenValue);\n res.status(404).json({ error: \"remote_file_url_expired\" });\n return;\n }\n\n const proxyWs = this.deps.registry.getProxy(token.proxyId);\n if (!proxyWs || proxyWs.readyState !== WebSocket.OPEN) {\n res.status(502).json({ error: \"proxy_offline\" });\n return;\n }\n\n const streamId = nanoid(21);\n const metadataTimer = setTimeout(() => {\n this.failStream(streamId, 504, \"读取文件元数据超时\");\n }, REMOTE_FILE_METADATA_TIMEOUT_MS);\n const pending: PendingHttpStream = {\n streamId,\n token,\n res,\n metadataTimer,\n headersSent: false,\n finished: false,\n };\n this.pendingStreams.set(streamId, pending);\n\n res.on(\"close\", () => {\n if (pending.finished) return;\n pending.finished = true;\n this.pendingStreams.delete(streamId);\n clearTimeout(metadataTimer);\n this.sendCancel(token.proxyId, streamId);\n this.deps.logger.info({ streamId, proxyId: token.proxyId }, \"Remote file HTTP stream closed\");\n });\n\n proxyWs.send(\n serializeControl({\n type: \"remote_file_stream_request\",\n streamId,\n sessionId: token.sessionId,\n path: token.path,\n disposition: token.disposition,\n }),\n );\n this.deps.logger.info(\n { streamId, proxyId: token.proxyId, sessionId: token.sessionId, path: token.path },\n \"Remote file HTTP stream requested\",\n );\n }\n\n handleUploadHttpRequest(req: Request, res: Response): void {\n const tokenValue = req.params.token;\n const token = typeof tokenValue === \"string\" ? this.uploadTokens.get(tokenValue) : undefined;\n if (!token || token.expiresAt <= Date.now()) {\n if (typeof tokenValue === \"string\") this.uploadTokens.delete(tokenValue);\n res.status(404).json({ error: \"remote_file_upload_url_expired\" });\n return;\n }\n\n const proxyWs = this.deps.registry.getProxy(token.proxyId);\n if (!proxyWs || proxyWs.readyState !== WebSocket.OPEN) {\n res.status(502).json({ error: \"proxy_offline\" });\n return;\n }\n\n const uploadId = nanoid(21);\n const pending: PendingHttpUpload = {\n uploadId,\n token,\n res,\n chunkSeq: 0,\n requestEnded: false,\n finished: false,\n responseTimer: null,\n };\n this.pendingUploads.set(uploadId, pending);\n\n proxyWs.send(\n serializeControl({\n type: \"remote_file_upload_stream_request\",\n uploadId,\n sessionId: token.sessionId,\n kind: token.kind,\n mimeType: token.mimeType,\n ...(token.fileName ? { fileName: token.fileName } : {}),\n ...(token.size !== undefined ? { size: token.size } : {}),\n }),\n );\n\n req.on(\"data\", (chunk: Buffer) => {\n if (pending.finished) return;\n req.pause();\n const frame = encodeFileStreamFrame(uploadId, pending.chunkSeq, Buffer.from(chunk));\n pending.chunkSeq += 1;\n proxyWs.send(frame, { binary: true, compress: false }, (err) => {\n if (err) {\n this.failUpload(uploadId, 502, err.message);\n return;\n }\n req.resume();\n });\n });\n\n req.on(\"end\", () => {\n if (pending.finished) return;\n pending.requestEnded = true;\n pending.responseTimer = setTimeout(() => {\n this.failUpload(uploadId, 504, \"等待上传写入结果超时\");\n }, REMOTE_FILE_UPLOAD_RESPONSE_TIMEOUT_MS);\n proxyWs.send(serializeControl({ type: \"remote_file_upload_stream_complete\", uploadId }));\n });\n\n req.on(\"error\", (err) => {\n this.failUpload(uploadId, 400, err.message);\n });\n\n req.on(\"close\", () => {\n if (pending.finished || pending.requestEnded) return;\n this.failUpload(uploadId, 499, \"上传请求已断开\");\n });\n\n this.deps.logger.info(\n { uploadId, proxyId: token.proxyId, sessionId: token.sessionId, kind: token.kind },\n \"Remote file HTTP upload requested\",\n );\n }\n\n handleProxyControl(proxyId: string, msg: ControlMessage<\"remote_file_stream_response\">): boolean;\n handleProxyControl(proxyId: string, msg: ControlMessage<\"remote_file_stream_complete\">): boolean;\n handleProxyControl(\n proxyId: string,\n msg: ControlMessage<\"remote_file_metadata_response\">,\n ): boolean;\n handleProxyControl(\n proxyId: string,\n msg: ControlMessage<\"remote_file_upload_stream_response\">,\n ): boolean;\n handleProxyControl(\n proxyId: string,\n msg:\n | ControlMessage<\"remote_file_stream_response\">\n | ControlMessage<\"remote_file_stream_complete\">\n | ControlMessage<\"remote_file_metadata_response\">\n | ControlMessage<\"remote_file_upload_stream_response\">,\n ): boolean {\n if (msg.type === \"remote_file_upload_stream_response\") {\n return this.handleUploadResponse(proxyId, msg);\n }\n\n if (msg.type === \"remote_file_metadata_response\") {\n return this.handleUrlMetadataResponse(proxyId, msg);\n }\n\n const pending = this.pendingStreams.get(msg.streamId);\n if (!pending) return true;\n if (pending.token.proxyId !== proxyId) {\n this.deps.logger.warn(\n { streamId: msg.streamId, expectedProxyId: pending.token.proxyId, proxyId },\n \"Remote file stream control ignored: proxy mismatch\",\n );\n return true;\n }\n\n if (msg.type === \"remote_file_stream_response\") {\n this.handleStreamResponse(pending, msg);\n return true;\n }\n\n this.handleStreamComplete(pending, msg);\n return true;\n }\n\n private issueUrlToken(input: {\n clientId: string;\n proxyId: string;\n sessionId: string;\n path: string;\n disposition: RemoteFileDisposition;\n }): { url: string; expiresAt: number } {\n const token = nanoid(32);\n const expiresAt = Date.now() + REMOTE_FILE_TOKEN_TTL_MS;\n this.tokens.set(token, {\n token,\n clientId: input.clientId,\n proxyId: input.proxyId,\n sessionId: input.sessionId,\n path: input.path,\n disposition: input.disposition,\n expiresAt,\n });\n return { url: `/api/remote-files/${token}`, expiresAt };\n }\n\n private handleUrlMetadataResponse(\n proxyId: string,\n msg: ControlMessage<\"remote_file_metadata_response\">,\n ): boolean {\n const pending = this.pendingUrlMetadata.get(msg.requestId);\n if (!pending) return true;\n if (pending.proxyId !== proxyId) {\n this.deps.logger.warn(\n { requestId: msg.requestId, expectedProxyId: pending.proxyId, proxyId },\n \"Remote file metadata ignored: proxy mismatch\",\n );\n return true;\n }\n\n this.pendingUrlMetadata.delete(msg.requestId);\n clearTimeout(pending.timer);\n\n if (!msg.success) {\n pending.resolve({\n success: false,\n path: pending.path,\n error: msg.error ?? \"读取文件失败\",\n ...(msg.errorCode ? { errorCode: msg.errorCode } : {}),\n });\n return true;\n }\n\n const { url, expiresAt } = this.issueUrlToken(pending);\n pending.resolve({\n success: true,\n path: pending.path,\n url,\n expiresAt,\n });\n return true;\n }\n\n handleProxyBinary(proxyId: string, data: Buffer): boolean {\n const decoded = decodeFileStreamFrame(data);\n if (!decoded) return false;\n\n const pending = this.pendingStreams.get(decoded.streamId);\n if (!pending) return true;\n if (pending.token.proxyId !== proxyId) {\n this.deps.logger.warn(\n { streamId: decoded.streamId, expectedProxyId: pending.token.proxyId, proxyId },\n \"Remote file stream chunk ignored: proxy mismatch\",\n );\n return true;\n }\n if (!pending.headersSent || pending.finished) return true;\n\n pending.res.write(Buffer.from(decoded.data));\n return true;\n }\n\n private handleStreamResponse(\n pending: PendingHttpStream,\n msg: ControlMessage<\"remote_file_stream_response\">,\n ): void {\n clearTimeout(pending.metadataTimer);\n if (!msg.success) {\n this.failStream(\n pending.streamId,\n statusForErrorCode(msg.errorCode),\n msg.error ?? \"读取文件失败\",\n msg.errorCode,\n );\n return;\n }\n\n try {\n pending.res.status(200);\n pending.res.setHeader(\"Content-Type\", msg.mimeType ?? \"application/octet-stream\");\n pending.res.setHeader(\"Cache-Control\", \"no-store\");\n pending.res.setHeader(\"X-Content-Type-Options\", \"nosniff\");\n if (msg.size !== undefined) {\n pending.res.setHeader(\"Content-Length\", String(msg.size));\n }\n pending.res.setHeader(\n \"Content-Disposition\",\n encodeContentDisposition(pending.token.disposition, msg.fileName ?? \"download\"),\n );\n pending.res.flushHeaders();\n pending.headersSent = true;\n } catch (error) {\n pending.headersSent = pending.res.headersSent;\n this.deps.logger.error(\n { err: error, streamId: pending.streamId, fileName: msg.fileName },\n \"Remote file response headers rejected\",\n );\n this.failStream(pending.streamId, 500, \"文件下载响应无效\");\n }\n }\n\n private handleStreamComplete(\n pending: PendingHttpStream,\n msg: ControlMessage<\"remote_file_stream_complete\">,\n ): void {\n clearTimeout(pending.metadataTimer);\n pending.finished = true;\n this.pendingStreams.delete(pending.streamId);\n if (!msg.success) {\n if (!pending.headersSent) {\n this.writeJsonError(\n pending.res,\n statusForErrorCode(msg.errorCode),\n msg.error ?? \"读取文件失败\",\n msg.errorCode,\n );\n } else {\n pending.res.destroy(new Error(msg.error ?? \"Remote file stream failed\"));\n }\n return;\n }\n pending.res.end();\n }\n\n private handleUploadResponse(\n proxyId: string,\n msg: ControlMessage<\"remote_file_upload_stream_response\">,\n ): boolean {\n const pending = this.pendingUploads.get(msg.uploadId);\n if (!pending) return true;\n if (pending.token.proxyId !== proxyId) {\n this.deps.logger.warn(\n { uploadId: msg.uploadId, expectedProxyId: pending.token.proxyId, proxyId },\n \"Remote file upload response ignored: proxy mismatch\",\n );\n return true;\n }\n pending.finished = true;\n this.pendingUploads.delete(msg.uploadId);\n if (pending.responseTimer) clearTimeout(pending.responseTimer);\n if (!msg.success) {\n this.writeJsonError(\n pending.res,\n statusForErrorCode(msg.errorCode),\n msg.error ?? \"上传文件失败\",\n msg.errorCode,\n );\n return true;\n }\n pending.res.status(200).json({\n sessionId: msg.sessionId,\n success: true,\n path: msg.path,\n });\n return true;\n }\n\n private failStream(streamId: string, status: number, error: string, errorCode?: string): void {\n const pending = this.pendingStreams.get(streamId);\n if (!pending) return;\n pending.finished = true;\n this.pendingStreams.delete(streamId);\n clearTimeout(pending.metadataTimer);\n this.sendCancel(pending.token.proxyId, streamId);\n if (!pending.headersSent) {\n this.writeJsonError(pending.res, status, error, errorCode);\n } else {\n pending.res.destroy(new Error(error));\n }\n }\n\n private failUpload(uploadId: string, status: number, error: string, errorCode?: string): void {\n const pending = this.pendingUploads.get(uploadId);\n if (!pending) return;\n pending.finished = true;\n this.pendingUploads.delete(uploadId);\n if (pending.responseTimer) clearTimeout(pending.responseTimer);\n this.sendUploadCancel(pending.token.proxyId, uploadId);\n if (!pending.res.headersSent) {\n this.writeJsonError(pending.res, status, error, errorCode);\n } else {\n pending.res.destroy(new Error(error));\n }\n }\n\n private writeJsonError(res: Response, status: number, error: string, errorCode?: string): void {\n res.status(status).json({\n error,\n ...(errorCode ? { errorCode } : {}),\n });\n }\n\n private sendCancel(proxyId: string, streamId: string): void {\n const proxyWs = this.deps.registry.getProxy(proxyId);\n if (!proxyWs || proxyWs.readyState !== WebSocket.OPEN) return;\n proxyWs.send(serializeControl({ type: \"remote_file_stream_cancel\", streamId }));\n }\n\n private sendUploadCancel(proxyId: string, uploadId: string): void {\n const proxyWs = this.deps.registry.getProxy(proxyId);\n if (!proxyWs || proxyWs.readyState !== WebSocket.OPEN) return;\n proxyWs.send(serializeControl({ type: \"remote_file_upload_stream_cancel\", uploadId }));\n }\n\n private cleanupExpiredTokens(): void {\n const now = Date.now();\n for (const [token, meta] of this.tokens) {\n if (meta.expiresAt <= now) this.tokens.delete(token);\n }\n for (const [token, meta] of this.uploadTokens) {\n if (meta.expiresAt <= now) this.uploadTokens.delete(token);\n }\n }\n}\n","import compression from \"compression\";\nimport express, { type Express, type Request, type Response } from \"express\";\nimport { existsSync } from \"node:fs\";\nimport { basename, join, relative } from \"node:path\";\nimport type { Logger } from \"@dev-anywhere/shared/logger\";\n\nconst IMMUTABLE_CACHE_SECONDS = 365 * 24 * 60 * 60;\nconst SHORT_CACHE_SECONDS = 60 * 60;\n\nconst RELAY_ROUTE_ROOTS = new Set([\n \"/api\",\n \"/client\",\n \"/fonts\",\n \"/health\",\n \"/proxy\",\n \"/proxy-stream\",\n \"/status\",\n \"/voice\",\n]);\n\nfunction isRelayRoute(pathname: string): boolean {\n for (const root of RELAY_ROUTE_ROOTS) {\n if (pathname === root || pathname.startsWith(`${root}/`)) return true;\n }\n return false;\n}\n\nfunction setStaticCacheHeaders(response: Response, filePath: string, webAssetDir: string): void {\n const fileName = basename(filePath);\n const relativePath = relative(webAssetDir, filePath).replaceAll(\"\\\\\", \"/\");\n if (relativePath.startsWith(\"assets/\") || /^workbox-.+\\.js$/.test(fileName)) {\n response.setHeader(\"Cache-Control\", `public, max-age=${IMMUTABLE_CACHE_SECONDS}, immutable`);\n return;\n }\n\n if (\n fileName === \"index.html\" ||\n fileName === \"sw.js\" ||\n fileName === \"registerSW.js\" ||\n fileName === \"manifest.webmanifest\"\n ) {\n response.setHeader(\"Cache-Control\", \"no-cache, no-store, must-revalidate\");\n return;\n }\n\n response.setHeader(\"Cache-Control\", `public, max-age=${SHORT_CACHE_SECONDS}`);\n}\n\nexport function mountWebApp(\n app: Express,\n options: {\n webAssetDir: string;\n logger: Logger;\n },\n): boolean {\n const { webAssetDir, logger } = options;\n const indexPath = join(webAssetDir, \"index.html\");\n if (!existsSync(indexPath)) {\n logger.warn({ webAssetDir }, \"Web assets not found; Relay will run without the Web UI\");\n return false;\n }\n\n app.use(compression());\n app.use(\n express.static(webAssetDir, {\n index: false,\n fallthrough: true,\n setHeaders: (response, filePath) => setStaticCacheHeaders(response, filePath, webAssetDir),\n }),\n );\n\n app.use((request: Request, response: Response, next) => {\n if (request.method !== \"GET\" && request.method !== \"HEAD\") {\n next();\n return;\n }\n\n if (isRelayRoute(request.path)) {\n response.status(404).json({ error: \"not_found\" });\n return;\n }\n\n if (!request.accepts(\"html\")) {\n next();\n return;\n }\n\n response.setHeader(\"Cache-Control\", \"no-cache, no-store, must-revalidate\");\n response.sendFile(\"index.html\", { root: webAssetDir });\n });\n\n logger.info({ webAssetDir }, \"Web UI mounted\");\n return true;\n}\n","import type { WebSocket } from \"ws\";\n\nconst DEFAULT_MAX_ENTRIES = 4_096;\nconst DEFAULT_MAX_PENDING_PER_CLIENT = 64;\n// Keep this below the browser's 30s delivery retry. A small scheduling/network delay must not\n// suppress the first retry and postpone recovery until the following 60s attempt.\nconst DEFAULT_RETRY_FORWARD_INTERVAL_MS = 25_000;\nconst DEFAULT_PENDING_TTL_MS = 5 * 60_000;\nconst DEFAULT_TOMBSTONE_TTL_MS = 120_000;\n\ntype PendingRoute = {\n state: \"pending\";\n proxyId: string;\n proxyWs: WebSocket;\n clientWs: WebSocket;\n lastForwardedAt: number;\n expiresAt: number;\n};\n\ntype TombstoneRoute = {\n state: \"tombstone\";\n proxyId: string;\n expiresAt: number;\n};\n\ntype SnapshotRoute = PendingRoute | TombstoneRoute;\n\nexport type SnapshotRouteRegistration =\n | \"registered\"\n | \"duplicate\"\n | \"retry_due\"\n | \"collision\"\n | \"client_capacity_exceeded\"\n | \"capacity_exceeded\";\n\nexport type SnapshotRouteResolution =\n | { kind: \"matched\"; clientWs: WebSocket }\n | { kind: \"stale_proxy\" }\n | { kind: \"tombstone\" }\n | { kind: \"unmatched\" };\n\nexport interface PtySnapshotRouteRegistryOptions {\n maxEntries?: number;\n maxPendingPerClient?: number;\n retryForwardIntervalMs?: number;\n pendingTtlMs?: number;\n tombstoneTtlMs?: number;\n now?: () => number;\n}\n\nfunction routeKey(proxyId: string, sessionId: string, requestId: string): string {\n return JSON.stringify([proxyId, sessionId, requestId]);\n}\n\n/**\n * Correlates a request-scoped PTY snapshot with the exact browser socket that requested it.\n * Entries are capacity- and TTL-bounded; tombstones retain no socket reference and ensure a\n * response arriving after disconnect is dropped rather than falling back to a broadcast.\n */\nexport class PtySnapshotRouteRegistry {\n private readonly routes = new Map<string, SnapshotRoute>();\n private readonly maxEntries: number;\n private readonly maxPendingPerClient: number;\n private readonly retryForwardIntervalMs: number;\n private readonly pendingTtlMs: number;\n private readonly tombstoneTtlMs: number;\n private readonly now: () => number;\n\n constructor(options: PtySnapshotRouteRegistryOptions = {}) {\n this.maxEntries = Math.max(1, options.maxEntries ?? DEFAULT_MAX_ENTRIES);\n this.maxPendingPerClient = Math.max(\n 1,\n options.maxPendingPerClient ?? DEFAULT_MAX_PENDING_PER_CLIENT,\n );\n this.retryForwardIntervalMs = Math.max(\n 1,\n options.retryForwardIntervalMs ?? DEFAULT_RETRY_FORWARD_INTERVAL_MS,\n );\n this.pendingTtlMs = Math.max(1, options.pendingTtlMs ?? DEFAULT_PENDING_TTL_MS);\n this.tombstoneTtlMs = Math.max(1, options.tombstoneTtlMs ?? DEFAULT_TOMBSTONE_TTL_MS);\n this.now = options.now ?? Date.now;\n }\n\n register(\n proxyId: string,\n sessionId: string,\n requestId: string,\n clientWs: WebSocket,\n proxyWs: WebSocket,\n ): SnapshotRouteRegistration {\n const now = this.now();\n this.pruneExpired(now);\n const key = routeKey(proxyId, sessionId, requestId);\n const existing = this.routes.get(key);\n if (existing) {\n if (\n existing.state === \"pending\" &&\n existing.clientWs === clientWs &&\n existing.proxyWs === proxyWs\n ) {\n if (now - existing.lastForwardedAt >= this.retryForwardIntervalMs) {\n existing.lastForwardedAt = now;\n return \"retry_due\";\n }\n return \"duplicate\";\n }\n return \"collision\";\n }\n let clientPendingCount = 0;\n for (const route of this.routes.values()) {\n if (route.state === \"pending\" && route.clientWs === clientWs) {\n clientPendingCount += 1;\n if (clientPendingCount >= this.maxPendingPerClient) {\n return \"client_capacity_exceeded\";\n }\n }\n }\n if (this.routes.size >= this.maxEntries) {\n let oldestTombstoneKey: string | undefined;\n let oldestTombstoneExpiry = Number.POSITIVE_INFINITY;\n for (const [candidateKey, route] of this.routes) {\n if (route.state === \"tombstone\" && route.expiresAt < oldestTombstoneExpiry) {\n oldestTombstoneKey = candidateKey;\n oldestTombstoneExpiry = route.expiresAt;\n }\n }\n if (oldestTombstoneKey) this.routes.delete(oldestTombstoneKey);\n else return \"capacity_exceeded\";\n }\n\n this.routes.set(key, {\n state: \"pending\",\n proxyId,\n proxyWs,\n clientWs,\n lastForwardedAt: now,\n expiresAt: now + this.pendingTtlMs,\n });\n return \"registered\";\n }\n\n resolve(\n proxyId: string,\n sessionId: string,\n requestId: string,\n proxyWs: WebSocket,\n ): SnapshotRouteResolution {\n const now = this.now();\n this.pruneExpired(now);\n const key = routeKey(proxyId, sessionId, requestId);\n const route = this.routes.get(key);\n if (!route) return { kind: \"unmatched\" };\n if (route.state === \"tombstone\") return { kind: \"tombstone\" };\n if (route.proxyWs !== proxyWs) return { kind: \"stale_proxy\" };\n\n this.routes.set(key, {\n state: \"tombstone\",\n proxyId,\n expiresAt: now + this.tombstoneTtlMs,\n });\n return { kind: \"matched\", clientWs: route.clientWs };\n }\n\n abandonSocket(clientWs: WebSocket): void {\n const now = this.now();\n this.pruneExpired(now);\n for (const [key, route] of this.routes) {\n if (route.state === \"pending\" && route.clientWs === clientWs) {\n this.routes.set(key, {\n state: \"tombstone\",\n proxyId: route.proxyId,\n expiresAt: now + this.tombstoneTtlMs,\n });\n }\n }\n }\n\n clearProxy(proxyId: string): void {\n for (const [key, route] of this.routes) {\n if (route.proxyId === proxyId) this.routes.delete(key);\n }\n }\n\n private pruneExpired(now: number): void {\n for (const [key, route] of this.routes) {\n if (route.expiresAt <= now) this.routes.delete(key);\n }\n }\n}\n","import { nanoid } from \"nanoid\";\nimport type { WebSocket } from \"ws\";\n\nconst DEFAULT_MAX_ENTRIES = 4_096;\nconst DEFAULT_MAX_PENDING_PER_CLIENT = 64;\nconst DEFAULT_PENDING_TTL_MS = 20_000;\nconst DEFAULT_JOIN_WINDOW_MS = 8_000;\nconst DEFAULT_TOMBSTONE_TTL_MS = 60_000;\n\ntype PendingRoute = {\n state: \"pending\";\n proxyId: string;\n proxyWs: WebSocket;\n clientWs: WebSocket;\n upstreamRequestId: string;\n expiresAt: number;\n};\n\ntype TombstoneRoute = {\n state: \"tombstone\";\n proxyId: string;\n expiresAt: number;\n};\n\ntype HistoryRoute = PendingRoute | TombstoneRoute;\n\ntype HistoryFlight = {\n proxyId: string;\n proxyWs: WebSocket;\n upstreamRequestId: string;\n requestIds: Set<string>;\n joinUntil: number;\n expiresAt: number;\n};\n\ntype FlightTombstone = {\n proxyId: string;\n expiresAt: number;\n};\n\nexport type HistoryRouteRegistration =\n | { kind: \"leader\"; upstreamRequestId: string }\n | { kind: \"joined\"; upstreamRequestId: string }\n | { kind: \"duplicate\" }\n | { kind: \"collision\" }\n | { kind: \"client_capacity_exceeded\" }\n | { kind: \"capacity_exceeded\" };\n\nexport type HistoryRouteTarget = {\n clientWs: WebSocket;\n requestId: string;\n};\n\nexport type HistoryRouteResolution =\n | { kind: \"matched\"; targets: HistoryRouteTarget[] }\n | { kind: \"stale_proxy\" }\n | { kind: \"tombstone\" }\n | { kind: \"unmatched\" };\n\nexport interface SessionHistoryRouteRegistryOptions {\n maxEntries?: number;\n maxPendingPerClient?: number;\n pendingTtlMs?: number;\n joinWindowMs?: number;\n tombstoneTtlMs?: number;\n now?: () => number;\n upstreamRequestIdFactory?: () => string;\n}\n\nfunction routeKey(proxyId: string, requestId: string): string {\n return JSON.stringify([proxyId, requestId]);\n}\n\n/**\n * Coalesces overlapping history requests for the same live proxy socket and correlates the one\n * upstream response with every exact browser waiter. External request IDs never cross the proxy\n * wire: a relay-owned ID prevents a late response from being confused with a reused client ID.\n */\nexport class SessionHistoryRouteRegistry {\n private readonly routes = new Map<string, HistoryRoute>();\n private readonly flights = new Map<string, HistoryFlight>();\n private readonly flightTombstones = new Map<string, FlightTombstone>();\n private readonly maxEntries: number;\n private readonly maxPendingPerClient: number;\n private readonly pendingTtlMs: number;\n private readonly joinWindowMs: number;\n private readonly tombstoneTtlMs: number;\n private readonly now: () => number;\n private readonly upstreamRequestIdFactory: () => string;\n private upstreamRequestSequence = 0;\n\n constructor(options: SessionHistoryRouteRegistryOptions = {}) {\n this.maxEntries = Math.max(1, options.maxEntries ?? DEFAULT_MAX_ENTRIES);\n this.maxPendingPerClient = Math.max(\n 1,\n options.maxPendingPerClient ?? DEFAULT_MAX_PENDING_PER_CLIENT,\n );\n this.pendingTtlMs = Math.max(1, options.pendingTtlMs ?? DEFAULT_PENDING_TTL_MS);\n this.joinWindowMs = Math.max(\n 1,\n Math.min(options.joinWindowMs ?? DEFAULT_JOIN_WINDOW_MS, this.pendingTtlMs),\n );\n this.tombstoneTtlMs = Math.max(1, options.tombstoneTtlMs ?? DEFAULT_TOMBSTONE_TTL_MS);\n this.now = options.now ?? Date.now;\n this.upstreamRequestIdFactory =\n options.upstreamRequestIdFactory ??\n (() => {\n this.upstreamRequestSequence += 1;\n return `relay-history-${this.upstreamRequestSequence.toString(36)}-${nanoid(12)}`;\n });\n }\n\n register(\n proxyId: string,\n requestId: string,\n clientWs: WebSocket,\n proxyWs: WebSocket,\n ): HistoryRouteRegistration {\n const now = this.now();\n this.pruneExpired(now);\n const key = routeKey(proxyId, requestId);\n const existing = this.routes.get(key);\n if (existing) {\n if (\n existing.state === \"pending\" &&\n existing.clientWs === clientWs &&\n existing.proxyWs === proxyWs\n ) {\n return { kind: \"duplicate\" };\n }\n return { kind: \"collision\" };\n }\n\n let clientPendingCount = 0;\n for (const route of this.routes.values()) {\n if (route.state === \"pending\" && route.clientWs === clientWs) {\n clientPendingCount += 1;\n if (clientPendingCount >= this.maxPendingPerClient) {\n return { kind: \"client_capacity_exceeded\" };\n }\n }\n }\n\n if (this.routes.size >= this.maxEntries && !this.evictOldestRouteTombstone()) {\n return { kind: \"capacity_exceeded\" };\n }\n\n let flight = this.flights.get(proxyId);\n if (flight && flight.proxyWs !== proxyWs) {\n this.expireFlight(flight, now);\n flight = undefined;\n }\n\n let kind: \"leader\" | \"joined\";\n if (!flight || flight.joinUntil <= now) {\n const replacement = this.createFlight(proxyId, proxyWs, now);\n if (flight) this.migrateFlight(flight, replacement, now);\n this.flights.set(proxyId, replacement);\n flight = replacement;\n kind = \"leader\";\n } else {\n kind = \"joined\";\n }\n\n const routeExpiresAt = now + this.pendingTtlMs;\n flight.requestIds.add(requestId);\n flight.expiresAt = Math.max(flight.expiresAt, routeExpiresAt);\n this.routes.set(key, {\n state: \"pending\",\n proxyId,\n proxyWs,\n clientWs,\n upstreamRequestId: flight.upstreamRequestId,\n expiresAt: routeExpiresAt,\n });\n return { kind, upstreamRequestId: flight.upstreamRequestId };\n }\n\n resolve(proxyId: string, requestId: string, proxyWs: WebSocket): HistoryRouteResolution {\n const now = this.now();\n this.pruneExpired(now);\n const flight = this.flights.get(proxyId);\n if (!flight || flight.upstreamRequestId !== requestId) {\n return this.flightTombstones.has(routeKey(proxyId, requestId))\n ? { kind: \"tombstone\" }\n : { kind: \"unmatched\" };\n }\n if (flight.proxyWs !== proxyWs) return { kind: \"stale_proxy\" };\n\n this.flights.delete(proxyId);\n this.setFlightTombstone(flight, now);\n\n const targets: HistoryRouteTarget[] = [];\n for (const externalRequestId of flight.requestIds) {\n const key = routeKey(proxyId, externalRequestId);\n const route = this.routes.get(key);\n if (\n !route ||\n route.state !== \"pending\" ||\n route.proxyWs !== proxyWs ||\n route.upstreamRequestId !== requestId\n ) {\n continue;\n }\n this.routes.set(key, {\n state: \"tombstone\",\n proxyId,\n expiresAt: now + this.tombstoneTtlMs,\n });\n targets.push({ clientWs: route.clientWs, requestId: externalRequestId });\n }\n return { kind: \"matched\", targets };\n }\n\n abandonSocket(clientWs: WebSocket): void {\n const now = this.now();\n this.pruneExpired(now);\n for (const [key, route] of this.routes) {\n if (route.state === \"pending\" && route.clientWs === clientWs) {\n this.routes.set(key, {\n state: \"tombstone\",\n proxyId: route.proxyId,\n expiresAt: now + this.tombstoneTtlMs,\n });\n }\n }\n }\n\n clearProxy(proxyId: string): void {\n for (const [key, route] of this.routes) {\n if (route.proxyId === proxyId) this.routes.delete(key);\n }\n this.flights.delete(proxyId);\n for (const [key, tombstone] of this.flightTombstones) {\n if (tombstone.proxyId === proxyId) this.flightTombstones.delete(key);\n }\n }\n\n private createFlight(proxyId: string, proxyWs: WebSocket, now: number): HistoryFlight {\n return {\n proxyId,\n proxyWs,\n upstreamRequestId: this.upstreamRequestIdFactory(),\n requestIds: new Set<string>(),\n joinUntil: now + this.joinWindowMs,\n expiresAt: now + this.pendingTtlMs,\n };\n }\n\n private migrateFlight(previous: HistoryFlight, replacement: HistoryFlight, now: number): void {\n if (this.flights.get(previous.proxyId) === previous) this.flights.delete(previous.proxyId);\n this.setFlightTombstone(previous, now);\n for (const externalRequestId of previous.requestIds) {\n const key = routeKey(previous.proxyId, externalRequestId);\n const route = this.routes.get(key);\n if (\n !route ||\n route.state !== \"pending\" ||\n route.proxyWs !== previous.proxyWs ||\n route.upstreamRequestId !== previous.upstreamRequestId\n ) {\n continue;\n }\n route.upstreamRequestId = replacement.upstreamRequestId;\n replacement.requestIds.add(externalRequestId);\n replacement.expiresAt = Math.max(replacement.expiresAt, route.expiresAt);\n }\n }\n\n private expireFlight(flight: HistoryFlight, now: number): void {\n if (this.flights.get(flight.proxyId) === flight) this.flights.delete(flight.proxyId);\n this.setFlightTombstone(flight, now);\n for (const externalRequestId of flight.requestIds) {\n const key = routeKey(flight.proxyId, externalRequestId);\n const route = this.routes.get(key);\n if (route?.state === \"pending\" && route.upstreamRequestId === flight.upstreamRequestId) {\n this.routes.delete(key);\n }\n }\n }\n\n private setFlightTombstone(flight: HistoryFlight, now: number): void {\n const key = routeKey(flight.proxyId, flight.upstreamRequestId);\n if (!this.flightTombstones.has(key) && this.flightTombstones.size >= this.maxEntries) {\n const oldest = this.flightTombstones.keys().next().value;\n if (oldest !== undefined) this.flightTombstones.delete(oldest);\n }\n this.flightTombstones.set(key, {\n proxyId: flight.proxyId,\n expiresAt: now + this.tombstoneTtlMs,\n });\n }\n\n private evictOldestRouteTombstone(): boolean {\n let oldestTombstoneKey: string | undefined;\n let oldestTombstoneExpiry = Number.POSITIVE_INFINITY;\n for (const [candidateKey, route] of this.routes) {\n if (route.state === \"tombstone\" && route.expiresAt < oldestTombstoneExpiry) {\n oldestTombstoneKey = candidateKey;\n oldestTombstoneExpiry = route.expiresAt;\n }\n }\n if (!oldestTombstoneKey) return false;\n this.routes.delete(oldestTombstoneKey);\n return true;\n }\n\n private pruneExpired(now: number): void {\n for (const flight of this.flights.values()) {\n if (flight.expiresAt <= now) this.expireFlight(flight, now);\n }\n for (const [key, route] of this.routes) {\n if (route.expiresAt <= now) this.routes.delete(key);\n }\n for (const [key, tombstone] of this.flightTombstones) {\n if (tombstone.expiresAt <= now) this.flightTombstones.delete(key);\n }\n }\n}\n","import type { Request, Response } from \"express\";\nimport { nanoid } from \"nanoid\";\nimport { WebSocket } from \"ws\";\nimport {\n ControlErrorCode,\n DEVICE_PREVIEW_FRAME_MAX_BYTES,\n DEVICE_PREVIEW_H264_PACKET_SENTINEL,\n DevicePreviewStreamRegisterSchema,\n RelayCloseCode,\n decodeDevicePreviewFrame,\n decodeDevicePreviewH264ProxyPacket,\n encodeDevicePreviewH264HttpPacket,\n encodeDevicePreviewHttpFrame,\n serializeControl,\n type ControlMessage,\n type ControlErrorCodeType,\n type DevicePreviewStreamProfile,\n type DevicePreviewStreamFormat,\n type DevicePreviewH264Packet,\n type DevicePreviewStreamStopReason,\n type RelayControlMessage,\n} from \"@dev-anywhere/shared\";\nimport type { Logger } from \"@dev-anywhere/shared/logger\";\nimport type { RelayChaos } from \"./chaos.js\";\nimport {\n DevicePreviewRouteRegistry,\n devicePreviewResponseByRequest,\n isDevicePreviewRequestMessage,\n isDevicePreviewResponseMessage,\n type DevicePreviewRequestMessage,\n type DevicePreviewResponseMessage,\n} from \"./device-preview-route-registry.js\";\nimport type { RelayRegistry } from \"./registry.js\";\nimport { rewriteForwardedControl } from \"./forwarded-control.js\";\n\nconst DEFAULT_TOKEN_TTL_MS = 20_000;\nconst DEFAULT_START_TIMEOUT_MS = 10_000;\nconst DEFAULT_FIRST_FRAME_TIMEOUT_MS = 20_000;\nconst DEFAULT_DRAIN_TIMEOUT_MS = 5_000;\nconst DEFAULT_REGISTER_TIMEOUT_MS = 5_000;\nconst DEFAULT_MAX_STREAMS = 64;\nconst DEFAULT_MAX_STREAMS_PER_PROXY = 8;\nconst DEFAULT_MAX_STREAMS_PER_CLIENT = 2;\nconst DEFAULT_MAX_STREAMS_PER_PREVIEW = 3;\nconst DEFAULT_MAX_INPUTS_PER_SECOND = 120;\nconst DEFAULT_MAX_OUTSTANDING_INPUTS_PER_LEASE = 32;\nconst STREAM_CONTENT_TYPE = \"application/x-dev-anywhere-device-preview\";\nconst MAX_BUFFERED_STARTING_H264_BYTES = 4 * 1024 * 1024;\nconst MAX_BUFFERED_STARTING_H264_PACKETS = 512;\n\ntype H264SyncState = \"awaiting_configuration\" | \"awaiting_keyframe\" | \"synced\";\ntype StreamWriteResult = \"writable\" | \"backpressured\" | \"failed\";\n\ntype ClientSocket = WebSocket & {\n clientId?: string;\n boundProxyId?: string;\n bindingId?: string;\n};\ntype StreamTransportSocket = WebSocket & {\n isAlive?: boolean;\n devicePreviewProxyId?: string;\n devicePreviewConnectionId?: string;\n};\n\ninterface ProxyConnection {\n proxyWs: WebSocket;\n connectionId: string;\n}\n\ninterface StreamTransport {\n ws: StreamTransportSocket;\n proxyId: string;\n connectionId: string;\n}\n\ninterface ControlLease {\n leaseId: string;\n clientId: string;\n clientWs: ClientSocket;\n proxyId: string;\n bindingId: string;\n proxyWs: WebSocket;\n previewId: string;\n controller: boolean;\n streamId?: string;\n token?: string;\n lastInputSeq: number;\n rateWindowStartedAt: number;\n inputCount: number;\n outstandingInputSeqs: Set<number>;\n}\n\ninterface StreamToken {\n token: string;\n leaseId: string;\n profile: DevicePreviewStreamProfile;\n expiresAt: number;\n timer: ReturnType<typeof setTimeout>;\n}\n\ninterface BufferedStartingFrame {\n sequence: number;\n jpeg: Uint8Array;\n}\n\ninterface BufferedStartingH264Packet extends DevicePreviewH264Packet {\n annexB: Uint8Array;\n}\n\ninterface BufferedStartingH264State {\n configuration: BufferedStartingH264Packet;\n packets: BufferedStartingH264Packet[];\n totalBytes: number;\n hasKeyframe: boolean;\n}\n\ninterface ActiveStream {\n streamId: string;\n lease: ControlLease;\n transport: StreamTransport;\n res: Response;\n state: \"starting\" | \"streaming\";\n startTimer: ReturnType<typeof setTimeout>;\n firstFrameTimer: ReturnType<typeof setTimeout> | null;\n headersSent: boolean;\n finished: boolean;\n paused: boolean;\n requestedFormat: DevicePreviewStreamFormat;\n format?: DevicePreviewStreamFormat;\n h264SyncState: H264SyncState;\n h264DroppedWhilePaused: boolean;\n lastFrameSequence: number | null;\n bufferedStartingFrame?: BufferedStartingFrame;\n bufferedStartingH264?: BufferedStartingH264State;\n drainListener?: () => void;\n drainTimer?: ReturnType<typeof setTimeout>;\n}\n\ninterface DevicePreviewBridgeOptions {\n registry: RelayRegistry;\n logger: Logger;\n chaos?: RelayChaos;\n clientTokenRequired?: boolean;\n validateClientToken?: (token: string | null) => boolean;\n tokenTtlMs?: number;\n startTimeoutMs?: number;\n firstFrameTimeoutMs?: number;\n drainTimeoutMs?: number;\n registerTimeoutMs?: number;\n maxStreams?: number;\n maxStreamsPerProxy?: number;\n maxStreamsPerClient?: number;\n maxStreamsPerPreview?: number;\n maxInputsPerSecond?: number;\n maxOutstandingInputsPerLease?: number;\n now?: () => number;\n tokenFactory?: () => string;\n idFactory?: () => string;\n}\n\nfunction bearerToken(header: string | undefined): string | null {\n return /^Bearer\\s+(.+)$/i.exec(header ?? \"\")?.[1] ?? null;\n}\n\nfunction previewKey(proxyId: string, previewId: string): string {\n return JSON.stringify([proxyId, previewId]);\n}\n\nfunction streamErrorStatus(errorCode?: string): number {\n switch (errorCode) {\n case ControlErrorCode.PROXY_OFFLINE:\n case ControlErrorCode.PROXY_NOT_FOUND:\n return 502;\n case ControlErrorCode.STREAM_CAPACITY_EXCEEDED:\n return 429;\n default:\n return 502;\n }\n}\n\nfunction errorText(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nexport class DevicePreviewBridge {\n private readonly routes = new DevicePreviewRouteRegistry();\n private readonly proxyConnections = new Map<string, ProxyConnection>();\n private readonly transports = new Map<string, StreamTransport>();\n private readonly tokens = new Map<string, StreamToken>();\n private readonly leases = new Map<string, ControlLease>();\n private readonly controllerByPreview = new Map<string, string>();\n private readonly streams = new Map<string, ActiveStream>();\n private readonly tokenTtlMs: number;\n private readonly startTimeoutMs: number;\n private readonly firstFrameTimeoutMs: number;\n private readonly drainTimeoutMs: number;\n private readonly registerTimeoutMs: number;\n private readonly maxStreams: number;\n private readonly maxStreamsPerProxy: number;\n private readonly maxStreamsPerClient: number;\n private readonly maxStreamsPerPreview: number;\n private readonly maxInputsPerSecond: number;\n private readonly maxOutstandingInputsPerLease: number;\n private readonly now: () => number;\n private readonly tokenFactory: () => string;\n private readonly idFactory: () => string;\n private disposed = false;\n\n constructor(private readonly options: DevicePreviewBridgeOptions) {\n this.tokenTtlMs = Math.max(1, options.tokenTtlMs ?? DEFAULT_TOKEN_TTL_MS);\n this.startTimeoutMs = Math.max(1, options.startTimeoutMs ?? DEFAULT_START_TIMEOUT_MS);\n this.firstFrameTimeoutMs = Math.max(\n 1,\n options.firstFrameTimeoutMs ?? DEFAULT_FIRST_FRAME_TIMEOUT_MS,\n );\n this.drainTimeoutMs = Math.max(1, options.drainTimeoutMs ?? DEFAULT_DRAIN_TIMEOUT_MS);\n this.registerTimeoutMs = Math.max(1, options.registerTimeoutMs ?? DEFAULT_REGISTER_TIMEOUT_MS);\n this.maxStreams = Math.max(1, options.maxStreams ?? DEFAULT_MAX_STREAMS);\n this.maxStreamsPerProxy = Math.max(\n 1,\n options.maxStreamsPerProxy ?? DEFAULT_MAX_STREAMS_PER_PROXY,\n );\n this.maxStreamsPerClient = Math.max(\n 1,\n options.maxStreamsPerClient ?? DEFAULT_MAX_STREAMS_PER_CLIENT,\n );\n this.maxStreamsPerPreview = Math.max(\n 1,\n options.maxStreamsPerPreview ?? DEFAULT_MAX_STREAMS_PER_PREVIEW,\n );\n this.maxInputsPerSecond = Math.max(\n 1,\n options.maxInputsPerSecond ?? DEFAULT_MAX_INPUTS_PER_SECOND,\n );\n this.maxOutstandingInputsPerLease = Math.max(\n 1,\n options.maxOutstandingInputsPerLease ?? DEFAULT_MAX_OUTSTANDING_INPUTS_PER_LEASE,\n );\n this.now = options.now ?? Date.now;\n this.tokenFactory = options.tokenFactory ?? (() => nanoid(32));\n this.idFactory = options.idFactory ?? (() => nanoid(21));\n }\n\n /** Called for every successful main `/proxy` registration; returns a per-connection nonce. */\n registerProxyConnection(proxyId: string, proxyWs: WebSocket): string {\n this.clearProxyRuntime(proxyId, \"proxy_offline\", false);\n const connectionId = this.idFactory();\n this.proxyConnections.set(proxyId, { proxyWs, connectionId });\n return connectionId;\n }\n\n handleStreamTransportConnection(ws: WebSocket): void {\n const transportWs = ws as StreamTransportSocket;\n transportWs.isAlive = true;\n let registered: StreamTransport | null = null;\n const registerTimer = setTimeout(() => {\n if (!registered && transportWs.readyState === WebSocket.OPEN) {\n transportWs.close(\n RelayCloseCode.DEVICE_STREAM_PROTOCOL_REJECTED,\n \"device stream registration timeout\",\n );\n }\n }, this.registerTimeoutMs);\n registerTimer.unref?.();\n\n transportWs.on(\"pong\", () => {\n transportWs.isAlive = true;\n });\n transportWs.on(\"message\", (data: Buffer, isBinary: boolean) => {\n if (!registered) {\n if (isBinary || data.length > 8 * 1024) {\n this.rejectTransport(transportWs, \"device stream must register before sending frames\");\n return;\n }\n let raw: unknown;\n try {\n raw = JSON.parse(data.toString());\n } catch {\n this.rejectTransport(transportWs, \"invalid device stream registration JSON\");\n return;\n }\n const parsed = DevicePreviewStreamRegisterSchema.safeParse(raw);\n if (!parsed.success) {\n this.rejectTransport(transportWs, \"invalid device stream registration\");\n return;\n }\n const current = this.proxyConnections.get(parsed.data.proxyId);\n if (\n !current ||\n current.connectionId !== parsed.data.connectionId ||\n current.proxyWs !== this.options.registry.getProxy(parsed.data.proxyId) ||\n current.proxyWs.readyState !== WebSocket.OPEN\n ) {\n transportWs.send(\n JSON.stringify({\n type: \"device_preview_stream_register_response\",\n success: false,\n error: \"stale or unknown Proxy connection\",\n }),\n );\n transportWs.close(\n RelayCloseCode.DEVICE_STREAM_BINDING_REJECTED,\n \"device stream binding rejected\",\n );\n return;\n }\n const prior = this.transports.get(parsed.data.proxyId);\n if (prior && prior.ws !== transportWs) {\n // A second transport for the same main Proxy generation supersedes the first one. Stop\n // its viewers through the still-live control socket before dropping the data socket, so\n // Proxy capture jobs cannot survive with nowhere valid to publish.\n this.failStreamsForTransport(prior, \"设备画面连接已被替换\");\n this.transports.delete(parsed.data.proxyId);\n prior.ws.terminate();\n }\n registered = {\n ws: transportWs,\n proxyId: parsed.data.proxyId,\n connectionId: parsed.data.connectionId,\n };\n transportWs.devicePreviewProxyId = parsed.data.proxyId;\n transportWs.devicePreviewConnectionId = parsed.data.connectionId;\n this.transports.set(parsed.data.proxyId, registered);\n clearTimeout(registerTimer);\n transportWs.send(\n JSON.stringify({ type: \"device_preview_stream_register_response\", success: true }),\n );\n this.options.logger.info(\n { proxyId: parsed.data.proxyId },\n \"Device preview stream transport registered\",\n );\n return;\n }\n\n if (!isBinary) {\n this.rejectTransport(transportWs, \"unexpected device stream transport message\");\n return;\n }\n if (data.length > DEVICE_PREVIEW_FRAME_MAX_BYTES + 512) {\n this.options.logger.warn(\n { proxyId: registered.proxyId, bytes: data.length },\n \"Oversized device preview frame dropped\",\n );\n return;\n }\n const h264Packet =\n data[0] === DEVICE_PREVIEW_H264_PACKET_SENTINEL\n ? decodeDevicePreviewH264ProxyPacket(data)\n : null;\n if (h264Packet) {\n this.handleH264Packet(registered, h264Packet.streamId, h264Packet);\n return;\n }\n const frame = decodeDevicePreviewFrame(data);\n if (!frame) {\n this.options.logger.warn(\n { proxyId: registered.proxyId, bytes: data.length },\n \"Malformed device preview frame dropped\",\n );\n return;\n }\n this.handleFrame(registered, frame.streamId, frame.frameSequence, frame.jpeg);\n });\n\n transportWs.on(\"close\", () => {\n clearTimeout(registerTimer);\n if (!registered || this.transports.get(registered.proxyId)?.ws !== transportWs) return;\n this.transports.delete(registered.proxyId);\n this.failStreamsForTransport(registered, \"设备画面连接已断开\");\n this.options.logger.info(\n { proxyId: registered.proxyId },\n \"Device preview stream transport disconnected\",\n );\n });\n transportWs.on(\"error\", (error) => {\n this.options.logger.warn(\n { proxyId: registered?.proxyId, error: errorText(error) },\n \"Device preview stream transport error\",\n );\n });\n }\n\n handleClientControl(clientWs: WebSocket, message: RelayControlMessage): boolean {\n const socket = clientWs as ClientSocket;\n if (isDevicePreviewRequestMessage(message)) {\n this.forwardManagementRequest(socket, message);\n return true;\n }\n switch (message.type) {\n case \"device_preview_stream_url_request\":\n this.issueStreamUrl(socket, message);\n return true;\n case \"device_preview_input\":\n this.forwardInput(socket, message);\n return true;\n case \"device_preview_control_claim_request\":\n this.claimControl(socket, message);\n return true;\n default:\n return false;\n }\n }\n\n handleProxyControl(\n proxyId: string,\n proxyWs: WebSocket,\n message: RelayControlMessage,\n raw: string,\n ): boolean {\n if (!this.isCurrentProxyConnection(proxyId, proxyWs)) return this.isDeviceMessage(message);\n if (isDevicePreviewResponseMessage(message)) {\n this.resolveManagementResponse(proxyId, proxyWs, message, raw);\n return true;\n }\n switch (message.type) {\n case \"device_preview_stream_start_response\":\n this.handleStreamStartResponse(proxyId, message);\n return true;\n case \"device_preview_stream_complete\":\n this.handleStreamComplete(proxyId, message);\n return true;\n case \"device_preview_input_ack\":\n this.handleInputAck(proxyId, message, raw);\n return true;\n default:\n // Every device_preview_* message has an explicit Relay-owned route. Never let an\n // unexpected or locally-generated variant fall through to generic Proxy broadcasting.\n return this.isDeviceMessage(message);\n }\n }\n\n handlePreviewRemovedEvent(proxyId: string, proxyWs: WebSocket, previewId: string): void {\n if (!this.isCurrentProxyConnection(proxyId, proxyWs)) return;\n this.stopPreviewStreams(proxyId, previewId, \"preview_closed\");\n }\n\n handleHttpRequest(req: Request, res: Response): void {\n // Tokens and their validity are private, short-lived state; never let an intermediary cache\n // either successful streams or authentication/expiry responses.\n res.setHeader(\"Cache-Control\", \"no-store\");\n res.setHeader(\"Referrer-Policy\", \"no-referrer\");\n if (\n this.options.clientTokenRequired &&\n !this.options.validateClientToken?.(bearerToken(req.get(\"authorization\")))\n ) {\n res.status(401).json({ error: \"invalid_client_token\" });\n return;\n }\n\n const tokenValue = req.params.token;\n const token = typeof tokenValue === \"string\" ? this.tokens.get(tokenValue) : undefined;\n if (!token || token.expiresAt <= this.now()) {\n if (token) this.expireToken(token);\n res.status(404).json({ error: \"device_preview_stream_url_expired\" });\n return;\n }\n\n // Single-use is atomic: remove the bearer before any Proxy lookup or asynchronous operation.\n this.tokens.delete(token.token);\n clearTimeout(token.timer);\n const lease = this.leases.get(token.leaseId);\n if (!lease || lease.token !== token.token || !this.clientLeaseStillValid(lease)) {\n if (lease) this.releaseLease(lease, \"lease_expired\", true);\n res.status(410).json({ error: \"device_preview_stream_lease_expired\" });\n return;\n }\n lease.token = undefined;\n\n const transport = this.transports.get(lease.proxyId);\n const connection = this.proxyConnections.get(lease.proxyId);\n if (\n !transport ||\n transport.ws.readyState !== WebSocket.OPEN ||\n !connection ||\n connection.proxyWs !== lease.proxyWs ||\n transport.connectionId !== connection.connectionId\n ) {\n this.releaseLease(lease, \"proxy_offline\", true);\n res.status(502).json({ error: \"device_preview_stream_transport_offline\" });\n return;\n }\n\n let streamId: string;\n try {\n streamId = this.allocateUniqueRuntimeId(this.streams, \"stream\");\n } catch (error) {\n this.options.logger.error(\n { proxyId: lease.proxyId, previewId: lease.previewId, error: errorText(error) },\n \"Could not allocate Device Preview stream ID\",\n );\n this.releaseLease(lease, \"stream_closed\", true);\n res.status(503).json({ error: \"device_preview_stream_id_unavailable\" });\n return;\n }\n const startTimer = setTimeout(() => {\n this.failStream(streamId, 504, \"等待设备画面超时\", \"stream_error\");\n }, this.startTimeoutMs);\n startTimer.unref?.();\n const stream: ActiveStream = {\n streamId,\n lease,\n transport,\n res,\n state: \"starting\",\n startTimer,\n firstFrameTimer: null,\n headersSent: false,\n finished: false,\n paused: false,\n requestedFormat: token.profile.format,\n h264SyncState: \"awaiting_configuration\",\n h264DroppedWhilePaused: false,\n lastFrameSequence: null,\n };\n lease.streamId = streamId;\n this.streams.set(streamId, stream);\n\n res.on(\"close\", () => {\n if (stream.finished) return;\n this.finishStream(stream, \"client_closed\", true, \"设备画面连接已关闭\");\n });\n\n const profile = token.profile;\n const startMessage = serializeControl({\n type: \"device_preview_stream_start\",\n streamId,\n leaseId: lease.leaseId,\n previewId: lease.previewId,\n format: profile.format,\n ...(profile.format === \"jpeg\" && profile.maxFps !== undefined\n ? { maxFps: profile.maxFps }\n : {}),\n });\n try {\n lease.proxyWs.send(startMessage, (error) => {\n if (error) this.failStream(streamId, 502, \"无法向开发机启动设备画面\");\n });\n } catch (error) {\n this.failStream(streamId, 502, errorText(error));\n return;\n }\n this.options.logger.info(\n { streamId, proxyId: lease.proxyId, previewId: lease.previewId },\n \"Device preview HTTP stream requested\",\n );\n }\n\n abandonClientSocket(clientWs: WebSocket): void {\n this.routes.abandonSocket(clientWs);\n for (const lease of [...this.leases.values()]) {\n if (lease.clientWs !== clientWs) continue;\n const stream = lease.streamId ? this.streams.get(lease.streamId) : undefined;\n if (stream) this.finishStream(stream, \"client_closed\", true, \"客户端已断开\");\n else this.releaseLease(lease, \"lease_expired\", false);\n }\n }\n\n clearProxy(proxyId: string): void {\n this.clearProxyRuntime(proxyId, \"proxy_offline\", true);\n this.proxyConnections.delete(proxyId);\n }\n\n revokeProxy(proxyId: string): void {\n this.clearProxy(proxyId);\n }\n\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n this.routes.dispose();\n for (const stream of [...this.streams.values()]) {\n this.finishStream(stream, \"relay_shutdown\", true, \"Relay 正在停止\");\n }\n for (const token of [...this.tokens.values()]) this.expireToken(token);\n for (const transport of this.transports.values()) transport.ws.terminate();\n this.transports.clear();\n this.proxyConnections.clear();\n }\n\n private forwardManagementRequest(\n clientWs: ClientSocket,\n message: DevicePreviewRequestMessage,\n ): void {\n if (!clientWs.clientId) {\n if (\n !this.sendManagementFailure(\n clientWs,\n message,\n \"客户端未注册\",\n ControlErrorCode.PROXY_OFFLINE,\n )\n ) {\n this.sendRelayError(clientWs, message.requestId, \"NOT_REGISTERED\", \"客户端未注册\");\n }\n return;\n }\n const proxyId = clientWs.boundProxyId;\n if (!proxyId) {\n if (\n !this.sendManagementFailure(\n clientWs,\n message,\n \"当前未连接开发机\",\n ControlErrorCode.PROXY_OFFLINE,\n )\n ) {\n this.sendRelayError(clientWs, message.requestId, \"NOT_BOUND\", \"当前未连接开发机\");\n }\n return;\n }\n const proxyWs = this.options.registry.getProxy(proxyId);\n if (!proxyWs || proxyWs.readyState !== WebSocket.OPEN) {\n if (\n !this.sendManagementFailure(\n clientWs,\n message,\n \"当前开发机不在线\",\n ControlErrorCode.PROXY_OFFLINE,\n )\n ) {\n this.sendRelayError(clientWs, message.requestId, \"PROXY_OFFLINE\", \"当前开发机不在线\");\n }\n return;\n }\n let registration: ReturnType<DevicePreviewRouteRegistry[\"register\"]>;\n try {\n registration = this.routes.register(\n proxyId,\n message.requestId,\n devicePreviewResponseByRequest[message.type],\n clientWs,\n proxyWs,\n );\n } catch (error) {\n this.options.logger.error(\n { proxyId, type: message.type, error: errorText(error) },\n \"Could not allocate Device Preview management route\",\n );\n if (\n !this.sendManagementFailure(\n clientWs,\n message,\n \"暂时无法处理设备预览请求\",\n ControlErrorCode.UNKNOWN,\n )\n ) {\n this.sendRelayError(\n clientWs,\n message.requestId,\n \"INVALID_MESSAGE\",\n \"暂时无法处理设备预览请求\",\n );\n }\n return;\n }\n if (registration.kind !== \"registered\") {\n const error =\n registration.kind === \"client_capacity_exceeded\"\n ? \"当前客户端有过多待处理的设备预览请求\"\n : \"设备预览请求过多\";\n if (!this.sendManagementFailure(clientWs, message, error, ControlErrorCode.RATE_LIMITED)) {\n this.sendRelayError(clientWs, message.requestId, \"INVALID_MESSAGE\", error);\n }\n return;\n }\n const upstream = {\n ...message,\n requestId: registration.upstreamRequestId,\n } as DevicePreviewRequestMessage;\n const requestRouteStillCurrent = (): boolean =>\n clientWs.readyState === WebSocket.OPEN &&\n proxyWs.readyState === WebSocket.OPEN &&\n this.options.registry.getProxy(proxyId) === proxyWs &&\n this.options.registry.isCurrentClientBinding(clientWs.clientId, clientWs, message.scope);\n this.sendProxy(proxyWs, serializeControl(upstream), message.type, requestRouteStillCurrent);\n }\n\n private sendManagementFailure(\n clientWs: ClientSocket,\n message: DevicePreviewRequestMessage,\n error: string,\n errorCode: ControlErrorCodeType,\n ): boolean {\n switch (message.type) {\n case \"device_preview_capability_request\":\n this.sendClient(\n clientWs,\n serializeControl({\n type: \"device_preview_capability_response\",\n requestId: message.requestId,\n scope: message.scope,\n success: false,\n error,\n errorCode,\n }),\n \"device_preview_capability_response\",\n );\n return true;\n case \"device_preview_targets_request\":\n this.sendClient(\n clientWs,\n serializeControl({\n type: \"device_preview_targets_response\",\n requestId: message.requestId,\n scope: message.scope,\n success: false,\n error,\n errorCode,\n }),\n \"device_preview_targets_response\",\n );\n return true;\n case \"device_preview_create_request\":\n this.sendClient(\n clientWs,\n serializeControl({\n type: \"device_preview_create_response\",\n requestId: message.requestId,\n scope: message.scope,\n operationId: message.operationId,\n accepted: false,\n error,\n errorCode,\n }),\n \"device_preview_create_response\",\n );\n return true;\n case \"device_preview_rename_request\":\n this.sendClient(\n clientWs,\n serializeControl({\n type: \"device_preview_rename_response\",\n requestId: message.requestId,\n scope: message.scope,\n operationId: message.operationId,\n previewId: message.previewId,\n success: false,\n error,\n errorCode,\n }),\n \"device_preview_rename_response\",\n );\n return true;\n case \"device_preview_reconnect_request\":\n this.sendClient(\n clientWs,\n serializeControl({\n type: \"device_preview_reconnect_response\",\n requestId: message.requestId,\n scope: message.scope,\n operationId: message.operationId,\n previewId: message.previewId,\n success: false,\n error,\n errorCode,\n }),\n \"device_preview_reconnect_response\",\n );\n return true;\n case \"device_preview_close_request\":\n this.sendClient(\n clientWs,\n serializeControl({\n type: \"device_preview_close_response\",\n requestId: message.requestId,\n scope: message.scope,\n operationId: message.operationId,\n previewId: message.previewId,\n success: false,\n error,\n errorCode,\n }),\n \"device_preview_close_response\",\n );\n return true;\n case \"device_preview_list_request\":\n return false;\n }\n }\n\n private resolveManagementResponse(\n proxyId: string,\n proxyWs: WebSocket,\n message: DevicePreviewResponseMessage,\n raw: string,\n ): void {\n if (message.type === \"device_preview_close_response\" && message.success) {\n // The current Proxy's authoritative resource cleanup applies even if the requesting\n // browser disconnected and its exact response route has become a tombstone.\n this.stopPreviewStreams(proxyId, message.previewId, \"preview_closed\");\n }\n const route = this.routes.resolve(proxyId, message.requestId, message.type, proxyWs);\n if (route.kind !== \"matched\") {\n this.options.logger.debug(\n { proxyId, requestId: message.requestId, type: message.type, route: route.kind },\n \"Unmatched Device Preview response dropped\",\n );\n return;\n }\n const isCurrentRoute = (): boolean =>\n this.isCurrentProxyConnection(proxyId, proxyWs) &&\n this.options.registry.isCurrentClientBinding(route.clientId, route.clientWs, route.scope);\n if (route.clientWs.readyState !== WebSocket.OPEN || !isCurrentRoute()) return;\n const response = rewriteForwardedControl(raw, {\n type: message.type,\n requestId: route.clientRequestId,\n scope: route.scope,\n });\n this.sendClient(route.clientWs, response, message.type, isCurrentRoute);\n }\n\n private issueStreamUrl(\n clientWs: ClientSocket,\n message: ControlMessage<\"device_preview_stream_url_request\">,\n ): void {\n const requestBindingStillCurrent = (): boolean =>\n this.options.registry.isCurrentClientBinding(clientWs.clientId, clientWs, message.scope);\n const failure = (\n error: string,\n errorCode: ControlErrorCodeType = ControlErrorCode.UNKNOWN,\n ): void => {\n this.sendClient(\n clientWs,\n serializeControl({\n type: \"device_preview_stream_url_response\",\n requestId: message.requestId,\n scope: message.scope,\n previewId: message.previewId,\n success: false,\n error,\n errorCode,\n }),\n \"device_preview_stream_url_response\",\n requestBindingStillCurrent,\n );\n };\n if (!clientWs.clientId) {\n failure(\"客户端未注册\", ControlErrorCode.CONTROL_LEASE_INVALID);\n return;\n }\n const proxyId = clientWs.boundProxyId;\n const proxyWs = proxyId ? this.options.registry.getProxy(proxyId) : undefined;\n if (!proxyId || !proxyWs || proxyWs.readyState !== WebSocket.OPEN) {\n failure(\"当前开发机不在线\", ControlErrorCode.PROXY_OFFLINE);\n return;\n }\n const connection = this.proxyConnections.get(proxyId);\n const transport = this.transports.get(proxyId);\n if (\n !connection ||\n connection.proxyWs !== proxyWs ||\n !transport ||\n transport.connectionId !== connection.connectionId ||\n transport.ws.readyState !== WebSocket.OPEN\n ) {\n failure(\"设备画面连接尚未就绪\", ControlErrorCode.PROCESS_START_FAILED);\n return;\n }\n this.cleanupExpiredTokens();\n // A component may unmount after requesting a URL but before receiving/consuming it. A retry\n // for the same browser socket and preview supersedes only that unconsumed token; active HTTP\n // streams are deliberately untouched.\n for (const oldLease of [...this.leases.values()]) {\n if (\n oldLease.clientWs === clientWs &&\n oldLease.proxyId === proxyId &&\n oldLease.previewId === message.previewId &&\n oldLease.token !== undefined &&\n oldLease.streamId === undefined\n ) {\n this.releaseLease(oldLease, \"lease_expired\", false);\n }\n }\n if (!this.hasLeaseCapacity(clientWs.clientId, proxyId, message.previewId)) {\n failure(\"同时打开的设备画面过多\", ControlErrorCode.STREAM_CAPACITY_EXCEEDED);\n return;\n }\n\n let leaseId: string;\n let tokenValue: string;\n try {\n leaseId = this.allocateUniqueRuntimeId(this.leases, \"lease\");\n tokenValue = this.allocateUniqueToken();\n } catch (error) {\n this.options.logger.error(\n { proxyId, previewId: message.previewId, error: errorText(error) },\n \"Could not allocate Device Preview stream token\",\n );\n failure(\"暂时无法创建设备画面链接\");\n return;\n }\n const key = previewKey(proxyId, message.previewId);\n const controller = !this.controllerByPreview.has(key);\n const lease: ControlLease = {\n leaseId,\n clientId: clientWs.clientId,\n clientWs,\n proxyId,\n bindingId: message.scope.bindingId,\n proxyWs,\n previewId: message.previewId,\n controller,\n lastInputSeq: -1,\n rateWindowStartedAt: this.now(),\n inputCount: 0,\n outstandingInputSeqs: new Set(),\n };\n if (controller) this.controllerByPreview.set(key, leaseId);\n const expiresAt = this.now() + this.tokenTtlMs;\n const timer = setTimeout(() => {\n const token = this.tokens.get(tokenValue);\n if (token) this.expireToken(token);\n }, this.tokenTtlMs);\n timer.unref?.();\n const token: StreamToken = {\n token: tokenValue,\n leaseId,\n profile: message.profile,\n expiresAt,\n timer,\n };\n lease.token = tokenValue;\n this.leases.set(leaseId, lease);\n this.tokens.set(tokenValue, token);\n this.sendClient(\n clientWs,\n serializeControl({\n type: \"device_preview_stream_url_response\",\n requestId: message.requestId,\n scope: message.scope,\n previewId: message.previewId,\n success: true,\n url: `/api/device-preview-streams/${tokenValue}`,\n leaseId,\n expiresAt,\n controlMode: controller ? \"controller\" : \"view_only\",\n }),\n \"device_preview_stream_url_response\",\n () => this.leases.get(lease.leaseId) === lease && this.clientLeaseStillValid(lease),\n );\n }\n\n private forwardInput(\n clientWs: ClientSocket,\n message: ControlMessage<\"device_preview_input\">,\n ): void {\n const requestBindingStillCurrent = (): boolean =>\n this.options.registry.isCurrentClientBinding(clientWs.clientId, clientWs, message.scope);\n const lease = this.leases.get(message.leaseId);\n const reject = (\n error: string,\n errorCode: ControlErrorCodeType = ControlErrorCode.CONTROL_LEASE_INVALID,\n ): void => {\n this.sendClient(\n clientWs,\n serializeControl({\n type: \"device_preview_input_ack\",\n scope: message.scope,\n leaseId: message.leaseId,\n inputSeq: message.inputSeq,\n success: false,\n error,\n errorCode,\n }),\n \"device_preview_input_ack\",\n requestBindingStillCurrent,\n );\n };\n const inputStillAuthorized = (): boolean => {\n if (!lease) return false;\n const streamId = lease.streamId;\n return (\n message.scope.proxyId === lease.proxyId &&\n message.scope.bindingId === lease.bindingId &&\n lease.clientWs === clientWs &&\n this.leases.get(lease.leaseId) === lease &&\n lease.controller &&\n streamId !== undefined &&\n this.streams.get(streamId)?.lease === lease &&\n lease.outstandingInputSeqs.has(message.inputSeq) &&\n this.clientLeaseStillValid(lease)\n );\n };\n if (\n !lease ||\n lease.clientWs !== clientWs ||\n !lease.controller ||\n !lease.streamId ||\n this.streams.get(lease.streamId)?.lease !== lease ||\n !this.clientLeaseStillValid(lease)\n ) {\n reject(\"设备控制权已失效\");\n return;\n }\n if (message.inputSeq <= lease.lastInputSeq) {\n reject(\"设备输入序号已过期\");\n return;\n }\n if (lease.outstandingInputSeqs.size >= this.maxOutstandingInputsPerLease) {\n reject(\"设备输入队列已满\", ControlErrorCode.RATE_LIMITED);\n return;\n }\n const now = this.now();\n if (now - lease.rateWindowStartedAt >= 1_000) {\n lease.rateWindowStartedAt = now;\n lease.inputCount = 0;\n }\n if (lease.inputCount >= this.maxInputsPerSecond) {\n reject(\"设备输入过于频繁\", ControlErrorCode.RATE_LIMITED);\n return;\n }\n lease.inputCount += 1;\n lease.lastInputSeq = message.inputSeq;\n lease.outstandingInputSeqs.add(message.inputSeq);\n this.sendProxy(lease.proxyWs, serializeControl(message), message.type, inputStillAuthorized);\n }\n\n private claimControl(\n clientWs: ClientSocket,\n message: ControlMessage<\"device_preview_control_claim_request\">,\n ): void {\n const requestBindingStillCurrent = (): boolean =>\n this.options.registry.isCurrentClientBinding(clientWs.clientId, clientWs, message.scope);\n const lease = this.leases.get(message.leaseId);\n if (\n !lease ||\n lease.clientWs !== clientWs ||\n !lease.streamId ||\n !this.streams.has(lease.streamId) ||\n !this.clientLeaseStillValid(lease)\n ) {\n this.sendClient(\n clientWs,\n serializeControl({\n type: \"device_preview_control_claim_response\",\n requestId: message.requestId,\n scope: message.scope,\n leaseId: message.leaseId,\n success: false,\n error: \"设备画面已失效\",\n errorCode: ControlErrorCode.CONTROL_LEASE_INVALID,\n }),\n \"device_preview_control_claim_response\",\n requestBindingStillCurrent,\n );\n return;\n }\n\n const key = previewKey(lease.proxyId, lease.previewId);\n const oldControllerId = this.controllerByPreview.get(key);\n if (oldControllerId && oldControllerId !== lease.leaseId) {\n const old = this.leases.get(oldControllerId);\n if (old) {\n const revokeSent = this.sendProxyInternal(\n old.proxyWs,\n serializeControl({\n type: \"device_preview_input_revoke\",\n leaseId: old.leaseId,\n reason: \"control_taken_over\",\n }),\n );\n if (!revokeSent) {\n this.sendClient(\n clientWs,\n serializeControl({\n type: \"device_preview_control_claim_response\",\n requestId: message.requestId,\n scope: message.scope,\n leaseId: message.leaseId,\n success: false,\n error: \"开发机连接已断开\",\n errorCode: ControlErrorCode.PROXY_OFFLINE,\n }),\n \"device_preview_control_claim_response\",\n requestBindingStillCurrent,\n );\n return;\n }\n old.controller = false;\n old.rateWindowStartedAt = this.now();\n old.inputCount = 0;\n for (const inputSeq of old.outstandingInputSeqs) {\n this.sendClient(\n old.clientWs,\n serializeControl({\n type: \"device_preview_input_ack\",\n scope: { proxyId: old.proxyId, bindingId: old.bindingId },\n leaseId: old.leaseId,\n inputSeq,\n success: false,\n error: \"设备控制权已被其他客户端接管\",\n errorCode: ControlErrorCode.CONTROL_LEASE_INVALID,\n }),\n \"device_preview_input_ack\",\n () =>\n this.leases.get(old.leaseId) === old &&\n !old.controller &&\n this.clientBindingStillMatches(old),\n );\n }\n old.outstandingInputSeqs.clear();\n this.sendControlRevoked(old, \"taken_over\");\n }\n }\n lease.controller = true;\n this.controllerByPreview.set(key, lease.leaseId);\n this.sendClient(\n clientWs,\n serializeControl({\n type: \"device_preview_control_claim_response\",\n requestId: message.requestId,\n scope: message.scope,\n leaseId: lease.leaseId,\n success: true,\n controlMode: \"controller\",\n }),\n \"device_preview_control_claim_response\",\n () =>\n this.leases.get(lease.leaseId) === lease &&\n lease.controller &&\n this.clientLeaseStillValid(lease),\n );\n }\n\n private handleStreamStartResponse(\n proxyId: string,\n message: ControlMessage<\"device_preview_stream_start_response\">,\n ): void {\n const stream = this.streams.get(message.streamId);\n if (\n !stream ||\n stream.lease.proxyId !== proxyId ||\n stream.lease.leaseId !== message.leaseId ||\n stream.lease.previewId !== message.previewId\n ) {\n return;\n }\n clearTimeout(stream.startTimer);\n if (!message.success) {\n this.options.logger.warn(\n { streamId: stream.streamId, proxyId, error: message.error },\n \"Device preview stream failed to start\",\n );\n this.failStream(stream.streamId, streamErrorStatus(message.errorCode), message.error);\n return;\n }\n const format = message.format;\n if (stream.requestedFormat !== format) {\n this.failStream(stream.streamId, 502, \"开发机返回了错误的设备画面格式\", \"stream_error\");\n return;\n }\n stream.format = format;\n try {\n stream.res.status(200);\n stream.res.setHeader(\"Content-Type\", STREAM_CONTENT_TYPE);\n stream.res.setHeader(\"Cache-Control\", \"no-store, no-cache, must-revalidate\");\n stream.res.setHeader(\"Cross-Origin-Resource-Policy\", \"same-origin\");\n stream.res.setHeader(\"X-Content-Type-Options\", \"nosniff\");\n stream.res.setHeader(\"X-Accel-Buffering\", \"no\");\n stream.res.setHeader(\"X-Device-Preview-Format\", format);\n if (message.width !== undefined)\n stream.res.setHeader(\"X-Device-Width\", String(message.width));\n if (message.height !== undefined)\n stream.res.setHeader(\"X-Device-Height\", String(message.height));\n stream.res.flushHeaders();\n stream.headersSent = true;\n stream.state = \"streaming\";\n // Both backends are allowed to be change-driven: a static simulator can legitimately emit\n // nothing after its first renderable image. This deadline proves startup only. Ongoing\n // liveness comes from the Proxy stream WebSocket heartbeat and explicit capture completion,\n // not from visual changes on the device.\n this.armFirstFrameTimer(stream);\n const bufferedFrame = stream.bufferedStartingFrame;\n stream.bufferedStartingFrame = undefined;\n const bufferedH264 = stream.bufferedStartingH264;\n stream.bufferedStartingH264 = undefined;\n if (format === \"h264_annex_b\" && bufferedH264) {\n for (const packet of bufferedH264.packets) this.writeH264Packet(stream, packet);\n } else if (format === \"jpeg\" && bufferedFrame) {\n this.writeFrame(stream, bufferedFrame.sequence, bufferedFrame.jpeg);\n }\n } catch (error) {\n this.failStream(stream.streamId, 500, errorText(error), \"stream_error\");\n }\n }\n\n private handleStreamComplete(\n proxyId: string,\n message: ControlMessage<\"device_preview_stream_complete\">,\n ): void {\n const stream = this.streams.get(message.streamId);\n if (\n !stream ||\n stream.lease.proxyId !== proxyId ||\n stream.lease.leaseId !== message.leaseId ||\n stream.lease.previewId !== message.previewId\n ) {\n return;\n }\n this.options.logger.warn(\n { streamId: stream.streamId, proxyId, error: message.error },\n \"Device preview stream capture failed\",\n );\n this.failStream(stream.streamId, 502, message.error);\n }\n\n private handleInputAck(\n proxyId: string,\n message: ControlMessage<\"device_preview_input_ack\">,\n raw: string,\n ): void {\n const lease = this.leases.get(message.leaseId);\n if (\n !lease ||\n lease.proxyId !== proxyId ||\n !lease.outstandingInputSeqs.delete(message.inputSeq) ||\n lease.clientWs.readyState !== WebSocket.OPEN\n ) {\n return;\n }\n const response = rewriteForwardedControl(raw, {\n type: message.type,\n scope: { proxyId: lease.proxyId, bindingId: lease.bindingId },\n });\n this.sendClient(lease.clientWs, response, message.type, () => {\n return (\n this.leases.get(lease.leaseId) === lease &&\n lease.controller &&\n this.clientLeaseStillValid(lease)\n );\n });\n }\n\n private handleFrame(\n transport: StreamTransport,\n streamId: string,\n sequence: number,\n jpeg: Uint8Array,\n ): void {\n const stream = this.streams.get(streamId);\n if (\n !stream ||\n stream.finished ||\n stream.transport !== transport ||\n stream.lease.proxyId !== transport.proxyId\n ) {\n return;\n }\n if (stream.requestedFormat !== \"jpeg\") return;\n if (stream.state === \"streaming\" && stream.format !== undefined && stream.format !== \"jpeg\") {\n this.failStream(streamId, 502, \"开发机发送了错误的设备画面格式\", \"stream_error\");\n return;\n }\n if (stream.lastFrameSequence !== null && sequence <= stream.lastFrameSequence) return;\n stream.lastFrameSequence = sequence;\n if (stream.state === \"starting\") {\n // Proxy can synchronously publish a capture group's cached frame before its async start\n // response reaches Relay. Keep only the newest validated JPEG, scoped to this exact stream\n // transport, so a still device can render immediately once the HTTP response is established.\n stream.bufferedStartingFrame = { sequence, jpeg: Buffer.from(jpeg) };\n return;\n }\n this.writeFrame(stream, sequence, jpeg);\n }\n\n private handleH264Packet(\n transport: StreamTransport,\n streamId: string,\n packet: DevicePreviewH264Packet,\n ): void {\n const stream = this.streams.get(streamId);\n if (\n !stream ||\n stream.finished ||\n stream.transport !== transport ||\n stream.lease.proxyId !== transport.proxyId\n ) {\n return;\n }\n if (stream.requestedFormat !== \"h264_annex_b\") {\n return;\n }\n if (stream.state === \"streaming\" && stream.format !== \"h264_annex_b\") {\n this.failStream(streamId, 502, \"开发机发送了错误的设备画面格式\", \"stream_error\");\n return;\n }\n if (stream.lastFrameSequence !== null && packet.packetSequence <= stream.lastFrameSequence) {\n return;\n }\n stream.lastFrameSequence = packet.packetSequence;\n if (stream.state === \"starting\") {\n if (packet.configuration) {\n const configuration: BufferedStartingH264Packet = {\n ...packet,\n annexB: Buffer.from(packet.annexB),\n };\n stream.bufferedStartingH264 = {\n configuration,\n packets: [configuration],\n totalBytes: configuration.annexB.length,\n hasKeyframe: false,\n };\n return;\n }\n const buffered = stream.bufferedStartingH264;\n if (!buffered) return;\n if (packet.keyframe) {\n const keyframe: BufferedStartingH264Packet = {\n ...packet,\n annexB: Buffer.from(packet.annexB),\n };\n buffered.packets = [buffered.configuration, keyframe];\n buffered.totalBytes = buffered.configuration.annexB.length + keyframe.annexB.length;\n buffered.hasKeyframe = true;\n return;\n }\n if (!buffered.hasKeyframe) return;\n if (\n buffered.packets.length >= MAX_BUFFERED_STARTING_H264_PACKETS ||\n buffered.totalBytes + packet.annexB.length > MAX_BUFFERED_STARTING_H264_BYTES\n ) {\n buffered.packets = [buffered.configuration];\n buffered.totalBytes = buffered.configuration.annexB.length;\n buffered.hasKeyframe = false;\n this.requestH264Resync(stream);\n return;\n }\n const copy: BufferedStartingH264Packet = {\n ...packet,\n annexB: Buffer.from(packet.annexB),\n };\n buffered.packets.push(copy);\n buffered.totalBytes += copy.annexB.length;\n return;\n }\n this.writeH264Packet(stream, packet);\n }\n\n private writeFrame(stream: ActiveStream, sequence: number, jpeg: Uint8Array): void {\n if (stream.paused) return;\n\n const record = encodeDevicePreviewHttpFrame(sequence, jpeg);\n const writeResult = this.writeStreamRecord(stream, record);\n if (writeResult !== \"failed\") this.clearFirstFrameTimer(stream);\n }\n\n private writeH264Packet(stream: ActiveStream, packet: DevicePreviewH264Packet): void {\n if (stream.paused) {\n stream.h264DroppedWhilePaused = true;\n return;\n }\n if (stream.h264SyncState === \"awaiting_configuration\" && !packet.configuration) return;\n if (stream.h264SyncState === \"awaiting_keyframe\" && !packet.configuration && !packet.keyframe) {\n return;\n }\n const establishesSync =\n stream.h264SyncState === \"awaiting_keyframe\" && !packet.configuration && packet.keyframe;\n const record = encodeDevicePreviewH264HttpPacket(packet);\n const writeResult = this.writeStreamRecord(stream, record);\n if (writeResult === \"failed\" || stream.finished) return;\n\n if (packet.configuration) {\n stream.h264SyncState = \"awaiting_keyframe\";\n } else if (establishesSync) {\n stream.h264SyncState = \"synced\";\n this.clearFirstFrameTimer(stream);\n }\n }\n\n private writeStreamRecord(stream: ActiveStream, record: Uint8Array): StreamWriteResult {\n let writable: boolean;\n try {\n writable = stream.res.write(Buffer.from(record));\n } catch (error) {\n this.failStream(stream.streamId, 502, errorText(error), \"stream_error\");\n return \"failed\";\n }\n if (writable) return \"writable\";\n\n stream.paused = true;\n stream.h264DroppedWhilePaused = false;\n this.sendFlow(stream, true, false);\n const onDrain = (): void => {\n stream.drainListener = undefined;\n if (stream.drainTimer) clearTimeout(stream.drainTimer);\n stream.drainTimer = undefined;\n if (stream.finished || !stream.paused) return;\n stream.paused = false;\n const resyncRequired = stream.format === \"h264_annex_b\" && stream.h264DroppedWhilePaused;\n stream.h264DroppedWhilePaused = false;\n if (resyncRequired) {\n stream.h264SyncState = \"awaiting_configuration\";\n }\n this.sendFlow(stream, false, resyncRequired);\n };\n stream.drainListener = onDrain;\n stream.res.once(\"drain\", onDrain);\n stream.drainTimer = setTimeout(() => {\n stream.drainTimer = undefined;\n if (stream.finished || !stream.paused) return;\n this.failStream(stream.streamId, 504, \"设备画面发送超时\", \"stream_error\");\n }, this.drainTimeoutMs);\n stream.drainTimer.unref?.();\n return \"backpressured\";\n }\n\n private requestH264Resync(stream: ActiveStream): void {\n if (stream.finished || stream.transport.ws.readyState !== WebSocket.OPEN) return;\n // Reuse per-stream flow control to discard the Proxy viewer's stale GOP and request a fresh\n // configuration + keyframe pair without disturbing other viewers sharing the capture source.\n this.sendFlow(stream, true, false);\n this.sendFlow(stream, false, true);\n }\n\n private armFirstFrameTimer(stream: ActiveStream): void {\n if (stream.firstFrameTimer || stream.finished) return;\n stream.firstFrameTimer = setTimeout(() => {\n this.failStream(stream.streamId, 504, \"等待设备画面首帧超时\", \"stream_error\");\n }, this.firstFrameTimeoutMs);\n stream.firstFrameTimer.unref?.();\n }\n\n private clearFirstFrameTimer(stream: ActiveStream): void {\n if (!stream.firstFrameTimer) return;\n clearTimeout(stream.firstFrameTimer);\n stream.firstFrameTimer = null;\n }\n\n private sendFlow(stream: ActiveStream, paused: boolean, resyncRequired: boolean): void {\n if (stream.transport.ws.readyState !== WebSocket.OPEN) return;\n stream.transport.ws.send(\n JSON.stringify({\n type: \"device_preview_stream_flow\",\n streamId: stream.streamId,\n paused,\n resyncRequired,\n }),\n );\n }\n\n private failStream(\n streamId: string,\n status: number,\n error: string,\n stopReason?: DevicePreviewStreamStopReason,\n ): void {\n const stream = this.streams.get(streamId);\n if (!stream) return;\n if (!stream.headersSent) {\n this.markStreamFinished(stream, stopReason);\n stream.res.status(status).json({ error });\n this.releaseLease(stream.lease, \"stream_closed\", true);\n return;\n }\n this.markStreamFinished(stream, stopReason);\n stream.res.destroy(new Error(error));\n this.releaseLease(stream.lease, \"stream_closed\", true);\n }\n\n private finishStream(\n stream: ActiveStream,\n reason: DevicePreviewStreamStopReason,\n sendStop: boolean,\n error?: string,\n notifyLease = true,\n ): void {\n if (stream.finished) return;\n this.markStreamFinished(stream, sendStop ? reason : undefined);\n if (error) {\n if (!stream.headersSent) stream.res.status(502).json({ error });\n else stream.res.destroy(new Error(error));\n } else {\n stream.res.end();\n }\n this.releaseLease(\n stream.lease,\n reason === \"proxy_offline\" ? \"proxy_offline\" : \"stream_closed\",\n notifyLease,\n );\n }\n\n private markStreamFinished(\n stream: ActiveStream,\n stopReason?: DevicePreviewStreamStopReason,\n ): void {\n stream.finished = true;\n this.streams.delete(stream.streamId);\n stream.bufferedStartingFrame = undefined;\n stream.bufferedStartingH264 = undefined;\n clearTimeout(stream.startTimer);\n this.clearFirstFrameTimer(stream);\n if (stream.drainListener) stream.res.removeListener(\"drain\", stream.drainListener);\n if (stream.drainTimer) clearTimeout(stream.drainTimer);\n stream.drainListener = undefined;\n stream.drainTimer = undefined;\n if (stopReason && stream.lease.proxyWs.readyState === WebSocket.OPEN) {\n this.sendProxyInternal(\n stream.lease.proxyWs,\n serializeControl({\n type: \"device_preview_stream_stop\",\n streamId: stream.streamId,\n reason: stopReason,\n }),\n );\n }\n if (stream.lease.streamId === stream.streamId) stream.lease.streamId = undefined;\n }\n\n private stopPreviewStreams(\n proxyId: string,\n previewId: string,\n reason: DevicePreviewStreamStopReason,\n ): void {\n for (const stream of [...this.streams.values()]) {\n if (stream.lease.proxyId === proxyId && stream.lease.previewId === previewId) {\n this.finishStream(stream, reason, true, \"设备预览已关闭\");\n }\n }\n for (const lease of [...this.leases.values()]) {\n if (lease.proxyId === proxyId && lease.previewId === previewId && !lease.streamId) {\n this.releaseLease(lease, \"stream_closed\", true);\n }\n }\n }\n\n private failStreamsForTransport(transport: StreamTransport, error: string): void {\n for (const stream of [...this.streams.values()]) {\n if (stream.transport.ws === transport.ws) {\n this.failStream(stream.streamId, 502, error, \"stream_error\");\n }\n }\n }\n\n private releaseLease(\n lease: ControlLease,\n reason: \"stream_closed\" | \"proxy_offline\" | \"lease_expired\",\n notify: boolean,\n ): void {\n if (this.leases.get(lease.leaseId) !== lease) return;\n this.leases.delete(lease.leaseId);\n if (lease.token) {\n const token = this.tokens.get(lease.token);\n if (token) {\n clearTimeout(token.timer);\n this.tokens.delete(token.token);\n }\n lease.token = undefined;\n }\n const key = previewKey(lease.proxyId, lease.previewId);\n if (this.controllerByPreview.get(key) === lease.leaseId) {\n this.controllerByPreview.delete(key);\n if (notify) this.sendControlRevoked(lease, reason);\n }\n }\n\n private expireToken(token: StreamToken): void {\n if (this.tokens.get(token.token) !== token) return;\n this.tokens.delete(token.token);\n clearTimeout(token.timer);\n const lease = this.leases.get(token.leaseId);\n if (lease && !lease.streamId) this.releaseLease(lease, \"lease_expired\", true);\n }\n\n private cleanupExpiredTokens(): void {\n const now = this.now();\n for (const token of [...this.tokens.values()]) {\n if (token.expiresAt <= now) this.expireToken(token);\n }\n }\n\n private hasLeaseCapacity(clientId: string, proxyId: string, previewId: string): boolean {\n if (this.leases.size >= this.maxStreams) return false;\n let forClient = 0;\n let forProxy = 0;\n let forPreview = 0;\n for (const lease of this.leases.values()) {\n if (lease.clientId === clientId) forClient += 1;\n if (lease.proxyId === proxyId) forProxy += 1;\n if (lease.proxyId === proxyId && lease.previewId === previewId) forPreview += 1;\n }\n return (\n forClient < this.maxStreamsPerClient &&\n forProxy < this.maxStreamsPerProxy &&\n forPreview < this.maxStreamsPerPreview\n );\n }\n\n private clientBindingStillMatches(lease: ControlLease): boolean {\n const binding = this.options.registry.getClientBinding(lease.clientId);\n return (\n lease.clientWs.readyState === WebSocket.OPEN &&\n lease.clientWs.boundProxyId === lease.proxyId &&\n lease.clientWs.bindingId === lease.bindingId &&\n binding?.proxyId === lease.proxyId &&\n binding.bindingId === lease.bindingId &&\n binding.ws === lease.clientWs\n );\n }\n\n private clientLeaseStillValid(lease: ControlLease): boolean {\n const connection = this.proxyConnections.get(lease.proxyId);\n return (\n this.clientBindingStillMatches(lease) &&\n this.options.registry.getProxy(lease.proxyId) === lease.proxyWs &&\n connection?.proxyWs === lease.proxyWs\n );\n }\n\n private sendControlRevoked(\n lease: ControlLease,\n reason: \"taken_over\" | \"stream_closed\" | \"proxy_offline\" | \"lease_expired\",\n ): void {\n const isStillRelevant = (): boolean =>\n this.clientBindingStillMatches(lease) &&\n (reason !== \"taken_over\" || (this.leases.get(lease.leaseId) === lease && !lease.controller));\n if (!isStillRelevant()) return;\n this.sendClient(\n lease.clientWs,\n serializeControl({\n type: \"device_preview_control_revoked_push\",\n scope: { proxyId: lease.proxyId, bindingId: lease.bindingId },\n leaseId: lease.leaseId,\n reason,\n }),\n \"device_preview_control_revoked_push\",\n isStillRelevant,\n );\n }\n\n private allocateUniqueToken(): string {\n for (let attempt = 0; attempt < 16; attempt += 1) {\n const token = this.tokenFactory();\n if (!this.tokens.has(token)) return token;\n }\n throw new Error(\"Unable to allocate a unique Device Preview stream token\");\n }\n\n private allocateUniqueRuntimeId(\n values: ReadonlyMap<string, unknown>,\n kind: \"lease\" | \"stream\",\n ): string {\n for (let attempt = 0; attempt < 16; attempt += 1) {\n const id = this.idFactory();\n if (!values.has(id)) return id;\n }\n throw new Error(`Unable to allocate a unique Device Preview ${kind} ID`);\n }\n\n private clearProxyRuntime(proxyId: string, reason: \"proxy_offline\", notify: boolean): void {\n this.routes.clearProxy(proxyId);\n const transport = this.transports.get(proxyId);\n if (transport) {\n this.transports.delete(proxyId);\n transport.ws.terminate();\n }\n for (const stream of [...this.streams.values()]) {\n if (stream.lease.proxyId !== proxyId) continue;\n this.finishStream(stream, \"proxy_offline\", false, \"开发机已断开\", notify);\n }\n for (const lease of [...this.leases.values()]) {\n if (lease.proxyId === proxyId && !lease.streamId) this.releaseLease(lease, reason, notify);\n }\n }\n\n private isCurrentProxyConnection(proxyId: string, proxyWs: WebSocket): boolean {\n return (\n this.proxyConnections.get(proxyId)?.proxyWs === proxyWs &&\n this.options.registry.getProxy(proxyId) === proxyWs\n );\n }\n\n private isDeviceMessage(message: RelayControlMessage): boolean {\n return message.type.startsWith(\"device_preview_\");\n }\n\n private rejectTransport(ws: WebSocket, reason: string): void {\n if (ws.readyState === WebSocket.OPEN) {\n ws.close(RelayCloseCode.DEVICE_STREAM_PROTOCOL_REJECTED, reason.slice(0, 123));\n }\n }\n\n private sendClient(ws: WebSocket, raw: string, type: string, guard?: () => boolean): void {\n if (ws.readyState !== WebSocket.OPEN || (guard && !guard())) return;\n if (this.options.chaos) {\n this.options.chaos.send(ws, raw, {\n direction: \"proxy_to_client\",\n type,\n ...(guard ? { guard } : {}),\n });\n } else if (!guard || guard()) {\n ws.send(raw);\n }\n }\n\n private sendProxy(ws: WebSocket, raw: string, type: string, guard?: () => boolean): void {\n if (ws.readyState !== WebSocket.OPEN || (guard && !guard())) return;\n if (this.options.chaos) {\n this.options.chaos.send(ws, raw, {\n direction: \"client_to_proxy\",\n type,\n ...(guard ? { guard } : {}),\n });\n } else if (!guard || guard()) {\n ws.send(raw);\n }\n }\n\n /** Relay-owned lifecycle barriers bypass public chaos routing to preserve main-WS ordering. */\n private sendProxyInternal(ws: WebSocket, raw: string): boolean {\n if (ws.readyState !== WebSocket.OPEN) return false;\n try {\n ws.send(raw);\n return true;\n } catch (error) {\n this.options.logger.warn(\n { error: errorText(error) },\n \"Failed to send internal Device Preview control\",\n );\n return false;\n }\n }\n\n private sendRelayError(\n ws: WebSocket,\n requestId: string,\n code: \"NOT_REGISTERED\" | \"NOT_BOUND\" | \"PROXY_OFFLINE\" | \"INVALID_MESSAGE\",\n message: string,\n ): void {\n this.sendClient(\n ws,\n JSON.stringify({ type: \"relay_error\", requestId, code, message }),\n \"relay_error\",\n );\n }\n}\n"],"mappings":"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","names":["express","existsSync","dirname","fileURLToPath","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","WebSocket","WebSocket","WebSocket","WebSocket","nanoid","route","z","WebSocket","WebSocket","nanoid","WebSocket","WebSocket","nanoid","EventEmitter","nanoid","WebSocket","OPEN","defaultSocketFactory","WebSocket","EventEmitter","nanoid","resolve","requestTypes","responseTypes","broadcastProxyList","rejectNotRegistered","WebSocket","result","WebSocket","readFileSync","dirname","join","join","readFileSync","dirname","WebSocket","WebSocket","WebSocket","sendJson","parseJson","buildStats","statsLogFields","require","nanoid","WebSocket","WebSocket","nanoid","resolve","existsSync","join","DEFAULT_MAX_ENTRIES","DEFAULT_MAX_PENDING_PER_CLIENT","DEFAULT_PENDING_TTL_MS","DEFAULT_TOMBSTONE_TTL_MS","routeKey","nanoid","DEFAULT_MAX_ENTRIES","DEFAULT_MAX_PENDING_PER_CLIENT","DEFAULT_PENDING_TTL_MS","DEFAULT_TOMBSTONE_TTL_MS","routeKey","nanoid","WebSocket","bearerToken","nanoid","WebSocket","token","dirname","fileURLToPath","express","existsSync","resolve"]}