跳到主要内容

中继 API 参考

本页是 Otto 中继的完整 HTTP 和 WebSocket API 参考。实现源码:packages/relay/src/index.ts

认证

大多数端点需要在 Authorization 头部中提供持有者令牌:

Authorization: Bearer <accessToken>

角色期望:

  • 控制器访问令牌 — 用于面向控制器的端点(命令、日志、节点发现)。
  • 节点访问令牌 — 用于节点 ACL 端点(/api/controller/access)。

配对端点

方法路径描述
POST/api/pairing/request节点请求配对挑战
GET/api/pairing/pending列出待处理的配对码(需要节点认证)
POST/api/pairing/approve控制器批准配对码
GET/api/pairing/status检查挑战的配对状态

请求:POST /api/pairing/request

{ "nodeId": "node_local_1" }

请求:POST /api/pairing/approve

{ "code": "ABCD-1234" }

错误码: nodeId_requiredcode_requiredpairing_not_foundpairing_not_pendingchallengeId_requiredchallenge_not_found

认证端点

方法路径描述
POST/api/auth/refresh使用刷新令牌刷新访问令牌
POST/api/auth/revoke撤销刷新令牌

请求:POST /api/auth/refresh

{ "refreshToken": "<refresh_token>" }

错误码: refreshToken_requiredinvalid_refresh_token

控制器客户端端点

方法路径认证描述
POST/api/controller/register无(或密钥)注册新控制器客户端
POST/api/controller/token用客户端凭据交换令牌
POST/api/controller/remove控制器持有者按 ID 撤销控制器客户端
POST/api/controller/remove-all控制器持有者撤销并清除所有控制器客户端

请求:POST /api/controller/register

{ "name": "my-controller", "description": "automation worker", "avatarSeed": "optional-seed" }

请求:POST /api/controller/token

{ "clientId": "clt_abc123", "clientSecret": "cs_xxx" }

请求:POST /api/controller/remove

{ "clientId": "clt_abc123" }

删除语义:

  • 单个删除撤销客户端记录并拆除 ACL 授权、刷新会话和活跃的控制器套接字。
  • 批量删除还会清除记录。后续 remove-all 调用返回 removedCount: 0,直到有新客户端注册。

错误码: registration_forbiddencontroller_metadata_requiredcontroller_name_conflictclient_credentials_requiredinvalid_client_credentialsclient_not_found

节点 ACL 端点

方法路径认证描述
GET/api/controller/access节点持有者列出已连接节点的 ACL 授权
POST/api/controller/access节点持有者授予或撤销控制器对节点的访问权限

请求:POST /api/controller/access

{ "clientId": "clt_abc123", "grant": true, "expiresAt": 1776165600000 }

没有活跃授权时,针对节点的命令返回 acl_missing_node_grant。客户端密钥仅用于 /api/controller/token;运行时命令授权使用访问令牌作用域和节点 ACL 授权。

错误码: missing_access_tokenforbidden_roleclientId_and_grant_requiredinvalid_expiresAt

节点发现端点

方法路径认证描述
GET/api/nodes/connected控制器持有者列出已连接的节点 ID

响应:GET /api/nodes/connected

{ "nodes": [{ "nodeId": "node_local_1" }] }

错误码: missing_access_tokenforbidden_roleinvalid_access_token

日志端点

方法路径认证描述
GET/api/logs控制器持有者查询操作日志
GET/api/logs/status控制器持有者日志存储状态和聚合字节大小
GET/api/logs/export控制器持有者以 NDJSON 导出日志

查询参数(logs 和 export):

参数描述
sinceISO-8601 时间戳下限
leveldebug | info | warn | error
sourcerelay | controller | node | all
latest限制返回最新的 N 条条目
nodeId按节点身份过滤
requestId按请求关联 ID 过滤

响应:GET /api/logs

{
"logs": [
{
"timestamp": "2026-04-14T13:00:00.000Z",
"source": "relay",
"type": "command_routed",
"requestId": "req_cmd_1"
}
]
}

错误码: invalid_sinceinvalid_levelinvalid_sourceinvalid_latest

WebSocket 连接

角色URL 模式
控制器ws://host:port?role=controller
节点ws://host:port?role=node

连接后,先发送 hello 然后发送 auth 帧。认证成功时中继响应 auth_ack。帧示例见可复用代码片段

CLI 映射

CLI 命令API 操作
otto authcodeGET /api/pairing/pending
otto pair <code>POST /api/pairing/approve
otto revokePOST /api/auth/revoke
otto client registerPOST /api/controller/register
otto client loginPOST /api/controller/token + POST /api/auth/refresh
otto client removePOST /api/controller/remove
otto client status验证存储的令牌
otto logs listGET /api/logs
otto logs exportGET /api/logs/export
otto logs statusGET /api/logs/status
otto commands listWebSocket command.list
otto cmdWebSocket command.run

下一步