@tool-bridge/server 0.19.0 → 0.20.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 (108) hide show
  1. package/dist/{airtable-23JBIM6X.js → airtable-ZNWHIJMO.js} +4 -4
  2. package/dist/{alt_text_generator_ai-ADWBTCIH.js → alt_text_generator_ai-X7RMDDM5.js} +4 -4
  3. package/dist/{amap-CYQCYW2Z.js → amap-3VER75VH.js} +4 -4
  4. package/dist/{anthropic-5P62HDNR.js → anthropic-N7NTB3UC.js} +4 -4
  5. package/dist/{apify-54RZUAGW.js → apify-JB5P5AJI.js} +4 -4
  6. package/dist/{brave_search-AHJ6FTD5.js → brave_search-USL5OOBS.js} +4 -4
  7. package/dist/{chunk-SWBNHIO4.js → chunk-3WL6EXYX.js} +1 -1
  8. package/dist/{chunk-B4P6YZFS.js → chunk-6ANLYNFB.js} +1 -1
  9. package/dist/{chunk-VLOIDU5U.js → chunk-6X55ALDX.js} +3 -3
  10. package/dist/{chunk-CLEZ6YQ6.js → chunk-RVUERWUZ.js} +584 -60
  11. package/dist/{chunk-OKRZPQ3R.js → chunk-WIGQCP6O.js} +869 -74
  12. package/dist/{circleci-UM3NSQJ3.js → circleci-LBGB25LP.js} +4 -4
  13. package/dist/{clerk-FE5LQ2CZ.js → clerk-6RX37CNZ.js} +4 -4
  14. package/dist/{cloudflare_dns-KEZABKUT.js → cloudflare_dns-NQGW7FHV.js} +4 -4
  15. package/dist/{cohere-4IPJADXP.js → cohere-XPC2NAEW.js} +4 -4
  16. package/dist/{confluence-56QEKNQI.js → confluence-ZUG2LT5A.js} +4 -4
  17. package/dist/{convertapi-3QRM5K5T.js → convertapi-ZLXKWV3L.js} +3 -3
  18. package/dist/{currencyapi-L6G4OND5.js → currencyapi-T3A3HSOD.js} +4 -4
  19. package/dist/{deepseek-LGC6HBFG.js → deepseek-NJMOD23E.js} +4 -4
  20. package/dist/{docker_hub-XDMK3BIU.js → docker_hub-D2MQCSJ7.js} +4 -4
  21. package/dist/{dropbox-4QARMFZU.js → dropbox-MI6U3SOT.js} +4 -4
  22. package/dist/{dub-C6JSJKOT.js → dub-P2BYBYV4.js} +4 -4
  23. package/dist/{e2b-6A6TVACJ.js → e2b-BGKIAE54.js} +4 -4
  24. package/dist/{exa-SIWWW6AA.js → exa-EUY7VV4C.js} +4 -4
  25. package/dist/{fal_ai-3IJXOKSP.js → fal_ai-AAOG5FYJ.js} +4 -4
  26. package/dist/{feishu-L4KDA4DC.js → feishu-AN5IJYOW.js} +2 -2
  27. package/dist/{feishu_custom_bot-SDM75H4P.js → feishu_custom_bot-BWGMNVXF.js} +3 -3
  28. package/dist/{figma-6DD436DN.js → figma-SJSWYCGD.js} +4 -4
  29. package/dist/{firehydrant-SYSGYB3R.js → firehydrant-MOXK2PST.js} +4 -4
  30. package/dist/{fixer-FZG7ASTF.js → fixer-ISIDUDZU.js} +4 -4
  31. package/dist/{fly-HMRCZBUC.js → fly-U4KPSGBF.js} +4 -4
  32. package/dist/{front-FAFSD7I3.js → front-ZHM2YX2E.js} +4 -4
  33. package/dist/{geocodio-4D3TWENM.js → geocodio-SVCCAXAV.js} +4 -4
  34. package/dist/{ghost-OSO2FOZS.js → ghost-INTR7FIY.js} +4 -4
  35. package/dist/{github-OR4I4RHE.js → github-T275VVWR.js} +4 -4
  36. package/dist/{gmail-5AOPJ63E.js → gmail-KSSPOE67.js} +4 -4
  37. package/dist/{googlecalendar-SOJIJUWH.js → googlecalendar-JB5RW27L.js} +4 -4
  38. package/dist/{googledocs-QSKN5TLN.js → googledocs-G522PUGW.js} +3 -3
  39. package/dist/{grafana-R3AIZM7M.js → grafana-44ZPIV5P.js} +4 -4
  40. package/dist/{graphhopper-4CR3QOAX.js → graphhopper-2MORXLOW.js} +4 -4
  41. package/dist/index.d.ts +21 -6
  42. package/dist/index.js +3 -3
  43. package/dist/{ip2proxy-OBCG6X6J.js → ip2proxy-R4K4KEMI.js} +4 -4
  44. package/dist/{ipgeolocation_io-NHH3DTQW.js → ipgeolocation_io-H4J55OGI.js} +4 -4
  45. package/dist/{ipqualityscore-7POMCBEC.js → ipqualityscore-XGID4OHA.js} +4 -4
  46. package/dist/{jina_ai-YXVKROV4.js → jina_ai-7ZVDOR3Z.js} +4 -4
  47. package/dist/{jira-LADO3VJU.js → jira-CTIYZTT3.js} +4 -4
  48. package/dist/{langsmith-XZ6UAQFU.js → langsmith-ISP567FS.js} +4 -4
  49. package/dist/{lemlist-P74GLNE7.js → lemlist-OGKK272F.js} +4 -4
  50. package/dist/{linear-CXJ7D37A.js → linear-6JX4E3JI.js} +3 -3
  51. package/dist/{logsnag-EVVHWFLK.js → logsnag-BVB36ZCL.js} +4 -4
  52. package/dist/main.js +102 -102
  53. package/dist/{mattermost-WG2MRGBD.js → mattermost-UECVPZGY.js} +4 -4
  54. package/dist/{mem0-HQWUKG6U.js → mem0-EUA7S2OO.js} +4 -4
  55. package/dist/{memos-SQMJIFOE.js → memos-BYSBJRWZ.js} +4 -4
  56. package/dist/{metabase-E27G2DZI.js → metabase-4JXZH3YG.js} +4 -4
  57. package/dist/{mistral_ai-MIL63NIT.js → mistral_ai-2C5BTBKW.js} +4 -4
  58. package/dist/{mother_duck-AIZVCBNR.js → mother_duck-ZGNNNR3X.js} +4 -4
  59. package/dist/{ngrok-XS4DVIQS.js → ngrok-NTPGMRXI.js} +4 -4
  60. package/dist/{notes-JEOUSL2Y.js → notes-KGYXX6N6.js} +1 -1
  61. package/dist/{notion-U4EZVDW2.js → notion-EX3X2G7G.js} +4 -4
  62. package/dist/{open_exchange_rates-AZSQEYEJ.js → open_exchange_rates-2V2LIGPS.js} +4 -4
  63. package/dist/{openai-HW3SYMTQ.js → openai-KQFQPK7Z.js} +4 -4
  64. package/dist/{opengraph_io-QX74MAEL.js → opengraph_io-B63SEYJY.js} +4 -4
  65. package/dist/{openrouter-OXSKYL6N.js → openrouter-62A4H62Q.js} +4 -4
  66. package/dist/{outline-CCQAPDSW.js → outline-QC33XLCK.js} +4 -4
  67. package/dist/{paddle-6KQPSSCK.js → paddle-HDZG35Y7.js} +4 -4
  68. package/dist/{perplexity-2TXO7IQE.js → perplexity-M7LOMJWA.js} +4 -4
  69. package/dist/{pinecone-YOO7NULI.js → pinecone-Y7YCJRZM.js} +4 -4
  70. package/dist/{pipedrive-Q6RIFIFP.js → pipedrive-FLJA62UX.js} +4 -4
  71. package/dist/{polar-KUMGCES3.js → polar-AE55Q425.js} +4 -4
  72. package/dist/{posthog-VXQHBSMB.js → posthog-IAY5D3YW.js} +4 -4
  73. package/dist/{postmark-YLIPF52S.js → postmark-NMKAXDXZ.js} +4 -4
  74. package/dist/{prerender-CRY7UJN5.js → prerender-CDJM7I7N.js} +4 -4
  75. package/dist/{pubmed-3Z4T5AM7.js → pubmed-N437ZJOR.js} +3 -3
  76. package/dist/{railway-BP37IGFL.js → railway-NBWYXCUM.js} +3 -3
  77. package/dist/{readwise-HTKICF4K.js → readwise-QRO3UC3R.js} +4 -4
  78. package/dist/{render-WIVTUXJH.js → render-NEW7SROG.js} +4 -4
  79. package/dist/{replicate-JJYPA43D.js → replicate-73YQLRTY.js} +4 -4
  80. package/dist/{resend-TKHZVG7A.js → resend-R5BAZFHZ.js} +4 -4
  81. package/dist/{rootly-FRSZLG5U.js → rootly-5BLALPCS.js} +4 -4
  82. package/dist/{scrapfly-M5WXGQWE.js → scrapfly-EHFLNNUZ.js} +4 -4
  83. package/dist/{scrapingbee-PMXNLLBK.js → scrapingbee-UXLYS72S.js} +4 -4
  84. package/dist/{screenshot_fyi-HFW4TAOH.js → screenshot_fyi-KC3NLTJ6.js} +4 -4
  85. package/dist/{semantic_scholar-KXVH2VZQ.js → semantic_scholar-SA5OIUWA.js} +4 -4
  86. package/dist/{sentry-WWOT2LRX.js → sentry-BAE3XLJN.js} +4 -4
  87. package/dist/{shodan-FY635H35.js → shodan-FJR6MKKW.js} +4 -4
  88. package/dist/{shopify-HQLBVSA5.js → shopify-7OA6SLN5.js} +4 -4
  89. package/dist/{stripe-GJN2GOHB.js → stripe-MUWDZGGF.js} +3 -3
  90. package/dist/{supabase-BBNZGQU6.js → supabase-SWWGNWYR.js} +4 -4
  91. package/dist/{tavily-DPENIBOG.js → tavily-XQNJ5EDI.js} +4 -4
  92. package/dist/{telegram-L4NONG6H.js → telegram-RR6JPZOG.js} +4 -4
  93. package/dist/{telnyx-H67MAEZS.js → telnyx-7PKXOWSO.js} +4 -4
  94. package/dist/{todoist-G2BSP4DX.js → todoist-63X5IUJE.js} +4 -4
  95. package/dist/{trello-7WMVFDG2.js → trello-MOG63DAI.js} +4 -4
  96. package/dist/{turso-ZUAESFC2.js → turso-ENWTSHDL.js} +4 -4
  97. package/dist/{twilio-EYFYIX3B.js → twilio-FDXUN7VX.js} +3 -3
  98. package/dist/{umami-AXAUDUVF.js → umami-TM7PROWF.js} +4 -4
  99. package/dist/{unsplash-UCQAWPLR.js → unsplash-NWXLKSOW.js} +4 -4
  100. package/dist/{upstash_redis-ZPZ4ASU6.js → upstash_redis-CUTQ5L2N.js} +4 -4
  101. package/dist/{uptimerobot-4QVKKUD5.js → uptimerobot-NNO32M3I.js} +3 -3
  102. package/dist/{v2ex-VGEFJTYC.js → v2ex-24KMSWS7.js} +4 -4
  103. package/dist/{vercel-JME4TSCN.js → vercel-B45LPF6I.js} +4 -4
  104. package/dist/{wolfram_alpha_api-TRGU2MDG.js → wolfram_alpha_api-DKJWVR6G.js} +4 -4
  105. package/dist/{wordpress-WRUKLCZR.js → wordpress-XYFSDZXY.js} +4 -4
  106. package/dist/{workos-ZDW4EHS4.js → workos-BEM7EPHM.js} +4 -4
  107. package/dist/{zhihu-4VI67CWU.js → zhihu-CFHZ4NC7.js} +4 -4
  108. package/package.json +5 -5
@@ -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) {
@@ -14893,17 +14893,17 @@ function assertSecretRefUse(scopes, config2) {
14893
14893
 
14894
14894
  // ../core/src/encoding/base64url.ts
14895
14895
  var ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
14896
- function base64urlEncode(bytes) {
14896
+ function base64urlEncode(bytes2) {
14897
14897
  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;
14898
+ for (let i = 0; i < bytes2.length; i += 3) {
14899
+ const a = bytes2[i] ?? 0;
14900
+ const b = bytes2[i + 1] ?? 0;
14901
+ const c = bytes2[i + 2] ?? 0;
14902
14902
  const n = a << 16 | b << 8 | c;
14903
14903
  out += ALPHABET[n >>> 18 & 63];
14904
14904
  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];
14905
+ if (i + 1 < bytes2.length) out += ALPHABET[n >>> 6 & 63];
14906
+ if (i + 2 < bytes2.length) out += ALPHABET[n & 63];
14907
14907
  }
14908
14908
  return out;
14909
14909
  }
@@ -14911,7 +14911,7 @@ function base64urlDecode(input) {
14911
14911
  if (input.length % 4 === 1 || !/^[A-Za-z0-9_-]*$/.test(input)) {
14912
14912
  throw new Error("base64urlDecode: malformed base64url input");
14913
14913
  }
14914
- const bytes = [];
14914
+ const bytes2 = [];
14915
14915
  for (let i = 0; i < input.length; i += 4) {
14916
14916
  const chunk = input.slice(i, i + 4);
14917
14917
  const a = ALPHABET.indexOf(chunk[0] ?? "");
@@ -14919,11 +14919,11 @@ function base64urlDecode(input) {
14919
14919
  const c = chunk.length >= 3 ? ALPHABET.indexOf(chunk[2] ?? "") : 0;
14920
14920
  const d = chunk.length >= 4 ? ALPHABET.indexOf(chunk[3] ?? "") : 0;
14921
14921
  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);
14922
+ bytes2.push(n >>> 16 & 255);
14923
+ if (chunk.length >= 3) bytes2.push(n >>> 8 & 255);
14924
+ if (chunk.length >= 4) bytes2.push(n & 255);
14925
14925
  }
14926
- return new Uint8Array(bytes);
14926
+ return new Uint8Array(bytes2);
14927
14927
  }
14928
14928
 
14929
14929
  // ../core/src/omit.ts
@@ -14942,8 +14942,8 @@ async function sha256Hex(text) {
14942
14942
  return Array.from(new Uint8Array(digest), (b) => b.toString(16).padStart(2, "0")).join("");
14943
14943
  }
14944
14944
  function generateSecret() {
14945
- const bytes = crypto.getRandomValues(new Uint8Array(16));
14946
- return `${SECRET_PREFIX}${base64urlEncode(bytes)}`;
14945
+ const bytes2 = crypto.getRandomValues(new Uint8Array(16));
14946
+ return `${SECRET_PREFIX}${base64urlEncode(bytes2)}`;
14947
14947
  }
14948
14948
  function normalizeExpiresAt(value) {
14949
14949
  const parsed = ISO_TIMESTAMP.safeParse(value);
@@ -15000,10 +15000,10 @@ function clampLimit(limit) {
15000
15000
  return Math.min(Math.max(1, limit), LIST_LIMIT_MAX);
15001
15001
  }
15002
15002
  var SKRegistryStore = class {
15003
+ store;
15003
15004
  constructor(store) {
15004
15005
  this.store = store;
15005
15006
  }
15006
- store;
15007
15007
  async recordById(id) {
15008
15008
  const hash2 = await this.store.get(KEY_SK_ID + id);
15009
15009
  if (typeof hash2 !== "string") return null;
@@ -15115,6 +15115,7 @@ var OperationRegistry = class {
15115
15115
  const schema = spec.inputSchema !== void 0 ? normalizeSchema(spec.inputSchema) : void 0;
15116
15116
  const toolSpec = { name };
15117
15117
  if (spec.description !== void 0) toolSpec.description = spec.description;
15118
+ if (spec.delivery !== void 0) toolSpec.delivery = spec.delivery;
15118
15119
  if (spec.effect !== void 0) toolSpec.effect = spec.effect;
15119
15120
  if (spec.confirm !== void 0) toolSpec.confirm = spec.confirm;
15120
15121
  if (schema !== void 0) toolSpec.inputSchema = toJsonSchema(schema);
@@ -16617,6 +16618,661 @@ function createFederationModule(deps) {
16617
16618
  return COMMANDS5.module(deps);
16618
16619
  }
16619
16620
 
16621
+ // ../core/src/device/mailbox.ts
16622
+ var KEY_DEVICE_OPERATION = "deviceop:";
16623
+ var DEVICE_OPERATION_STATES = [
16624
+ "queued",
16625
+ "claimed",
16626
+ "succeeded",
16627
+ "rejected",
16628
+ "failed",
16629
+ "result_unknown",
16630
+ "cancelled",
16631
+ "expired"
16632
+ ];
16633
+ var DEFAULT_TTL_SECONDS = 24 * 60 * 60;
16634
+ var MAX_TTL_SECONDS = 7 * 24 * 60 * 60;
16635
+ var DEFAULT_LEASE_SECONDS = 60;
16636
+ var DEFAULT_MAX_PAYLOAD_BYTES = 256 * 1024;
16637
+ var DEFAULT_MAX_PENDING_PER_DEVICE = 1e3;
16638
+ var DEFAULT_TERMINAL_RETENTION_SECONDS = 7 * 24 * 60 * 60;
16639
+ var MAX_CAS_ATTEMPTS = 8;
16640
+ var LIST_LIMIT_DEFAULT2 = 50;
16641
+ var LIST_LIMIT_MAX2 = 200;
16642
+ var HKDF_SALT = new TextEncoder().encode("tool-bridge:device-mailbox:v1");
16643
+ var HKDF_INFO = new TextEncoder().encode("aes-256-gcm:operation-payload-and-result:v1");
16644
+ function mailboxUnavailable(message) {
16645
+ return new TBError("unavailable", message, { retryable: false });
16646
+ }
16647
+ function finiteTimestamp(value) {
16648
+ return typeof value === "string" && Number.isFinite(Date.parse(value));
16649
+ }
16650
+ function nonEmpty(value) {
16651
+ return typeof value === "string" && value !== "";
16652
+ }
16653
+ function positiveInteger(value, fallback, field) {
16654
+ const actual = value ?? fallback;
16655
+ if (!Number.isSafeInteger(actual) || actual < 1) {
16656
+ throw new TBError("invalid_argument", `${field} must be a positive integer`);
16657
+ }
16658
+ return actual;
16659
+ }
16660
+ function clampLimit3(value) {
16661
+ if (value === void 0) return LIST_LIMIT_DEFAULT2;
16662
+ if (!Number.isSafeInteger(value) || value < 1) {
16663
+ throw new TBError("invalid_argument", "limit must be a positive integer");
16664
+ }
16665
+ return Math.min(value, LIST_LIMIT_MAX2);
16666
+ }
16667
+ function isState(value) {
16668
+ return typeof value === "string" && DEVICE_OPERATION_STATES.includes(value);
16669
+ }
16670
+ function isTerminal(state) {
16671
+ return state !== "queued" && state !== "claimed";
16672
+ }
16673
+ function parseEncrypted(value) {
16674
+ if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error("invalid encrypted value");
16675
+ const raw = value;
16676
+ if (raw.v !== 1 || !nonEmpty(raw.iv) || !nonEmpty(raw.ciphertext)) {
16677
+ throw new Error("invalid encrypted value");
16678
+ }
16679
+ return { v: 1, iv: raw.iv, ciphertext: raw.ciphertext };
16680
+ }
16681
+ function parseRecord(value) {
16682
+ try {
16683
+ if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error();
16684
+ const raw = value;
16685
+ if (raw.v !== 1 || !Number.isSafeInteger(raw.revision) || raw.revision < 1 || !nonEmpty(raw.operationId) || raw.commandId !== 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();
16686
+ if (raw.leaseId === void 0 !== (raw.leaseUntil === void 0)) throw new Error();
16687
+ if (raw.leaseId !== void 0 && (!nonEmpty(raw.leaseId) || !finiteTimestamp(raw.leaseUntil))) {
16688
+ throw new Error();
16689
+ }
16690
+ if (raw.cancelRequestedAt !== void 0 && !finiteTimestamp(raw.cancelRequestedAt)) throw new Error();
16691
+ if (raw.terminalAt !== void 0 && !finiteTimestamp(raw.terminalAt)) throw new Error();
16692
+ if (isTerminal(raw.state) && raw.terminalAt === void 0) throw new Error();
16693
+ return {
16694
+ v: 1,
16695
+ revision: raw.revision,
16696
+ operationId: raw.operationId,
16697
+ commandId: raw.commandId,
16698
+ deviceId: raw.deviceId,
16699
+ deviceKeyId: raw.deviceKeyId,
16700
+ mountPath: raw.mountPath,
16701
+ targetPath: raw.targetPath,
16702
+ path: raw.path,
16703
+ callerKeyId: raw.callerKeyId,
16704
+ callerOwner: raw.callerOwner,
16705
+ traceId: raw.traceId,
16706
+ createdAt: raw.createdAt,
16707
+ updatedAt: raw.updatedAt,
16708
+ expiresAt: raw.expiresAt,
16709
+ state: raw.state,
16710
+ attempt: raw.attempt,
16711
+ executionMayHaveOccurred: raw.executionMayHaveOccurred,
16712
+ payload: parseEncrypted(raw.payload),
16713
+ ...raw.leaseId === void 0 ? {} : { leaseId: raw.leaseId, leaseUntil: raw.leaseUntil },
16714
+ ...raw.cancelRequestedAt === void 0 ? {} : { cancelRequestedAt: raw.cancelRequestedAt },
16715
+ ...raw.completedLeaseId === void 0 ? {} : { completedLeaseId: String(raw.completedLeaseId) },
16716
+ ...raw.terminalAt === void 0 ? {} : { terminalAt: raw.terminalAt },
16717
+ ...raw.terminalData === void 0 ? {} : { terminalData: parseEncrypted(raw.terminalData) },
16718
+ ...raw.idempotencyFingerprint === void 0 ? {} : { idempotencyFingerprint: String(raw.idempotencyFingerprint) }
16719
+ };
16720
+ } catch {
16721
+ throw new TBError("internal", "device mailbox record is invalid", { retryable: false });
16722
+ }
16723
+ }
16724
+ function canonicalJson(value) {
16725
+ if (value === null) return "null";
16726
+ if (typeof value === "string" || typeof value === "boolean") return JSON.stringify(value);
16727
+ if (typeof value === "number") {
16728
+ if (!Number.isFinite(value)) throw new TBError("invalid_argument", "mailbox data must be valid JSON");
16729
+ return JSON.stringify(value);
16730
+ }
16731
+ if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
16732
+ if (typeof value !== "object") {
16733
+ throw new TBError("invalid_argument", "mailbox data must be valid JSON");
16734
+ }
16735
+ const object2 = value;
16736
+ const keys = Object.keys(object2).sort();
16737
+ return `{${keys.map((key) => `${JSON.stringify(key)}:${canonicalJson(object2[key])}`).join(",")}}`;
16738
+ }
16739
+ function safeError(value) {
16740
+ 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");
16741
+ return { code: value.code, message: value.message, retryable: value.retryable };
16742
+ }
16743
+ function normalizeCompletion(value) {
16744
+ if (value.outcome === "succeeded") {
16745
+ canonicalJson(value.result);
16746
+ return { outcome: "succeeded", result: value.result };
16747
+ }
16748
+ if (value.outcome === "rejected" || value.outcome === "failed") {
16749
+ return { outcome: value.outcome, error: safeError(value.error) };
16750
+ }
16751
+ return {
16752
+ outcome: "result_unknown",
16753
+ ...value.error === void 0 ? {} : { error: safeError(value.error) }
16754
+ };
16755
+ }
16756
+ function bytes(value) {
16757
+ return new TextEncoder().encode(value).byteLength;
16758
+ }
16759
+ function randomId(randomBytes) {
16760
+ const value = randomBytes(18);
16761
+ if (!(value instanceof Uint8Array) || value.length !== 18) {
16762
+ throw mailboxUnavailable("device mailbox randomness is unavailable");
16763
+ }
16764
+ return `dop_${base64urlEncode(value)}`;
16765
+ }
16766
+ async function digestBytes(value) {
16767
+ return new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value)));
16768
+ }
16769
+ async function deterministicOperationId(binding) {
16770
+ return `dop_${base64urlEncode((await digestBytes(binding)).slice(0, 18))}`;
16771
+ }
16772
+ async function devicePrefix(deviceId) {
16773
+ return `${KEY_DEVICE_OPERATION}${await sha256Hex(deviceId)}:`;
16774
+ }
16775
+ async function stateKey(deviceId, operationId) {
16776
+ if (!/^dop_[A-Za-z0-9_-]{24}$/.test(operationId)) {
16777
+ throw new TBError("invalid_argument", "operationId is invalid");
16778
+ }
16779
+ return await devicePrefix(deviceId) + operationId;
16780
+ }
16781
+ var DeviceMailboxCipher = class {
16782
+ root;
16783
+ keyPromise;
16784
+ constructor(masterKey) {
16785
+ let decoded;
16786
+ try {
16787
+ decoded = base64urlDecode(masterKey);
16788
+ } catch {
16789
+ throw mailboxUnavailable("device mailbox encryption key is invalid");
16790
+ }
16791
+ if (decoded.length !== 32) {
16792
+ throw mailboxUnavailable("device mailbox encryption key is invalid");
16793
+ }
16794
+ this.root = decoded;
16795
+ }
16796
+ key() {
16797
+ this.keyPromise ??= (async () => {
16798
+ const rootKey = await crypto.subtle.importKey("raw", this.root, "HKDF", false, ["deriveKey"]);
16799
+ return await crypto.subtle.deriveKey(
16800
+ { name: "HKDF", hash: "SHA-256", salt: HKDF_SALT, info: HKDF_INFO },
16801
+ rootKey,
16802
+ { name: "AES-GCM", length: 256 },
16803
+ false,
16804
+ ["encrypt", "decrypt"]
16805
+ );
16806
+ })();
16807
+ return this.keyPromise;
16808
+ }
16809
+ async encrypt(operationId, field, value) {
16810
+ const plaintext = canonicalJson(value);
16811
+ const iv = crypto.getRandomValues(new Uint8Array(12));
16812
+ const additionalData = new TextEncoder().encode(`tool-bridge:device-mailbox:v1:${operationId}:${field}`);
16813
+ const ciphertext = await crypto.subtle.encrypt(
16814
+ { name: "AES-GCM", iv, additionalData },
16815
+ await this.key(),
16816
+ new TextEncoder().encode(plaintext)
16817
+ );
16818
+ return {
16819
+ v: 1,
16820
+ iv: base64urlEncode(iv),
16821
+ ciphertext: base64urlEncode(new Uint8Array(ciphertext))
16822
+ };
16823
+ }
16824
+ async decrypt(operationId, field, value) {
16825
+ try {
16826
+ const iv = base64urlDecode(value.iv);
16827
+ const ciphertext = base64urlDecode(value.ciphertext);
16828
+ if (iv.length !== 12) throw new Error("invalid iv");
16829
+ const additionalData = new TextEncoder().encode(`tool-bridge:device-mailbox:v1:${operationId}:${field}`);
16830
+ const plaintext = await crypto.subtle.decrypt(
16831
+ { name: "AES-GCM", iv, additionalData },
16832
+ await this.key(),
16833
+ ciphertext
16834
+ );
16835
+ return JSON.parse(new TextDecoder().decode(plaintext));
16836
+ } catch {
16837
+ throw new TBError("internal", "device mailbox data cannot be decrypted", { retryable: false });
16838
+ }
16839
+ }
16840
+ };
16841
+ var DeviceMailboxService = class {
16842
+ cas;
16843
+ cipher;
16844
+ defaultTtlSeconds;
16845
+ leaseSeconds;
16846
+ maxPayloadBytes;
16847
+ maxPendingPerDevice;
16848
+ maxTtlSeconds;
16849
+ now;
16850
+ randomBytes;
16851
+ state;
16852
+ terminalRetentionSeconds;
16853
+ constructor(state, encryptionRoot, opts = {}) {
16854
+ if (state.compareAndSwap === void 0) {
16855
+ throw mailboxUnavailable("device mailbox requires StateStore.compareAndSwap");
16856
+ }
16857
+ if (encryptionRoot === void 0) {
16858
+ throw mailboxUnavailable("device mailbox requires TB_SECRET_ENCRYPTION_KEY");
16859
+ }
16860
+ this.cas = state.compareAndSwap.bind(state);
16861
+ this.state = state;
16862
+ this.cipher = new DeviceMailboxCipher(encryptionRoot);
16863
+ this.defaultTtlSeconds = positiveInteger(
16864
+ opts.defaultTtlSeconds,
16865
+ DEFAULT_TTL_SECONDS,
16866
+ "defaultTtlSeconds"
16867
+ );
16868
+ this.maxTtlSeconds = positiveInteger(opts.maxTtlSeconds, MAX_TTL_SECONDS, "maxTtlSeconds");
16869
+ if (this.defaultTtlSeconds > this.maxTtlSeconds) {
16870
+ throw new TBError("invalid_argument", "defaultTtlSeconds cannot exceed maxTtlSeconds");
16871
+ }
16872
+ this.leaseSeconds = positiveInteger(opts.leaseSeconds, DEFAULT_LEASE_SECONDS, "leaseSeconds");
16873
+ this.maxPayloadBytes = positiveInteger(
16874
+ opts.maxPayloadBytes,
16875
+ DEFAULT_MAX_PAYLOAD_BYTES,
16876
+ "maxPayloadBytes"
16877
+ );
16878
+ this.maxPendingPerDevice = positiveInteger(
16879
+ opts.maxPendingPerDevice,
16880
+ DEFAULT_MAX_PENDING_PER_DEVICE,
16881
+ "maxPendingPerDevice"
16882
+ );
16883
+ this.terminalRetentionSeconds = positiveInteger(
16884
+ opts.terminalRetentionSeconds,
16885
+ DEFAULT_TERMINAL_RETENTION_SECONDS,
16886
+ "terminalRetentionSeconds"
16887
+ );
16888
+ this.now = opts.now ?? (() => Date.now());
16889
+ this.randomBytes = opts.randomBytes ?? ((length) => crypto.getRandomValues(new Uint8Array(length)));
16890
+ }
16891
+ nowIso() {
16892
+ return new Date(this.now()).toISOString();
16893
+ }
16894
+ async read(deviceId, operationId) {
16895
+ const key = await stateKey(deviceId, operationId);
16896
+ const value = await this.state.get(key);
16897
+ if (value === null) throw TBError.notFound("device operation not found");
16898
+ const record2 = parseRecord(value);
16899
+ if (record2.deviceId !== deviceId || record2.operationId !== operationId) {
16900
+ throw new TBError("internal", "device mailbox record identity mismatch", { retryable: false });
16901
+ }
16902
+ return { key, record: record2 };
16903
+ }
16904
+ summary(record2) {
16905
+ return {
16906
+ operationId: record2.operationId,
16907
+ commandId: record2.commandId,
16908
+ deviceId: record2.deviceId,
16909
+ mountPath: record2.mountPath,
16910
+ targetPath: record2.targetPath,
16911
+ caller: { keyId: record2.callerKeyId, owner: record2.callerOwner },
16912
+ traceId: record2.traceId,
16913
+ createdAt: record2.createdAt,
16914
+ updatedAt: record2.updatedAt,
16915
+ expiresAt: record2.expiresAt,
16916
+ state: record2.state,
16917
+ attempt: record2.attempt,
16918
+ executionMayHaveOccurred: record2.executionMayHaveOccurred,
16919
+ ...record2.leaseUntil === void 0 ? {} : { leaseUntil: record2.leaseUntil },
16920
+ ...record2.cancelRequestedAt === void 0 ? {} : { cancelRequestedAt: record2.cancelRequestedAt },
16921
+ ...record2.terminalAt === void 0 ? {} : { terminalAt: record2.terminalAt }
16922
+ };
16923
+ }
16924
+ async detail(record2) {
16925
+ const summary = this.summary(record2);
16926
+ if (record2.terminalData === void 0) return summary;
16927
+ const terminal = await this.cipher.decrypt(
16928
+ record2.operationId,
16929
+ "terminal",
16930
+ record2.terminalData
16931
+ );
16932
+ if (record2.state === "succeeded") return { ...summary, result: terminal.result };
16933
+ const error51 = terminal.error;
16934
+ if (error51 === void 0) return summary;
16935
+ return { ...summary, error: safeError(error51) };
16936
+ }
16937
+ async expireRecord(key, record2) {
16938
+ let current = record2;
16939
+ for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {
16940
+ if (isTerminal(current.state) || Date.parse(current.expiresAt) > this.now()) return current;
16941
+ const now = this.nowIso();
16942
+ const next = {
16943
+ ...current,
16944
+ revision: current.revision + 1,
16945
+ state: "expired",
16946
+ updatedAt: now,
16947
+ terminalAt: now,
16948
+ executionMayHaveOccurred: current.state === "claimed"
16949
+ };
16950
+ if (await this.cas(key, current.revision, next)) return next;
16951
+ const winner = await this.state.get(key);
16952
+ if (winner === null) throw TBError.notFound("device operation not found");
16953
+ current = parseRecord(winner);
16954
+ }
16955
+ throw new TBError("unavailable", "device operation expiry is busy", { retryable: true });
16956
+ }
16957
+ async enforcePendingCap(deviceId) {
16958
+ const prefix = await devicePrefix(deviceId);
16959
+ let cursor;
16960
+ let pending = 0;
16961
+ do {
16962
+ const page = await this.state.list(prefix, {
16963
+ limit: LIST_LIMIT_MAX2,
16964
+ ...cursor === void 0 ? {} : { cursor }
16965
+ });
16966
+ for (const item of page.items) {
16967
+ let record2 = parseRecord(item.value);
16968
+ if (record2.deviceId !== deviceId) continue;
16969
+ record2 = await this.expireRecord(item.key, record2);
16970
+ if (!isTerminal(record2.state)) pending++;
16971
+ if (pending >= this.maxPendingPerDevice) {
16972
+ throw new TBError("rate_limited", "device mailbox pending limit reached", {
16973
+ retryable: true
16974
+ });
16975
+ }
16976
+ }
16977
+ cursor = page.cursor;
16978
+ } while (cursor !== void 0);
16979
+ }
16980
+ async enqueue(input) {
16981
+ const ttlSeconds = input.ttlSeconds ?? this.defaultTtlSeconds;
16982
+ if (!Number.isSafeInteger(ttlSeconds) || ttlSeconds < 1 || ttlSeconds > this.maxTtlSeconds) {
16983
+ throw new TBError("invalid_argument", `ttlSeconds must be between 1 and ${this.maxTtlSeconds}`);
16984
+ }
16985
+ const payloadText = canonicalJson({ arguments: input.arguments });
16986
+ if (bytes(payloadText) > this.maxPayloadBytes) {
16987
+ throw new TBError("rate_limited", "device mailbox payload is too large", { retryable: false });
16988
+ }
16989
+ 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");
16990
+ const binding = input.idempotencyKey === void 0 ? void 0 : canonicalJson({
16991
+ callerOwner: input.caller.owner,
16992
+ deviceId: input.deviceId,
16993
+ targetPath: input.targetPath,
16994
+ idempotencyKey: input.idempotencyKey
16995
+ });
16996
+ const operationId = binding === void 0 ? randomId(this.randomBytes) : await deterministicOperationId(binding);
16997
+ const fingerprint = binding === void 0 ? void 0 : await sha256Hex(canonicalJson({
16998
+ arguments: input.arguments,
16999
+ deviceKeyId: input.deviceKeyId,
17000
+ path: input.path,
17001
+ ttlSeconds
17002
+ }));
17003
+ const key = await stateKey(input.deviceId, operationId);
17004
+ if (binding !== void 0) {
17005
+ const existing2 = await this.state.get(key);
17006
+ if (existing2 !== null) {
17007
+ const record3 = parseRecord(existing2);
17008
+ 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");
17009
+ return await this.detail(record3);
17010
+ }
17011
+ }
17012
+ await this.enforcePendingCap(input.deviceId);
17013
+ const now = this.nowIso();
17014
+ const record2 = {
17015
+ v: 1,
17016
+ revision: 1,
17017
+ operationId,
17018
+ commandId: operationId,
17019
+ deviceId: input.deviceId,
17020
+ deviceKeyId: input.deviceKeyId,
17021
+ mountPath: input.mountPath,
17022
+ targetPath: input.targetPath,
17023
+ path: input.path,
17024
+ callerKeyId: input.caller.keyId,
17025
+ callerOwner: input.caller.owner,
17026
+ traceId: input.traceId,
17027
+ createdAt: now,
17028
+ updatedAt: now,
17029
+ expiresAt: new Date(this.now() + ttlSeconds * 1e3).toISOString(),
17030
+ state: "queued",
17031
+ attempt: 0,
17032
+ executionMayHaveOccurred: false,
17033
+ payload: await this.cipher.encrypt(operationId, "payload", { arguments: input.arguments }),
17034
+ ...fingerprint === void 0 ? {} : { idempotencyFingerprint: fingerprint }
17035
+ };
17036
+ if (await this.cas(key, null, record2)) return await this.detail(record2);
17037
+ if (binding === void 0) {
17038
+ throw new TBError("conflict", "device operation id collision", { retryable: true });
17039
+ }
17040
+ const winner = await this.state.get(key);
17041
+ if (winner === null) throw new TBError("conflict", "device operation enqueue conflicted");
17042
+ const existing = parseRecord(winner);
17043
+ if (existing.idempotencyFingerprint !== fingerprint) {
17044
+ throw new TBError("conflict", "idempotency key is bound to another operation");
17045
+ }
17046
+ return await this.detail(existing);
17047
+ }
17048
+ async get(deviceId, operationId) {
17049
+ const { key, record: record2 } = await this.read(deviceId, operationId);
17050
+ return await this.detail(await this.expireRecord(key, record2));
17051
+ }
17052
+ async list(input) {
17053
+ const limit = clampLimit3(input.limit);
17054
+ const states = input.states === void 0 ? void 0 : new Set(input.states);
17055
+ if (states !== void 0 && [...states].some((state) => !isState(state))) {
17056
+ throw new TBError("invalid_argument", "states contains an invalid operation state");
17057
+ }
17058
+ const page = await this.state.list(await devicePrefix(input.deviceId), {
17059
+ limit,
17060
+ ...input.cursor === void 0 ? {} : { cursor: input.cursor }
17061
+ });
17062
+ const items = [];
17063
+ for (const item of page.items) {
17064
+ let record2 = parseRecord(item.value);
17065
+ if (record2.deviceId !== input.deviceId) continue;
17066
+ record2 = await this.expireRecord(item.key, record2);
17067
+ if (states !== void 0 && !states.has(record2.state)) continue;
17068
+ items.push(this.summary(record2));
17069
+ }
17070
+ return { items, ...page.cursor === void 0 ? {} : { cursor: page.cursor } };
17071
+ }
17072
+ async claim(input) {
17073
+ const serverNow = this.nowIso();
17074
+ const page = await this.state.list(await devicePrefix(input.deviceId), {
17075
+ limit: clampLimit3(input.limit),
17076
+ ...input.cursor === void 0 ? {} : { cursor: input.cursor }
17077
+ });
17078
+ for (const item of page.items) {
17079
+ let record2 = parseRecord(item.value);
17080
+ if (record2.deviceId !== input.deviceId || record2.deviceKeyId !== input.deviceKeyId) continue;
17081
+ record2 = await this.expireRecord(item.key, record2);
17082
+ const reclaimable = record2.state === "claimed" && record2.leaseUntil !== void 0 && Date.parse(record2.leaseUntil) <= this.now();
17083
+ if (record2.state !== "queued" && !reclaimable) continue;
17084
+ await input.authorize?.({
17085
+ deviceId: record2.deviceId,
17086
+ deviceKeyId: record2.deviceKeyId,
17087
+ mountPath: record2.mountPath,
17088
+ targetPath: record2.targetPath
17089
+ });
17090
+ const leaseId = randomId(this.randomBytes);
17091
+ const leaseUntil = new Date(Math.min(
17092
+ this.now() + this.leaseSeconds * 1e3,
17093
+ Date.parse(record2.expiresAt)
17094
+ )).toISOString();
17095
+ const next = {
17096
+ ...record2,
17097
+ revision: record2.revision + 1,
17098
+ state: "claimed",
17099
+ attempt: record2.attempt + 1,
17100
+ leaseId,
17101
+ leaseUntil,
17102
+ updatedAt: serverNow
17103
+ };
17104
+ if (!await this.cas(item.key, record2.revision, next)) continue;
17105
+ const payload = await this.cipher.decrypt(
17106
+ record2.operationId,
17107
+ "payload",
17108
+ record2.payload
17109
+ );
17110
+ 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 });
17111
+ return {
17112
+ serverNow,
17113
+ ...page.cursor === void 0 ? {} : { cursor: page.cursor },
17114
+ operation: {
17115
+ operationId: next.operationId,
17116
+ commandId: next.commandId,
17117
+ targetPath: next.targetPath,
17118
+ path: next.path,
17119
+ arguments: payload.arguments,
17120
+ caller: { keyId: next.callerKeyId, owner: next.callerOwner },
17121
+ traceId: next.traceId,
17122
+ createdAt: next.createdAt,
17123
+ expiresAt: next.expiresAt,
17124
+ attempt: next.attempt,
17125
+ leaseId,
17126
+ leaseUntil,
17127
+ ...next.cancelRequestedAt === void 0 ? {} : { cancelRequestedAt: next.cancelRequestedAt }
17128
+ }
17129
+ };
17130
+ }
17131
+ return {
17132
+ serverNow,
17133
+ ...page.cursor === void 0 ? {} : { cursor: page.cursor }
17134
+ };
17135
+ }
17136
+ async activeLease(input) {
17137
+ const current = await this.read(input.deviceId, input.operationId);
17138
+ const record2 = await this.expireRecord(current.key, current.record);
17139
+ 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");
17140
+ await input.authorize?.({
17141
+ deviceId: record2.deviceId,
17142
+ deviceKeyId: record2.deviceKeyId,
17143
+ mountPath: record2.mountPath,
17144
+ targetPath: record2.targetPath
17145
+ });
17146
+ return { key: current.key, record: record2 };
17147
+ }
17148
+ async renew(input) {
17149
+ for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {
17150
+ const { key, record: record2 } = await this.activeLease(input);
17151
+ const serverNow = this.nowIso();
17152
+ const leaseUntil = new Date(Math.min(
17153
+ this.now() + this.leaseSeconds * 1e3,
17154
+ Date.parse(record2.expiresAt)
17155
+ )).toISOString();
17156
+ const next = {
17157
+ ...record2,
17158
+ revision: record2.revision + 1,
17159
+ leaseUntil,
17160
+ updatedAt: serverNow
17161
+ };
17162
+ if (await this.cas(key, record2.revision, next)) {
17163
+ return {
17164
+ serverNow,
17165
+ leaseUntil,
17166
+ ...next.cancelRequestedAt === void 0 ? {} : { cancelRequestedAt: next.cancelRequestedAt }
17167
+ };
17168
+ }
17169
+ }
17170
+ throw new TBError("unavailable", "device operation lease is busy", { retryable: true });
17171
+ }
17172
+ async complete(input, completionInput) {
17173
+ const completion = normalizeCompletion(completionInput);
17174
+ const terminalData = completion.outcome === "succeeded" ? { result: completion.result } : completion.error === void 0 ? {} : { error: completion.error };
17175
+ if (bytes(canonicalJson(terminalData)) > this.maxPayloadBytes) {
17176
+ throw new TBError("rate_limited", "device mailbox terminal payload is too large", {
17177
+ retryable: false
17178
+ });
17179
+ }
17180
+ for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {
17181
+ const current = await this.read(input.deviceId, input.operationId);
17182
+ let record2 = await this.expireRecord(current.key, current.record);
17183
+ if (record2.deviceKeyId !== input.deviceKeyId) {
17184
+ throw new TBError("conflict", "device operation credential does not match");
17185
+ }
17186
+ await input.authorize?.({
17187
+ deviceId: record2.deviceId,
17188
+ deviceKeyId: record2.deviceKeyId,
17189
+ mountPath: record2.mountPath,
17190
+ targetPath: record2.targetPath
17191
+ });
17192
+ if (isTerminal(record2.state)) {
17193
+ if (record2.completedLeaseId !== input.leaseId || record2.state !== completion.outcome || record2.terminalData === void 0) throw new TBError("conflict", "device operation is already terminal");
17194
+ const existing = await this.cipher.decrypt(
17195
+ record2.operationId,
17196
+ "terminal",
17197
+ record2.terminalData
17198
+ );
17199
+ const requested = completion.outcome === "succeeded" ? { result: completion.result } : completion.error === void 0 ? {} : { error: completion.error };
17200
+ if (canonicalJson(existing) !== canonicalJson(requested)) {
17201
+ throw new TBError("conflict", "device operation completion differs from terminal result");
17202
+ }
17203
+ return await this.detail(record2);
17204
+ }
17205
+ const active = await this.activeLease(input);
17206
+ record2 = active.record;
17207
+ const now = this.nowIso();
17208
+ const next = {
17209
+ ...record2,
17210
+ revision: record2.revision + 1,
17211
+ state: completion.outcome,
17212
+ terminalAt: now,
17213
+ terminalData: await this.cipher.encrypt(record2.operationId, "terminal", terminalData),
17214
+ completedLeaseId: input.leaseId,
17215
+ updatedAt: now
17216
+ };
17217
+ if (await this.cas(active.key, record2.revision, next)) return await this.detail(next);
17218
+ }
17219
+ throw new TBError("unavailable", "device operation completion is busy", { retryable: true });
17220
+ }
17221
+ async cancel(deviceId, operationId) {
17222
+ for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {
17223
+ const current = await this.read(deviceId, operationId);
17224
+ const record2 = await this.expireRecord(current.key, current.record);
17225
+ if (isTerminal(record2.state) || record2.cancelRequestedAt !== void 0) {
17226
+ return await this.detail(record2);
17227
+ }
17228
+ const now = this.nowIso();
17229
+ const next = record2.state === "queued" ? {
17230
+ ...record2,
17231
+ revision: record2.revision + 1,
17232
+ state: "cancelled",
17233
+ cancelRequestedAt: now,
17234
+ terminalAt: now,
17235
+ updatedAt: now
17236
+ } : {
17237
+ ...record2,
17238
+ revision: record2.revision + 1,
17239
+ cancelRequestedAt: now,
17240
+ updatedAt: now
17241
+ };
17242
+ if (await this.cas(current.key, record2.revision, next)) return await this.detail(next);
17243
+ }
17244
+ throw new TBError("unavailable", "device operation cancellation is busy", { retryable: true });
17245
+ }
17246
+ async cleanup(opts = {}) {
17247
+ const page = await this.state.list(KEY_DEVICE_OPERATION, {
17248
+ limit: clampLimit3(opts.limit),
17249
+ ...opts.cursor === void 0 ? {} : { cursor: opts.cursor }
17250
+ });
17251
+ let deleted = 0;
17252
+ let expired = 0;
17253
+ for (const item of page.items) {
17254
+ let record2;
17255
+ try {
17256
+ record2 = parseRecord(item.value);
17257
+ } catch {
17258
+ continue;
17259
+ }
17260
+ if (!isTerminal(record2.state) && Date.parse(record2.expiresAt) <= this.now()) {
17261
+ const next = await this.expireRecord(item.key, record2);
17262
+ if (next.state === "expired") expired++;
17263
+ record2 = next;
17264
+ }
17265
+ 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++;
17266
+ }
17267
+ return {
17268
+ scanned: page.items.length,
17269
+ expired,
17270
+ deleted,
17271
+ ...page.cursor === void 0 ? {} : { cursor: page.cursor }
17272
+ };
17273
+ }
17274
+ };
17275
+
16620
17276
  // ../core/src/protocol/errorWire.ts
16621
17277
  var tbErrorCodeSchema = external_exports.enum(TB_ERROR_CODES);
16622
17278
  var tbErrorBodySchema = external_exports.object({
@@ -16663,6 +17319,7 @@ var helpChildSchema = external_exports.object({
16663
17319
  });
16664
17320
  var helpCommandSchema = external_exports.object({
16665
17321
  confirm: external_exports.boolean().optional(),
17322
+ delivery: external_exports.enum(["realtime", "mailbox", "both"]).optional(),
16666
17323
  effect: external_exports.string().optional(),
16667
17324
  h: external_exports.string().optional(),
16668
17325
  inputSchema: external_exports.unknown().optional(),
@@ -16696,6 +17353,7 @@ var treeJsonSchema = external_exports.lazy(() => external_exports.object({
16696
17353
  }));
16697
17354
  var toolSpecSchema = external_exports.object({
16698
17355
  confirm: external_exports.boolean().optional(),
17356
+ delivery: external_exports.enum(["realtime", "mailbox", "both"]).optional(),
16699
17357
  description: external_exports.string().optional(),
16700
17358
  effect: external_exports.string().optional(),
16701
17359
  inputSchema: external_exports.unknown().optional(),
@@ -16733,6 +17391,12 @@ var toolSearchItemSchema = external_exports.strictObject({
16733
17391
  source: toolSearchSourceSchema.optional(),
16734
17392
  tool: toolSpecSchema
16735
17393
  });
17394
+ function pageSchema(itemSchema) {
17395
+ return external_exports.object({
17396
+ cursor: external_exports.string().optional(),
17397
+ items: external_exports.array(itemSchema)
17398
+ });
17399
+ }
16736
17400
  var toolSearchPageSchema = external_exports.strictObject({
16737
17401
  cursor: external_exports.string().optional(),
16738
17402
  items: external_exports.array(toolSearchItemSchema),
@@ -16754,10 +17418,115 @@ var toolSearchRequestSchema = external_exports.strictObject({
16754
17418
  }).optional(),
16755
17419
  query: external_exports.string().trim().min(1)
16756
17420
  });
17421
+ var deviceOperationStateSchema = external_exports.enum(
17422
+ DEVICE_OPERATION_STATES
17423
+ );
17424
+ var deviceOperationCallerSchema = external_exports.object({
17425
+ keyId: external_exports.string().min(1),
17426
+ owner: external_exports.string().min(1)
17427
+ });
17428
+ var deviceOperationSummaryShape = {
17429
+ attempt: external_exports.number().int().nonnegative(),
17430
+ caller: deviceOperationCallerSchema,
17431
+ cancelRequestedAt: external_exports.iso.datetime({ offset: true }).optional(),
17432
+ commandId: external_exports.string().min(1),
17433
+ createdAt: external_exports.iso.datetime({ offset: true }),
17434
+ deviceId: external_exports.string().min(1),
17435
+ executionMayHaveOccurred: external_exports.boolean(),
17436
+ expiresAt: external_exports.iso.datetime({ offset: true }),
17437
+ leaseUntil: external_exports.iso.datetime({ offset: true }).optional(),
17438
+ mountPath: external_exports.string().min(1),
17439
+ operationId: external_exports.string().min(1),
17440
+ state: deviceOperationStateSchema,
17441
+ targetPath: external_exports.string().min(1),
17442
+ terminalAt: external_exports.iso.datetime({ offset: true }).optional(),
17443
+ traceId: external_exports.string().min(1),
17444
+ updatedAt: external_exports.iso.datetime({ offset: true })
17445
+ };
17446
+ var deviceOperationSummarySchema = external_exports.object(
17447
+ deviceOperationSummaryShape
17448
+ );
17449
+ var deviceOperationDetailSchema = external_exports.object({
17450
+ ...deviceOperationSummaryShape,
17451
+ error: tbErrorBodySchema.optional(),
17452
+ result: external_exports.json().optional()
17453
+ });
17454
+ var deviceOperationListRequestSchema = external_exports.strictObject({
17455
+ deviceId: external_exports.string().min(1),
17456
+ opts: external_exports.strictObject({
17457
+ cursor: external_exports.string().min(1).optional(),
17458
+ limit: external_exports.number().int().positive().optional(),
17459
+ states: external_exports.array(deviceOperationStateSchema).min(1).optional()
17460
+ }).optional()
17461
+ });
17462
+ var deviceOperationListResponseSchema = pageSchema(deviceOperationSummarySchema);
17463
+ var deviceOperationIdentityRequestSchema = external_exports.strictObject({
17464
+ deviceId: external_exports.string().min(1),
17465
+ operationId: external_exports.string().min(1)
17466
+ });
17467
+ var deviceOperationClaimRequestSchema = external_exports.strictObject({
17468
+ cursor: external_exports.string().min(1).optional(),
17469
+ deviceId: external_exports.string().min(1),
17470
+ limit: external_exports.number().int().positive().optional()
17471
+ });
17472
+ var deviceOperationClaimSchema = external_exports.object({
17473
+ arguments: external_exports.record(external_exports.string(), external_exports.json()),
17474
+ attempt: external_exports.number().int().positive(),
17475
+ caller: deviceOperationCallerSchema,
17476
+ cancelRequestedAt: external_exports.iso.datetime({ offset: true }).optional(),
17477
+ commandId: external_exports.string().min(1),
17478
+ createdAt: external_exports.iso.datetime({ offset: true }),
17479
+ expiresAt: external_exports.iso.datetime({ offset: true }),
17480
+ leaseId: external_exports.string().min(1),
17481
+ leaseUntil: external_exports.iso.datetime({ offset: true }),
17482
+ operationId: external_exports.string().min(1),
17483
+ path: external_exports.string().min(1),
17484
+ targetPath: external_exports.string().min(1),
17485
+ traceId: external_exports.string().min(1)
17486
+ });
17487
+ var deviceOperationClaimResponseSchema = external_exports.object({
17488
+ cursor: external_exports.string().optional(),
17489
+ operation: deviceOperationClaimSchema.optional(),
17490
+ serverNow: external_exports.iso.datetime({ offset: true })
17491
+ });
17492
+ var deviceOperationLeaseShape = {
17493
+ deviceId: external_exports.string().min(1),
17494
+ leaseId: external_exports.string().min(1),
17495
+ operationId: external_exports.string().min(1)
17496
+ };
17497
+ var deviceOperationRenewRequestSchema = external_exports.strictObject(deviceOperationLeaseShape);
17498
+ var deviceOperationRenewResponseSchema = external_exports.object({
17499
+ cancelRequestedAt: external_exports.iso.datetime({ offset: true }).optional(),
17500
+ leaseUntil: external_exports.iso.datetime({ offset: true }),
17501
+ serverNow: external_exports.iso.datetime({ offset: true })
17502
+ });
17503
+ var deviceOperationCompleteRequestSchema = external_exports.discriminatedUnion("outcome", [
17504
+ external_exports.strictObject({
17505
+ ...deviceOperationLeaseShape,
17506
+ outcome: external_exports.literal("succeeded"),
17507
+ result: external_exports.json()
17508
+ }),
17509
+ external_exports.strictObject({
17510
+ ...deviceOperationLeaseShape,
17511
+ error: tbErrorBodySchema,
17512
+ outcome: external_exports.literal("rejected")
17513
+ }),
17514
+ external_exports.strictObject({
17515
+ ...deviceOperationLeaseShape,
17516
+ error: tbErrorBodySchema,
17517
+ outcome: external_exports.literal("failed")
17518
+ }),
17519
+ external_exports.strictObject({
17520
+ ...deviceOperationLeaseShape,
17521
+ error: tbErrorBodySchema.optional(),
17522
+ outcome: external_exports.literal("result_unknown")
17523
+ })
17524
+ ]);
16757
17525
  var registryNodeSchema = external_exports.object({
16758
17526
  config: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
16759
17527
  createdAt: external_exports.string().optional(),
16760
17528
  description: external_exports.string(),
17529
+ deviceId: external_exports.string().optional(),
16761
17530
  kind: nodeKindSchema,
16762
17531
  lastSeenAt: external_exports.string().optional(),
16763
17532
  online: external_exports.boolean().optional(),
@@ -17206,7 +17975,7 @@ async function objectBodyToBytes(body) {
17206
17975
  if (body instanceof ArrayBuffer) return new Uint8Array(body);
17207
17976
  return readStreamBytes(body);
17208
17977
  }
17209
- function bytesToObjectStream(bytes) {
17978
+ function bytesToObjectStream(bytes2) {
17210
17979
  return {
17211
17980
  getReader() {
17212
17981
  let done = false;
@@ -17214,7 +17983,7 @@ function bytesToObjectStream(bytes) {
17214
17983
  async read() {
17215
17984
  if (done) return { done: true };
17216
17985
  done = true;
17217
- return { done: false, value: bytes };
17986
+ return { done: false, value: bytes2 };
17218
17987
  },
17219
17988
  releaseLock() {
17220
17989
  },
@@ -17339,7 +18108,7 @@ async function createObjectContextUploadGrant(store, opts, input) {
17339
18108
  expiresAt
17340
18109
  };
17341
18110
  }
17342
- function clampLimit3(limit) {
18111
+ function clampLimit4(limit) {
17343
18112
  if (limit === void 0) return LIST_LIMIT_DEFAULT;
17344
18113
  if (!Number.isInteger(limit) || limit < 1) {
17345
18114
  throw new TBError("invalid_argument", `limit \u975E\u6CD5:${limit}`);
@@ -17413,7 +18182,7 @@ function createObjectContextProvider(store, opts) {
17413
18182
  return {
17414
18183
  async list(path, listOpts) {
17415
18184
  rejectFilter(listOpts);
17416
- const limit = clampLimit3(listOpts?.limit);
18185
+ const limit = clampLimit4(listOpts?.limit);
17417
18186
  const rel = path === "" ? "" : `${normalizeEntryPath(path)}/`;
17418
18187
  const full = keyPrefix + rel;
17419
18188
  assertContextKeyAllowed(full.slice(0, -1), path, false);
@@ -17523,7 +18292,7 @@ function createObjectContextProvider(store, opts) {
17523
18292
  throw new TBError("invalid_argument", "query \u4E0D\u80FD\u4E3A\u7A7A");
17524
18293
  }
17525
18294
  rejectFilter(searchOpts);
17526
- const limit = clampLimit3(searchOpts?.limit);
18295
+ const limit = clampLimit4(searchOpts?.limit);
17527
18296
  const q = query.toLowerCase();
17528
18297
  const after = searchOpts?.cursor;
17529
18298
  const items = [];
@@ -17580,6 +18349,7 @@ function isContextExpired(createdAt, ttlSec, now) {
17580
18349
  // ../core/src/device/frames.ts
17581
18350
  var deviceNodeCmdSchema = external_exports.object({
17582
18351
  name: external_exports.string().min(1),
18352
+ delivery: external_exports.enum(["realtime", "mailbox", "both"]).optional(),
17583
18353
  description: external_exports.string().optional(),
17584
18354
  inputSchema: external_exports.unknown().optional(),
17585
18355
  outputSchema: external_exports.unknown().optional(),
@@ -17846,7 +18616,7 @@ var DeviceGatewaySession = class {
17846
18616
  call(req, done) {
17847
18617
  const cached2 = this.results.get(req.id);
17848
18618
  if (cached2 !== void 0) {
17849
- done(cached2);
18619
+ done(cached2, "completed");
17850
18620
  return;
17851
18621
  }
17852
18622
  const inflight = this.pending.get(req.id);
@@ -17855,19 +18625,28 @@ var DeviceGatewaySession = class {
17855
18625
  return;
17856
18626
  }
17857
18627
  if (this.phase_ !== "ready") {
17858
- done({ ok: false, error: TBError.deviceOffline().toJSON() });
18628
+ done({ ok: false, error: TBError.deviceOffline().toJSON() }, "not_dispatched");
17859
18629
  return;
17860
18630
  }
17861
18631
  const cancelTimer = this.opts.setTimer(() => this.onCallTimeout(req.id), this.timeoutMs);
17862
18632
  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
- });
18633
+ try {
18634
+ this.io.send({
18635
+ type: "call",
18636
+ id: req.id,
18637
+ path: req.path,
18638
+ arguments: req.arguments,
18639
+ // undefined JSON.stringify 丢弃:老网关不带 context 时帧形状不变。
18640
+ ...req.context !== void 0 ? { context: req.context } : {}
18641
+ });
18642
+ } catch {
18643
+ this.pending.delete(req.id);
18644
+ cancelTimer();
18645
+ done({
18646
+ ok: false,
18647
+ error: new TBError("unavailable", "\u8BBE\u5907\u8C03\u7528\u53D1\u9001\u5931\u8D25", { retryable: true }).toJSON()
18648
+ }, "unknown");
18649
+ }
17871
18650
  }
17872
18651
  /** 幂等表回放种子(DO 从 ctx.storage 恢复时用);已有同 id 结果则忽略。 */
17873
18652
  seedResult(id, result) {
@@ -17887,7 +18666,7 @@ var DeviceGatewaySession = class {
17887
18666
  };
17888
18667
  for (const entry of entries) {
17889
18668
  entry.cancelTimer();
17890
- for (const waiter of entry.waiters) waiter(result);
18669
+ for (const waiter of entry.waiters) waiter(result, "unknown");
17891
18670
  }
17892
18671
  }
17893
18672
  protocolReject(message) {
@@ -17901,7 +18680,7 @@ var DeviceGatewaySession = class {
17901
18680
  if (entry === void 0) return;
17902
18681
  this.pending.delete(id);
17903
18682
  entry.cancelTimer();
17904
- for (const waiter of entry.waiters) waiter(result);
18683
+ for (const waiter of entry.waiters) waiter(result, "completed");
17905
18684
  }
17906
18685
  onCallTimeout(id) {
17907
18686
  const entry = this.pending.get(id);
@@ -17914,7 +18693,7 @@ var DeviceGatewaySession = class {
17914
18693
  retryable: true
17915
18694
  }).toJSON()
17916
18695
  };
17917
- for (const waiter of entry.waiters) waiter(result);
18696
+ for (const waiter of entry.waiters) waiter(result, "unknown");
17918
18697
  }
17919
18698
  };
17920
18699
 
@@ -17988,10 +18767,10 @@ function toView(entry) {
17988
18767
  }
17989
18768
  var ID_ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789";
17990
18769
  function randomFeedbackId() {
17991
- const bytes = new Uint8Array(6);
17992
- crypto.getRandomValues(bytes);
18770
+ const bytes2 = new Uint8Array(6);
18771
+ crypto.getRandomValues(bytes2);
17993
18772
  let out = "fb_";
17994
- for (const b of bytes) out += ID_ALPHABET[b % ID_ALPHABET.length];
18773
+ for (const b of bytes2) out += ID_ALPHABET[b % ID_ALPHABET.length];
17995
18774
  return out;
17996
18775
  }
17997
18776
  function requireShort(value, field, max) {
@@ -18136,6 +18915,7 @@ function renderHelpDsl(model) {
18136
18915
  if (cmd.outputSchema !== void 0) lines.push(` result ${JSON.stringify(cmd.outputSchema)}`);
18137
18916
  if (cmd.returns !== void 0) lines.push(...attrLines("returns", cmd.returns));
18138
18917
  lines.push(` scope ${cmd.scope}`);
18918
+ if (cmd.delivery !== void 0) lines.push(` delivery ${cmd.delivery}`);
18139
18919
  if (cmd.effect !== void 0) lines.push(` effect ${cmd.effect}`);
18140
18920
  if (cmd.confirm) lines.push(" confirm");
18141
18921
  }
@@ -18168,6 +18948,7 @@ function renderHelpJson(model) {
18168
18948
  if (cmd.inputSchema !== void 0) out.inputSchema = cmd.inputSchema;
18169
18949
  if (cmd.outputSchema !== void 0) out.outputSchema = cmd.outputSchema;
18170
18950
  if (cmd.returns !== void 0) out.returns = cmd.returns;
18951
+ if (cmd.delivery !== void 0) out.delivery = cmd.delivery;
18171
18952
  if (cmd.effect !== void 0) out.effect = cmd.effect;
18172
18953
  if (cmd.confirm) out.confirm = cmd.confirm;
18173
18954
  return out;
@@ -18207,6 +18988,7 @@ function cmdSection(cmd, index) {
18207
18988
  }
18208
18989
  lines.push(`- Invoke: \`POST ${cmd.path}\` with body \`{...arguments}\``);
18209
18990
  lines.push(`- Required scope: \`${cmd.scope}\``);
18991
+ if (cmd.delivery !== void 0) lines.push(`- Delivery: \`${cmd.delivery}\``);
18210
18992
  if (cmd.effect !== void 0) {
18211
18993
  lines.push(
18212
18994
  `- Effect: \`${cmd.effect}\`${cmd.confirm ? " \u2014 **ask the user to confirm before calling**" : ""}`
@@ -18424,7 +19206,7 @@ var KEY_STORE_IDEMPOTENCY = "store:idempotency:";
18424
19206
  var UPLOAD_TTL_SEC_DEFAULT = 15 * 60;
18425
19207
  var SHARE_TTL_SEC_DEFAULT = 15 * 60;
18426
19208
  var MAX_OBJECT_BYTES_DEFAULT = 256 * 1024 * 1024;
18427
- var MAX_CAS_ATTEMPTS = 32;
19209
+ var MAX_CAS_ATTEMPTS2 = 32;
18428
19210
  var CAPABILITY_TTL_SEC_MAX = 7 * 24 * 60 * 60;
18429
19211
  var TOKEN_PREFIX = {
18430
19212
  call: "tbc",
@@ -18774,7 +19556,7 @@ var StoreService = class {
18774
19556
  }
18775
19557
  async revokeCallUploadCapability(token) {
18776
19558
  const id = this.tokenId(token, "call");
18777
- for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {
19559
+ for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS2; attempt++) {
18778
19560
  const raw = await this.state.get(`${KEY_STORE_CALL_CAPABILITY}${id}`);
18779
19561
  if (raw === null) throw new TBError("permission_denied", "call upload capability \u65E0\u6548");
18780
19562
  const capability = parseCallCapability(raw);
@@ -18988,7 +19770,7 @@ var StoreService = class {
18988
19770
  }
18989
19771
  async delete(uri, actor) {
18990
19772
  const { objectId } = parseStoreUri(uri);
18991
- for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {
19773
+ for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS2; attempt++) {
18992
19774
  const object2 = await this.requireObject(objectId);
18993
19775
  if (!actor.admin && object2.owner !== actor.owner) {
18994
19776
  throw new TBError("not_found", "Store \u5BF9\u8C61\u4E0D\u5B58\u5728");
@@ -19052,7 +19834,7 @@ var StoreService = class {
19052
19834
  }
19053
19835
  async revokeShare(shareId, actor) {
19054
19836
  const owner = requireOwner(actor);
19055
- for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {
19837
+ for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS2; attempt++) {
19056
19838
  const raw = await this.state.get(`${KEY_STORE_SHARE}${shareId}`);
19057
19839
  if (raw === null) throw new TBError("not_found", "share grant \u4E0D\u5B58\u5728");
19058
19840
  const grant = parseShare(raw);
@@ -19376,7 +20158,7 @@ var StoreService = class {
19376
20158
  await this.compareRecord(resolved.key, resolved.binding, null);
19377
20159
  }
19378
20160
  async reserveCallCapability(token, objectId, input, transportMaxBytes) {
19379
- for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {
20161
+ for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS2; attempt++) {
19380
20162
  const capability = await this.verifyCallUploadCapability(token);
19381
20163
  const previous = capability.reservations.find((r) => r.objectId === objectId);
19382
20164
  if (previous !== void 0) {
@@ -19498,7 +20280,7 @@ var StoreService = class {
19498
20280
  }
19499
20281
  /** driver DELETE 成功后持久化证据;后续 cleanup 只收 tombstone,不再重复外部 DELETE。 */
19500
20282
  async markBytesDeleted(objectId, expectedDriverKey) {
19501
- for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {
20283
+ for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS2; attempt++) {
19502
20284
  const raw = await this.state.get(`${KEY_STORE_OBJECT}${objectId}`);
19503
20285
  if (raw === null) return;
19504
20286
  const object2 = parseObject(raw);
@@ -19598,7 +20380,7 @@ var StoreService = class {
19598
20380
  }
19599
20381
  async markReady(sessionInput, meta3) {
19600
20382
  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++) {
20383
+ for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS2; attempt++) {
19602
20384
  const object2 = await this.requireObject(sessionInput.objectId);
19603
20385
  if (object2.status === "ready") {
19604
20386
  await this.completeSessionBestEffort(await this.requireSession(sessionInput.id));
@@ -19628,7 +20410,7 @@ var StoreService = class {
19628
20410
  throw new TBError("conflict", "\u5BF9\u8C61\u5E76\u53D1\u72B6\u6001\u51B2\u7A81:pending");
19629
20411
  }
19630
20412
  async completeSessionBestEffort(sessionInput) {
19631
- for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {
20413
+ for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS2; attempt++) {
19632
20414
  const session = await this.requireSession(sessionInput.id);
19633
20415
  if (session.status === "completed" || session.status !== "created") return;
19634
20416
  const completedAt = this.nowIso();
@@ -19804,8 +20586,8 @@ function canonicalCatalogJson(value) {
19804
20586
  return JSON.stringify(normalize(value));
19805
20587
  }
19806
20588
  async function catalogDigest(value) {
19807
- const bytes = new TextEncoder().encode(canonicalCatalogJson(value));
19808
- const hash2 = await crypto.subtle.digest("SHA-256", bytes);
20589
+ const bytes2 = new TextEncoder().encode(canonicalCatalogJson(value));
20590
+ const hash2 = await crypto.subtle.digest("SHA-256", bytes2);
19809
20591
  return [...new Uint8Array(hash2)].map((b) => b.toString(16).padStart(2, "0")).join("");
19810
20592
  }
19811
20593
  async function catalogSetDigest(catalog) {
@@ -19999,11 +20781,11 @@ var pluginCallSchema = external_exports.object({
19999
20781
  arguments: external_exports.record(external_exports.string(), external_exports.unknown())
20000
20782
  });
20001
20783
  function assertPluginPayloadSize(payload) {
20002
- const bytes = new TextEncoder().encode(payload).length;
20003
- if (bytes > PLUGIN_PAYLOAD_MAX_BYTES) {
20784
+ const bytes2 = new TextEncoder().encode(payload).length;
20785
+ if (bytes2 > PLUGIN_PAYLOAD_MAX_BYTES) {
20004
20786
  throw new TBError(
20005
20787
  "invalid_argument",
20006
- `payload ${bytes} \u5B57\u8282\u8D85\u8FC7\u4E0A\u9650 ${PLUGIN_PAYLOAD_MAX_BYTES}(\u2264 1 MiB;\u66F4\u5927\u5185\u5BB9\u7ECF $ref)`
20788
+ `payload ${bytes2} \u5B57\u8282\u8D85\u8FC7\u4E0A\u9650 ${PLUGIN_PAYLOAD_MAX_BYTES}(\u2264 1 MiB;\u66F4\u5927\u5185\u5BB9\u7ECF $ref)`
20007
20789
  );
20008
20790
  }
20009
20791
  }
@@ -20181,9 +20963,9 @@ function searchUnitAllowsPath(unit) {
20181
20963
  return !/^%[A-Za-z0-9]{1,2}%$/u.test(unit.pattern);
20182
20964
  }
20183
20965
  function stableDigest(value) {
20184
- const bytes = new TextEncoder().encode(JSON.stringify(value));
20966
+ const bytes2 = new TextEncoder().encode(JSON.stringify(value));
20185
20967
  let hash2 = 0xcbf29ce484222325n;
20186
- for (const byte of bytes) {
20968
+ for (const byte of bytes2) {
20187
20969
  hash2 ^= BigInt(byte);
20188
20970
  hash2 = BigInt.asUintN(64, hash2 * 0x100000001b3n);
20189
20971
  }
@@ -20193,12 +20975,12 @@ function truncateUtf8(value, maxBytes) {
20193
20975
  const encoder = new TextEncoder();
20194
20976
  if (encoder.encode(value).length <= maxBytes) return value;
20195
20977
  let result = "";
20196
- let bytes = 0;
20978
+ let bytes2 = 0;
20197
20979
  for (const char of value) {
20198
20980
  const size = encoder.encode(char).length;
20199
- if (bytes + size > maxBytes) break;
20981
+ if (bytes2 + size > maxBytes) break;
20200
20982
  result += char;
20201
- bytes += size;
20983
+ bytes2 += size;
20202
20984
  }
20203
20985
  return result;
20204
20986
  }
@@ -21387,7 +22169,7 @@ function guessContentType(path) {
21387
22169
  if (dot < 0) return "text/plain";
21388
22170
  return CONTENT_TYPE_BY_EXT[path.slice(dot + 1).toLowerCase()] ?? "text/plain";
21389
22171
  }
21390
- function clampLimit4(limit) {
22172
+ function clampLimit5(limit) {
21391
22173
  if (limit === void 0) return LIST_LIMIT_DEFAULT;
21392
22174
  if (!Number.isInteger(limit) || limit < 1) {
21393
22175
  throw new TBError("invalid_argument", `limit \u975E\u6CD5:${limit}`);
@@ -21442,7 +22224,7 @@ function createSkillhubProvider(store, opts) {
21442
22224
  };
21443
22225
  return {
21444
22226
  async list(listOpts) {
21445
- const limit = clampLimit4(listOpts?.limit);
22227
+ const limit = clampLimit5(listOpts?.limit);
21446
22228
  const res = await store.list(keyPrefix, {
21447
22229
  delimiter: "/",
21448
22230
  cursor: listOpts?.cursor,
@@ -21502,7 +22284,7 @@ function createSkillhubProvider(store, opts) {
21502
22284
  if (typeof query !== "string" || query === "") {
21503
22285
  throw new TBError("invalid_argument", "query \u4E0D\u80FD\u4E3A\u7A7A");
21504
22286
  }
21505
- const limit = clampLimit4(searchOpts?.limit);
22287
+ const limit = clampLimit5(searchOpts?.limit);
21506
22288
  const q = query.toLowerCase();
21507
22289
  const after = searchOpts?.cursor;
21508
22290
  const items = [];
@@ -21677,6 +22459,7 @@ function toolToCmd(nodePath, tool, index) {
21677
22459
  if (tool.description !== void 0) {
21678
22460
  cmd.h = index ? summarizeOneLine(tool.description) : tool.description;
21679
22461
  }
22462
+ if (tool.delivery !== void 0) cmd.delivery = tool.delivery;
21680
22463
  if (!index && tool.inputSchema !== void 0) cmd.inputSchema = tool.inputSchema;
21681
22464
  if (!index && tool.outputSchema !== void 0) cmd.outputSchema = tool.outputSchema;
21682
22465
  if (tool.effect !== void 0) cmd.effect = tool.effect;
@@ -21808,7 +22591,7 @@ function resolveUpstreamTool(v, source, virtualName2) {
21808
22591
  }
21809
22592
 
21810
22593
  // ../core/src/tree/registry.ts
21811
- function clampLimit5(limit) {
22594
+ function clampLimit6(limit) {
21812
22595
  if (limit === void 0 || limit < 1) return LIST_LIMIT_DEFAULT;
21813
22596
  return limit > LIST_LIMIT_MAX ? LIST_LIMIT_MAX : limit;
21814
22597
  }
@@ -21909,7 +22692,7 @@ var NodeRegistryStore = class {
21909
22692
  */
21910
22693
  async list(prefix, opts) {
21911
22694
  const normPrefix = prefix === void 0 ? "" : canonicalizePath(prefix);
21912
- const limit = clampLimit5(opts?.limit);
22695
+ const limit = clampLimit6(opts?.limit);
21913
22696
  const all = (await this.scanAll()).filter((n) => isPrefixOf(normPrefix, n.path)).sort(byPath);
21914
22697
  const cursor = opts?.cursor;
21915
22698
  const start = cursor ? all.findIndex((n) => n.path === cursor) + 1 : 0;
@@ -21998,6 +22781,7 @@ var NodeRegistryStore = class {
21998
22781
  description: node.description,
21999
22782
  ...node.config !== void 0 ? { config: node.config } : {},
22000
22783
  ...node.virtualize !== void 0 ? { virtualize: node.virtualize } : {},
22784
+ ...opts.deviceId !== void 0 ? { deviceId: opts.deviceId } : {},
22001
22785
  ...opts.online !== void 0 ? { online: opts.online } : {},
22002
22786
  ...opts.lastSeenAt !== void 0 ? { lastSeenAt: opts.lastSeenAt } : {},
22003
22787
  registeredBy,
@@ -22218,8 +23002,8 @@ function createPlugin(opts = {}) {
22218
23002
  const b64 = raw.replaceAll("-", "+").replaceAll("_", "/");
22219
23003
  const padded = b64.padEnd(b64.length + (4 - b64.length % 4) % 4, "=");
22220
23004
  try {
22221
- const bytes = Uint8Array.from(atob(padded), (c) => c.charCodeAt(0));
22222
- return new TextDecoder().decode(bytes);
23005
+ const bytes2 = Uint8Array.from(atob(padded), (c) => c.charCodeAt(0));
23006
+ return new TextDecoder().decode(bytes2);
22223
23007
  } catch {
22224
23008
  throw new TBError("invalid_argument", `${HEADER_TB_UPSTREAM_AUTH} is not valid base64url`);
22225
23009
  }
@@ -22545,6 +23329,7 @@ export {
22545
23329
  pluginTokenSecretName,
22546
23330
  createStoreModule,
22547
23331
  RemoteAllowlistStore,
23332
+ DeviceMailboxService,
22548
23333
  tbErrorBodySchema,
22549
23334
  nodeInputSchema,
22550
23335
  helpJsonSchema,
@@ -22554,6 +23339,16 @@ export {
22554
23339
  toolSearchSourceResultSchema,
22555
23340
  toolSearchPageSchema,
22556
23341
  toolSearchRequestSchema,
23342
+ deviceOperationSummarySchema,
23343
+ deviceOperationDetailSchema,
23344
+ deviceOperationListRequestSchema,
23345
+ deviceOperationListResponseSchema,
23346
+ deviceOperationIdentityRequestSchema,
23347
+ deviceOperationClaimRequestSchema,
23348
+ deviceOperationClaimResponseSchema,
23349
+ deviceOperationRenewRequestSchema,
23350
+ deviceOperationRenewResponseSchema,
23351
+ deviceOperationCompleteRequestSchema,
22557
23352
  registryNodeSchema,
22558
23353
  feedbackViewSchema,
22559
23354
  feedbackDetailSchema,