@clawos-dev/clawd 0.2.530 → 0.2.532

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.
@@ -21947,6 +21947,11 @@ var AuthApiKeyRegenerateResponseSchema = external_exports.object({
21947
21947
  createdAt: external_exports.string().min(1),
21948
21948
  gatewayUrl: GatewayUrl
21949
21949
  });
21950
+ var AuthApiKeyRevokeResponseSchema = external_exports.object({
21951
+ type: external_exports.literal("auth:apiKey:revoke:ok"),
21952
+ /** 之前有没有那把——没发过也算成功(幂等) */
21953
+ revoked: external_exports.boolean()
21954
+ });
21950
21955
  var AuthLoginDoneEventSchema = external_exports.object({
21951
21956
  type: external_exports.literal("auth:login:done"),
21952
21957
  identity: FeishuIdentitySchema
@@ -24494,6 +24499,10 @@ var METHOD_DOCS = {
24494
24499
  summary: "\u6362\u4E00\u628A\u65B0\u7684\u4E91 persona \u8C03\u7528 key\uFF0C**\u65E7\u7684\u5F53\u573A\u5931\u6548**\uFF08\u4E00\u4EBA\u4E00\u628A\uFF0C\u4E2D\u5FC3\u6309 union_id \u8986\u76D6\uFF09\u3002owner-only",
24495
24500
  args: NO_ARGS
24496
24501
  },
24502
+ "auth:apiKey:revoke": {
24503
+ summary: "\u64A4\u9500\u81EA\u5DF1\u7684\u4E91 persona \u8C03\u7528 key\uFF1A\u4E2D\u5FC3\u5220\u6389\u90A3\u4E00\u884C\u3001**\u4E0D\u53D1\u65B0\u7684**\u3002gateway \u53EA\u5728\u5F00\u4F1A\u8BDD\u548C\u6BCF\u6B21\u4E0A\u884C\u65F6\u9A8C key\uFF0C\u6240\u4EE5\u5F00\u7740\u7684\u4E91\u4F1A\u8BDD\u4E0B\u4E00\u6761\u6D88\u606F\u624D\u53D1\u4E0D\u51FA\u53BB\u3001\u6B63\u5728\u8DD1\u7684\u90A3\u4E00\u8F6E\u4F1A\u8DD1\u5B8C\u3002\u6CA1\u53D1\u8FC7\u4E5F\u56DE ok\uFF08revoked:false\uFF09\u3002owner-only",
24504
+ args: NO_ARGS
24505
+ },
24497
24506
  "device:list": {
24498
24507
  summary: "\u5217\u51FA\u516C\u5171\u8BBE\u5907\u76EE\u5F55\u91CC\u53EF\u8FDE\u63A5\u7684\u8BBE\u5907\uFF08daemon \u4EE3\u7406\u4E2D\u5FC3 server\uFF09\u3002owner-only",
24499
24508
  args: NO_ARGS
package/dist/cli.cjs CHANGED
@@ -6431,7 +6431,7 @@ var init_contact = __esm({
6431
6431
  });
6432
6432
 
6433
6433
  // ../protocol/src/feishu-auth.ts
6434
- var FEISHU_GATED_METHODS, LOGIN_EXPIRED_ERROR_MARKER, DeviceEntrySchema, DeviceListResponseSchema, DeviceConnectArgsSchema, DeviceConnectResponseSchema, FeishuIdentitySchema, AuthLoginStartResponseSchema, AuthGetIdentityResponseSchema, AuthLogoutResponseSchema, GatewayUrl, AuthApiKeyGetResponseSchema, AuthApiKeyRegenerateResponseSchema, AuthLoginDoneEventSchema, AuthLoginFailedEventSchema;
6434
+ var FEISHU_GATED_METHODS, LOGIN_EXPIRED_ERROR_MARKER, DeviceEntrySchema, DeviceListResponseSchema, DeviceConnectArgsSchema, DeviceConnectResponseSchema, FeishuIdentitySchema, AuthLoginStartResponseSchema, AuthGetIdentityResponseSchema, AuthLogoutResponseSchema, GatewayUrl, AuthApiKeyGetResponseSchema, AuthApiKeyRegenerateResponseSchema, AuthApiKeyRevokeResponseSchema, AuthLoginDoneEventSchema, AuthLoginFailedEventSchema;
6435
6435
  var init_feishu_auth = __esm({
6436
6436
  "../protocol/src/feishu-auth.ts"() {
6437
6437
  "use strict";
@@ -6538,6 +6538,11 @@ var init_feishu_auth = __esm({
6538
6538
  createdAt: external_exports.string().min(1),
6539
6539
  gatewayUrl: GatewayUrl
6540
6540
  });
6541
+ AuthApiKeyRevokeResponseSchema = external_exports.object({
6542
+ type: external_exports.literal("auth:apiKey:revoke:ok"),
6543
+ /** 之前有没有那把——没发过也算成功(幂等) */
6544
+ revoked: external_exports.boolean()
6545
+ });
6541
6546
  AuthLoginDoneEventSchema = external_exports.object({
6542
6547
  type: external_exports.literal("auth:login:done"),
6543
6548
  identity: FeishuIdentitySchema
@@ -9311,6 +9316,10 @@ var init_methods = __esm({
9311
9316
  summary: "\u6362\u4E00\u628A\u65B0\u7684\u4E91 persona \u8C03\u7528 key\uFF0C**\u65E7\u7684\u5F53\u573A\u5931\u6548**\uFF08\u4E00\u4EBA\u4E00\u628A\uFF0C\u4E2D\u5FC3\u6309 union_id \u8986\u76D6\uFF09\u3002owner-only",
9312
9317
  args: NO_ARGS
9313
9318
  },
9319
+ "auth:apiKey:revoke": {
9320
+ summary: "\u64A4\u9500\u81EA\u5DF1\u7684\u4E91 persona \u8C03\u7528 key\uFF1A\u4E2D\u5FC3\u5220\u6389\u90A3\u4E00\u884C\u3001**\u4E0D\u53D1\u65B0\u7684**\u3002gateway \u53EA\u5728\u5F00\u4F1A\u8BDD\u548C\u6BCF\u6B21\u4E0A\u884C\u65F6\u9A8C key\uFF0C\u6240\u4EE5\u5F00\u7740\u7684\u4E91\u4F1A\u8BDD\u4E0B\u4E00\u6761\u6D88\u606F\u624D\u53D1\u4E0D\u51FA\u53BB\u3001\u6B63\u5728\u8DD1\u7684\u90A3\u4E00\u8F6E\u4F1A\u8DD1\u5B8C\u3002\u6CA1\u53D1\u8FC7\u4E5F\u56DE ok\uFF08revoked:false\uFF09\u3002owner-only",
9321
+ args: NO_ARGS
9322
+ },
9314
9323
  "device:list": {
9315
9324
  summary: "\u5217\u51FA\u516C\u5171\u8BBE\u5907\u76EE\u5F55\u91CC\u53EF\u8FDE\u63A5\u7684\u8BBE\u5907\uFF08daemon \u4EE3\u7406\u4E2D\u5FC3 server\uFF09\u3002owner-only",
9316
9325
  args: NO_ARGS
@@ -62214,6 +62223,16 @@ async function centralIssueApiKey(opts) {
62214
62223
  gatewayUrl: typeof body.gatewayUrl === "string" ? body.gatewayUrl : null
62215
62224
  };
62216
62225
  }
62226
+ async function centralRevokeApiKey(opts) {
62227
+ const body = await centralRequest(opts, "/api/persona-cloud/api-key", {
62228
+ method: "DELETE",
62229
+ bearer: opts.loginPass
62230
+ });
62231
+ if (typeof body.revoked !== "boolean") {
62232
+ throw new CentralClientError("BAD_RESPONSE", "api-key: revoked must be boolean");
62233
+ }
62234
+ return { revoked: body.revoked };
62235
+ }
62217
62236
  async function centralListDevices(opts) {
62218
62237
  const body = await centralRequest(opts, "/api/clawd-identity/devices", {
62219
62238
  method: "GET",
@@ -62278,6 +62297,12 @@ var GATEWAY_ROUTES = {
62278
62297
  thread: (threadId) => `/threads/${encodeURIComponent(threadId)}`
62279
62298
  };
62280
62299
  var trimSlash = (u2) => u2.replace(/\/+$/, "");
62300
+ var CloudApiKeyRequiredError = class extends Error {
62301
+ constructor() {
62302
+ super("\u8FD8\u6CA1\u751F\u6210\u4E91 persona \u7684\u8C03\u7528 key\u3002\u5230\u300C\u8BBE\u7F6E \u2192 \u8D26\u53F7\u300D\u6216\u8FD9\u4E2A persona \u7684\u5361\u7247\u4E0A\u751F\u6210\u4E00\u628A\uFF0C\u518D\u5F00\u4F1A\u8BDD");
62303
+ this.name = "CloudApiKeyRequiredError";
62304
+ }
62305
+ };
62281
62306
  var CLOUD_PERSONA_ID_SUFFIX = "-cloud";
62282
62307
  function cloudPersonaToFile(p3) {
62283
62308
  const at3 = p3.registeredAt ?? 0;
@@ -62315,7 +62340,7 @@ var CloudGatewayClient = class {
62315
62340
  }
62316
62341
  async credentials() {
62317
62342
  const { apiKey, gatewayUrl } = await this.locate();
62318
- if (!apiKey) throw new Error("\u8FD8\u6CA1\u751F\u6210\u4E91 persona \u7684\u8C03\u7528 key\uFF0C\u53BB\u300C\u8BBE\u7F6E \u2192 \u4E91\u4E0A persona\u300D\u751F\u6210\u4E00\u628A");
62343
+ if (!apiKey) throw new CloudApiKeyRequiredError();
62319
62344
  return { apiKey, gatewayUrl };
62320
62345
  }
62321
62346
  async listPersonas() {
@@ -62435,7 +62460,9 @@ function openHttpLineStream(opts) {
62435
62460
  }
62436
62461
  if (!res.ok) {
62437
62462
  logger?.warn("cloud session send failed", { status: res.status });
62438
- fail(`\u4E0A\u884C\u53D1\u4E0D\u51FA\u53BB\uFF08gateway \u56DE ${res.status}\uFF09\uFF0C\u8FD9\u6761\u4F1A\u8BDD\u65AD\u4E86`);
62463
+ fail(
62464
+ res.status === 401 ? "\u8C03\u7528 key \u5DF2\u5931\u6548\uFF08\u64A4\u9500\u6216\u91CD\u65B0\u751F\u6210\u8FC7\uFF09\uFF0C\u8FD9\u6761\u4F1A\u8BDD\u65AD\u4E86\u3002\u5230\u300C\u8BBE\u7F6E \u2192 \u8D26\u53F7\u300D\u6216\u8FD9\u4E2A persona \u7684\u5361\u7247\u4E0A\u751F\u6210\u4E00\u628A\uFF0C\u518D\u5F00\u65B0\u4F1A\u8BDD" : `\u4E0A\u884C\u53D1\u4E0D\u51FA\u53BB\uFF08gateway \u56DE ${res.status}\uFF09\uFF0C\u8FD9\u6761\u4F1A\u8BDD\u65AD\u4E86`
62465
+ );
62439
62466
  }
62440
62467
  }).catch((e) => {
62441
62468
  if (closed) return;
@@ -62726,7 +62753,7 @@ function createCloudCodexSession(ctx, sink, deps) {
62726
62753
  stream.attach(channel);
62727
62754
  },
62728
62755
  (e) => {
62729
- sink.onError(`\u8FDE\u4E0D\u4E0A\u4E91 gateway\uFF1A${e.message}`);
62756
+ sink.onError(e instanceof CloudApiKeyRequiredError ? e.message : `\u8FDE\u4E0D\u4E0A\u4E91 gateway\uFF1A${e.message}`);
62730
62757
  stream.close();
62731
62758
  }
62732
62759
  );
@@ -67416,7 +67443,8 @@ function loadOrCreateAuthFile(opts) {
67416
67443
  token: existing.token,
67417
67444
  ownerPrincipalId: existing.ownerPrincipalId,
67418
67445
  deviceId: existing.deviceId,
67419
- createdAt: existing.createdAt ?? (/* @__PURE__ */ new Date(0)).toISOString()
67446
+ createdAt: existing.createdAt ?? (/* @__PURE__ */ new Date(0)).toISOString(),
67447
+ ...existing.tunnelDeviceKey ? { tunnelDeviceKey: existing.tunnelDeviceKey } : {}
67420
67448
  };
67421
67449
  }
67422
67450
  const token = existing?.token || generate();
@@ -67424,9 +67452,17 @@ function loadOrCreateAuthFile(opts) {
67424
67452
  const deviceId = ownerPrincipalId;
67425
67453
  const createdAt = existing?.createdAt || now().toISOString();
67426
67454
  const next = { token, ownerPrincipalId, deviceId, createdAt };
67455
+ if (existing?.tunnelDeviceKey) next.tunnelDeviceKey = existing.tunnelDeviceKey;
67427
67456
  writeAuthFile(file, next);
67428
67457
  return next;
67429
67458
  }
67459
+ function loadOrCreateTunnelDeviceKey(opts) {
67460
+ const current = loadOrCreateAuthFile(opts);
67461
+ if (current.tunnelDeviceKey) return current.tunnelDeviceKey;
67462
+ const tunnelDeviceKey = opts.derive();
67463
+ writeAuthFile(authFilePath(opts.dataDir), { ...current, tunnelDeviceKey });
67464
+ return tunnelDeviceKey;
67465
+ }
67430
67466
  function defaultGenerateToken() {
67431
67467
  return import_node_crypto15.default.randomBytes(32).toString("base64url");
67432
67468
  }
@@ -67445,6 +67481,7 @@ function readAuthFile(file) {
67445
67481
  ownerPrincipalId: typeof parsed.ownerPrincipalId === "string" && parsed.ownerPrincipalId.length > 0 ? parsed.ownerPrincipalId : void 0,
67446
67482
  deviceId: typeof parsed.deviceId === "string" && parsed.deviceId.length > 0 ? parsed.deviceId : void 0,
67447
67483
  createdAt: typeof parsed.createdAt === "string" ? parsed.createdAt : void 0,
67484
+ tunnelDeviceKey: typeof parsed.tunnelDeviceKey === "string" && parsed.tunnelDeviceKey.length > 0 ? parsed.tunnelDeviceKey : void 0,
67448
67485
  // 单 secret 合并前的旧字段:出现即触发清理写回(值无所谓,硬切不再使用)
67449
67486
  hasLegacySecrets: "signSecret" in parsed || "visitorTokenSecret" in parsed
67450
67487
  };
@@ -67779,22 +67816,51 @@ var lastPeers = [];
67779
67816
  function getCachedOrgPeers() {
67780
67817
  return lastPeers;
67781
67818
  }
67819
+ function sameOrigin(a2, b3) {
67820
+ const oa2 = toOrigin(a2);
67821
+ const ob = toOrigin(b3);
67822
+ return oa2 != null && ob != null ? oa2 === ob : a2 === b3;
67823
+ }
67824
+ function toOrigin(raw) {
67825
+ const http2 = raw.replace(/^wss:\/\//i, "https://").replace(/^ws:\/\//i, "http://");
67826
+ try {
67827
+ const origin = new URL(http2).origin;
67828
+ return origin === "null" ? null : origin;
67829
+ } catch {
67830
+ return null;
67831
+ }
67832
+ }
67782
67833
  async function syncOrgMesh(deps) {
67783
67834
  const peers = await deps.fetchPeers();
67784
67835
  lastPeers = peers;
67785
67836
  if (peers.length === 0) {
67786
67837
  deps.log("org-mesh: \u4E0D\u5728\u4EFB\u4F55\u7EC4\u7EC7\uFF08\u6216\u7EC4\u91CC\u53EA\u6709\u81EA\u5DF1\uFF09\uFF0C\u8DF3\u8FC7");
67787
67838
  deps.onProgress?.({ total: 0, done: 0, connected: 0, failed: 0, active: false });
67788
- return { peers: 0, attempted: 0, connected: 0, failed: 0 };
67839
+ return { peers: 0, attempted: 0, connected: 0, failed: 0, refreshed: 0 };
67789
67840
  }
67790
67841
  const targets = [];
67842
+ let refreshed = 0;
67791
67843
  for (const p3 of peers) {
67792
67844
  for (const d2 of p3.devices) {
67793
- if (deps.store.get(d2.deviceId)) continue;
67794
- targets.push({ deviceId: d2.deviceId, displayName: p3.displayName });
67845
+ const existing = deps.store.get(d2.deviceId);
67846
+ if (!existing) {
67847
+ targets.push({ deviceId: d2.deviceId, displayName: p3.displayName });
67848
+ continue;
67849
+ }
67850
+ if (d2.url == null || sameOrigin(existing.remoteUrl, d2.url)) continue;
67851
+ const updated = { ...existing, remoteUrl: d2.url };
67852
+ deps.store.upsert(updated);
67853
+ refreshed += 1;
67854
+ deps.log("org-mesh: \u8054\u7CFB\u4EBA\u5730\u5740\u5DF2\u5237\u65B0", {
67855
+ deviceId: d2.deviceId,
67856
+ name: p3.displayName,
67857
+ from: existing.remoteUrl,
67858
+ to: d2.url
67859
+ });
67860
+ deps.onContactUpdated?.(updated);
67795
67861
  }
67796
67862
  }
67797
- deps.log("org-mesh: \u5F00\u59CB\u540C\u6B65", { peers: peers.length, targets: targets.length });
67863
+ deps.log("org-mesh: \u5F00\u59CB\u540C\u6B65", { peers: peers.length, targets: targets.length, refreshed });
67798
67864
  let connected = 0;
67799
67865
  let failed = 0;
67800
67866
  deps.onProgress?.({
@@ -67825,8 +67891,14 @@ async function syncOrgMesh(deps) {
67825
67891
  active: connected + failed < targets.length
67826
67892
  });
67827
67893
  }
67828
- deps.log("org-mesh: \u540C\u6B65\u5B8C\u6210", { peers: peers.length, attempted: targets.length, connected, failed });
67829
- return { peers: peers.length, attempted: targets.length, connected, failed };
67894
+ deps.log("org-mesh: \u540C\u6B65\u5B8C\u6210", {
67895
+ peers: peers.length,
67896
+ attempted: targets.length,
67897
+ connected,
67898
+ failed,
67899
+ refreshed
67900
+ });
67901
+ return { peers: peers.length, attempted: targets.length, connected, failed, refreshed };
67830
67902
  }
67831
67903
 
67832
67904
  // src/handlers/device.ts
@@ -69976,12 +70048,19 @@ function buildFeishuAuthHandlers(deps) {
69976
70048
  response: { type: "auth:apiKey:regenerate:ok", apiKey, createdAt, gatewayUrl }
69977
70049
  };
69978
70050
  };
70051
+ const apiKeyRevoke = async () => {
70052
+ const { revoked } = await deps.apiKeyClient.revoke(requireLogin());
70053
+ return {
70054
+ response: { type: "auth:apiKey:revoke:ok", revoked }
70055
+ };
70056
+ };
69979
70057
  return {
69980
70058
  "auth:login:start": loginStart,
69981
70059
  "auth:getIdentity": getIdentity,
69982
70060
  "auth:logout": logout,
69983
70061
  "auth:apiKey:get": apiKeyGet,
69984
- "auth:apiKey:regenerate": apiKeyRegenerate
70062
+ "auth:apiKey:regenerate": apiKeyRegenerate,
70063
+ "auth:apiKey:revoke": apiKeyRevoke
69985
70064
  };
69986
70065
  }
69987
70066
 
@@ -70281,6 +70360,7 @@ var METHOD_GRANT_MAP = {
70281
70360
  // 云 persona 调用 key:本机主人自己的东西,guest 一律够不着
70282
70361
  "auth:apiKey:get": ADMIN_ANY,
70283
70362
  "auth:apiKey:regenerate": ADMIN_ANY,
70363
+ "auth:apiKey:revoke": ADMIN_ANY,
70284
70364
  // ---- device:* 设备目录 + 连接(决策 #15,owner-only) ----
70285
70365
  // 设备目录 / 连接都是 owner 本机操作(用本机登录票找中心 server),guest 不可调
70286
70366
  "device:list": ADMIN_ANY,
@@ -70335,7 +70415,7 @@ function computeMethodAccess(args) {
70335
70415
  }
70336
70416
 
70337
70417
  // src/version.ts
70338
- var version = "0.2.530".length > 0 ? "0.2.530" : "dev";
70418
+ var version = "0.2.532".length > 0 ? "0.2.532" : "dev";
70339
70419
 
70340
70420
  // src/cli-probe/probe.ts
70341
70421
  var fs77 = __toESM(require("fs"), 1);
@@ -73693,7 +73773,10 @@ async function startDaemon(config) {
73693
73773
  connectToDevice: createConnectToDevice(feishuDeviceDeps),
73694
73774
  log: (msg, meta) => logger.info(msg, meta),
73695
73775
  // 进度上报:串行建联 20+ 台要几十秒,UI 靠这个帧渲染进度条
73696
- onProgress: (progress) => wsServer?.broadcastToOwners({ type: "org-mesh:progress", ...progress })
73776
+ onProgress: (progress) => wsServer?.broadcastToOwners({ type: "org-mesh:progress", ...progress }),
73777
+ // 已有联系人的地址被中心最新 url 刷新 → 复用 contact:added(UI reducer 按 deviceId upsert,
73778
+ // auto-reverse 重握手也发这一帧),不新增帧
73779
+ onContactUpdated: (contact) => wsServer?.broadcastToOwners({ type: "contact:added", contact })
73697
73780
  });
73698
73781
  } catch (err) {
73699
73782
  logger.warn("org-mesh sync failed (best-effort)", { err: err.message });
@@ -73971,7 +74054,8 @@ async function startDaemon(config) {
73971
74054
  // 凭证不出 ws —— UI 只拿到 key 本身,跟 exchange / listDevices 同一条纪律。
73972
74055
  apiKeyClient: {
73973
74056
  get: (args) => centralGetApiKey({ api: config.clawosApi ?? DEFAULT_CLAWOS_API, ...args }),
73974
- issue: (args) => centralIssueApiKey({ api: config.clawosApi ?? DEFAULT_CLAWOS_API, ...args })
74057
+ issue: (args) => centralIssueApiKey({ api: config.clawosApi ?? DEFAULT_CLAWOS_API, ...args }),
74058
+ revoke: (args) => centralRevokeApiKey({ api: config.clawosApi ?? DEFAULT_CLAWOS_API, ...args })
73975
74059
  }
73976
74060
  },
73977
74061
  // 云 persona 卡片上的连接器区(design 2026-09-11-mcp-connector §3.8):装了什么以 gateway 登记行为真源,
@@ -74443,7 +74527,12 @@ async function startDaemon(config) {
74443
74527
  tunnelMgr = new TunnelManager({
74444
74528
  dataDir: config.dataDir,
74445
74529
  clawosApi: config.clawosApi,
74446
- deviceKey: deriveStableDeviceKey({ dataDir: config.dataDir }),
74530
+ // 子域指纹落盘于 auth.json,首次缺失才由 hostname+uid 算初值——改电脑名不再换对外地址
74531
+ // (design 2026-09-16-tunnel-address-stability §3.1)
74532
+ deviceKey: loadOrCreateTunnelDeviceKey({
74533
+ dataDir: config.dataDir,
74534
+ derive: () => deriveStableDeviceKey({ dataDir: config.dataDir })
74535
+ }),
74447
74536
  frpcBinaryOverride: config.frpcBinary,
74448
74537
  noPersist: config.noTunnelPersist,
74449
74538
  logger,
@@ -21762,6 +21762,11 @@ var AuthApiKeyRegenerateResponseSchema = external_exports.object({
21762
21762
  createdAt: external_exports.string().min(1),
21763
21763
  gatewayUrl: GatewayUrl
21764
21764
  });
21765
+ var AuthApiKeyRevokeResponseSchema = external_exports.object({
21766
+ type: external_exports.literal("auth:apiKey:revoke:ok"),
21767
+ /** 之前有没有那把——没发过也算成功(幂等) */
21768
+ revoked: external_exports.boolean()
21769
+ });
21765
21770
  var AuthLoginDoneEventSchema = external_exports.object({
21766
21771
  type: external_exports.literal("auth:login:done"),
21767
21772
  identity: FeishuIdentitySchema
@@ -24309,6 +24314,10 @@ var METHOD_DOCS = {
24309
24314
  summary: "\u6362\u4E00\u628A\u65B0\u7684\u4E91 persona \u8C03\u7528 key\uFF0C**\u65E7\u7684\u5F53\u573A\u5931\u6548**\uFF08\u4E00\u4EBA\u4E00\u628A\uFF0C\u4E2D\u5FC3\u6309 union_id \u8986\u76D6\uFF09\u3002owner-only",
24310
24315
  args: NO_ARGS
24311
24316
  },
24317
+ "auth:apiKey:revoke": {
24318
+ summary: "\u64A4\u9500\u81EA\u5DF1\u7684\u4E91 persona \u8C03\u7528 key\uFF1A\u4E2D\u5FC3\u5220\u6389\u90A3\u4E00\u884C\u3001**\u4E0D\u53D1\u65B0\u7684**\u3002gateway \u53EA\u5728\u5F00\u4F1A\u8BDD\u548C\u6BCF\u6B21\u4E0A\u884C\u65F6\u9A8C key\uFF0C\u6240\u4EE5\u5F00\u7740\u7684\u4E91\u4F1A\u8BDD\u4E0B\u4E00\u6761\u6D88\u606F\u624D\u53D1\u4E0D\u51FA\u53BB\u3001\u6B63\u5728\u8DD1\u7684\u90A3\u4E00\u8F6E\u4F1A\u8DD1\u5B8C\u3002\u6CA1\u53D1\u8FC7\u4E5F\u56DE ok\uFF08revoked:false\uFF09\u3002owner-only",
24319
+ args: NO_ARGS
24320
+ },
24312
24321
  "device:list": {
24313
24322
  summary: "\u5217\u51FA\u516C\u5171\u8BBE\u5907\u76EE\u5F55\u91CC\u53EF\u8FDE\u63A5\u7684\u8BBE\u5907\uFF08daemon \u4EE3\u7406\u4E2D\u5FC3 server\uFF09\u3002owner-only",
24314
24323
  args: NO_ARGS