@tool-bridge/server 0.19.0 → 0.21.0

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.
Files changed (109) hide show
  1. package/dist/{airtable-23JBIM6X.js → airtable-DMJEEGJP.js} +19 -16
  2. package/dist/{alt_text_generator_ai-ADWBTCIH.js → alt_text_generator_ai-RELFQ5FV.js} +4 -4
  3. package/dist/{amap-CYQCYW2Z.js → amap-YSYEACKQ.js} +4 -4
  4. package/dist/{anthropic-5P62HDNR.js → anthropic-D5X5GSYE.js} +23 -25
  5. package/dist/{apify-54RZUAGW.js → apify-5NVFU3IZ.js} +20 -19
  6. package/dist/{brave_search-AHJ6FTD5.js → brave_search-X557FMGO.js} +16 -14
  7. package/dist/chunk-JEWFX6Z6.js +71 -0
  8. package/dist/{chunk-CLEZ6YQ6.js → chunk-MDY7K5CX.js} +1090 -606
  9. package/dist/{chunk-OKRZPQ3R.js → chunk-MZCIPUNQ.js} +1002 -242
  10. package/dist/{chunk-VLOIDU5U.js → chunk-Q74GLIDK.js} +3 -3
  11. package/dist/{chunk-B4P6YZFS.js → chunk-QR4LK3HF.js} +1 -1
  12. package/dist/{chunk-SWBNHIO4.js → chunk-ZTTN6AJG.js} +1 -1
  13. package/dist/{circleci-UM3NSQJ3.js → circleci-3P3QTUX2.js} +20 -24
  14. package/dist/{clerk-FE5LQ2CZ.js → clerk-GNMZQ2MY.js} +22 -21
  15. package/dist/{cloudflare_dns-KEZABKUT.js → cloudflare_dns-VWZH3ZTR.js} +21 -17
  16. package/dist/{cohere-4IPJADXP.js → cohere-C7QVIIMG.js} +19 -17
  17. package/dist/{confluence-56QEKNQI.js → confluence-52I37IUT.js} +16 -11
  18. package/dist/{convertapi-3QRM5K5T.js → convertapi-3TRJ3WEO.js} +3 -3
  19. package/dist/{currencyapi-L6G4OND5.js → currencyapi-LWEANWVI.js} +23 -26
  20. package/dist/{deepseek-LGC6HBFG.js → deepseek-5U24YG4P.js} +27 -17
  21. package/dist/{docker_hub-XDMK3BIU.js → docker_hub-CMISLRSE.js} +4 -4
  22. package/dist/{dropbox-4QARMFZU.js → dropbox-TW4QN6FT.js} +9 -8
  23. package/dist/{dub-C6JSJKOT.js → dub-EFXGI5UH.js} +22 -19
  24. package/dist/{e2b-6A6TVACJ.js → e2b-PHM63OVF.js} +20 -20
  25. package/dist/{exa-SIWWW6AA.js → exa-DYOQWURR.js} +22 -25
  26. package/dist/{fal_ai-3IJXOKSP.js → fal_ai-VJPMCNRH.js} +18 -17
  27. package/dist/{feishu-L4KDA4DC.js → feishu-TFIZXPIN.js} +2 -2
  28. package/dist/{feishu_custom_bot-SDM75H4P.js → feishu_custom_bot-ADSE23KU.js} +3 -3
  29. package/dist/{figma-6DD436DN.js → figma-4AK47AYY.js} +21 -23
  30. package/dist/{firehydrant-SYSGYB3R.js → firehydrant-RGPTW4EA.js} +15 -15
  31. package/dist/{fixer-FZG7ASTF.js → fixer-OAMF4DKP.js} +4 -4
  32. package/dist/{fly-HMRCZBUC.js → fly-YB4AQD4O.js} +20 -16
  33. package/dist/{front-FAFSD7I3.js → front-6GTVYKUM.js} +20 -23
  34. package/dist/{geocodio-4D3TWENM.js → geocodio-YRT4K25M.js} +4 -4
  35. package/dist/{ghost-OSO2FOZS.js → ghost-JCW6UIP2.js} +4 -4
  36. package/dist/{github-OR4I4RHE.js → github-CEGVRMNX.js} +28 -27
  37. package/dist/{gmail-5AOPJ63E.js → gmail-JCMJD55P.js} +17 -17
  38. package/dist/{googlecalendar-SOJIJUWH.js → googlecalendar-2EAW4MNM.js} +16 -14
  39. package/dist/{googledocs-QSKN5TLN.js → googledocs-YNKKBM6Q.js} +3 -3
  40. package/dist/{grafana-R3AIZM7M.js → grafana-353VSGXN.js} +24 -25
  41. package/dist/{graphhopper-4CR3QOAX.js → graphhopper-H3IVJNDS.js} +4 -4
  42. package/dist/index.d.ts +52 -36
  43. package/dist/index.js +3 -3
  44. package/dist/{ip2proxy-OBCG6X6J.js → ip2proxy-DBGRWH7S.js} +4 -4
  45. package/dist/{ipgeolocation_io-NHH3DTQW.js → ipgeolocation_io-5I2BDVMG.js} +4 -4
  46. package/dist/{ipqualityscore-7POMCBEC.js → ipqualityscore-ILV7TQCV.js} +4 -4
  47. package/dist/{jina_ai-YXVKROV4.js → jina_ai-L5BH455V.js} +20 -21
  48. package/dist/{jira-LADO3VJU.js → jira-IGTILUZA.js} +20 -16
  49. package/dist/{langsmith-XZ6UAQFU.js → langsmith-BYRX4AOF.js} +25 -25
  50. package/dist/{lemlist-P74GLNE7.js → lemlist-ZGNYTIQO.js} +23 -24
  51. package/dist/{linear-CXJ7D37A.js → linear-HLGOWISN.js} +3 -3
  52. package/dist/{logsnag-EVVHWFLK.js → logsnag-5RGTMTU2.js} +20 -22
  53. package/dist/main.js +102 -102
  54. package/dist/{mattermost-WG2MRGBD.js → mattermost-BONGXVC7.js} +21 -17
  55. package/dist/{mem0-HQWUKG6U.js → mem0-RUVNUPTE.js} +15 -15
  56. package/dist/{memos-SQMJIFOE.js → memos-TED4HI54.js} +36 -32
  57. package/dist/{metabase-E27G2DZI.js → metabase-ZHXHRHZK.js} +22 -18
  58. package/dist/{mistral_ai-MIL63NIT.js → mistral_ai-NGP5SHU7.js} +24 -21
  59. package/dist/{mother_duck-AIZVCBNR.js → mother_duck-TKVQM35M.js} +23 -19
  60. package/dist/{ngrok-XS4DVIQS.js → ngrok-BYCUJ7QV.js} +17 -22
  61. package/dist/{notes-JEOUSL2Y.js → notes-KXRNNYDW.js} +1 -1
  62. package/dist/{notion-U4EZVDW2.js → notion-2ILYKJOO.js} +20 -17
  63. package/dist/{open_exchange_rates-AZSQEYEJ.js → open_exchange_rates-JU4DC6HZ.js} +4 -4
  64. package/dist/{openai-HW3SYMTQ.js → openai-6SOT26ZK.js} +22 -16
  65. package/dist/{opengraph_io-QX74MAEL.js → opengraph_io-ZEFHV2OL.js} +4 -4
  66. package/dist/{openrouter-OXSKYL6N.js → openrouter-R4P7JL5L.js} +19 -14
  67. package/dist/{outline-CCQAPDSW.js → outline-VCTQ5V2X.js} +18 -20
  68. package/dist/{paddle-6KQPSSCK.js → paddle-AZOAKBJS.js} +17 -15
  69. package/dist/{perplexity-2TXO7IQE.js → perplexity-OMRLGVAT.js} +19 -23
  70. package/dist/{pinecone-YOO7NULI.js → pinecone-DI62W3ZX.js} +19 -24
  71. package/dist/{pipedrive-Q6RIFIFP.js → pipedrive-CW7HONYW.js} +22 -23
  72. package/dist/{polar-KUMGCES3.js → polar-5DRGTXNR.js} +19 -17
  73. package/dist/{posthog-VXQHBSMB.js → posthog-3DTHFCKE.js} +29 -24
  74. package/dist/{postmark-YLIPF52S.js → postmark-ME2V2XXI.js} +19 -17
  75. package/dist/{prerender-CRY7UJN5.js → prerender-5EAY7GDM.js} +4 -4
  76. package/dist/{pubmed-3Z4T5AM7.js → pubmed-GRQUBGVA.js} +3 -3
  77. package/dist/{railway-BP37IGFL.js → railway-FTM75TMX.js} +3 -3
  78. package/dist/{readwise-HTKICF4K.js → readwise-IJQGV6IQ.js} +16 -15
  79. package/dist/{render-WIVTUXJH.js → render-TMSPHRTY.js} +21 -20
  80. package/dist/{replicate-JJYPA43D.js → replicate-RJCMDB7H.js} +20 -21
  81. package/dist/{resend-TKHZVG7A.js → resend-YYN22NIL.js} +15 -11
  82. package/dist/{rootly-FRSZLG5U.js → rootly-7RXE4K7L.js} +19 -18
  83. package/dist/{scrapfly-M5WXGQWE.js → scrapfly-ZJJ6XM4Q.js} +4 -4
  84. package/dist/{scrapingbee-PMXNLLBK.js → scrapingbee-QNGEOD6D.js} +4 -4
  85. package/dist/{screenshot_fyi-HFW4TAOH.js → screenshot_fyi-SPZAABVD.js} +4 -4
  86. package/dist/{semantic_scholar-KXVH2VZQ.js → semantic_scholar-SDPVGDDI.js} +21 -20
  87. package/dist/{sentry-WWOT2LRX.js → sentry-SJ5NN4C4.js} +22 -19
  88. package/dist/{shodan-FY635H35.js → shodan-YMGOY7KW.js} +4 -4
  89. package/dist/{shopify-HQLBVSA5.js → shopify-SU5ABP54.js} +23 -19
  90. package/dist/{stripe-GJN2GOHB.js → stripe-JAC425KE.js} +3 -3
  91. package/dist/{supabase-BBNZGQU6.js → supabase-GQ2OFVIL.js} +18 -17
  92. package/dist/{tavily-DPENIBOG.js → tavily-Y7MDA5CI.js} +20 -20
  93. package/dist/{telegram-L4NONG6H.js → telegram-OIDT3ZLH.js} +4 -4
  94. package/dist/{telnyx-H67MAEZS.js → telnyx-4JGMC3K7.js} +19 -19
  95. package/dist/{todoist-G2BSP4DX.js → todoist-O7S2OUGX.js} +18 -17
  96. package/dist/{trello-7WMVFDG2.js → trello-3LDE4TAQ.js} +4 -4
  97. package/dist/{turso-ZUAESFC2.js → turso-MUQ44KCA.js} +23 -30
  98. package/dist/{twilio-EYFYIX3B.js → twilio-VYF3HUU6.js} +3 -3
  99. package/dist/{umami-AXAUDUVF.js → umami-SVQIK26J.js} +23 -28
  100. package/dist/{unsplash-UCQAWPLR.js → unsplash-333XYDCJ.js} +19 -18
  101. package/dist/{upstash_redis-ZPZ4ASU6.js → upstash_redis-IUM2HDLU.js} +17 -13
  102. package/dist/{uptimerobot-4QVKKUD5.js → uptimerobot-7ZRU2NJV.js} +3 -3
  103. package/dist/{v2ex-VGEFJTYC.js → v2ex-AVSJCQPS.js} +35 -18
  104. package/dist/{vercel-JME4TSCN.js → vercel-J7RGXNSA.js} +21 -18
  105. package/dist/{wolfram_alpha_api-TRGU2MDG.js → wolfram_alpha_api-6CRVUZOJ.js} +4 -4
  106. package/dist/{wordpress-WRUKLCZR.js → wordpress-THOJLPKA.js} +21 -17
  107. package/dist/{workos-ZDW4EHS4.js → workos-ENTGRWF2.js} +26 -27
  108. package/dist/{zhihu-4VI67CWU.js → zhihu-W2BXICTX.js} +21 -21
  109. package/package.json +3 -3
@@ -1328,16 +1328,16 @@ function cleanEnum(obj) {
1328
1328
  }
1329
1329
  function base64ToUint8Array(base644) {
1330
1330
  const binaryString = atob(base644);
1331
- const bytes = new Uint8Array(binaryString.length);
1331
+ const bytes2 = new Uint8Array(binaryString.length);
1332
1332
  for (let i = 0; i < binaryString.length; i++) {
1333
- bytes[i] = binaryString.charCodeAt(i);
1333
+ bytes2[i] = binaryString.charCodeAt(i);
1334
1334
  }
1335
- return bytes;
1335
+ return bytes2;
1336
1336
  }
1337
- function uint8ArrayToBase64(bytes) {
1337
+ function uint8ArrayToBase64(bytes2) {
1338
1338
  let binaryString = "";
1339
- for (let i = 0; i < bytes.length; i++) {
1340
- binaryString += String.fromCharCode(bytes[i]);
1339
+ for (let i = 0; i < bytes2.length; i++) {
1340
+ binaryString += String.fromCharCode(bytes2[i]);
1341
1341
  }
1342
1342
  return btoa(binaryString);
1343
1343
  }
@@ -1346,22 +1346,22 @@ function base64urlToUint8Array(base64url3) {
1346
1346
  const padding = "=".repeat((4 - base644.length % 4) % 4);
1347
1347
  return base64ToUint8Array(base644 + padding);
1348
1348
  }
1349
- function uint8ArrayToBase64url(bytes) {
1350
- return uint8ArrayToBase64(bytes).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
1349
+ function uint8ArrayToBase64url(bytes2) {
1350
+ return uint8ArrayToBase64(bytes2).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
1351
1351
  }
1352
1352
  function hexToUint8Array(hex3) {
1353
1353
  const cleanHex = hex3.replace(/^0x/, "");
1354
1354
  if (cleanHex.length % 2 !== 0) {
1355
1355
  throw new Error("Invalid hex string length");
1356
1356
  }
1357
- const bytes = new Uint8Array(cleanHex.length / 2);
1357
+ const bytes2 = new Uint8Array(cleanHex.length / 2);
1358
1358
  for (let i = 0; i < cleanHex.length; i += 2) {
1359
- bytes[i / 2] = Number.parseInt(cleanHex.slice(i, i + 2), 16);
1359
+ bytes2[i / 2] = Number.parseInt(cleanHex.slice(i, i + 2), 16);
1360
1360
  }
1361
- return bytes;
1361
+ return bytes2;
1362
1362
  }
1363
- function uint8ArrayToHex(bytes) {
1364
- return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
1363
+ function uint8ArrayToHex(bytes2) {
1364
+ return Array.from(bytes2).map((b) => b.toString(16).padStart(2, "0")).join("");
1365
1365
  }
1366
1366
  var Class = class {
1367
1367
  constructor(..._args) {
@@ -14609,6 +14609,20 @@ function canonicalizePath(path) {
14609
14609
  if (norm === "") return "";
14610
14610
  return norm.split("/").map((seg) => canonicalizeSegment(seg)).join("/");
14611
14611
  }
14612
+ function assertNoCollision(names, context) {
14613
+ const seen = /* @__PURE__ */ new Map();
14614
+ for (const name of names) {
14615
+ const lower = name.toLowerCase();
14616
+ const prev = seen.get(lower);
14617
+ if (prev !== void 0 && prev !== name) {
14618
+ throw new TBError(
14619
+ "invalid_argument",
14620
+ `${context}:\u6807\u8BC6\u7B26 '${prev}' \u4E0E '${name}' \u5C0F\u5199\u89C4\u8303\u5316\u540E\u51B2\u7A81`
14621
+ );
14622
+ }
14623
+ seen.set(lower, name);
14624
+ }
14625
+ }
14612
14626
  function segments(path) {
14613
14627
  const p = normalizePath(path);
14614
14628
  return p === "" ? [] : p.split("/");
@@ -14682,10 +14696,10 @@ function normalizeAnnotationPath(path) {
14682
14696
  return norm;
14683
14697
  }
14684
14698
  var AnnotationStore = class {
14699
+ store;
14685
14700
  constructor(store) {
14686
14701
  this.store = store;
14687
14702
  }
14688
- store;
14689
14703
  keyOf(path) {
14690
14704
  return KEY_ANNOTATION + path;
14691
14705
  }
@@ -14823,7 +14837,7 @@ var SYSTEM_AUTO = "system:auto";
14823
14837
  var RESERVED_ROOTS = ["system", "ui"];
14824
14838
 
14825
14839
  // ../core/src/auth/registerPath.ts
14826
- var segments3 = (path) => path.split("/").filter((s) => s.length > 0);
14840
+ var foldedSegments = (path) => segments(path).map((seg) => seg.toLowerCase());
14827
14841
  function isUnderPrefix(target, prefix) {
14828
14842
  if (prefix.length > target.length) return false;
14829
14843
  return prefix.every((seg, i) => seg === target[i]);
@@ -14834,7 +14848,7 @@ var deny = (message) => ({
14834
14848
  });
14835
14849
  function checkRegisterPath(input) {
14836
14850
  const { sk, targetPath, existing, reservedRoots = [] } = input;
14837
- const target = segments3(targetPath);
14851
+ const target = foldedSegments(targetPath);
14838
14852
  if (target.some((seg) => seg.startsWith("~"))) {
14839
14853
  return {
14840
14854
  allow: false,
@@ -14842,12 +14856,12 @@ function checkRegisterPath(input) {
14842
14856
  };
14843
14857
  }
14844
14858
  if (sk.registerPaths !== void 0) {
14845
- const ok = sk.registerPaths.some((p) => isUnderPrefix(target, segments3(p)));
14859
+ const ok = sk.registerPaths.some((p) => isUnderPrefix(target, foldedSegments(p)));
14846
14860
  if (!ok) {
14847
14861
  return deny(`path '${targetPath}' is outside declared registerPaths`);
14848
14862
  }
14849
14863
  } else {
14850
- const roots = /* @__PURE__ */ new Set([...RESERVED_ROOTS, ...reservedRoots]);
14864
+ const roots = /* @__PURE__ */ new Set([...RESERVED_ROOTS, ...reservedRoots.map((r) => r.toLowerCase())]);
14851
14865
  const head = target[0];
14852
14866
  if (head !== void 0 && roots.has(head)) {
14853
14867
  return deny(`cannot register under reserved root '${head}'`);
@@ -14893,25 +14907,29 @@ function assertSecretRefUse(scopes, config2) {
14893
14907
 
14894
14908
  // ../core/src/encoding/base64url.ts
14895
14909
  var ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
14896
- function base64urlEncode(bytes) {
14910
+ function base64urlEncode(bytes2) {
14897
14911
  let out = "";
14898
- for (let i = 0; i < bytes.length; i += 3) {
14899
- const a = bytes[i] ?? 0;
14900
- const b = bytes[i + 1] ?? 0;
14901
- const c = bytes[i + 2] ?? 0;
14912
+ for (let i = 0; i < bytes2.length; i += 3) {
14913
+ const a = bytes2[i] ?? 0;
14914
+ const b = bytes2[i + 1] ?? 0;
14915
+ const c = bytes2[i + 2] ?? 0;
14902
14916
  const n = a << 16 | b << 8 | c;
14903
14917
  out += ALPHABET[n >>> 18 & 63];
14904
14918
  out += ALPHABET[n >>> 12 & 63];
14905
- if (i + 1 < bytes.length) out += ALPHABET[n >>> 6 & 63];
14906
- if (i + 2 < bytes.length) out += ALPHABET[n & 63];
14919
+ if (i + 1 < bytes2.length) out += ALPHABET[n >>> 6 & 63];
14920
+ if (i + 2 < bytes2.length) out += ALPHABET[n & 63];
14907
14921
  }
14908
14922
  return out;
14909
14923
  }
14924
+ function base64Encode(bytes2) {
14925
+ const url2 = base64urlEncode(bytes2).replaceAll("-", "+").replaceAll("_", "/");
14926
+ return url2 + "=".repeat((4 - url2.length % 4) % 4);
14927
+ }
14910
14928
  function base64urlDecode(input) {
14911
14929
  if (input.length % 4 === 1 || !/^[A-Za-z0-9_-]*$/.test(input)) {
14912
14930
  throw new Error("base64urlDecode: malformed base64url input");
14913
14931
  }
14914
- const bytes = [];
14932
+ const bytes2 = [];
14915
14933
  for (let i = 0; i < input.length; i += 4) {
14916
14934
  const chunk = input.slice(i, i + 4);
14917
14935
  const a = ALPHABET.indexOf(chunk[0] ?? "");
@@ -14919,13 +14937,19 @@ function base64urlDecode(input) {
14919
14937
  const c = chunk.length >= 3 ? ALPHABET.indexOf(chunk[2] ?? "") : 0;
14920
14938
  const d = chunk.length >= 4 ? ALPHABET.indexOf(chunk[3] ?? "") : 0;
14921
14939
  const n = a << 18 | b << 12 | c << 6 | d;
14922
- bytes.push(n >>> 16 & 255);
14923
- if (chunk.length >= 3) bytes.push(n >>> 8 & 255);
14924
- if (chunk.length >= 4) bytes.push(n & 255);
14940
+ bytes2.push(n >>> 16 & 255);
14941
+ if (chunk.length >= 3) bytes2.push(n >>> 8 & 255);
14942
+ if (chunk.length >= 4) bytes2.push(n & 255);
14925
14943
  }
14926
- return new Uint8Array(bytes);
14944
+ return new Uint8Array(bytes2);
14927
14945
  }
14928
14946
 
14947
+ // ../core/src/webGlobals.ts
14948
+ var g = globalThis;
14949
+ var crypto = g.crypto;
14950
+ var TextDecoder2 = g.TextDecoder;
14951
+ var TextEncoder = g.TextEncoder;
14952
+
14929
14953
  // ../core/src/omit.ts
14930
14954
  function omit2(obj, ...keys) {
14931
14955
  const rest = { ...obj };
@@ -14942,8 +14966,8 @@ async function sha256Hex(text) {
14942
14966
  return Array.from(new Uint8Array(digest), (b) => b.toString(16).padStart(2, "0")).join("");
14943
14967
  }
14944
14968
  function generateSecret() {
14945
- const bytes = crypto.getRandomValues(new Uint8Array(16));
14946
- return `${SECRET_PREFIX}${base64urlEncode(bytes)}`;
14969
+ const bytes2 = crypto.getRandomValues(new Uint8Array(16));
14970
+ return `${SECRET_PREFIX}${base64urlEncode(bytes2)}`;
14947
14971
  }
14948
14972
  function normalizeExpiresAt(value) {
14949
14973
  const parsed = ISO_TIMESTAMP.safeParse(value);
@@ -15000,10 +15024,10 @@ function clampLimit(limit) {
15000
15024
  return Math.min(Math.max(1, limit), LIST_LIMIT_MAX);
15001
15025
  }
15002
15026
  var SKRegistryStore = class {
15027
+ store;
15003
15028
  constructor(store) {
15004
15029
  this.store = store;
15005
15030
  }
15006
- store;
15007
15031
  async recordById(id) {
15008
15032
  const hash2 = await this.store.get(KEY_SK_ID + id);
15009
15033
  if (typeof hash2 !== "string") return null;
@@ -15014,10 +15038,17 @@ var SKRegistryStore = class {
15014
15038
  const listOpts = { limit: clampLimit(opts?.limit) };
15015
15039
  if (opts?.cursor !== void 0) listOpts.cursor = opts.cursor;
15016
15040
  const page = await this.store.list(KEY_SK_ID, listOpts);
15041
+ const hashes = page.items.map(({ value }) => value).filter((value) => typeof value === "string");
15042
+ const records = /* @__PURE__ */ new Map();
15043
+ for (let i = 0; i < hashes.length; i += 100) {
15044
+ const chunk = await this.store.getMany(
15045
+ hashes.slice(i, i + 100).map((hash2) => KEY_SK_HASH + hash2)
15046
+ );
15047
+ for (const [key, value] of chunk) records.set(key, value);
15048
+ }
15017
15049
  const items = [];
15018
- for (const { value } of page.items) {
15019
- if (typeof value !== "string") continue;
15020
- const rec = await this.store.get(KEY_SK_HASH + value);
15050
+ for (const hash2 of hashes) {
15051
+ const rec = records.get(KEY_SK_HASH + hash2);
15021
15052
  if (rec) items.push(projectKey(rec));
15022
15053
  }
15023
15054
  return page.cursor !== void 0 ? { items, cursor: page.cursor } : { items };
@@ -15115,6 +15146,7 @@ var OperationRegistry = class {
15115
15146
  const schema = spec.inputSchema !== void 0 ? normalizeSchema(spec.inputSchema) : void 0;
15116
15147
  const toolSpec = { name };
15117
15148
  if (spec.description !== void 0) toolSpec.description = spec.description;
15149
+ if (spec.delivery !== void 0) toolSpec.delivery = spec.delivery;
15118
15150
  if (spec.effect !== void 0) toolSpec.effect = spec.effect;
15119
15151
  if (spec.confirm !== void 0) toolSpec.confirm = spec.confirm;
15120
15152
  if (schema !== void 0) toolSpec.inputSchema = toJsonSchema(schema);
@@ -15187,7 +15219,7 @@ var HtbpCommandRegistry = class {
15187
15219
  metadata = /* @__PURE__ */ new Map();
15188
15220
  operations = new OperationRegistry();
15189
15221
  register(name, spec, handler) {
15190
- const { h, returns, scope, ...operationSpec } = spec;
15222
+ const { h, hostOnly, returns, scope, ...operationSpec } = spec;
15191
15223
  this.operations.register(
15192
15224
  name,
15193
15225
  { ...operationSpec, description: h },
@@ -15195,6 +15227,7 @@ var HtbpCommandRegistry = class {
15195
15227
  );
15196
15228
  this.metadata.set(name, {
15197
15229
  scope,
15230
+ ...hostOnly !== void 0 ? { hostOnly } : {},
15198
15231
  ...returns !== void 0 ? { returns } : {}
15199
15232
  });
15200
15233
  return this;
@@ -15208,6 +15241,10 @@ var HtbpCommandRegistry = class {
15208
15241
  scopeFor(name) {
15209
15242
  return this.metadata.get(name)?.scope;
15210
15243
  }
15244
+ /** 该命令是否宿主专属扩展(见 {@link HtbpCommandSpec.hostOnly});未注册按 false。 */
15245
+ isHostOnly(name) {
15246
+ return this.metadata.get(name)?.hostOnly === true;
15247
+ }
15211
15248
  commandSpecs(nodePath) {
15212
15249
  return this.operations.list().map((operation) => {
15213
15250
  const metadata = this.metadata.get(operation.name);
@@ -15248,13 +15285,13 @@ var HtbpCommandRegistry = class {
15248
15285
 
15249
15286
  // ../core/src/builtin/commandRegistry.ts
15250
15287
  var BuiltinCommandRegistry = class extends HtbpCommandRegistry {
15288
+ moduleName;
15289
+ moduleDescription;
15251
15290
  constructor(moduleName, moduleDescription) {
15252
15291
  super();
15253
15292
  this.moduleName = moduleName;
15254
15293
  this.moduleDescription = moduleDescription;
15255
15294
  }
15256
- moduleName;
15257
- moduleDescription;
15258
15295
  help(nodePath) {
15259
15296
  return this.helpModel({
15260
15297
  path: nodePath,
@@ -15461,18 +15498,7 @@ function encodeForm(entries) {
15461
15498
  return [...entries].map(([key, value]) => `${encode3(key)}=${encode3(value)}`).join("&");
15462
15499
  }
15463
15500
  function base643(ascii) {
15464
- const table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
15465
- let out = "";
15466
- for (let i = 0; i < ascii.length; i += 3) {
15467
- const a = ascii.charCodeAt(i);
15468
- const b = i + 1 < ascii.length ? ascii.charCodeAt(i + 1) : Number.NaN;
15469
- const c = i + 2 < ascii.length ? ascii.charCodeAt(i + 2) : Number.NaN;
15470
- out += table[a >> 2];
15471
- out += table[(a & 3) << 4 | (Number.isNaN(b) ? 0 : b >> 4)];
15472
- out += Number.isNaN(b) ? "=" : table[(b & 15) << 2 | (Number.isNaN(c) ? 0 : c >> 6)];
15473
- out += Number.isNaN(c) ? "=" : table[c & 63];
15474
- }
15475
- return out;
15501
+ return base64Encode(Uint8Array.from(ascii, (char) => char.charCodeAt(0)));
15476
15502
  }
15477
15503
  function asRecord(value) {
15478
15504
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
@@ -15663,6 +15689,8 @@ var contextCommands = new HtbpCommandRegistry().register(
15663
15689
  "create_upload",
15664
15690
  {
15665
15691
  h: "create a short-lived, path-scoped direct-upload grant; persist the returned uri, not url",
15692
+ // 宿主专属扩展:仅在底层具备直传签名能力时由宿主装配,不进基础动词表。
15693
+ hostOnly: true,
15666
15694
  inputSchema: external_exports.strictObject({
15667
15695
  path: external_exports.string().describe("target entry path inside the namespace"),
15668
15696
  contentType: external_exports.string().describe("media type signed into the PUT request"),
@@ -15686,14 +15714,14 @@ function contextScopeForCmd(command) {
15686
15714
  }
15687
15715
  function parseContextCmdArgs(command, args) {
15688
15716
  const normalized = command.toLowerCase();
15689
- if (!contextCommands.has(normalized) || normalized === "create_upload") {
15717
+ if (!contextCommands.has(normalized) || contextCommands.isHostOnly(normalized)) {
15690
15718
  throw new TBError("invalid_argument", `unknown cmd '${command}'`);
15691
15719
  }
15692
15720
  return contextCommands.parse(normalized, args);
15693
15721
  }
15694
15722
  async function dispatchContextCmd(provider, command, args) {
15695
15723
  const normalized = command.toLowerCase();
15696
- if (!contextCommands.has(normalized) || normalized === "create_upload") {
15724
+ if (!contextCommands.has(normalized) || contextCommands.isHostOnly(normalized)) {
15697
15725
  throw new TBError("invalid_argument", `unknown cmd '${command}'`);
15698
15726
  }
15699
15727
  const method = normalized;
@@ -15715,7 +15743,7 @@ async function dispatchContextUploadCmd(args, upload) {
15715
15743
  }
15716
15744
 
15717
15745
  // ../core/src/context/capabilities.ts
15718
- var CONTEXT_METHODS = contextCommands.names().filter((name) => name !== "create_upload");
15746
+ var CONTEXT_METHODS = contextCommands.names().filter((name) => !contextCommands.isHostOnly(name));
15719
15747
  var CONTEXT_WRITE_METHODS = CONTEXT_METHODS.filter((method) => contextCommands.scopeFor(method) === "write");
15720
15748
  function contextMethodsOf(provider) {
15721
15749
  const methods = /* @__PURE__ */ new Set();
@@ -16502,10 +16530,10 @@ function normalizeAllowHost(raw) {
16502
16530
  return host;
16503
16531
  }
16504
16532
  var RemoteAllowlistStore = class {
16533
+ store;
16505
16534
  constructor(store) {
16506
16535
  this.store = store;
16507
16536
  }
16508
- store;
16509
16537
  /** 读全部运行时条目(缺省/脏值 → 空数组);按 host 升序稳定输出。 */
16510
16538
  async list() {
16511
16539
  const raw = await this.store.get(KEY_REMOTE_ALLOWLIST);
@@ -16617,6 +16645,657 @@ function createFederationModule(deps) {
16617
16645
  return COMMANDS5.module(deps);
16618
16646
  }
16619
16647
 
16648
+ // ../core/src/device/mailbox.ts
16649
+ var KEY_DEVICE_OPERATION = "deviceop:";
16650
+ var DEVICE_OPERATION_STATES = [
16651
+ "queued",
16652
+ "claimed",
16653
+ "succeeded",
16654
+ "rejected",
16655
+ "failed",
16656
+ "result_unknown",
16657
+ "cancelled",
16658
+ "expired"
16659
+ ];
16660
+ var DEFAULT_TTL_SECONDS = 24 * 60 * 60;
16661
+ var MAX_TTL_SECONDS = 7 * 24 * 60 * 60;
16662
+ var DEFAULT_LEASE_SECONDS = 60;
16663
+ var DEFAULT_MAX_PAYLOAD_BYTES = 256 * 1024;
16664
+ var DEFAULT_MAX_PENDING_PER_DEVICE = 1e3;
16665
+ var DEFAULT_TERMINAL_RETENTION_SECONDS = 7 * 24 * 60 * 60;
16666
+ var MAX_CAS_ATTEMPTS = 8;
16667
+ var LIST_LIMIT_DEFAULT2 = 50;
16668
+ var LIST_LIMIT_MAX2 = 200;
16669
+ var HKDF_SALT = new TextEncoder().encode("tool-bridge:device-mailbox:v1");
16670
+ var HKDF_INFO = new TextEncoder().encode("aes-256-gcm:operation-payload-and-result:v1");
16671
+ function mailboxUnavailable(message) {
16672
+ return new TBError("unavailable", message, { retryable: false });
16673
+ }
16674
+ function finiteTimestamp(value) {
16675
+ return typeof value === "string" && Number.isFinite(Date.parse(value));
16676
+ }
16677
+ function nonEmpty(value) {
16678
+ return typeof value === "string" && value !== "";
16679
+ }
16680
+ function positiveInteger(value, fallback, field) {
16681
+ const actual = value ?? fallback;
16682
+ if (!Number.isSafeInteger(actual) || actual < 1) {
16683
+ throw new TBError("invalid_argument", `${field} must be a positive integer`);
16684
+ }
16685
+ return actual;
16686
+ }
16687
+ function clampLimit3(value) {
16688
+ if (value === void 0) return LIST_LIMIT_DEFAULT2;
16689
+ if (!Number.isSafeInteger(value) || value < 1) {
16690
+ throw new TBError("invalid_argument", "limit must be a positive integer");
16691
+ }
16692
+ return Math.min(value, LIST_LIMIT_MAX2);
16693
+ }
16694
+ function isState(value) {
16695
+ return typeof value === "string" && DEVICE_OPERATION_STATES.includes(value);
16696
+ }
16697
+ function isTerminal(state) {
16698
+ return state !== "queued" && state !== "claimed";
16699
+ }
16700
+ function parseEncrypted(value) {
16701
+ if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error("invalid encrypted value");
16702
+ const raw = value;
16703
+ if (raw.v !== 1 || !nonEmpty(raw.iv) || !nonEmpty(raw.ciphertext)) {
16704
+ throw new Error("invalid encrypted value");
16705
+ }
16706
+ return { v: 1, iv: raw.iv, ciphertext: raw.ciphertext };
16707
+ }
16708
+ function parseRecord(value) {
16709
+ try {
16710
+ if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error();
16711
+ const raw = value;
16712
+ if (raw.v !== 1 || !Number.isSafeInteger(raw.revision) || raw.revision < 1 || !nonEmpty(raw.operationId) || !nonEmpty(raw.deviceId) || !nonEmpty(raw.deviceKeyId) || !nonEmpty(raw.mountPath) || !nonEmpty(raw.targetPath) || !nonEmpty(raw.path) || !nonEmpty(raw.callerKeyId) || !nonEmpty(raw.callerOwner) || !nonEmpty(raw.traceId) || !finiteTimestamp(raw.createdAt) || !finiteTimestamp(raw.updatedAt) || !finiteTimestamp(raw.expiresAt) || !isState(raw.state) || !Number.isSafeInteger(raw.attempt) || raw.attempt < 0 || typeof raw.executionMayHaveOccurred !== "boolean") throw new Error();
16713
+ if (raw.leaseId === void 0 !== (raw.leaseUntil === void 0)) throw new Error();
16714
+ if (raw.leaseId !== void 0 && (!nonEmpty(raw.leaseId) || !finiteTimestamp(raw.leaseUntil))) {
16715
+ throw new Error();
16716
+ }
16717
+ if (raw.cancelRequestedAt !== void 0 && !finiteTimestamp(raw.cancelRequestedAt)) throw new Error();
16718
+ if (raw.terminalAt !== void 0 && !finiteTimestamp(raw.terminalAt)) throw new Error();
16719
+ if (isTerminal(raw.state) && raw.terminalAt === void 0) throw new Error();
16720
+ return {
16721
+ v: 1,
16722
+ revision: raw.revision,
16723
+ operationId: raw.operationId,
16724
+ deviceId: raw.deviceId,
16725
+ deviceKeyId: raw.deviceKeyId,
16726
+ mountPath: raw.mountPath,
16727
+ targetPath: raw.targetPath,
16728
+ path: raw.path,
16729
+ callerKeyId: raw.callerKeyId,
16730
+ callerOwner: raw.callerOwner,
16731
+ traceId: raw.traceId,
16732
+ createdAt: raw.createdAt,
16733
+ updatedAt: raw.updatedAt,
16734
+ expiresAt: raw.expiresAt,
16735
+ state: raw.state,
16736
+ attempt: raw.attempt,
16737
+ executionMayHaveOccurred: raw.executionMayHaveOccurred,
16738
+ payload: parseEncrypted(raw.payload),
16739
+ ...raw.leaseId === void 0 ? {} : { leaseId: raw.leaseId, leaseUntil: raw.leaseUntil },
16740
+ ...raw.cancelRequestedAt === void 0 ? {} : { cancelRequestedAt: raw.cancelRequestedAt },
16741
+ ...raw.completedLeaseId === void 0 ? {} : { completedLeaseId: String(raw.completedLeaseId) },
16742
+ ...raw.terminalAt === void 0 ? {} : { terminalAt: raw.terminalAt },
16743
+ ...raw.terminalData === void 0 ? {} : { terminalData: parseEncrypted(raw.terminalData) },
16744
+ ...raw.idempotencyFingerprint === void 0 ? {} : { idempotencyFingerprint: String(raw.idempotencyFingerprint) }
16745
+ };
16746
+ } catch {
16747
+ throw new TBError("internal", "device mailbox record is invalid", { retryable: false });
16748
+ }
16749
+ }
16750
+ function canonicalJson(value) {
16751
+ if (value === null) return "null";
16752
+ if (typeof value === "string" || typeof value === "boolean") return JSON.stringify(value);
16753
+ if (typeof value === "number") {
16754
+ if (!Number.isFinite(value)) throw new TBError("invalid_argument", "mailbox data must be valid JSON");
16755
+ return JSON.stringify(value);
16756
+ }
16757
+ if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
16758
+ if (typeof value !== "object") {
16759
+ throw new TBError("invalid_argument", "mailbox data must be valid JSON");
16760
+ }
16761
+ const object2 = value;
16762
+ const keys = Object.keys(object2).sort();
16763
+ return `{${keys.map((key) => `${JSON.stringify(key)}:${canonicalJson(object2[key])}`).join(",")}}`;
16764
+ }
16765
+ function safeError(value) {
16766
+ if (typeof value !== "object" || value === null || typeof value.code !== "string" || typeof value.message !== "string" || typeof value.retryable !== "boolean") throw new TBError("invalid_argument", "completion error is invalid");
16767
+ return { code: value.code, message: value.message, retryable: value.retryable };
16768
+ }
16769
+ function normalizeCompletion(value) {
16770
+ if (value.outcome === "succeeded") {
16771
+ canonicalJson(value.result);
16772
+ return { outcome: "succeeded", result: value.result };
16773
+ }
16774
+ if (value.outcome === "rejected" || value.outcome === "failed") {
16775
+ return { outcome: value.outcome, error: safeError(value.error) };
16776
+ }
16777
+ return {
16778
+ outcome: "result_unknown",
16779
+ ...value.error === void 0 ? {} : { error: safeError(value.error) }
16780
+ };
16781
+ }
16782
+ function bytes(value) {
16783
+ return new TextEncoder().encode(value).byteLength;
16784
+ }
16785
+ function randomId(randomBytes) {
16786
+ const value = randomBytes(18);
16787
+ if (!(value instanceof Uint8Array) || value.length !== 18) {
16788
+ throw mailboxUnavailable("device mailbox randomness is unavailable");
16789
+ }
16790
+ return `dop_${base64urlEncode(value)}`;
16791
+ }
16792
+ async function digestBytes(value) {
16793
+ return new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value)));
16794
+ }
16795
+ async function deterministicOperationId(binding) {
16796
+ return `dop_${base64urlEncode((await digestBytes(binding)).slice(0, 18))}`;
16797
+ }
16798
+ async function devicePrefix(deviceId) {
16799
+ return `${KEY_DEVICE_OPERATION}${await sha256Hex(deviceId)}:`;
16800
+ }
16801
+ async function stateKey(deviceId, operationId) {
16802
+ if (!/^dop_[A-Za-z0-9_-]{24}$/.test(operationId)) {
16803
+ throw new TBError("invalid_argument", "operationId is invalid");
16804
+ }
16805
+ return await devicePrefix(deviceId) + operationId;
16806
+ }
16807
+ var DeviceMailboxCipher = class {
16808
+ root;
16809
+ keyPromise;
16810
+ constructor(masterKey) {
16811
+ let decoded;
16812
+ try {
16813
+ decoded = base64urlDecode(masterKey);
16814
+ } catch {
16815
+ throw mailboxUnavailable("device mailbox encryption key is invalid");
16816
+ }
16817
+ if (decoded.length !== 32) {
16818
+ throw mailboxUnavailable("device mailbox encryption key is invalid");
16819
+ }
16820
+ this.root = decoded;
16821
+ }
16822
+ key() {
16823
+ this.keyPromise ??= (async () => {
16824
+ const rootKey = await crypto.subtle.importKey("raw", this.root, "HKDF", false, ["deriveKey"]);
16825
+ return await crypto.subtle.deriveKey(
16826
+ { name: "HKDF", hash: "SHA-256", salt: HKDF_SALT, info: HKDF_INFO },
16827
+ rootKey,
16828
+ { name: "AES-GCM", length: 256 },
16829
+ false,
16830
+ ["encrypt", "decrypt"]
16831
+ );
16832
+ })();
16833
+ return this.keyPromise;
16834
+ }
16835
+ async encrypt(operationId, field, value) {
16836
+ const plaintext = canonicalJson(value);
16837
+ const iv = crypto.getRandomValues(new Uint8Array(12));
16838
+ const additionalData = new TextEncoder().encode(`tool-bridge:device-mailbox:v1:${operationId}:${field}`);
16839
+ const ciphertext = await crypto.subtle.encrypt(
16840
+ { name: "AES-GCM", iv, additionalData },
16841
+ await this.key(),
16842
+ new TextEncoder().encode(plaintext)
16843
+ );
16844
+ return {
16845
+ v: 1,
16846
+ iv: base64urlEncode(iv),
16847
+ ciphertext: base64urlEncode(new Uint8Array(ciphertext))
16848
+ };
16849
+ }
16850
+ async decrypt(operationId, field, value) {
16851
+ try {
16852
+ const iv = base64urlDecode(value.iv);
16853
+ const ciphertext = base64urlDecode(value.ciphertext);
16854
+ if (iv.length !== 12) throw new Error("invalid iv");
16855
+ const additionalData = new TextEncoder().encode(`tool-bridge:device-mailbox:v1:${operationId}:${field}`);
16856
+ const plaintext = await crypto.subtle.decrypt(
16857
+ { name: "AES-GCM", iv, additionalData },
16858
+ await this.key(),
16859
+ ciphertext
16860
+ );
16861
+ return JSON.parse(new TextDecoder2().decode(plaintext));
16862
+ } catch {
16863
+ throw new TBError("internal", "device mailbox data cannot be decrypted", { retryable: false });
16864
+ }
16865
+ }
16866
+ };
16867
+ var DeviceMailboxService = class {
16868
+ cas;
16869
+ cipher;
16870
+ defaultTtlSeconds;
16871
+ leaseSeconds;
16872
+ maxPayloadBytes;
16873
+ maxPendingPerDevice;
16874
+ maxTtlSeconds;
16875
+ now;
16876
+ randomBytes;
16877
+ state;
16878
+ terminalRetentionSeconds;
16879
+ constructor(state, encryptionRoot, opts = {}) {
16880
+ if (state.compareAndSwap === void 0) {
16881
+ throw mailboxUnavailable("device mailbox requires StateStore.compareAndSwap");
16882
+ }
16883
+ if (encryptionRoot === void 0) {
16884
+ throw mailboxUnavailable("device mailbox requires TB_SECRET_ENCRYPTION_KEY");
16885
+ }
16886
+ this.cas = state.compareAndSwap.bind(state);
16887
+ this.state = state;
16888
+ this.cipher = new DeviceMailboxCipher(encryptionRoot);
16889
+ this.defaultTtlSeconds = positiveInteger(
16890
+ opts.defaultTtlSeconds,
16891
+ DEFAULT_TTL_SECONDS,
16892
+ "defaultTtlSeconds"
16893
+ );
16894
+ this.maxTtlSeconds = positiveInteger(opts.maxTtlSeconds, MAX_TTL_SECONDS, "maxTtlSeconds");
16895
+ if (this.defaultTtlSeconds > this.maxTtlSeconds) {
16896
+ throw new TBError("invalid_argument", "defaultTtlSeconds cannot exceed maxTtlSeconds");
16897
+ }
16898
+ this.leaseSeconds = positiveInteger(opts.leaseSeconds, DEFAULT_LEASE_SECONDS, "leaseSeconds");
16899
+ this.maxPayloadBytes = positiveInteger(
16900
+ opts.maxPayloadBytes,
16901
+ DEFAULT_MAX_PAYLOAD_BYTES,
16902
+ "maxPayloadBytes"
16903
+ );
16904
+ this.maxPendingPerDevice = positiveInteger(
16905
+ opts.maxPendingPerDevice,
16906
+ DEFAULT_MAX_PENDING_PER_DEVICE,
16907
+ "maxPendingPerDevice"
16908
+ );
16909
+ this.terminalRetentionSeconds = positiveInteger(
16910
+ opts.terminalRetentionSeconds,
16911
+ DEFAULT_TERMINAL_RETENTION_SECONDS,
16912
+ "terminalRetentionSeconds"
16913
+ );
16914
+ this.now = opts.now ?? (() => Date.now());
16915
+ this.randomBytes = opts.randomBytes ?? ((length) => crypto.getRandomValues(new Uint8Array(length)));
16916
+ }
16917
+ nowIso() {
16918
+ return new Date(this.now()).toISOString();
16919
+ }
16920
+ async read(deviceId, operationId) {
16921
+ const key = await stateKey(deviceId, operationId);
16922
+ const value = await this.state.get(key);
16923
+ if (value === null) throw TBError.notFound("device operation not found");
16924
+ const record2 = parseRecord(value);
16925
+ if (record2.deviceId !== deviceId || record2.operationId !== operationId) {
16926
+ throw new TBError("internal", "device mailbox record identity mismatch", { retryable: false });
16927
+ }
16928
+ return { key, record: record2 };
16929
+ }
16930
+ summary(record2) {
16931
+ return {
16932
+ operationId: record2.operationId,
16933
+ deviceId: record2.deviceId,
16934
+ mountPath: record2.mountPath,
16935
+ targetPath: record2.targetPath,
16936
+ caller: { keyId: record2.callerKeyId, owner: record2.callerOwner },
16937
+ traceId: record2.traceId,
16938
+ createdAt: record2.createdAt,
16939
+ updatedAt: record2.updatedAt,
16940
+ expiresAt: record2.expiresAt,
16941
+ state: record2.state,
16942
+ attempt: record2.attempt,
16943
+ executionMayHaveOccurred: record2.executionMayHaveOccurred,
16944
+ ...record2.leaseUntil === void 0 ? {} : { leaseUntil: record2.leaseUntil },
16945
+ ...record2.cancelRequestedAt === void 0 ? {} : { cancelRequestedAt: record2.cancelRequestedAt },
16946
+ ...record2.terminalAt === void 0 ? {} : { terminalAt: record2.terminalAt }
16947
+ };
16948
+ }
16949
+ async detail(record2) {
16950
+ const summary = this.summary(record2);
16951
+ if (record2.terminalData === void 0) return summary;
16952
+ const terminal = await this.cipher.decrypt(
16953
+ record2.operationId,
16954
+ "terminal",
16955
+ record2.terminalData
16956
+ );
16957
+ if (record2.state === "succeeded") return { ...summary, result: terminal.result };
16958
+ const error51 = terminal.error;
16959
+ if (error51 === void 0) return summary;
16960
+ return { ...summary, error: safeError(error51) };
16961
+ }
16962
+ async expireRecord(key, record2) {
16963
+ let current = record2;
16964
+ for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {
16965
+ if (isTerminal(current.state) || Date.parse(current.expiresAt) > this.now()) return current;
16966
+ const now = this.nowIso();
16967
+ const next = {
16968
+ ...current,
16969
+ revision: current.revision + 1,
16970
+ state: "expired",
16971
+ updatedAt: now,
16972
+ terminalAt: now,
16973
+ executionMayHaveOccurred: current.state === "claimed"
16974
+ };
16975
+ if (await this.cas(key, current.revision, next)) return next;
16976
+ const winner = await this.state.get(key);
16977
+ if (winner === null) throw TBError.notFound("device operation not found");
16978
+ current = parseRecord(winner);
16979
+ }
16980
+ throw new TBError("unavailable", "device operation expiry is busy", { retryable: true });
16981
+ }
16982
+ async enforcePendingCap(deviceId) {
16983
+ const prefix = await devicePrefix(deviceId);
16984
+ let cursor;
16985
+ let pending = 0;
16986
+ do {
16987
+ const page = await this.state.list(prefix, {
16988
+ limit: LIST_LIMIT_MAX2,
16989
+ ...cursor === void 0 ? {} : { cursor }
16990
+ });
16991
+ for (const item of page.items) {
16992
+ let record2 = parseRecord(item.value);
16993
+ if (record2.deviceId !== deviceId) continue;
16994
+ record2 = await this.expireRecord(item.key, record2);
16995
+ if (!isTerminal(record2.state)) pending++;
16996
+ if (pending >= this.maxPendingPerDevice) {
16997
+ throw new TBError("rate_limited", "device mailbox pending limit reached", {
16998
+ retryable: true
16999
+ });
17000
+ }
17001
+ }
17002
+ cursor = page.cursor;
17003
+ } while (cursor !== void 0);
17004
+ }
17005
+ async enqueue(input) {
17006
+ const ttlSeconds = input.ttlSeconds ?? this.defaultTtlSeconds;
17007
+ if (!Number.isSafeInteger(ttlSeconds) || ttlSeconds < 1 || ttlSeconds > this.maxTtlSeconds) {
17008
+ throw new TBError("invalid_argument", `ttlSeconds must be between 1 and ${this.maxTtlSeconds}`);
17009
+ }
17010
+ const payloadText = canonicalJson({ arguments: input.arguments });
17011
+ if (bytes(payloadText) > this.maxPayloadBytes) {
17012
+ throw new TBError("rate_limited", "device mailbox payload is too large", { retryable: false });
17013
+ }
17014
+ if (input.idempotencyKey !== void 0 && (input.idempotencyKey.length < 1 || input.idempotencyKey.length > 255 || /[\r\n\0]/.test(input.idempotencyKey))) throw new TBError("invalid_argument", "idempotency key is invalid");
17015
+ const binding = input.idempotencyKey === void 0 ? void 0 : canonicalJson({
17016
+ callerOwner: input.caller.owner,
17017
+ deviceId: input.deviceId,
17018
+ targetPath: input.targetPath,
17019
+ idempotencyKey: input.idempotencyKey
17020
+ });
17021
+ const operationId = binding === void 0 ? randomId(this.randomBytes) : await deterministicOperationId(binding);
17022
+ const fingerprint = binding === void 0 ? void 0 : await sha256Hex(canonicalJson({
17023
+ arguments: input.arguments,
17024
+ deviceKeyId: input.deviceKeyId,
17025
+ path: input.path,
17026
+ ttlSeconds
17027
+ }));
17028
+ const key = await stateKey(input.deviceId, operationId);
17029
+ if (binding !== void 0) {
17030
+ const existing2 = await this.state.get(key);
17031
+ if (existing2 !== null) {
17032
+ const record3 = parseRecord(existing2);
17033
+ if (record3.callerOwner !== input.caller.owner || record3.deviceId !== input.deviceId || record3.targetPath !== input.targetPath || record3.idempotencyFingerprint !== fingerprint) throw new TBError("conflict", "idempotency key is bound to another operation");
17034
+ return await this.detail(record3);
17035
+ }
17036
+ }
17037
+ await this.enforcePendingCap(input.deviceId);
17038
+ const now = this.nowIso();
17039
+ const record2 = {
17040
+ v: 1,
17041
+ revision: 1,
17042
+ operationId,
17043
+ deviceId: input.deviceId,
17044
+ deviceKeyId: input.deviceKeyId,
17045
+ mountPath: input.mountPath,
17046
+ targetPath: input.targetPath,
17047
+ path: input.path,
17048
+ callerKeyId: input.caller.keyId,
17049
+ callerOwner: input.caller.owner,
17050
+ traceId: input.traceId,
17051
+ createdAt: now,
17052
+ updatedAt: now,
17053
+ expiresAt: new Date(this.now() + ttlSeconds * 1e3).toISOString(),
17054
+ state: "queued",
17055
+ attempt: 0,
17056
+ executionMayHaveOccurred: false,
17057
+ payload: await this.cipher.encrypt(operationId, "payload", { arguments: input.arguments }),
17058
+ ...fingerprint === void 0 ? {} : { idempotencyFingerprint: fingerprint }
17059
+ };
17060
+ if (await this.cas(key, null, record2)) return await this.detail(record2);
17061
+ if (binding === void 0) {
17062
+ throw new TBError("conflict", "device operation id collision", { retryable: true });
17063
+ }
17064
+ const winner = await this.state.get(key);
17065
+ if (winner === null) throw new TBError("conflict", "device operation enqueue conflicted");
17066
+ const existing = parseRecord(winner);
17067
+ if (existing.idempotencyFingerprint !== fingerprint) {
17068
+ throw new TBError("conflict", "idempotency key is bound to another operation");
17069
+ }
17070
+ return await this.detail(existing);
17071
+ }
17072
+ async get(deviceId, operationId) {
17073
+ const { key, record: record2 } = await this.read(deviceId, operationId);
17074
+ return await this.detail(await this.expireRecord(key, record2));
17075
+ }
17076
+ async list(input) {
17077
+ const limit = clampLimit3(input.limit);
17078
+ const states = input.states === void 0 ? void 0 : new Set(input.states);
17079
+ if (states !== void 0 && [...states].some((state) => !isState(state))) {
17080
+ throw new TBError("invalid_argument", "states contains an invalid operation state");
17081
+ }
17082
+ const page = await this.state.list(await devicePrefix(input.deviceId), {
17083
+ limit,
17084
+ ...input.cursor === void 0 ? {} : { cursor: input.cursor }
17085
+ });
17086
+ const items = [];
17087
+ for (const item of page.items) {
17088
+ let record2 = parseRecord(item.value);
17089
+ if (record2.deviceId !== input.deviceId) continue;
17090
+ record2 = await this.expireRecord(item.key, record2);
17091
+ if (states !== void 0 && !states.has(record2.state)) continue;
17092
+ items.push(this.summary(record2));
17093
+ }
17094
+ return { items, ...page.cursor === void 0 ? {} : { cursor: page.cursor } };
17095
+ }
17096
+ async claim(input) {
17097
+ const serverNow = this.nowIso();
17098
+ const page = await this.state.list(await devicePrefix(input.deviceId), {
17099
+ limit: clampLimit3(input.limit),
17100
+ ...input.cursor === void 0 ? {} : { cursor: input.cursor }
17101
+ });
17102
+ for (const item of page.items) {
17103
+ let record2 = parseRecord(item.value);
17104
+ if (record2.deviceId !== input.deviceId || record2.deviceKeyId !== input.deviceKeyId) continue;
17105
+ record2 = await this.expireRecord(item.key, record2);
17106
+ const reclaimable = record2.state === "claimed" && record2.leaseUntil !== void 0 && Date.parse(record2.leaseUntil) <= this.now();
17107
+ if (record2.state !== "queued" && !reclaimable) continue;
17108
+ await input.authorize?.({
17109
+ deviceId: record2.deviceId,
17110
+ deviceKeyId: record2.deviceKeyId,
17111
+ mountPath: record2.mountPath,
17112
+ targetPath: record2.targetPath
17113
+ });
17114
+ const leaseId = randomId(this.randomBytes);
17115
+ const leaseUntil = new Date(Math.min(
17116
+ this.now() + this.leaseSeconds * 1e3,
17117
+ Date.parse(record2.expiresAt)
17118
+ )).toISOString();
17119
+ const next = {
17120
+ ...record2,
17121
+ revision: record2.revision + 1,
17122
+ state: "claimed",
17123
+ attempt: record2.attempt + 1,
17124
+ leaseId,
17125
+ leaseUntil,
17126
+ updatedAt: serverNow
17127
+ };
17128
+ if (!await this.cas(item.key, record2.revision, next)) continue;
17129
+ const payload = await this.cipher.decrypt(
17130
+ record2.operationId,
17131
+ "payload",
17132
+ record2.payload
17133
+ );
17134
+ if (typeof payload !== "object" || payload === null || typeof payload.arguments !== "object" || payload.arguments === null || Array.isArray(payload.arguments)) throw new TBError("internal", "device mailbox payload is invalid", { retryable: false });
17135
+ return {
17136
+ serverNow,
17137
+ ...page.cursor === void 0 ? {} : { cursor: page.cursor },
17138
+ operation: {
17139
+ operationId: next.operationId,
17140
+ targetPath: next.targetPath,
17141
+ path: next.path,
17142
+ arguments: payload.arguments,
17143
+ caller: { keyId: next.callerKeyId, owner: next.callerOwner },
17144
+ traceId: next.traceId,
17145
+ createdAt: next.createdAt,
17146
+ expiresAt: next.expiresAt,
17147
+ attempt: next.attempt,
17148
+ leaseId,
17149
+ leaseUntil,
17150
+ ...next.cancelRequestedAt === void 0 ? {} : { cancelRequestedAt: next.cancelRequestedAt }
17151
+ }
17152
+ };
17153
+ }
17154
+ return {
17155
+ serverNow,
17156
+ ...page.cursor === void 0 ? {} : { cursor: page.cursor }
17157
+ };
17158
+ }
17159
+ async activeLease(input) {
17160
+ const current = await this.read(input.deviceId, input.operationId);
17161
+ const record2 = await this.expireRecord(current.key, current.record);
17162
+ if (record2.deviceKeyId !== input.deviceKeyId || record2.state !== "claimed" || record2.leaseId !== input.leaseId || record2.leaseUntil === void 0 || Date.parse(record2.leaseUntil) <= this.now()) throw new TBError("conflict", "device operation lease is no longer active");
17163
+ await input.authorize?.({
17164
+ deviceId: record2.deviceId,
17165
+ deviceKeyId: record2.deviceKeyId,
17166
+ mountPath: record2.mountPath,
17167
+ targetPath: record2.targetPath
17168
+ });
17169
+ return { key: current.key, record: record2 };
17170
+ }
17171
+ async renew(input) {
17172
+ for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {
17173
+ const { key, record: record2 } = await this.activeLease(input);
17174
+ const serverNow = this.nowIso();
17175
+ const leaseUntil = new Date(Math.min(
17176
+ this.now() + this.leaseSeconds * 1e3,
17177
+ Date.parse(record2.expiresAt)
17178
+ )).toISOString();
17179
+ const next = {
17180
+ ...record2,
17181
+ revision: record2.revision + 1,
17182
+ leaseUntil,
17183
+ updatedAt: serverNow
17184
+ };
17185
+ if (await this.cas(key, record2.revision, next)) {
17186
+ return {
17187
+ serverNow,
17188
+ leaseUntil,
17189
+ ...next.cancelRequestedAt === void 0 ? {} : { cancelRequestedAt: next.cancelRequestedAt }
17190
+ };
17191
+ }
17192
+ }
17193
+ throw new TBError("unavailable", "device operation lease is busy", { retryable: true });
17194
+ }
17195
+ async complete(input, completionInput) {
17196
+ const completion = normalizeCompletion(completionInput);
17197
+ const terminalData = completion.outcome === "succeeded" ? { result: completion.result } : completion.error === void 0 ? {} : { error: completion.error };
17198
+ if (bytes(canonicalJson(terminalData)) > this.maxPayloadBytes) {
17199
+ throw new TBError("rate_limited", "device mailbox terminal payload is too large", {
17200
+ retryable: false
17201
+ });
17202
+ }
17203
+ for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {
17204
+ const current = await this.read(input.deviceId, input.operationId);
17205
+ let record2 = await this.expireRecord(current.key, current.record);
17206
+ if (record2.deviceKeyId !== input.deviceKeyId) {
17207
+ throw new TBError("conflict", "device operation credential does not match");
17208
+ }
17209
+ await input.authorize?.({
17210
+ deviceId: record2.deviceId,
17211
+ deviceKeyId: record2.deviceKeyId,
17212
+ mountPath: record2.mountPath,
17213
+ targetPath: record2.targetPath
17214
+ });
17215
+ if (isTerminal(record2.state)) {
17216
+ if (record2.completedLeaseId !== input.leaseId || record2.state !== completion.outcome || record2.terminalData === void 0) throw new TBError("conflict", "device operation is already terminal");
17217
+ const existing = await this.cipher.decrypt(
17218
+ record2.operationId,
17219
+ "terminal",
17220
+ record2.terminalData
17221
+ );
17222
+ const requested = completion.outcome === "succeeded" ? { result: completion.result } : completion.error === void 0 ? {} : { error: completion.error };
17223
+ if (canonicalJson(existing) !== canonicalJson(requested)) {
17224
+ throw new TBError("conflict", "device operation completion differs from terminal result");
17225
+ }
17226
+ return await this.detail(record2);
17227
+ }
17228
+ const active = await this.activeLease(input);
17229
+ record2 = active.record;
17230
+ const now = this.nowIso();
17231
+ const next = {
17232
+ ...record2,
17233
+ revision: record2.revision + 1,
17234
+ state: completion.outcome,
17235
+ terminalAt: now,
17236
+ terminalData: await this.cipher.encrypt(record2.operationId, "terminal", terminalData),
17237
+ completedLeaseId: input.leaseId,
17238
+ updatedAt: now
17239
+ };
17240
+ if (await this.cas(active.key, record2.revision, next)) return await this.detail(next);
17241
+ }
17242
+ throw new TBError("unavailable", "device operation completion is busy", { retryable: true });
17243
+ }
17244
+ async cancel(deviceId, operationId) {
17245
+ for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {
17246
+ const current = await this.read(deviceId, operationId);
17247
+ const record2 = await this.expireRecord(current.key, current.record);
17248
+ if (isTerminal(record2.state) || record2.cancelRequestedAt !== void 0) {
17249
+ return await this.detail(record2);
17250
+ }
17251
+ const now = this.nowIso();
17252
+ const next = record2.state === "queued" ? {
17253
+ ...record2,
17254
+ revision: record2.revision + 1,
17255
+ state: "cancelled",
17256
+ cancelRequestedAt: now,
17257
+ terminalAt: now,
17258
+ updatedAt: now
17259
+ } : {
17260
+ ...record2,
17261
+ revision: record2.revision + 1,
17262
+ cancelRequestedAt: now,
17263
+ updatedAt: now
17264
+ };
17265
+ if (await this.cas(current.key, record2.revision, next)) return await this.detail(next);
17266
+ }
17267
+ throw new TBError("unavailable", "device operation cancellation is busy", { retryable: true });
17268
+ }
17269
+ async cleanup(opts = {}) {
17270
+ const page = await this.state.list(KEY_DEVICE_OPERATION, {
17271
+ limit: clampLimit3(opts.limit),
17272
+ ...opts.cursor === void 0 ? {} : { cursor: opts.cursor }
17273
+ });
17274
+ let deleted = 0;
17275
+ let expired = 0;
17276
+ for (const item of page.items) {
17277
+ let record2;
17278
+ try {
17279
+ record2 = parseRecord(item.value);
17280
+ } catch {
17281
+ continue;
17282
+ }
17283
+ if (!isTerminal(record2.state) && Date.parse(record2.expiresAt) <= this.now()) {
17284
+ const next = await this.expireRecord(item.key, record2);
17285
+ if (next.state === "expired") expired++;
17286
+ record2 = next;
17287
+ }
17288
+ if (isTerminal(record2.state) && record2.terminalAt !== void 0 && Date.parse(record2.terminalAt) + this.terminalRetentionSeconds * 1e3 <= this.now() && await this.cas(item.key, record2.revision, null)) deleted++;
17289
+ }
17290
+ return {
17291
+ scanned: page.items.length,
17292
+ expired,
17293
+ deleted,
17294
+ ...page.cursor === void 0 ? {} : { cursor: page.cursor }
17295
+ };
17296
+ }
17297
+ };
17298
+
16620
17299
  // ../core/src/protocol/errorWire.ts
16621
17300
  var tbErrorCodeSchema = external_exports.enum(TB_ERROR_CODES);
16622
17301
  var tbErrorBodySchema = external_exports.object({
@@ -16663,6 +17342,7 @@ var helpChildSchema = external_exports.object({
16663
17342
  });
16664
17343
  var helpCommandSchema = external_exports.object({
16665
17344
  confirm: external_exports.boolean().optional(),
17345
+ delivery: external_exports.enum(["realtime", "mailbox", "both"]).optional(),
16666
17346
  effect: external_exports.string().optional(),
16667
17347
  h: external_exports.string().optional(),
16668
17348
  inputSchema: external_exports.unknown().optional(),
@@ -16696,6 +17376,7 @@ var treeJsonSchema = external_exports.lazy(() => external_exports.object({
16696
17376
  }));
16697
17377
  var toolSpecSchema = external_exports.object({
16698
17378
  confirm: external_exports.boolean().optional(),
17379
+ delivery: external_exports.enum(["realtime", "mailbox", "both"]).optional(),
16699
17380
  description: external_exports.string().optional(),
16700
17381
  effect: external_exports.string().optional(),
16701
17382
  inputSchema: external_exports.unknown().optional(),
@@ -16733,6 +17414,12 @@ var toolSearchItemSchema = external_exports.strictObject({
16733
17414
  source: toolSearchSourceSchema.optional(),
16734
17415
  tool: toolSpecSchema
16735
17416
  });
17417
+ function pageSchema(itemSchema) {
17418
+ return external_exports.object({
17419
+ cursor: external_exports.string().optional(),
17420
+ items: external_exports.array(itemSchema)
17421
+ });
17422
+ }
16736
17423
  var toolSearchPageSchema = external_exports.strictObject({
16737
17424
  cursor: external_exports.string().optional(),
16738
17425
  items: external_exports.array(toolSearchItemSchema),
@@ -16749,15 +17436,118 @@ var toolSearchRequestSchema = external_exports.strictObject({
16749
17436
  limit: external_exports.number().int().optional(),
16750
17437
  matching: external_exports.enum(["best", "all"]).optional(),
16751
17438
  minCoverage: external_exports.number().gt(0).max(1).optional(),
16752
- mode: external_exports.enum(["keyword", "semantic"]).optional(),
17439
+ mode: external_exports.enum(["keyword"]).optional(),
16753
17440
  pathPrefix: external_exports.string().optional()
16754
17441
  }).optional(),
16755
17442
  query: external_exports.string().trim().min(1)
16756
17443
  });
17444
+ var deviceOperationStateSchema = external_exports.enum(
17445
+ DEVICE_OPERATION_STATES
17446
+ );
17447
+ var deviceOperationCallerSchema = external_exports.object({
17448
+ keyId: external_exports.string().min(1),
17449
+ owner: external_exports.string().min(1)
17450
+ });
17451
+ var deviceOperationSummaryShape = {
17452
+ attempt: external_exports.number().int().nonnegative(),
17453
+ caller: deviceOperationCallerSchema,
17454
+ cancelRequestedAt: external_exports.iso.datetime({ offset: true }).optional(),
17455
+ createdAt: external_exports.iso.datetime({ offset: true }),
17456
+ deviceId: external_exports.string().min(1),
17457
+ executionMayHaveOccurred: external_exports.boolean(),
17458
+ expiresAt: external_exports.iso.datetime({ offset: true }),
17459
+ leaseUntil: external_exports.iso.datetime({ offset: true }).optional(),
17460
+ mountPath: external_exports.string().min(1),
17461
+ operationId: external_exports.string().min(1),
17462
+ state: deviceOperationStateSchema,
17463
+ targetPath: external_exports.string().min(1),
17464
+ terminalAt: external_exports.iso.datetime({ offset: true }).optional(),
17465
+ traceId: external_exports.string().min(1),
17466
+ updatedAt: external_exports.iso.datetime({ offset: true })
17467
+ };
17468
+ var deviceOperationSummarySchema = external_exports.object(
17469
+ deviceOperationSummaryShape
17470
+ );
17471
+ var deviceOperationDetailSchema = external_exports.object({
17472
+ ...deviceOperationSummaryShape,
17473
+ error: tbErrorBodySchema.optional(),
17474
+ result: external_exports.json().optional()
17475
+ });
17476
+ var deviceOperationListRequestSchema = external_exports.strictObject({
17477
+ deviceId: external_exports.string().min(1),
17478
+ opts: external_exports.strictObject({
17479
+ cursor: external_exports.string().min(1).optional(),
17480
+ limit: external_exports.number().int().positive().optional(),
17481
+ states: external_exports.array(deviceOperationStateSchema).min(1).optional()
17482
+ }).optional()
17483
+ });
17484
+ var deviceOperationListResponseSchema = pageSchema(deviceOperationSummarySchema);
17485
+ var deviceOperationIdentityRequestSchema = external_exports.strictObject({
17486
+ deviceId: external_exports.string().min(1),
17487
+ operationId: external_exports.string().min(1)
17488
+ });
17489
+ var deviceOperationClaimRequestSchema = external_exports.strictObject({
17490
+ cursor: external_exports.string().min(1).optional(),
17491
+ deviceId: external_exports.string().min(1),
17492
+ limit: external_exports.number().int().positive().optional()
17493
+ });
17494
+ var deviceOperationClaimSchema = external_exports.object({
17495
+ arguments: external_exports.record(external_exports.string(), external_exports.json()),
17496
+ attempt: external_exports.number().int().positive(),
17497
+ caller: deviceOperationCallerSchema,
17498
+ cancelRequestedAt: external_exports.iso.datetime({ offset: true }).optional(),
17499
+ createdAt: external_exports.iso.datetime({ offset: true }),
17500
+ expiresAt: external_exports.iso.datetime({ offset: true }),
17501
+ leaseId: external_exports.string().min(1),
17502
+ leaseUntil: external_exports.iso.datetime({ offset: true }),
17503
+ operationId: external_exports.string().min(1),
17504
+ path: external_exports.string().min(1),
17505
+ targetPath: external_exports.string().min(1),
17506
+ traceId: external_exports.string().min(1)
17507
+ });
17508
+ var deviceOperationClaimResponseSchema = external_exports.object({
17509
+ cursor: external_exports.string().optional(),
17510
+ operation: deviceOperationClaimSchema.optional(),
17511
+ serverNow: external_exports.iso.datetime({ offset: true })
17512
+ });
17513
+ var deviceOperationLeaseShape = {
17514
+ deviceId: external_exports.string().min(1),
17515
+ leaseId: external_exports.string().min(1),
17516
+ operationId: external_exports.string().min(1)
17517
+ };
17518
+ var deviceOperationRenewRequestSchema = external_exports.strictObject(deviceOperationLeaseShape);
17519
+ var deviceOperationRenewResponseSchema = external_exports.object({
17520
+ cancelRequestedAt: external_exports.iso.datetime({ offset: true }).optional(),
17521
+ leaseUntil: external_exports.iso.datetime({ offset: true }),
17522
+ serverNow: external_exports.iso.datetime({ offset: true })
17523
+ });
17524
+ var deviceOperationCompleteRequestSchema = external_exports.discriminatedUnion("outcome", [
17525
+ external_exports.strictObject({
17526
+ ...deviceOperationLeaseShape,
17527
+ outcome: external_exports.literal("succeeded"),
17528
+ result: external_exports.json()
17529
+ }),
17530
+ external_exports.strictObject({
17531
+ ...deviceOperationLeaseShape,
17532
+ error: tbErrorBodySchema,
17533
+ outcome: external_exports.literal("rejected")
17534
+ }),
17535
+ external_exports.strictObject({
17536
+ ...deviceOperationLeaseShape,
17537
+ error: tbErrorBodySchema,
17538
+ outcome: external_exports.literal("failed")
17539
+ }),
17540
+ external_exports.strictObject({
17541
+ ...deviceOperationLeaseShape,
17542
+ error: tbErrorBodySchema.optional(),
17543
+ outcome: external_exports.literal("result_unknown")
17544
+ })
17545
+ ]);
16757
17546
  var registryNodeSchema = external_exports.object({
16758
17547
  config: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
16759
17548
  createdAt: external_exports.string().optional(),
16760
17549
  description: external_exports.string(),
17550
+ deviceId: external_exports.string().optional(),
16761
17551
  kind: nodeKindSchema,
16762
17552
  lastSeenAt: external_exports.string().optional(),
16763
17553
  online: external_exports.boolean().optional(),
@@ -17106,17 +17896,7 @@ function createSkModule(store, now) {
17106
17896
 
17107
17897
  // ../core/src/builtin/index.ts
17108
17898
  async function countNodes(registry2) {
17109
- let count = 0;
17110
- let cursor;
17111
- do {
17112
- const page = await registry2.list(void 0, {
17113
- limit: LIST_LIMIT_MAX,
17114
- ...cursor !== void 0 ? { cursor } : {}
17115
- });
17116
- count += page.items.length;
17117
- cursor = page.cursor;
17118
- } while (cursor);
17119
- return count;
17899
+ return (await registry2.subtree("")).length;
17120
17900
  }
17121
17901
  function createBuiltins(deps) {
17122
17902
  const now = deps.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
@@ -17165,7 +17945,7 @@ function contextHelpModel(node, opts = {}) {
17165
17945
  return contextCommands.helpModel(
17166
17946
  { path: node.path, kind: "context", description: node.description },
17167
17947
  (command) => {
17168
- if (command.name === "create_upload") return false;
17948
+ if (contextCommands.isHostOnly(command.name)) return false;
17169
17949
  if (opts.methods !== void 0 && !opts.methods.has(command.name)) return false;
17170
17950
  return opts.readOnly !== true || command.scope === "read";
17171
17951
  }
@@ -17195,7 +17975,7 @@ async function readStreamBytes(stream) {
17195
17975
  return out;
17196
17976
  }
17197
17977
  async function readStreamText(stream) {
17198
- return new TextDecoder().decode(await readStreamBytes(stream));
17978
+ return new TextDecoder2().decode(await readStreamBytes(stream));
17199
17979
  }
17200
17980
  function ownedBytes(view) {
17201
17981
  return view.buffer instanceof ArrayBuffer ? new Uint8Array(view.buffer, view.byteOffset, view.byteLength) : new Uint8Array(view);
@@ -17206,7 +17986,7 @@ async function objectBodyToBytes(body) {
17206
17986
  if (body instanceof ArrayBuffer) return new Uint8Array(body);
17207
17987
  return readStreamBytes(body);
17208
17988
  }
17209
- function bytesToObjectStream(bytes) {
17989
+ function bytesToObjectStream(bytes2) {
17210
17990
  return {
17211
17991
  getReader() {
17212
17992
  let done = false;
@@ -17214,7 +17994,7 @@ function bytesToObjectStream(bytes) {
17214
17994
  async read() {
17215
17995
  if (done) return { done: true };
17216
17996
  done = true;
17217
- return { done: false, value: bytes };
17997
+ return { done: false, value: bytes2 };
17218
17998
  },
17219
17999
  releaseLock() {
17220
18000
  },
@@ -17232,6 +18012,14 @@ function bytesToObjectStream(bytes) {
17232
18012
  var DEFAULT_STORE_NAME = "default";
17233
18013
  var DEFAULT_STORE_DRIVER_KEY_ROOT = "__tool_bridge_internal__/store/v1";
17234
18014
 
18015
+ // ../core/src/context/contentType.ts
18016
+ function normalizeContentType(value, message) {
18017
+ if (typeof value !== "string" || value.trim() === "" || value.length > 255 || !value.includes("/") || /[\r\n\0]/.test(value)) {
18018
+ throw new TBError("invalid_argument", message);
18019
+ }
18020
+ return value.trim().toLowerCase();
18021
+ }
18022
+
17235
18023
  // ../core/src/context/path.ts
17236
18024
  function hasControlChar(s) {
17237
18025
  for (let i = 0; i < s.length; i++) {
@@ -17314,9 +18102,10 @@ async function createObjectContextUploadGrant(store, opts, input) {
17314
18102
  if (unknownKeys.length > 0) {
17315
18103
  throw new TBError("invalid_argument", `create_upload \u542B\u672A\u77E5\u5B57\u6BB5:${unknownKeys.join(",")}`);
17316
18104
  }
17317
- if (typeof input?.contentType !== "string" || input.contentType.trim() === "" || input.contentType.length > 255 || !input.contentType.includes("/") || /[\r\n\0]/.test(input.contentType)) {
17318
- throw new TBError("invalid_argument", "create_upload \u9700\u8981\u5408\u6CD5\u7684 'contentType'");
17319
- }
18105
+ const contentType = normalizeContentType(
18106
+ input?.contentType,
18107
+ "create_upload \u9700\u8981\u5408\u6CD5\u7684 'contentType'"
18108
+ );
17320
18109
  const nsPath = normalizePath(opts.nsPath);
17321
18110
  const entryPath = normalizeEntryPath(input.path);
17322
18111
  const key = `${keyPrefixBare === "" ? "" : `${keyPrefixBare}/`}${entryPath}`;
@@ -17325,7 +18114,6 @@ async function createObjectContextUploadGrant(store, opts, input) {
17325
18114
  throw new TBError("unavailable", "\u5BF9\u8C61\u5B58\u50A8\u672A\u914D\u7F6E\u76F4\u4F20\u7B7E\u540D\u80FD\u529B", { retryable: false });
17326
18115
  }
17327
18116
  const ttlSec = assertPresignTtlSec(opts.uploadGrantTtlSec ?? PRESIGN_TTL_SEC_DEFAULT);
17328
- const contentType = input.contentType.trim();
17329
18117
  const expiresAt = new Date(Date.now() + ttlSec * 1e3).toISOString();
17330
18118
  const signed = await store.presignPut(key, ttlSec, {
17331
18119
  contentType,
@@ -17339,7 +18127,7 @@ async function createObjectContextUploadGrant(store, opts, input) {
17339
18127
  expiresAt
17340
18128
  };
17341
18129
  }
17342
- function clampLimit3(limit) {
18130
+ function clampLimit4(limit) {
17343
18131
  if (limit === void 0) return LIST_LIMIT_DEFAULT;
17344
18132
  if (!Number.isInteger(limit) || limit < 1) {
17345
18133
  throw new TBError("invalid_argument", `limit \u975E\u6CD5:${limit}`);
@@ -17413,7 +18201,7 @@ function createObjectContextProvider(store, opts) {
17413
18201
  return {
17414
18202
  async list(path, listOpts) {
17415
18203
  rejectFilter(listOpts);
17416
- const limit = clampLimit3(listOpts?.limit);
18204
+ const limit = clampLimit4(listOpts?.limit);
17417
18205
  const rel = path === "" ? "" : `${normalizeEntryPath(path)}/`;
17418
18206
  const full = keyPrefix + rel;
17419
18207
  assertContextKeyAllowed(full.slice(0, -1), path, false);
@@ -17523,7 +18311,7 @@ function createObjectContextProvider(store, opts) {
17523
18311
  throw new TBError("invalid_argument", "query \u4E0D\u80FD\u4E3A\u7A7A");
17524
18312
  }
17525
18313
  rejectFilter(searchOpts);
17526
- const limit = clampLimit3(searchOpts?.limit);
18314
+ const limit = clampLimit4(searchOpts?.limit);
17527
18315
  const q = query.toLowerCase();
17528
18316
  const after = searchOpts?.cursor;
17529
18317
  const items = [];
@@ -17580,6 +18368,7 @@ function isContextExpired(createdAt, ttlSec, now) {
17580
18368
  // ../core/src/device/frames.ts
17581
18369
  var deviceNodeCmdSchema = external_exports.object({
17582
18370
  name: external_exports.string().min(1),
18371
+ delivery: external_exports.enum(["realtime", "mailbox", "both"]).optional(),
17583
18372
  description: external_exports.string().optional(),
17584
18373
  inputSchema: external_exports.unknown().optional(),
17585
18374
  outputSchema: external_exports.unknown().optional(),
@@ -17762,18 +18551,18 @@ function derivePresence(input) {
17762
18551
  var DEVICE_CALL_TIMEOUT_MS = 6e4;
17763
18552
  var DEVICE_REJECT_CLOSE_CODE = 1008;
17764
18553
  var DeviceGatewaySession = class {
17765
- constructor(io, opts) {
17766
- this.io = io;
17767
- this.opts = opts;
17768
- this.timeoutMs = opts.timeoutMs ?? DEVICE_CALL_TIMEOUT_MS;
17769
- }
17770
- io;
17771
- opts;
17772
18554
  phase_ = "awaiting-hello";
17773
18555
  helloSeen = false;
17774
18556
  results = /* @__PURE__ */ new Map();
17775
18557
  pending = /* @__PURE__ */ new Map();
17776
18558
  timeoutMs;
18559
+ io;
18560
+ opts;
18561
+ constructor(io, opts) {
18562
+ this.io = io;
18563
+ this.opts = opts;
18564
+ this.timeoutMs = opts.timeoutMs ?? DEVICE_CALL_TIMEOUT_MS;
18565
+ }
17777
18566
  get phase() {
17778
18567
  return this.phase_;
17779
18568
  }
@@ -17846,7 +18635,7 @@ var DeviceGatewaySession = class {
17846
18635
  call(req, done) {
17847
18636
  const cached2 = this.results.get(req.id);
17848
18637
  if (cached2 !== void 0) {
17849
- done(cached2);
18638
+ done(cached2, "completed");
17850
18639
  return;
17851
18640
  }
17852
18641
  const inflight = this.pending.get(req.id);
@@ -17855,19 +18644,28 @@ var DeviceGatewaySession = class {
17855
18644
  return;
17856
18645
  }
17857
18646
  if (this.phase_ !== "ready") {
17858
- done({ ok: false, error: TBError.deviceOffline().toJSON() });
18647
+ done({ ok: false, error: TBError.deviceOffline().toJSON() }, "not_dispatched");
17859
18648
  return;
17860
18649
  }
17861
18650
  const cancelTimer = this.opts.setTimer(() => this.onCallTimeout(req.id), this.timeoutMs);
17862
18651
  this.pending.set(req.id, { waiters: [done], cancelTimer });
17863
- this.io.send({
17864
- type: "call",
17865
- id: req.id,
17866
- path: req.path,
17867
- arguments: req.arguments,
17868
- // undefined 经 JSON.stringify 丢弃:老网关不带 context 时帧形状不变。
17869
- ...req.context !== void 0 ? { context: req.context } : {}
17870
- });
18652
+ try {
18653
+ this.io.send({
18654
+ type: "call",
18655
+ id: req.id,
18656
+ path: req.path,
18657
+ arguments: req.arguments,
18658
+ // undefined JSON.stringify 丢弃:老网关不带 context 时帧形状不变。
18659
+ ...req.context !== void 0 ? { context: req.context } : {}
18660
+ });
18661
+ } catch {
18662
+ this.pending.delete(req.id);
18663
+ cancelTimer();
18664
+ done({
18665
+ ok: false,
18666
+ error: new TBError("unavailable", "\u8BBE\u5907\u8C03\u7528\u53D1\u9001\u5931\u8D25", { retryable: true }).toJSON()
18667
+ }, "unknown");
18668
+ }
17871
18669
  }
17872
18670
  /** 幂等表回放种子(DO 从 ctx.storage 恢复时用);已有同 id 结果则忽略。 */
17873
18671
  seedResult(id, result) {
@@ -17887,7 +18685,7 @@ var DeviceGatewaySession = class {
17887
18685
  };
17888
18686
  for (const entry of entries) {
17889
18687
  entry.cancelTimer();
17890
- for (const waiter of entry.waiters) waiter(result);
18688
+ for (const waiter of entry.waiters) waiter(result, "unknown");
17891
18689
  }
17892
18690
  }
17893
18691
  protocolReject(message) {
@@ -17901,7 +18699,7 @@ var DeviceGatewaySession = class {
17901
18699
  if (entry === void 0) return;
17902
18700
  this.pending.delete(id);
17903
18701
  entry.cancelTimer();
17904
- for (const waiter of entry.waiters) waiter(result);
18702
+ for (const waiter of entry.waiters) waiter(result, "completed");
17905
18703
  }
17906
18704
  onCallTimeout(id) {
17907
18705
  const entry = this.pending.get(id);
@@ -17914,7 +18712,7 @@ var DeviceGatewaySession = class {
17914
18712
  retryable: true
17915
18713
  }).toJSON()
17916
18714
  };
17917
- for (const waiter of entry.waiters) waiter(result);
18715
+ for (const waiter of entry.waiters) waiter(result, "unknown");
17918
18716
  }
17919
18717
  };
17920
18718
 
@@ -17988,10 +18786,10 @@ function toView(entry) {
17988
18786
  }
17989
18787
  var ID_ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789";
17990
18788
  function randomFeedbackId() {
17991
- const bytes = new Uint8Array(6);
17992
- crypto.getRandomValues(bytes);
18789
+ const bytes2 = new Uint8Array(6);
18790
+ crypto.getRandomValues(bytes2);
17993
18791
  let out = "fb_";
17994
- for (const b of bytes) out += ID_ALPHABET[b % ID_ALPHABET.length];
18792
+ for (const b of bytes2) out += ID_ALPHABET[b % ID_ALPHABET.length];
17995
18793
  return out;
17996
18794
  }
17997
18795
  function requireShort(value, field, max) {
@@ -18136,6 +18934,7 @@ function renderHelpDsl(model) {
18136
18934
  if (cmd.outputSchema !== void 0) lines.push(` result ${JSON.stringify(cmd.outputSchema)}`);
18137
18935
  if (cmd.returns !== void 0) lines.push(...attrLines("returns", cmd.returns));
18138
18936
  lines.push(` scope ${cmd.scope}`);
18937
+ if (cmd.delivery !== void 0) lines.push(` delivery ${cmd.delivery}`);
18139
18938
  if (cmd.effect !== void 0) lines.push(` effect ${cmd.effect}`);
18140
18939
  if (cmd.confirm) lines.push(" confirm");
18141
18940
  }
@@ -18168,6 +18967,7 @@ function renderHelpJson(model) {
18168
18967
  if (cmd.inputSchema !== void 0) out.inputSchema = cmd.inputSchema;
18169
18968
  if (cmd.outputSchema !== void 0) out.outputSchema = cmd.outputSchema;
18170
18969
  if (cmd.returns !== void 0) out.returns = cmd.returns;
18970
+ if (cmd.delivery !== void 0) out.delivery = cmd.delivery;
18171
18971
  if (cmd.effect !== void 0) out.effect = cmd.effect;
18172
18972
  if (cmd.confirm) out.confirm = cmd.confirm;
18173
18973
  return out;
@@ -18207,6 +19007,7 @@ function cmdSection(cmd, index) {
18207
19007
  }
18208
19008
  lines.push(`- Invoke: \`POST ${cmd.path}\` with body \`{...arguments}\``);
18209
19009
  lines.push(`- Required scope: \`${cmd.scope}\``);
19010
+ if (cmd.delivery !== void 0) lines.push(`- Delivery: \`${cmd.delivery}\``);
18210
19011
  if (cmd.effect !== void 0) {
18211
19012
  lines.push(
18212
19013
  `- Effect: \`${cmd.effect}\`${cmd.confirm ? " \u2014 **ask the user to confirm before calling**" : ""}`
@@ -18424,7 +19225,7 @@ var KEY_STORE_IDEMPOTENCY = "store:idempotency:";
18424
19225
  var UPLOAD_TTL_SEC_DEFAULT = 15 * 60;
18425
19226
  var SHARE_TTL_SEC_DEFAULT = 15 * 60;
18426
19227
  var MAX_OBJECT_BYTES_DEFAULT = 256 * 1024 * 1024;
18427
- var MAX_CAS_ATTEMPTS = 32;
19228
+ var MAX_CAS_ATTEMPTS2 = 32;
18428
19229
  var CAPABILITY_TTL_SEC_MAX = 7 * 24 * 60 * 60;
18429
19230
  var TOKEN_PREFIX = {
18430
19231
  call: "tbc",
@@ -18574,12 +19375,6 @@ function normalizeTimestamp(value, field) {
18574
19375
  throw error51;
18575
19376
  }
18576
19377
  }
18577
- function normalizeContentType(value) {
18578
- if (typeof value !== "string" || value.trim() === "" || value.length > 255 || !value.includes("/") || /[\r\n\0]/.test(value)) {
18579
- throw new TBError("invalid_argument", "contentType \u4E0D\u5408\u6CD5");
18580
- }
18581
- return value.trim().toLowerCase();
18582
- }
18583
19378
  function normalizeChecksum(value) {
18584
19379
  if (value === void 0) return void 0;
18585
19380
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
@@ -18596,7 +19391,7 @@ function normalizeChecksum(value) {
18596
19391
  return { algorithm: "sha256", value: digest };
18597
19392
  }
18598
19393
  function normalizeUploadInput(input) {
18599
- const contentType = normalizeContentType(input?.contentType);
19394
+ const contentType = normalizeContentType(input?.contentType, "contentType \u4E0D\u5408\u6CD5");
18600
19395
  let filename;
18601
19396
  if (input.filename !== void 0) {
18602
19397
  if (typeof input.filename !== "string" || input.filename.trim() === "" || input.filename.length > 1024 || /[\r\n\0]/.test(input.filename)) throw new TBError("invalid_argument", "filename \u4E0D\u5408\u6CD5");
@@ -18645,7 +19440,7 @@ function normalizeContentTypePattern(value) {
18645
19440
  const prefix = value.slice(0, -1);
18646
19441
  if (prefix.length > 1 && !/[\r\n\0]/.test(value)) return value.toLowerCase();
18647
19442
  }
18648
- return normalizeContentType(value);
19443
+ return normalizeContentType(value, "contentType \u4E0D\u5408\u6CD5");
18649
19444
  }
18650
19445
  function descriptorOf(object2) {
18651
19446
  if (object2.status !== "ready" || object2.readyAt === void 0 || object2.size === void 0) throw stateCorrupt("ready object");
@@ -18667,6 +19462,15 @@ function descriptorOf(object2) {
18667
19462
  };
18668
19463
  }
18669
19464
  var StoreService = class {
19465
+ maxObjectBytes;
19466
+ now;
19467
+ relayMaxBytes;
19468
+ shareTtlSec;
19469
+ tokenSecret;
19470
+ uploadTtlSec;
19471
+ cas;
19472
+ state;
19473
+ objects;
18670
19474
  constructor(state, objects, opts) {
18671
19475
  this.state = state;
18672
19476
  this.objects = objects;
@@ -18698,15 +19502,6 @@ var StoreService = class {
18698
19502
  "shareTtlSec"
18699
19503
  );
18700
19504
  }
18701
- state;
18702
- objects;
18703
- maxObjectBytes;
18704
- now;
18705
- relayMaxBytes;
18706
- shareTtlSec;
18707
- tokenSecret;
18708
- uploadTtlSec;
18709
- cas;
18710
19505
  /** 所有已存在记录的 CAS 共用 revision 期望,并拒绝错误的版本跃迁。 */
18711
19506
  async compareRecord(key, current, next) {
18712
19507
  if (next !== null && next.revision !== current.revision + 1)
@@ -18774,7 +19569,7 @@ var StoreService = class {
18774
19569
  }
18775
19570
  async revokeCallUploadCapability(token) {
18776
19571
  const id = this.tokenId(token, "call");
18777
- for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {
19572
+ for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS2; attempt++) {
18778
19573
  const raw = await this.state.get(`${KEY_STORE_CALL_CAPABILITY}${id}`);
18779
19574
  if (raw === null) throw new TBError("permission_denied", "call upload capability \u65E0\u6548");
18780
19575
  const capability = parseCallCapability(raw);
@@ -18988,7 +19783,7 @@ var StoreService = class {
18988
19783
  }
18989
19784
  async delete(uri, actor) {
18990
19785
  const { objectId } = parseStoreUri(uri);
18991
- for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {
19786
+ for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS2; attempt++) {
18992
19787
  const object2 = await this.requireObject(objectId);
18993
19788
  if (!actor.admin && object2.owner !== actor.owner) {
18994
19789
  throw new TBError("not_found", "Store \u5BF9\u8C61\u4E0D\u5B58\u5728");
@@ -19052,7 +19847,7 @@ var StoreService = class {
19052
19847
  }
19053
19848
  async revokeShare(shareId, actor) {
19054
19849
  const owner = requireOwner(actor);
19055
- for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {
19850
+ for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS2; attempt++) {
19056
19851
  const raw = await this.state.get(`${KEY_STORE_SHARE}${shareId}`);
19057
19852
  if (raw === null) throw new TBError("not_found", "share grant \u4E0D\u5B58\u5728");
19058
19853
  const grant = parseShare(raw);
@@ -19376,7 +20171,7 @@ var StoreService = class {
19376
20171
  await this.compareRecord(resolved.key, resolved.binding, null);
19377
20172
  }
19378
20173
  async reserveCallCapability(token, objectId, input, transportMaxBytes) {
19379
- for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {
20174
+ for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS2; attempt++) {
19380
20175
  const capability = await this.verifyCallUploadCapability(token);
19381
20176
  const previous = capability.reservations.find((r) => r.objectId === objectId);
19382
20177
  if (previous !== void 0) {
@@ -19498,7 +20293,7 @@ var StoreService = class {
19498
20293
  }
19499
20294
  /** driver DELETE 成功后持久化证据;后续 cleanup 只收 tombstone,不再重复外部 DELETE。 */
19500
20295
  async markBytesDeleted(objectId, expectedDriverKey) {
19501
- for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {
20296
+ for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS2; attempt++) {
19502
20297
  const raw = await this.state.get(`${KEY_STORE_OBJECT}${objectId}`);
19503
20298
  if (raw === null) return;
19504
20299
  const object2 = parseObject(raw);
@@ -19598,7 +20393,7 @@ var StoreService = class {
19598
20393
  }
19599
20394
  async markReady(sessionInput, meta3) {
19600
20395
  const actualChecksum = sessionInput.expectedChecksum !== void 0 && meta3.metadata?.["checksum-sha256"]?.toLowerCase() === sessionInput.expectedChecksum.value ? sessionInput.expectedChecksum : void 0;
19601
- for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {
20396
+ for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS2; attempt++) {
19602
20397
  const object2 = await this.requireObject(sessionInput.objectId);
19603
20398
  if (object2.status === "ready") {
19604
20399
  await this.completeSessionBestEffort(await this.requireSession(sessionInput.id));
@@ -19628,7 +20423,7 @@ var StoreService = class {
19628
20423
  throw new TBError("conflict", "\u5BF9\u8C61\u5E76\u53D1\u72B6\u6001\u51B2\u7A81:pending");
19629
20424
  }
19630
20425
  async completeSessionBestEffort(sessionInput) {
19631
- for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {
20426
+ for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS2; attempt++) {
19632
20427
  const session = await this.requireSession(sessionInput.id);
19633
20428
  if (session.status === "completed" || session.status !== "created") return;
19634
20429
  const completedAt = this.nowIso();
@@ -19804,8 +20599,8 @@ function canonicalCatalogJson(value) {
19804
20599
  return JSON.stringify(normalize(value));
19805
20600
  }
19806
20601
  async function catalogDigest(value) {
19807
- const bytes = new TextEncoder().encode(canonicalCatalogJson(value));
19808
- const hash2 = await crypto.subtle.digest("SHA-256", bytes);
20602
+ const bytes2 = new TextEncoder().encode(canonicalCatalogJson(value));
20603
+ const hash2 = await crypto.subtle.digest("SHA-256", bytes2);
19809
20604
  return [...new Uint8Array(hash2)].map((b) => b.toString(16).padStart(2, "0")).join("");
19810
20605
  }
19811
20606
  async function catalogSetDigest(catalog) {
@@ -19974,7 +20769,7 @@ function encodeCallContext(ctx) {
19974
20769
  function decodeCallContext(header) {
19975
20770
  let text;
19976
20771
  try {
19977
- text = new TextDecoder().decode(base64urlDecode(header));
20772
+ text = new TextDecoder2().decode(base64urlDecode(header));
19978
20773
  } catch {
19979
20774
  throw new TBError("invalid_argument", `${HEADER_TB_CONTEXT} \u975E\u6CD5 base64url`);
19980
20775
  }
@@ -19999,11 +20794,11 @@ var pluginCallSchema = external_exports.object({
19999
20794
  arguments: external_exports.record(external_exports.string(), external_exports.unknown())
20000
20795
  });
20001
20796
  function assertPluginPayloadSize(payload) {
20002
- const bytes = new TextEncoder().encode(payload).length;
20003
- if (bytes > PLUGIN_PAYLOAD_MAX_BYTES) {
20797
+ const bytes2 = new TextEncoder().encode(payload).length;
20798
+ if (bytes2 > PLUGIN_PAYLOAD_MAX_BYTES) {
20004
20799
  throw new TBError(
20005
20800
  "invalid_argument",
20006
- `payload ${bytes} \u5B57\u8282\u8D85\u8FC7\u4E0A\u9650 ${PLUGIN_PAYLOAD_MAX_BYTES}(\u2264 1 MiB;\u66F4\u5927\u5185\u5BB9\u7ECF $ref)`
20801
+ `payload ${bytes2} \u5B57\u8282\u8D85\u8FC7\u4E0A\u9650 ${PLUGIN_PAYLOAD_MAX_BYTES}(\u2264 1 MiB;\u66F4\u5927\u5185\u5BB9\u7ECF $ref)`
20007
20802
  );
20008
20803
  }
20009
20804
  }
@@ -20181,9 +20976,9 @@ function searchUnitAllowsPath(unit) {
20181
20976
  return !/^%[A-Za-z0-9]{1,2}%$/u.test(unit.pattern);
20182
20977
  }
20183
20978
  function stableDigest(value) {
20184
- const bytes = new TextEncoder().encode(JSON.stringify(value));
20979
+ const bytes2 = new TextEncoder().encode(JSON.stringify(value));
20185
20980
  let hash2 = 0xcbf29ce484222325n;
20186
- for (const byte of bytes) {
20981
+ for (const byte of bytes2) {
20187
20982
  hash2 ^= BigInt(byte);
20188
20983
  hash2 = BigInt.asUintN(64, hash2 * 0x100000001b3n);
20189
20984
  }
@@ -20193,12 +20988,12 @@ function truncateUtf8(value, maxBytes) {
20193
20988
  const encoder = new TextEncoder();
20194
20989
  if (encoder.encode(value).length <= maxBytes) return value;
20195
20990
  let result = "";
20196
- let bytes = 0;
20991
+ let bytes2 = 0;
20197
20992
  for (const char of value) {
20198
20993
  const size = encoder.encode(char).length;
20199
- if (bytes + size > maxBytes) break;
20994
+ if (bytes2 + size > maxBytes) break;
20200
20995
  result += char;
20201
- bytes += size;
20996
+ bytes2 += size;
20202
20997
  }
20203
20998
  return result;
20204
20999
  }
@@ -20558,7 +21353,7 @@ async function decodeToolSearchCursor(cursor, query, mode, revision, secret, opt
20558
21353
  await cursorCryptoKey(secret),
20559
21354
  sealed.slice(12)
20560
21355
  );
20561
- value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(new Uint8Array(plaintext)));
21356
+ value = JSON.parse(new TextDecoder2("utf-8", { fatal: true }).decode(new Uint8Array(plaintext)));
20562
21357
  } catch (error51) {
20563
21358
  if (error51 instanceof TBError) throw error51;
20564
21359
  throw new TBError("invalid_argument", "\u641C\u7D22 cursor \u683C\u5F0F\u975E\u6CD5");
@@ -20626,36 +21421,45 @@ var TOOL_SEARCH_INSERT_SQL = `
20626
21421
  INSERT INTO tb_search_tools_v5 (path, name, description, effect, feedback)
20627
21422
  VALUES (?, ?, ?, ?, ?)
20628
21423
  `;
20629
- var TOOL_SEARCH_INSERT_SNAPSHOT_SQL = "INSERT INTO tb_search_snapshots_v5(path, digest) VALUES (?, ?)";
20630
- var META_SQL = "SELECT revision, seeded, cursor_secret FROM tb_search_meta_v5 WHERE singleton = 1";
20631
- var SNAPSHOT_DIGESTS_SQL = "SELECT path, digest FROM tb_search_snapshots_v5 ORDER BY path";
20632
- var PATH_STATE_SQL = `
21424
+ function toolSearchFixedStatements(syntax) {
21425
+ const p = (index) => syntax.placeholder(index);
21426
+ const int2 = syntax.castInt ?? ((expr) => expr);
21427
+ return {
21428
+ bumpRevision: "UPDATE tb_search_meta_v5 SET revision = revision + 1 WHERE singleton = 1",
21429
+ completeRebuild: "UPDATE tb_search_meta_v5 SET seeded = 1, revision = revision + 1 WHERE singleton = 1",
21430
+ deleteAllSnapshots: "DELETE FROM tb_search_snapshots_v5",
21431
+ deleteAllTools: "DELETE FROM tb_search_tools_v5",
21432
+ deleteSnapshot: `DELETE FROM tb_search_snapshots_v5 WHERE path = ${p(1)}`,
21433
+ deleteSnapshotPrefix: `
21434
+ DELETE FROM tb_search_snapshots_v5
21435
+ WHERE path = ${p(1)} OR substr(path, 1, length(${p(2)}) + 1) = ${p(3)} || '/'
21436
+ `,
21437
+ deleteTools: `DELETE FROM tb_search_tools_v5 WHERE path = ${p(1)}`,
21438
+ deleteToolsPrefix: `
21439
+ DELETE FROM tb_search_tools_v5
21440
+ WHERE path = ${p(1)} OR substr(path, 1, length(${p(2)}) + 1) = ${p(3)} || '/'
21441
+ `,
21442
+ insertSnapshot: `INSERT INTO tb_search_snapshots_v5(path, digest) VALUES (${p(1)}, ${p(2)})`,
21443
+ meta: `SELECT ${int2("revision")} AS revision, ${int2("seeded")} AS seeded, cursor_secret FROM tb_search_meta_v5 WHERE singleton = 1`,
21444
+ // replace 的前置探测:一次拿到本 path 的 digest、是否残留 source 行、已用节点数。
21445
+ pathState: `
20633
21446
  SELECT snapshots.digest,
20634
- EXISTS(SELECT 1 FROM tb_search_tools_v5 WHERE path = ?) AS has_tools,
20635
- (SELECT COUNT(*) FROM tb_search_snapshots_v5) AS path_count
21447
+ ${int2(`EXISTS(SELECT 1 FROM tb_search_tools_v5 WHERE path = ${p(1)})`)} AS has_tools,
21448
+ ${int2("(SELECT COUNT(*) FROM tb_search_snapshots_v5)")} AS path_count
20636
21449
  FROM (SELECT 1) AS singleton
20637
- LEFT JOIN tb_search_snapshots_v5 AS snapshots ON snapshots.path = ?
20638
- `;
20639
- var PRESENT_SQL = "SELECT 1 AS present FROM tb_search_tools_v5 WHERE path = ? LIMIT 1";
20640
- var PRESENT_PREFIX_SQL = `
21450
+ LEFT JOIN tb_search_snapshots_v5 AS snapshots ON snapshots.path = ${p(2)}
21451
+ `,
21452
+ present: `SELECT 1 AS present FROM tb_search_tools_v5 WHERE path = ${p(1)} LIMIT 1`,
21453
+ presentPrefix: `
20641
21454
  SELECT 1 AS present FROM tb_search_tools_v5
20642
- WHERE path = ? OR substr(path, 1, length(?) + 1) = ? || '/'
21455
+ WHERE path = ${p(1)} OR substr(path, 1, length(${p(2)}) + 1) = ${p(3)} || '/'
20643
21456
  LIMIT 1
20644
- `;
20645
- var DELETE_TOOLS_SQL = "DELETE FROM tb_search_tools_v5 WHERE path = ?";
20646
- var DELETE_SNAPSHOT_SQL = "DELETE FROM tb_search_snapshots_v5 WHERE path = ?";
20647
- var DELETE_TOOLS_PREFIX_SQL = `
20648
- DELETE FROM tb_search_tools_v5
20649
- WHERE path = ? OR substr(path, 1, length(?) + 1) = ? || '/'
20650
- `;
20651
- var DELETE_SNAPSHOT_PREFIX_SQL = `
20652
- DELETE FROM tb_search_snapshots_v5
20653
- WHERE path = ? OR substr(path, 1, length(?) + 1) = ? || '/'
20654
- `;
20655
- var DELETE_ALL_TOOLS_SQL = "DELETE FROM tb_search_tools_v5";
20656
- var DELETE_ALL_SNAPSHOTS_SQL = "DELETE FROM tb_search_snapshots_v5";
20657
- var BUMP_REVISION_SQL = "UPDATE tb_search_meta_v5 SET revision = revision + 1 WHERE singleton = 1";
20658
- var COMPLETE_REBUILD_SQL = "UPDATE tb_search_meta_v5 SET seeded = 1, revision = revision + 1 WHERE singleton = 1";
21457
+ `,
21458
+ snapshotDigests: "SELECT path, digest FROM tb_search_snapshots_v5 ORDER BY path"
21459
+ };
21460
+ }
21461
+ var SQLITE_FIXED_STATEMENTS = toolSearchFixedStatements({ placeholder: () => "?" });
21462
+ var TOOL_SEARCH_INSERT_SNAPSHOT_SQL = SQLITE_FIXED_STATEMENTS.insertSnapshot;
20659
21463
  function toolSearchEffectSql(effect) {
20660
21464
  switch (effect) {
20661
21465
  case "read":
@@ -20762,31 +21566,16 @@ var sqliteSearchDialect = {
20762
21566
  );
20763
21567
  },
20764
21568
  schemaStatements: TOOL_SEARCH_SCHEMA_STATEMENTS,
20765
- statements: {
20766
- bumpRevision: BUMP_REVISION_SQL,
20767
- completeRebuild: COMPLETE_REBUILD_SQL,
20768
- deleteAllSnapshots: DELETE_ALL_SNAPSHOTS_SQL,
20769
- deleteAllTools: DELETE_ALL_TOOLS_SQL,
20770
- deleteSnapshot: DELETE_SNAPSHOT_SQL,
20771
- deleteSnapshotPrefix: DELETE_SNAPSHOT_PREFIX_SQL,
20772
- deleteTools: DELETE_TOOLS_SQL,
20773
- deleteToolsPrefix: DELETE_TOOLS_PREFIX_SQL,
20774
- insertSnapshot: TOOL_SEARCH_INSERT_SNAPSHOT_SQL,
20775
- meta: META_SQL,
20776
- pathState: PATH_STATE_SQL,
20777
- present: PRESENT_SQL,
20778
- presentPrefix: PRESENT_PREFIX_SQL,
20779
- snapshotDigests: SNAPSHOT_DIGESTS_SQL
20780
- }
21569
+ statements: SQLITE_FIXED_STATEMENTS
20781
21570
  };
20782
21571
  var SqlSearchIndex = class {
21572
+ capabilities = ["search"];
21573
+ dialect;
21574
+ driver;
20783
21575
  constructor(driver, dialect = sqliteSearchDialect) {
20784
21576
  this.driver = driver;
20785
21577
  this.dialect = dialect;
20786
21578
  }
20787
- driver;
20788
- capabilities = ["search"];
20789
- dialect;
20790
21579
  /** 容量 trigger 的 ABORT 在各驱动里错误形状不同,统一按标记串归一。 */
20791
21580
  async writeOrCapacity(statements) {
20792
21581
  try {
@@ -21006,7 +21795,11 @@ var PG_SEARCH_SCHEMA_STATEMENTS = [
21006
21795
  FOR EACH ROW EXECUTE FUNCTION tb_search_snapshots_v5_capacity()`
21007
21796
  ];
21008
21797
  var PG_SEARCH_WRITE_LOCK_KEY = 2069799624;
21009
- var PG_SEARCH_INSERT_SNAPSHOT_SQL = "INSERT INTO tb_search_snapshots_v5(path, digest) VALUES ($1, $2)";
21798
+ var PG_FIXED_STATEMENTS = toolSearchFixedStatements({
21799
+ castInt: (expr) => `${expr}::int`,
21800
+ placeholder: (index) => `$${index}`
21801
+ });
21802
+ var PG_SEARCH_INSERT_SNAPSHOT_SQL = PG_FIXED_STATEMENTS.insertSnapshot;
21010
21803
  function pgBulkInsertSql(table, columns, rows) {
21011
21804
  const tuples = [];
21012
21805
  for (let r = 0; r < rows; r++) {
@@ -21026,38 +21819,6 @@ var PG_SEARCH_TOOLS_COLUMNS = [
21026
21819
  var PG_SEARCH_SNAPSHOTS_TABLE = "tb_search_snapshots_v5";
21027
21820
  var PG_SEARCH_SNAPSHOTS_COLUMNS = ["path", "digest"];
21028
21821
  var PG_SEARCH_INSERT_ROWS_MAX = 1e3;
21029
- var META_SQL2 = `
21030
- SELECT revision::int AS revision, seeded::int AS seeded, cursor_secret
21031
- FROM tb_search_meta_v5 WHERE singleton = 1
21032
- `;
21033
- var SNAPSHOT_DIGESTS_SQL2 = "SELECT path, digest FROM tb_search_snapshots_v5 ORDER BY path";
21034
- var PATH_STATE_SQL2 = `
21035
- SELECT snapshots.digest,
21036
- EXISTS(SELECT 1 FROM tb_search_tools_v5 WHERE path = $1)::int AS has_tools,
21037
- (SELECT COUNT(*) FROM tb_search_snapshots_v5)::int AS path_count
21038
- FROM (SELECT 1) AS singleton
21039
- LEFT JOIN tb_search_snapshots_v5 AS snapshots ON snapshots.path = $2
21040
- `;
21041
- var PRESENT_SQL2 = "SELECT 1 AS present FROM tb_search_tools_v5 WHERE path = $1 LIMIT 1";
21042
- var PRESENT_PREFIX_SQL2 = `
21043
- SELECT 1 AS present FROM tb_search_tools_v5
21044
- WHERE path = $1 OR substr(path, 1, length($2) + 1) = $3 || '/'
21045
- LIMIT 1
21046
- `;
21047
- var DELETE_TOOLS_SQL2 = "DELETE FROM tb_search_tools_v5 WHERE path = $1";
21048
- var DELETE_SNAPSHOT_SQL2 = "DELETE FROM tb_search_snapshots_v5 WHERE path = $1";
21049
- var DELETE_TOOLS_PREFIX_SQL2 = `
21050
- DELETE FROM tb_search_tools_v5
21051
- WHERE path = $1 OR substr(path, 1, length($2) + 1) = $3 || '/'
21052
- `;
21053
- var DELETE_SNAPSHOT_PREFIX_SQL2 = `
21054
- DELETE FROM tb_search_snapshots_v5
21055
- WHERE path = $1 OR substr(path, 1, length($2) + 1) = $3 || '/'
21056
- `;
21057
- var DELETE_ALL_TOOLS_SQL2 = "DELETE FROM tb_search_tools_v5";
21058
- var DELETE_ALL_SNAPSHOTS_SQL2 = "DELETE FROM tb_search_snapshots_v5";
21059
- var BUMP_REVISION_SQL2 = "UPDATE tb_search_meta_v5 SET revision = revision + 1 WHERE singleton = 1";
21060
- var COMPLETE_REBUILD_SQL2 = "UPDATE tb_search_meta_v5 SET seeded = 1, revision = revision + 1 WHERE singleton = 1";
21061
21822
  var pgSearchDialect = {
21062
21823
  candidateStatement: (query, limit, offset, rawConstraints) => {
21063
21824
  const constraints = normalizeToolSearchOptions(rawConstraints);
@@ -21075,22 +21836,7 @@ var pgSearchDialect = {
21075
21836
  );
21076
21837
  },
21077
21838
  schemaStatements: PG_SEARCH_SCHEMA_STATEMENTS,
21078
- statements: {
21079
- bumpRevision: BUMP_REVISION_SQL2,
21080
- completeRebuild: COMPLETE_REBUILD_SQL2,
21081
- deleteAllSnapshots: DELETE_ALL_SNAPSHOTS_SQL2,
21082
- deleteAllTools: DELETE_ALL_TOOLS_SQL2,
21083
- deleteSnapshot: DELETE_SNAPSHOT_SQL2,
21084
- deleteSnapshotPrefix: DELETE_SNAPSHOT_PREFIX_SQL2,
21085
- deleteTools: DELETE_TOOLS_SQL2,
21086
- deleteToolsPrefix: DELETE_TOOLS_PREFIX_SQL2,
21087
- insertSnapshot: PG_SEARCH_INSERT_SNAPSHOT_SQL,
21088
- meta: META_SQL2,
21089
- pathState: PATH_STATE_SQL2,
21090
- present: PRESENT_SQL2,
21091
- presentPrefix: PRESENT_PREFIX_SQL2,
21092
- snapshotDigests: SNAPSHOT_DIGESTS_SQL2
21093
- }
21839
+ statements: PG_FIXED_STATEMENTS
21094
21840
  };
21095
21841
 
21096
21842
  // ../core/src/secret/secretStore.ts
@@ -21222,7 +21968,7 @@ var SecretStoreImpl = class _SecretStoreImpl {
21222
21968
  await this.key(),
21223
21969
  ciphertext
21224
21970
  );
21225
- return new TextDecoder().decode(plaintext);
21971
+ return new TextDecoder2().decode(plaintext);
21226
21972
  }
21227
21973
  };
21228
21974
 
@@ -21387,7 +22133,7 @@ function guessContentType(path) {
21387
22133
  if (dot < 0) return "text/plain";
21388
22134
  return CONTENT_TYPE_BY_EXT[path.slice(dot + 1).toLowerCase()] ?? "text/plain";
21389
22135
  }
21390
- function clampLimit4(limit) {
22136
+ function clampLimit5(limit) {
21391
22137
  if (limit === void 0) return LIST_LIMIT_DEFAULT;
21392
22138
  if (!Number.isInteger(limit) || limit < 1) {
21393
22139
  throw new TBError("invalid_argument", `limit \u975E\u6CD5:${limit}`);
@@ -21442,7 +22188,7 @@ function createSkillhubProvider(store, opts) {
21442
22188
  };
21443
22189
  return {
21444
22190
  async list(listOpts) {
21445
- const limit = clampLimit4(listOpts?.limit);
22191
+ const limit = clampLimit5(listOpts?.limit);
21446
22192
  const res = await store.list(keyPrefix, {
21447
22193
  delimiter: "/",
21448
22194
  cursor: listOpts?.cursor,
@@ -21502,7 +22248,7 @@ function createSkillhubProvider(store, opts) {
21502
22248
  if (typeof query !== "string" || query === "") {
21503
22249
  throw new TBError("invalid_argument", "query \u4E0D\u80FD\u4E3A\u7A7A");
21504
22250
  }
21505
- const limit = clampLimit4(searchOpts?.limit);
22251
+ const limit = clampLimit5(searchOpts?.limit);
21506
22252
  const q = query.toLowerCase();
21507
22253
  const after = searchOpts?.cursor;
21508
22254
  const items = [];
@@ -21677,6 +22423,7 @@ function toolToCmd(nodePath, tool, index) {
21677
22423
  if (tool.description !== void 0) {
21678
22424
  cmd.h = index ? summarizeOneLine(tool.description) : tool.description;
21679
22425
  }
22426
+ if (tool.delivery !== void 0) cmd.delivery = tool.delivery;
21680
22427
  if (!index && tool.inputSchema !== void 0) cmd.inputSchema = tool.inputSchema;
21681
22428
  if (!index && tool.outputSchema !== void 0) cmd.outputSchema = tool.outputSchema;
21682
22429
  if (tool.effect !== void 0) cmd.effect = tool.effect;
@@ -21726,7 +22473,7 @@ function rewriteRemotePath(nodePath, requestPath, baseUrl) {
21726
22473
  return rel === "" ? base : `${base}/${rel}`;
21727
22474
  }
21728
22475
  function hostOf(url2) {
21729
- const m = /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\/([^/?#]*)/.exec(url2);
22476
+ const m = /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\/([^/?#\\]*)/.exec(url2);
21730
22477
  if (m === null) return void 0;
21731
22478
  let authority = m[1] ?? "";
21732
22479
  const at = authority.lastIndexOf("@");
@@ -21808,7 +22555,7 @@ function resolveUpstreamTool(v, source, virtualName2) {
21808
22555
  }
21809
22556
 
21810
22557
  // ../core/src/tree/registry.ts
21811
- function clampLimit5(limit) {
22558
+ function clampLimit6(limit) {
21812
22559
  if (limit === void 0 || limit < 1) return LIST_LIMIT_DEFAULT;
21813
22560
  return limit > LIST_LIMIT_MAX ? LIST_LIMIT_MAX : limit;
21814
22561
  }
@@ -21825,10 +22572,10 @@ function byPath(a, b) {
21825
22572
  return a.path < b.path ? -1 : a.path > b.path ? 1 : 0;
21826
22573
  }
21827
22574
  var NodeRegistryStore = class {
22575
+ store;
21828
22576
  constructor(store) {
21829
22577
  this.store = store;
21830
22578
  }
21831
- store;
21832
22579
  keyOf(path) {
21833
22580
  return KEY_NODE + path;
21834
22581
  }
@@ -21909,7 +22656,7 @@ var NodeRegistryStore = class {
21909
22656
  */
21910
22657
  async list(prefix, opts) {
21911
22658
  const normPrefix = prefix === void 0 ? "" : canonicalizePath(prefix);
21912
- const limit = clampLimit5(opts?.limit);
22659
+ const limit = clampLimit6(opts?.limit);
21913
22660
  const all = (await this.scanAll()).filter((n) => isPrefixOf(normPrefix, n.path)).sort(byPath);
21914
22661
  const cursor = opts?.cursor;
21915
22662
  const start = cursor ? all.findIndex((n) => n.path === cursor) + 1 : 0;
@@ -21998,6 +22745,7 @@ var NodeRegistryStore = class {
21998
22745
  description: node.description,
21999
22746
  ...node.config !== void 0 ? { config: node.config } : {},
22000
22747
  ...node.virtualize !== void 0 ? { virtualize: node.virtualize } : {},
22748
+ ...opts.deviceId !== void 0 ? { deviceId: opts.deviceId } : {},
22001
22749
  ...opts.online !== void 0 ? { online: opts.online } : {},
22002
22750
  ...opts.lastSeenAt !== void 0 ? { lastSeenAt: opts.lastSeenAt } : {},
22003
22751
  registeredBy,
@@ -22218,8 +22966,8 @@ function createPlugin(opts = {}) {
22218
22966
  const b64 = raw.replaceAll("-", "+").replaceAll("_", "/");
22219
22967
  const padded = b64.padEnd(b64.length + (4 - b64.length % 4) % 4, "=");
22220
22968
  try {
22221
- const bytes = Uint8Array.from(atob(padded), (c) => c.charCodeAt(0));
22222
- return new TextDecoder().decode(bytes);
22969
+ const bytes2 = Uint8Array.from(atob(padded), (c) => c.charCodeAt(0));
22970
+ return new TextDecoder().decode(bytes2);
22223
22971
  } catch {
22224
22972
  throw new TBError("invalid_argument", `${HEADER_TB_UPSTREAM_AUTH} is not valid base64url`);
22225
22973
  }
@@ -22481,6 +23229,7 @@ export {
22481
23229
  TBError,
22482
23230
  isTBError,
22483
23231
  normalizePath,
23232
+ assertNoCollision,
22484
23233
  validatePath,
22485
23234
  KEY_SK_HASH,
22486
23235
  KEY_SK_ID,
@@ -22545,6 +23294,7 @@ export {
22545
23294
  pluginTokenSecretName,
22546
23295
  createStoreModule,
22547
23296
  RemoteAllowlistStore,
23297
+ DeviceMailboxService,
22548
23298
  tbErrorBodySchema,
22549
23299
  nodeInputSchema,
22550
23300
  helpJsonSchema,
@@ -22554,6 +23304,16 @@ export {
22554
23304
  toolSearchSourceResultSchema,
22555
23305
  toolSearchPageSchema,
22556
23306
  toolSearchRequestSchema,
23307
+ deviceOperationSummarySchema,
23308
+ deviceOperationDetailSchema,
23309
+ deviceOperationListRequestSchema,
23310
+ deviceOperationListResponseSchema,
23311
+ deviceOperationIdentityRequestSchema,
23312
+ deviceOperationClaimRequestSchema,
23313
+ deviceOperationClaimResponseSchema,
23314
+ deviceOperationRenewRequestSchema,
23315
+ deviceOperationRenewResponseSchema,
23316
+ deviceOperationCompleteRequestSchema,
22557
23317
  registryNodeSchema,
22558
23318
  feedbackViewSchema,
22559
23319
  feedbackDetailSchema,