Skip to main content
直接通过 WebSocket 通道与一个 dev 会话对话。 控制桥接是 extension logs --follow 与动作类命令底下的那一层。只有当你要针对这个 socket 编写自己的 harness 时,才需要这个页面。除此之外,CLI 的命令才是受支持的接口。 dev 服务器把这个通道挂在 ready.json 公布的 controlPort 上的 /extjs-control 路径。客户端用信封版本 1 加一个角色来打招呼,角色为 producerconsumercontroller extension-develop 包会从它的 bridge-entry 模块导出本页涉及的每一个类型与常量,所以 harness 永远不必把这些线路字符串抄进自己的源码里。

LogEvent(版本 1)

每一帧一条日志记录,带 v: 1。broker 在接收时分配 seq,并把 runId 归一化为该会话 ready.json 中的值,这样这些行才能和契约对上。 已知时,可选的定位字段会一并附上:urlhostnametabIdframeIdwindowIdtitlestackerrorNamesourceExtensionIdincognito,以及一个自由形式的 data 对象。 dx.signal 事件是运行时针对 dev 循环自身发出的结构化诊断。请按它的 codestatus 分支处理,并把 remediation 呈现给用户。这个结构是先于它的生产者预留的:目前还没有任何发射方发布,所以今天流里的每个事件携带的都是 log

ReadyFrame 与 capabilities

握手成功后,服务端会回一个 ready 帧:
capabilities 告诉 controller 这个会话会接受什么:evalstoragereload、可打开的界面,以及用于深层 DOM 检查的 deepDomdeepDom 是一个桥接 capability 字段,不是 CLI flag。bufferedFrom 是仍可回放的最旧缓冲 seq

GapFrame

broker 宁可丢记录也不会卡住,而且它会明说。gap 帧会告诉你丢了多少条记录、以及为什么:
reasonring_overflowrate_limitdisk_slowslow_consumer 之一。

CommandFrame 与结果

controller 发命令时要带上 cmdId、一个 op 和一个目标上下文: 回应是一个结果帧,带有相同的 cmdIdok、可选的 value,以及在相关时出现的 truncateddurationMs。命令帧要求会话是以 --allow-control 启动的,而 eval 还额外要求 --allow-eval

拒绝码

当 guest 端拒绝一条命令时,结果帧的 error.code 会在浏览器自己那句话旁边带上一个机器名。请按码分支,永远不要按文字分支: 导出的常量是 REFUSAL_NEEDS_HEADED_WINDOWREFUSAL_NEEDS_USER_GESTUREREFUSAL_SURFACE_NOT_OPENREFUSAL_API_UNAVAILABLE

WebSocket 关闭码

4000 段的关闭码都是有意的拒绝,绝不是传输失败:

服务端的其他帧

服务端还会广播一些 dev 循环相关的帧,harness 应当容忍它们,也可以加以利用:
  • reload:发给 service worker producer 的一次性重载信号,带一个 reloadType,取值为 fullservice-workercontent-scriptspage。其中 page 这种只是通知,不做别的。
  • ping:一个保活帧,用来重置 MV3 service worker 的空闲计时器。忽略它即可。

下一步

  • 只要 CLI 命令够用就优先用它们,从 ready.json 开始。
  • 错误码 把桥接失败映射到信封里的错误码。