@lamplitisles/dsh-nanocodex 0.1.0-beta.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 (276) hide show
  1. package/LICENSE +65 -0
  2. package/NOTICE +2 -0
  3. package/README.md +182 -0
  4. package/THIRD_PARTY_NOTICES.md +29 -0
  5. package/cordis.patch.yml +52 -0
  6. package/dist/index.d.ts +435 -0
  7. package/dist/index.js +3405 -0
  8. package/dist/standard-preset.d.ts +7 -0
  9. package/dist/standard-preset.js +25 -0
  10. package/engine-release.json +14 -0
  11. package/package.json +119 -0
  12. package/presets/standard/agent.cordis.yml +6 -0
  13. package/presets/standard/preset.yml +2 -0
  14. package/vendor/nanocodex/README.md +1344 -0
  15. package/vendor/nanocodex/actions/events.d.mts +10 -0
  16. package/vendor/nanocodex/actions/events.mjs +163 -0
  17. package/vendor/nanocodex/actions/index.d.mts +13 -0
  18. package/vendor/nanocodex/actions/index.mjs +35 -0
  19. package/vendor/nanocodex/actions/session.d.mts +66 -0
  20. package/vendor/nanocodex/actions/session.mjs +59 -0
  21. package/vendor/nanocodex/actions/turn.d.mts +59 -0
  22. package/vendor/nanocodex/actions/turn.mjs +37 -0
  23. package/vendor/nanocodex/actions/voice.d.mts +22 -0
  24. package/vendor/nanocodex/actions/voice.mjs +50 -0
  25. package/vendor/nanocodex/browser/Agent.d.mts +55 -0
  26. package/vendor/nanocodex/browser/Agent.mjs +11 -0
  27. package/vendor/nanocodex/browser/ChatGptSubscription.d.mts +7 -0
  28. package/vendor/nanocodex/browser/ChatGptSubscription.mjs +19 -0
  29. package/vendor/nanocodex/browser/InlineAgent.mjs +266 -0
  30. package/vendor/nanocodex/browser/Transport.d.mts +74 -0
  31. package/vendor/nanocodex/browser/Transport.mjs +61 -0
  32. package/vendor/nanocodex/browser/Voice.d.mts +71 -0
  33. package/vendor/nanocodex/browser/Voice.mjs +291 -0
  34. package/vendor/nanocodex/browser/VoiceSession.mjs +688 -0
  35. package/vendor/nanocodex/browser/WorkerAgent.d.mts +65 -0
  36. package/vendor/nanocodex/browser/WorkerAgent.mjs +1472 -0
  37. package/vendor/nanocodex/browser/agent.worker.mjs +3 -0
  38. package/vendor/nanocodex/browser/config.d.mts +36 -0
  39. package/vendor/nanocodex/browser/config.mjs +439 -0
  40. package/vendor/nanocodex/browser/engine.mjs +13 -0
  41. package/vendor/nanocodex/browser/harness.mjs +55 -0
  42. package/vendor/nanocodex/browser/host.d.mts +83 -0
  43. package/vendor/nanocodex/browser/host.mjs +555 -0
  44. package/vendor/nanocodex/browser/hostManagedWebSocket.d.mts +14 -0
  45. package/vendor/nanocodex/browser/hostManagedWebSocket.mjs +110 -0
  46. package/vendor/nanocodex/browser/index.d.mts +92 -0
  47. package/vendor/nanocodex/browser/index.mjs +23 -0
  48. package/vendor/nanocodex/browser/indexeddb-durability-store.mjs +197 -0
  49. package/vendor/nanocodex/browser/workspace.d.mts +16 -0
  50. package/vendor/nanocodex/browser/workspace.mjs +107 -0
  51. package/vendor/nanocodex/cloud/Client.d.mts +83 -0
  52. package/vendor/nanocodex/cloud/Client.mjs +231 -0
  53. package/vendor/nanocodex/cloud/Decorator.d.mts +31 -0
  54. package/vendor/nanocodex/cloud/Decorator.mjs +37 -0
  55. package/vendor/nanocodex/cloud/Dialog.d.mts +113 -0
  56. package/vendor/nanocodex/cloud/Dialog.mjs +366 -0
  57. package/vendor/nanocodex/cloud/Errors.d.mts +22 -0
  58. package/vendor/nanocodex/cloud/Errors.mjs +39 -0
  59. package/vendor/nanocodex/cloud/Principal.d.mts +26 -0
  60. package/vendor/nanocodex/cloud/Principal.mjs +88 -0
  61. package/vendor/nanocodex/cloud/RemoteProvider.mjs +88 -0
  62. package/vendor/nanocodex/cloud/Transport.d.mts +47 -0
  63. package/vendor/nanocodex/cloud/Transport.mjs +454 -0
  64. package/vendor/nanocodex/cloud/actions/account.d.mts +9 -0
  65. package/vendor/nanocodex/cloud/actions/account.mjs +19 -0
  66. package/vendor/nanocodex/cloud/actions/agent.d.mts +18 -0
  67. package/vendor/nanocodex/cloud/actions/agent.mjs +428 -0
  68. package/vendor/nanocodex/cloud/actions/connection.d.mts +133 -0
  69. package/vendor/nanocodex/cloud/actions/connection.mjs +580 -0
  70. package/vendor/nanocodex/cloud/actions/grant.d.mts +10 -0
  71. package/vendor/nanocodex/cloud/actions/grant.mjs +12 -0
  72. package/vendor/nanocodex/cloud/actions/index.d.mts +7 -0
  73. package/vendor/nanocodex/cloud/actions/index.mjs +7 -0
  74. package/vendor/nanocodex/cloud/actions/machineUsd.d.mts +23 -0
  75. package/vendor/nanocodex/cloud/actions/machineUsd.mjs +37 -0
  76. package/vendor/nanocodex/cloud/actions/model.d.mts +12 -0
  77. package/vendor/nanocodex/cloud/actions/model.mjs +50 -0
  78. package/vendor/nanocodex/cloud/actions/mpp.d.mts +28 -0
  79. package/vendor/nanocodex/cloud/actions/mpp.mjs +39 -0
  80. package/vendor/nanocodex/cloud/index.d.mts +30 -0
  81. package/vendor/nanocodex/cloud/index.mjs +9 -0
  82. package/vendor/nanocodex/cloud/internal.mjs +533 -0
  83. package/vendor/nanocodex/cloud/mercator.mjs +108 -0
  84. package/vendor/nanocodex/cloud/server/HostPrincipal.d.mts +34 -0
  85. package/vendor/nanocodex/cloud/server/HostPrincipal.mjs +202 -0
  86. package/vendor/nanocodex/cloud/server/index.d.mts +1 -0
  87. package/vendor/nanocodex/cloud/server/index.mjs +1 -0
  88. package/vendor/nanocodex/cloud/types.d.mts +211 -0
  89. package/vendor/nanocodex/cloudflare/Agent.d.mts +133 -0
  90. package/vendor/nanocodex/cloudflare/Agent.mjs +811 -0
  91. package/vendor/nanocodex/cloudflare/egress-subject.mjs +19 -0
  92. package/vendor/nanocodex/cloudflare/egress.d.mts +41 -0
  93. package/vendor/nanocodex/cloudflare/egress.mjs +119 -0
  94. package/vendor/nanocodex/cloudflare/event-socket.mjs +316 -0
  95. package/vendor/nanocodex/cloudflare/index.d.mts +7 -0
  96. package/vendor/nanocodex/cloudflare/index.mjs +6 -0
  97. package/vendor/nanocodex/host/Agent.d.mts +55 -0
  98. package/vendor/nanocodex/host/Agent.mjs +1 -0
  99. package/vendor/nanocodex/host/index.d.mts +82 -0
  100. package/vendor/nanocodex/host/index.mjs +10 -0
  101. package/vendor/nanocodex/index.d.mts +81 -0
  102. package/vendor/nanocodex/index.mjs +12 -0
  103. package/vendor/nanocodex/internal.mjs +1275 -0
  104. package/vendor/nanocodex/managed/Agent.d.mts +380 -0
  105. package/vendor/nanocodex/managed/Agent.mjs +1694 -0
  106. package/vendor/nanocodex/managed/ManagedError.d.mts +9 -0
  107. package/vendor/nanocodex/managed/ManagedError.mjs +8 -0
  108. package/vendor/nanocodex/managed/README.md +241 -0
  109. package/vendor/nanocodex/managed/Voice.mjs +202 -0
  110. package/vendor/nanocodex/managed/index.d.mts +20 -0
  111. package/vendor/nanocodex/managed/index.mjs +2 -0
  112. package/vendor/nanocodex/managed/internal.mjs +119 -0
  113. package/vendor/nanocodex/node/Agent.d.mts +50 -0
  114. package/vendor/nanocodex/node/Agent.mjs +203 -0
  115. package/vendor/nanocodex/node/ChatGptSubscription.d.mts +9 -0
  116. package/vendor/nanocodex/node/ChatGptSubscription.mjs +17 -0
  117. package/vendor/nanocodex/node/Transport.d.mts +44 -0
  118. package/vendor/nanocodex/node/Transport.mjs +46 -0
  119. package/vendor/nanocodex/node/host.mjs +731 -0
  120. package/vendor/nanocodex/node/index.d.mts +73 -0
  121. package/vendor/nanocodex/node/index.mjs +17 -0
  122. package/vendor/nanocodex/node/workspace.d.mts +10 -0
  123. package/vendor/nanocodex/node/workspace.mjs +198 -0
  124. package/vendor/nanocodex/package.json +200 -0
  125. package/vendor/nanocodex/pkg-node/nanocodex.d.ts +675 -0
  126. package/vendor/nanocodex/pkg-node/nanocodex.js +2628 -0
  127. package/vendor/nanocodex/pkg-node/nanocodex_bg.wasm.d.ts +105 -0
  128. package/vendor/nanocodex/pkg-node/package.json +1 -0
  129. package/vendor/nanocodex/pkg-web/.nanocodex-bindgen-stamp +6 -0
  130. package/vendor/nanocodex/pkg-web/nanocodex-build.json +1 -0
  131. package/vendor/nanocodex/pkg-web/nanocodex.d.ts +805 -0
  132. package/vendor/nanocodex/pkg-web/nanocodex.js +2714 -0
  133. package/vendor/nanocodex/pkg-web/nanocodex_bg.js +2615 -0
  134. package/vendor/nanocodex/pkg-web/nanocodex_bg.wasm +0 -0
  135. package/vendor/nanocodex/pkg-web/nanocodex_bg.wasm.d.ts +105 -0
  136. package/vendor/nanocodex/pkg-web/nanocodex_worker.js +9 -0
  137. package/vendor/nanocodex/pkg-web/package.json +1 -0
  138. package/vendor/nanocodex/runtime/chatgpt-subscription.mjs +212 -0
  139. package/vendor/nanocodex/runtime/cloudflare-durability-store.d.mts +26 -0
  140. package/vendor/nanocodex/runtime/cloudflare-durability-store.mjs +168 -0
  141. package/vendor/nanocodex/runtime/code-evaluator.worker.mjs +137 -0
  142. package/vendor/nanocodex/runtime/code-runtime.mjs +1 -0
  143. package/vendor/nanocodex/runtime/durability-store.d.mts +85 -0
  144. package/vendor/nanocodex/runtime/durability-store.mjs +631 -0
  145. package/vendor/nanocodex/runtime/durability.mjs +153 -0
  146. package/vendor/nanocodex/runtime/managed-transport.mjs +460 -0
  147. package/vendor/nanocodex/runtime/mcp-runtime.mjs +534 -0
  148. package/vendor/nanocodex/runtime/postgres-durability-store.d.mts +64 -0
  149. package/vendor/nanocodex/runtime/postgres-durability-store.mjs +532 -0
  150. package/vendor/nanocodex/runtime/quickjs-evaluator.d.mts +17 -0
  151. package/vendor/nanocodex/runtime/quickjs-evaluator.mjs +236 -0
  152. package/vendor/nanocodex/runtime/responses-transport.mjs +22 -0
  153. package/vendor/nanocodex/runtime/subagents.d.mts +107 -0
  154. package/vendor/nanocodex/runtime/subagents.mjs +54 -0
  155. package/vendor/nanocodex/runtime/subscription-store.d.mts +8 -0
  156. package/vendor/nanocodex/runtime/subscription-store.mjs +42 -0
  157. package/vendor/nanocodex/runtime/tempo-provider.d.mts +125 -0
  158. package/vendor/nanocodex/runtime/tempo-provider.mjs +264 -0
  159. package/vendor/nanocodex/runtime/tool-configuration.mjs +1 -0
  160. package/vendor/nanocodex/runtime/tool-router.mjs +1 -0
  161. package/vendor/nanocodex/runtime/utf8.mjs +1 -0
  162. package/vendor/nanocodex/runtime/worker-evaluator.mjs +162 -0
  163. package/vendor/nanocodex/runtime/workspace.d.mts +1 -0
  164. package/vendor/nanocodex/runtime/workspace.mjs +1 -0
  165. package/vendor/nanocodex/tools/Tools.d.mts +56 -0
  166. package/vendor/nanocodex/tools/Tools.mjs +136 -0
  167. package/vendor/nanocodex/tools/artifact.d.mts +1 -0
  168. package/vendor/nanocodex/tools/artifact.mjs +1 -0
  169. package/vendor/nanocodex/tools/attachment.mjs +1 -0
  170. package/vendor/nanocodex/tools/bash.d.mts +1 -0
  171. package/vendor/nanocodex/tools/bash.mjs +1 -0
  172. package/vendor/nanocodex/tools/browser/accountInfo.mjs +795 -0
  173. package/vendor/nanocodex/tools/browser/browserBuffer.mjs +18 -0
  174. package/vendor/nanocodex/tools/browser/browserCompiler.mjs +155 -0
  175. package/vendor/nanocodex/tools/browser/browserEgress.mjs +161 -0
  176. package/vendor/nanocodex/tools/browser/browserPython.mjs +133 -0
  177. package/vendor/nanocodex/tools/browser/browserShell.mjs +1075 -0
  178. package/vendor/nanocodex/tools/browser/browserSprintf.mjs +4 -0
  179. package/vendor/nanocodex/tools/browser/browserSsh.mjs +201 -0
  180. package/vendor/nanocodex/tools/browser/browserZlib.mjs +136 -0
  181. package/vendor/nanocodex/tools/browser/compiler.worker.mjs +160 -0
  182. package/vendor/nanocodex/tools/browser/devTunnelsSshBrowser.mjs +13 -0
  183. package/vendor/nanocodex/tools/browser/index.d.mts +209 -0
  184. package/vendor/nanocodex/tools/browser/index.mjs +174 -0
  185. package/vendor/nanocodex/tools/browser/opfsGit.mjs +248 -0
  186. package/vendor/nanocodex/tools/browser/python.worker.mjs +114 -0
  187. package/vendor/nanocodex/tools/browser/threadGit.mjs +197 -0
  188. package/vendor/nanocodex/tools/browser/unsupportedNodeRsa.mjs +5 -0
  189. package/vendor/nanocodex/tools/browser/workspace.mjs +83 -0
  190. package/vendor/nanocodex/tools/dataset.d.mts +1 -0
  191. package/vendor/nanocodex/tools/dataset.mjs +1 -0
  192. package/vendor/nanocodex/tools/datasetContract.mjs +1 -0
  193. package/vendor/nanocodex/tools/datasetEngine.mjs +1 -0
  194. package/vendor/nanocodex/tools/hostedCatalog.d.mts +1 -0
  195. package/vendor/nanocodex/tools/hostedCatalog.mjs +1 -0
  196. package/vendor/nanocodex/tools/index.d.mts +49 -0
  197. package/vendor/nanocodex/tools/index.mjs +19 -0
  198. package/vendor/nanocodex/tools/namedTool.mjs +1 -0
  199. package/vendor/nanocodex/tools/repository-workspace.d.mts +1 -0
  200. package/vendor/nanocodex/tools/repository-workspace.mjs +1 -0
  201. package/vendor/nanocodex/tools/ssh.d.mts +1 -0
  202. package/vendor/nanocodex/tools/ssh.mjs +1 -0
  203. package/vendor/nanocodex/tools/standard.mjs +1 -0
  204. package/vendor/nanocodex/tools/standardDescriptions.mjs +1 -0
  205. package/vendor/nanocodex/types.d.mts +663 -0
  206. package/vendor/nanocodex/wasm.d.mts +4 -0
  207. package/vendor/nanocodex/worker/ChatGptSubscription.d.mts +9 -0
  208. package/vendor/nanocodex/worker/ChatGptSubscription.mjs +29 -0
  209. package/vendor/nanocodex/worker/index.d.mts +18 -0
  210. package/vendor/nanocodex/worker/index.mjs +5 -0
  211. package/vendor/nanocodex-tools/README.md +65 -0
  212. package/vendor/nanocodex-tools/dist/hosted/app-tool-catalog.d.ts +7 -0
  213. package/vendor/nanocodex-tools/dist/hosted/app-tool-catalog.js +14 -0
  214. package/vendor/nanocodex-tools/dist/hosted/broker-core.d.ts +172 -0
  215. package/vendor/nanocodex-tools/dist/hosted/broker-core.js +1278 -0
  216. package/vendor/nanocodex-tools/dist/hosted/index.d.ts +3 -0
  217. package/vendor/nanocodex-tools/dist/hosted/index.js +3 -0
  218. package/vendor/nanocodex-tools/dist/hosted/protocol.d.ts +120 -0
  219. package/vendor/nanocodex-tools/dist/hosted/protocol.js +415 -0
  220. package/vendor/nanocodex-tools/dist/index.d.ts +19 -0
  221. package/vendor/nanocodex-tools/dist/index.js +14 -0
  222. package/vendor/nanocodex-tools/dist/memory.d.ts +204 -0
  223. package/vendor/nanocodex-tools/dist/memory.js +411 -0
  224. package/vendor/nanocodex-tools/dist/namespace.d.ts +87 -0
  225. package/vendor/nanocodex-tools/dist/namespace.js +338 -0
  226. package/vendor/nanocodex-tools/dist/repository-archive.d.ts +4 -0
  227. package/vendor/nanocodex-tools/dist/repository-archive.js +104 -0
  228. package/vendor/nanocodex-tools/dist/runtime.d.ts +30 -0
  229. package/vendor/nanocodex-tools/dist/runtime.js +37 -0
  230. package/vendor/nanocodex-tools/dist/session.d.ts +167 -0
  231. package/vendor/nanocodex-tools/dist/session.js +286 -0
  232. package/vendor/nanocodex-tools/dist/shell.d.ts +51 -0
  233. package/vendor/nanocodex-tools/dist/shell.js +553 -0
  234. package/vendor/nanocodex-tools/dist/ssh.d.ts +29 -0
  235. package/vendor/nanocodex-tools/dist/ssh.js +66 -0
  236. package/vendor/nanocodex-tools/dist/workspace.d.ts +45 -0
  237. package/vendor/nanocodex-tools/dist/workspace.js +237 -0
  238. package/vendor/nanocodex-tools/package.json +122 -0
  239. package/vendor/nanocodex-tools/runtime/code-runtime.mjs +817 -0
  240. package/vendor/nanocodex-tools/runtime/tool-configuration.mjs +50 -0
  241. package/vendor/nanocodex-tools/runtime/tool-router.mjs +730 -0
  242. package/vendor/nanocodex-tools/runtime/utf8.d.mts +2 -0
  243. package/vendor/nanocodex-tools/runtime/utf8.mjs +25 -0
  244. package/vendor/nanocodex-tools/tools/artifact.d.mts +69 -0
  245. package/vendor/nanocodex-tools/tools/artifact.mjs +270 -0
  246. package/vendor/nanocodex-tools/tools/attachment.mjs +603 -0
  247. package/vendor/nanocodex-tools/tools/bash.d.mts +90 -0
  248. package/vendor/nanocodex-tools/tools/bash.mjs +742 -0
  249. package/vendor/nanocodex-tools/tools/dataset.d.mts +9 -0
  250. package/vendor/nanocodex-tools/tools/dataset.mjs +47 -0
  251. package/vendor/nanocodex-tools/tools/datasetContract.mjs +54 -0
  252. package/vendor/nanocodex-tools/tools/datasetEngine.mjs +1167 -0
  253. package/vendor/nanocodex-tools/tools/execution-contract.d.mts +5 -0
  254. package/vendor/nanocodex-tools/tools/execution-contract.mjs +63 -0
  255. package/vendor/nanocodex-tools/tools/hostedCatalog.d.mts +20 -0
  256. package/vendor/nanocodex-tools/tools/hostedCatalog.mjs +67 -0
  257. package/vendor/nanocodex-tools/tools/hostedMachine.d.mts +10 -0
  258. package/vendor/nanocodex-tools/tools/hostedMachine.mjs +56 -0
  259. package/vendor/nanocodex-tools/tools/just-bash-browser.d.mts +1 -0
  260. package/vendor/nanocodex-tools/tools/just-bash-browser.mjs +1 -0
  261. package/vendor/nanocodex-tools/tools/namedTool.d.mts +3 -0
  262. package/vendor/nanocodex-tools/tools/namedTool.mjs +3 -0
  263. package/vendor/nanocodex-tools/tools/nodeProcess.d.mts +10 -0
  264. package/vendor/nanocodex-tools/tools/nodeProcess.mjs +314 -0
  265. package/vendor/nanocodex-tools/tools/processOutput.mjs +56 -0
  266. package/vendor/nanocodex-tools/tools/repository-workspace.d.mts +55 -0
  267. package/vendor/nanocodex-tools/tools/repository-workspace.mjs +397 -0
  268. package/vendor/nanocodex-tools/tools/ssh.d.mts +56 -0
  269. package/vendor/nanocodex-tools/tools/ssh.mjs +503 -0
  270. package/vendor/nanocodex-tools/tools/standard.mjs +458 -0
  271. package/vendor/nanocodex-tools/tools/standardDescriptions.mjs +3 -0
  272. package/vendor/nanocodex-tools/tools/types.d.mts +83 -0
  273. package/vendor/nanocodex-tools/tools/workspace.d.mts +25 -0
  274. package/vendor/nanocodex-tools/tools/workspace.mjs +282 -0
  275. package/vendor/nanocodex-tools/tools/x.d.mts +30 -0
  276. package/vendor/nanocodex-tools/tools/x.mjs +91 -0
@@ -0,0 +1,795 @@
1
+ import { namedTool } from "../namedTool.mjs";
2
+ import { X_API } from "../../../nanocodex-tools/tools/x.mjs";
3
+
4
+ const CONNECTOR_IDS = [
5
+ "github",
6
+ "gmail",
7
+ "gdrive",
8
+ "gcalendar",
9
+ "gtasks",
10
+ "gdocs",
11
+ "gsheets",
12
+ "gslides",
13
+ "gcontacts",
14
+ "slack",
15
+ "x",
16
+ "chatgpt",
17
+ ];
18
+ const ACCOUNT_CONNECTION_IDS = Object.freeze(CONNECTOR_IDS.filter((id) => id !== "chatgpt"));
19
+ const ACCOUNT_CONNECTION_LABELS = Object.freeze({
20
+ github: "GitHub",
21
+ gmail: "Gmail",
22
+ gdrive: "Google Drive",
23
+ gcalendar: "Google Calendar",
24
+ gtasks: "Google Tasks",
25
+ gdocs: "Google Docs",
26
+ gsheets: "Google Sheets",
27
+ gslides: "Google Slides",
28
+ gcontacts: "Google Contacts",
29
+ slack: "Slack",
30
+ x: "X",
31
+ });
32
+ const GOOGLE_CONNECTION_IDS = new Set([
33
+ "gmail",
34
+ "gdrive",
35
+ "gcalendar",
36
+ "gtasks",
37
+ "gdocs",
38
+ "gsheets",
39
+ "gslides",
40
+ "gcontacts",
41
+ ]);
42
+ const ACCOUNT_AUTHORIZATION_ENDPOINTS = Object.freeze({
43
+ github: { origin: "https://github.com", pathname: "/login/oauth/authorize" },
44
+ google: { origin: "https://accounts.google.com", pathname: "/o/oauth2/v2/auth" },
45
+ slack: { origin: "https://slack.com", pathname: "/oauth/v2/authorize" },
46
+ x: { origin: "https://x.com", pathname: "/i/oauth2/authorize" },
47
+ });
48
+ const ACCOUNT_AUTHORIZATION_QUERY_KEYS = new Set([
49
+ "access_type",
50
+ "client_id",
51
+ "code_challenge",
52
+ "code_challenge_method",
53
+ "enable_granular_consent",
54
+ "include_granted_scopes",
55
+ "login_hint",
56
+ "prompt",
57
+ "redirect_uri",
58
+ "response_type",
59
+ "scope",
60
+ "state",
61
+ "team",
62
+ "user_scope",
63
+ ]);
64
+ const LOCAL_OAUTH_RELAY_ORIGIN = "http://127.0.0.1:47891";
65
+ const CONNECTOR_CONNECTION_IDS = CONNECTOR_IDS.filter((id) => id !== "chatgpt");
66
+ const CONNECTION_ID = /^[A-Za-z0-9_-]{43}$/;
67
+ const CONNECTOR_CONNECTION_SCHEMA = {
68
+ type: "object",
69
+ properties: {
70
+ id: { type: "string", pattern: "^[A-Za-z0-9_-]{43}$" },
71
+ label: { type: "string" },
72
+ accountId: { type: "string" },
73
+ capabilities: { type: "array", items: { type: "string", enum: CONNECTOR_IDS } },
74
+ },
75
+ required: ["id", "label"],
76
+ additionalProperties: false,
77
+ };
78
+ const HOST_PRINCIPAL_ID = /^[A-Za-z0-9_-]{43}$/;
79
+ const MAX_VAULT_ENTRIES = 100;
80
+ const VAULT_ID = /^[A-Za-z0-9_-]{22,64}$/;
81
+ const VAULT_ID_SCHEMA = { type: "string", pattern: "^[A-Za-z0-9_-]{22,64}$" };
82
+ const vaultTextSchema = (maxLength) => ({ type: "string", minLength: 1, maxLength });
83
+ const LIMIT_SCHEMA = {
84
+ type: "object",
85
+ properties: {
86
+ token: { type: "string" },
87
+ symbol: { type: "string" },
88
+ limit: { type: "string" },
89
+ period: { type: "integer" },
90
+ },
91
+ required: ["token", "symbol", "limit"],
92
+ additionalProperties: false,
93
+ };
94
+ const VAULT_ENTRY_SCHEMA = {
95
+ oneOf: [
96
+ {
97
+ type: "object",
98
+ properties: {
99
+ id: VAULT_ID_SCHEMA,
100
+ kind: { type: "string", enum: ["login"] },
101
+ name: vaultTextSchema(120),
102
+ created_at: { type: "integer", minimum: 0 },
103
+ username: vaultTextSchema(512),
104
+ },
105
+ required: ["id", "kind", "name", "created_at", "username"],
106
+ additionalProperties: false,
107
+ },
108
+ {
109
+ type: "object",
110
+ properties: {
111
+ id: VAULT_ID_SCHEMA,
112
+ kind: { type: "string", enum: ["card"] },
113
+ name: vaultTextSchema(120),
114
+ created_at: { type: "integer", minimum: 0 },
115
+ last4: { type: "string", pattern: "^[0-9]{4}$" },
116
+ },
117
+ required: ["id", "kind", "name", "created_at", "last4"],
118
+ additionalProperties: false,
119
+ },
120
+ {
121
+ type: "object",
122
+ properties: {
123
+ id: VAULT_ID_SCHEMA,
124
+ kind: { type: "string", enum: ["address"] },
125
+ name: vaultTextSchema(120),
126
+ created_at: { type: "integer", minimum: 0 },
127
+ address_line_1: vaultTextSchema(256),
128
+ address_line_2: vaultTextSchema(256),
129
+ city: vaultTextSchema(120),
130
+ state: vaultTextSchema(120),
131
+ zip: vaultTextSchema(32),
132
+ country: vaultTextSchema(120),
133
+ },
134
+ required: ["id", "kind", "name", "created_at", "address_line_1", "city", "state", "zip", "country"],
135
+ additionalProperties: false,
136
+ },
137
+ {
138
+ type: "object",
139
+ properties: {
140
+ id: VAULT_ID_SCHEMA,
141
+ kind: { type: "string", enum: ["phone"] },
142
+ name: vaultTextSchema(120),
143
+ created_at: { type: "integer", minimum: 0 },
144
+ phone_number: vaultTextSchema(64),
145
+ },
146
+ required: ["id", "kind", "name", "created_at", "phone_number"],
147
+ additionalProperties: false,
148
+ },
149
+ ],
150
+ };
151
+ const ACCOUNT_INFO_SCHEMA = Object.freeze({
152
+ type: "object",
153
+ properties: {
154
+ apis: {
155
+ type: "array",
156
+ items: {
157
+ type: "object",
158
+ properties: Object.fromEntries(Object.entries(X_API).map(([key, value]) => [key, { type: "string", const: value }])),
159
+ required: Object.keys(X_API),
160
+ additionalProperties: false,
161
+ },
162
+ },
163
+ status: {
164
+ type: "string",
165
+ enum: ["ready", "requires_login", "unavailable"],
166
+ },
167
+ authenticated: {
168
+ type: "array",
169
+ items: { type: "string", enum: CONNECTOR_IDS },
170
+ },
171
+ accounts: {
172
+ type: "object",
173
+ properties: Object.fromEntries(CONNECTOR_IDS.map((id) => [id, { type: "string" }])),
174
+ additionalProperties: false,
175
+ },
176
+ connectorAccounts: {
177
+ type: "object",
178
+ properties: Object.fromEntries(CONNECTOR_IDS.map((id) => [id, {
179
+ type: "array",
180
+ items: CONNECTOR_CONNECTION_SCHEMA,
181
+ }])),
182
+ additionalProperties: false,
183
+ },
184
+ identity: {
185
+ type: "object",
186
+ properties: {
187
+ tempoAddress: { type: "string" },
188
+ hostPrincipal: {
189
+ type: "object",
190
+ properties: {
191
+ kind: { type: "string", enum: ["host"] },
192
+ id: { type: "string" },
193
+ },
194
+ required: ["kind", "id"],
195
+ additionalProperties: false,
196
+ },
197
+ },
198
+ additionalProperties: false,
199
+ },
200
+ stablecoins: {
201
+ type: "array",
202
+ items: {
203
+ type: "object",
204
+ properties: {
205
+ token: { type: "string" },
206
+ symbol: { type: "string" },
207
+ balance: { type: "string" },
208
+ decimals: { type: "integer" },
209
+ },
210
+ required: ["token", "symbol", "balance", "decimals"],
211
+ additionalProperties: false,
212
+ },
213
+ },
214
+ authorizations: {
215
+ type: "array",
216
+ items: {
217
+ type: "object",
218
+ properties: {
219
+ appId: { type: "string" },
220
+ permission: { type: "string" },
221
+ status: { type: "string", enum: ["active", "revoked", "expired"] },
222
+ expiresAt: { type: "integer" },
223
+ capabilities: { type: "array", items: { type: "string" } },
224
+ connectors: { type: "array", items: { type: "string", enum: CONNECTOR_IDS } },
225
+ connectorConnections: {
226
+ type: "object",
227
+ properties: Object.fromEntries(CONNECTOR_CONNECTION_IDS.map((id) => [id, {
228
+ type: "array",
229
+ maxItems: 64,
230
+ uniqueItems: true,
231
+ items: { type: "string", pattern: "^[A-Za-z0-9_-]{43}$" },
232
+ }])),
233
+ additionalProperties: false,
234
+ },
235
+ authority: { type: "string", enum: ["hosted"] },
236
+ accessKey: {
237
+ type: "object",
238
+ properties: {
239
+ id: { type: "string" },
240
+ expiry: { type: "integer" },
241
+ limits: { type: "array", items: LIMIT_SCHEMA },
242
+ scopes: {
243
+ type: "array",
244
+ items: {
245
+ type: "object",
246
+ properties: {
247
+ address: { type: "string" },
248
+ selector: { type: "string" },
249
+ recipients: { type: "array", items: { type: "string" } },
250
+ },
251
+ required: ["address"],
252
+ additionalProperties: false,
253
+ },
254
+ },
255
+ },
256
+ required: ["id", "expiry", "limits", "scopes"],
257
+ additionalProperties: false,
258
+ },
259
+ spend: {
260
+ type: "object",
261
+ properties: {
262
+ token: { type: "string" },
263
+ symbol: { type: "string" },
264
+ spent: { type: "string" },
265
+ limit: { type: "string" },
266
+ period: { type: "integer" },
267
+ maxPerRequest: { type: "string" },
268
+ },
269
+ required: ["token", "symbol", "spent", "limit", "period", "maxPerRequest"],
270
+ additionalProperties: false,
271
+ },
272
+ },
273
+ required: [
274
+ "appId",
275
+ "permission",
276
+ "status",
277
+ "expiresAt",
278
+ "capabilities",
279
+ "connectors",
280
+ ],
281
+ oneOf: [
282
+ { required: ["authority"] },
283
+ { required: ["accessKey", "spend"] },
284
+ ],
285
+ additionalProperties: false,
286
+ },
287
+ },
288
+ vault: {
289
+ type: "array",
290
+ maxItems: MAX_VAULT_ENTRIES,
291
+ items: VAULT_ENTRY_SCHEMA,
292
+ },
293
+ },
294
+ required: [
295
+ "status", "authenticated", "accounts", "connectorAccounts", "identity",
296
+ "stablecoins", "authorizations", "vault", "apis",
297
+ ],
298
+ additionalProperties: false,
299
+ });
300
+
301
+ const ACCOUNT_CONNECTION_REQUEST_SCHEMA = Object.freeze({
302
+ type: "object",
303
+ properties: {
304
+ status: { type: "string", enum: ["authorization_required"] },
305
+ connector: { type: "string", enum: ACCOUNT_CONNECTION_IDS },
306
+ label: { type: "string" },
307
+ authorization_url: { type: "string" },
308
+ expires_in_seconds: { type: "integer", minimum: 1 },
309
+ message: { type: "string" },
310
+ },
311
+ required: [
312
+ "status",
313
+ "connector",
314
+ "label",
315
+ "authorization_url",
316
+ "expires_in_seconds",
317
+ "message",
318
+ ],
319
+ additionalProperties: false,
320
+ });
321
+
322
+ export function browserAccountInfoTool(options) {
323
+ return namedTool("accountInfo", {
324
+ description: "Report native public APIs, account authentication, safe Vault references, stablecoin balances, and app authorization boundaries. Native APIs in apis need no connector authorization; call their listed tools directly. Vault references never include passwords, full card numbers, CVVs, expiry details, or billing ZIPs.",
325
+ parameters: { type: "object", additionalProperties: false },
326
+ outputSchema: ACCOUNT_INFO_SCHEMA,
327
+ handler: (_input, context) => browserAccountInfo(options, context?.signal),
328
+ });
329
+ }
330
+
331
+ export function browserAccountConnectionTool(options) {
332
+ return namedTool("requestAccountConnection", {
333
+ description: "Request an account authorization link for GitHub, Gmail or another Google Workspace app, Slack, or X. Call this when the user asks to connect or authenticate one of these services. Return the exact authorization_url as a Markdown link in your response; do not claim the account is connected until accountInfo confirms it.",
334
+ parameters: {
335
+ type: "object",
336
+ properties: {
337
+ connector: { type: "string", enum: ACCOUNT_CONNECTION_IDS },
338
+ },
339
+ required: ["connector"],
340
+ additionalProperties: false,
341
+ },
342
+ outputSchema: ACCOUNT_CONNECTION_REQUEST_SCHEMA,
343
+ async handler(input, context) {
344
+ const connector = input?.connector;
345
+ if (!ACCOUNT_CONNECTION_IDS.includes(connector)) {
346
+ throw new TypeError("account connection connector is invalid");
347
+ }
348
+ const label = ACCOUNT_CONNECTION_LABELS[connector];
349
+ if (!label) throw new TypeError("account connection connector is invalid");
350
+ if (typeof options?.fetch !== "function") {
351
+ throw new TypeError("browser account connection requires fetch");
352
+ }
353
+ const provider = accountConnectionProvider(connector);
354
+ const endpoint = new URL(`/v1/connectors/${provider}`, options.origin);
355
+ const response = await options.fetch(endpoint, {
356
+ method: "POST",
357
+ headers: {
358
+ accept: "application/json",
359
+ "content-type": "application/json",
360
+ },
361
+ body: JSON.stringify({ return_to: "/connect" }),
362
+ credentials: "same-origin",
363
+ cache: "no-store",
364
+ signal: context?.signal,
365
+ });
366
+ if (!response.ok) {
367
+ await response.body?.cancel();
368
+ throw new Error(`account connection request failed with HTTP ${response.status}`);
369
+ }
370
+ const value = await response.json().catch(() => undefined);
371
+ const authorizationUrl = record(value) && typeof value.authorization_url === "string"
372
+ ? safeAccountAuthorizationUrl(value.authorization_url, provider, options.origin)
373
+ : undefined;
374
+ if (!authorizationUrl) {
375
+ throw new Error("account connection returned an invalid authorization URL");
376
+ }
377
+ return {
378
+ status: "authorization_required",
379
+ connector,
380
+ label,
381
+ authorization_url: authorizationUrl,
382
+ expires_in_seconds: 600,
383
+ message: `Open the authorization link to connect ${label}.`,
384
+ };
385
+ },
386
+ });
387
+ }
388
+
389
+ function accountConnectionProvider(connector) {
390
+ return GOOGLE_CONNECTION_IDS.has(connector) ? "google" : connector;
391
+ }
392
+
393
+ function safeAccountAuthorizationUrl(value, provider, publicOrigin) {
394
+ let authorization;
395
+ try { authorization = new URL(value); } catch { return undefined; }
396
+ const expected = ACCOUNT_AUTHORIZATION_ENDPOINTS[provider];
397
+ if (!expected
398
+ || authorization.origin !== expected.origin
399
+ || authorization.pathname !== expected.pathname
400
+ || authorization.username
401
+ || authorization.password
402
+ || authorization.hash
403
+ || !authorization.searchParams.get("client_id")
404
+ || !authorization.searchParams.get("state")
405
+ || !authorization.searchParams.get(provider === "slack" ? "user_scope" : "scope")
406
+ || !safeAccountRedirectUri(authorization.searchParams.get("redirect_uri"), provider, publicOrigin)) {
407
+ return undefined;
408
+ }
409
+ const seen = new Set();
410
+ for (const key of authorization.searchParams.keys()) {
411
+ if (!ACCOUNT_AUTHORIZATION_QUERY_KEYS.has(key) || seen.has(key)) return undefined;
412
+ seen.add(key);
413
+ }
414
+ const responseType = authorization.searchParams.get("response_type");
415
+ if (responseType !== null && responseType !== "code") return undefined;
416
+ if (provider !== "slack" && (
417
+ authorization.searchParams.get("code_challenge_method") !== "S256"
418
+ || !/^[A-Za-z0-9_-]{43}$/.test(authorization.searchParams.get("code_challenge") ?? "")
419
+ )) return undefined;
420
+ const granularConsent = authorization.searchParams.get("enable_granular_consent");
421
+ if (granularConsent !== null && (provider !== "google" || granularConsent !== "true")) {
422
+ return undefined;
423
+ }
424
+ return authorization.href;
425
+ }
426
+
427
+ function safeAccountRedirectUri(value, provider, publicOrigin) {
428
+ let redirect;
429
+ try { redirect = new URL(value); } catch { return false; }
430
+ if (redirect.username || redirect.password || redirect.search || redirect.hash
431
+ || redirect.pathname !== `/v1/connectors/${provider}/callback`) return false;
432
+ const origin = new URL(publicOrigin);
433
+ if (redirect.origin === origin.origin) return true;
434
+ return redirect.origin === LOCAL_OAUTH_RELAY_ORIGIN
435
+ && (origin.hostname === "nanocodex.localhost"
436
+ || origin.hostname.endsWith(".nanocodex.localhost"));
437
+ }
438
+
439
+ export function browserRuntimeInfoTool(options, descriptor) {
440
+ if (!descriptor || typeof descriptor !== "object" || Array.isArray(descriptor)) {
441
+ throw new TypeError("browser runtime info requires a shell descriptor");
442
+ }
443
+ return namedTool("runtimeInfo", {
444
+ description: "Return information about the browser agent runtime and connected accounts.",
445
+ parameters: { type: "object", additionalProperties: false },
446
+ async handler(_input, context) {
447
+ return {
448
+ runtime: "browser-worker",
449
+ shell: descriptor.shell,
450
+ shell_network: descriptor.network.mode,
451
+ sandbox: "browser",
452
+ workspace: descriptor.cwd,
453
+ commands: descriptor.commands,
454
+ custom_commands: descriptor.customCommands,
455
+ limits: descriptor.limits,
456
+ pty: descriptor.pty,
457
+ sessions: descriptor.sessions,
458
+ sandbox_escalation: descriptor.sandboxEscalation,
459
+ account: await browserAccountInfo(options, context?.signal),
460
+ };
461
+ },
462
+ });
463
+ }
464
+
465
+ export async function browserAccountInfo(options, signal) {
466
+ if (typeof options?.fetch !== "function") throw new TypeError("browser account info requires fetch");
467
+ const endpoint = new URL(options.endpoint ?? "/v1/connectors", options.origin);
468
+ try {
469
+ const response = await options.fetch(endpoint, {
470
+ headers: { accept: "application/json" },
471
+ credentials: "same-origin",
472
+ cache: "no-store",
473
+ signal,
474
+ });
475
+ if (response.status === 401) {
476
+ await response.body?.cancel();
477
+ return emptyInfo("requires_login");
478
+ }
479
+ if (!response.ok) {
480
+ await response.body?.cancel();
481
+ return emptyInfo("unavailable");
482
+ }
483
+ const value = await response.json();
484
+ if (!record(value) || !record(value.connectors)) return emptyInfo("unavailable");
485
+ const accounts = {};
486
+ const connectorAccounts = {};
487
+ const authenticated = CONNECTOR_IDS.filter((id) => {
488
+ const connector = value.connectors[id];
489
+ if (!record(connector) || connector.connected !== true) return false;
490
+ if (Array.isArray(connector.connections)) {
491
+ if (connector.connections.length > 64) throw new Error("too many connector accounts");
492
+ const connections = connector.connections.map(connectorAccount);
493
+ if (new Set(connections.map(({ id: connectionId }) => connectionId)).size
494
+ !== connections.length) throw new Error("duplicate connector accounts");
495
+ connectorAccounts[id] = connections;
496
+ if (connections.length === 1) accounts[id] = connections[0].label;
497
+ return connections.length > 0;
498
+ }
499
+ // Backward-compatible legacy singleton status.
500
+ const legacyLabel = boundedString(connector.label, 256)
501
+ ?? boundedString(connector.account_id, 256);
502
+ if (legacyLabel) accounts[id] = legacyLabel;
503
+ return true;
504
+ });
505
+ const accountIdentity = identity(value.identity);
506
+ const accountStablecoins = stablecoins(value.stablecoins);
507
+ const accountAuthorizations = authorizations(value.authorizations);
508
+ const accountVault = vaultEntries(value.vault);
509
+ if (options.requireAuthorization && (
510
+ (!accountIdentity.tempoAddress && !accountIdentity.hostPrincipal)
511
+ || !Array.isArray(value.stablecoins)
512
+ || accountStablecoins.length !== value.stablecoins.length
513
+ || (accountIdentity.tempoAddress && accountStablecoins.length === 0)
514
+ || !Array.isArray(value.authorizations)
515
+ || accountAuthorizations.length !== value.authorizations.length
516
+ || accountAuthorizations.length === 0
517
+ )) {
518
+ throw new Error("account authorization response is incomplete");
519
+ }
520
+ return {
521
+ status: "ready",
522
+ apis: [X_API],
523
+ authenticated,
524
+ accounts,
525
+ connectorAccounts,
526
+ identity: accountIdentity,
527
+ stablecoins: accountStablecoins,
528
+ authorizations: accountAuthorizations,
529
+ vault: accountVault,
530
+ };
531
+ } catch (error) {
532
+ if (signal?.aborted) throw error;
533
+ return emptyInfo("unavailable");
534
+ }
535
+ }
536
+
537
+ function emptyInfo(status) {
538
+ return {
539
+ status,
540
+ apis: [X_API],
541
+ authenticated: [],
542
+ accounts: {},
543
+ connectorAccounts: {},
544
+ identity: {},
545
+ stablecoins: [],
546
+ authorizations: [],
547
+ vault: [],
548
+ };
549
+ }
550
+
551
+ function connectorAccount(value) {
552
+ if (!record(value) || typeof value.id !== "string" || !CONNECTION_ID.test(value.id)) {
553
+ throw new Error("invalid connector account");
554
+ }
555
+ const label = boundedString(value.label, 256);
556
+ const accountId = value.account_id === undefined
557
+ ? undefined
558
+ : boundedString(value.account_id, 256);
559
+ const capabilities = value.capabilities === undefined
560
+ ? undefined
561
+ : connectorCapabilities(value.capabilities);
562
+ if (!label || (value.account_id !== undefined && !accountId)) {
563
+ throw new Error("invalid connector account");
564
+ }
565
+ return {
566
+ id: value.id,
567
+ label,
568
+ ...(accountId === undefined ? {} : { accountId }),
569
+ ...(capabilities === undefined ? {} : { capabilities }),
570
+ };
571
+ }
572
+
573
+ function connectorCapabilities(value) {
574
+ if (!Array.isArray(value) || value.length > CONNECTOR_IDS.length
575
+ || value.some((capability) => !CONNECTOR_IDS.includes(capability))
576
+ || new Set(value).size !== value.length) {
577
+ throw new Error("invalid connector capabilities");
578
+ }
579
+ return [...value];
580
+ }
581
+
582
+ function boundedString(value, maxLength) {
583
+ if (typeof value !== "string") return undefined;
584
+ const normalized = value.trim();
585
+ return normalized && normalized.length <= maxLength ? normalized : undefined;
586
+ }
587
+
588
+ function vaultEntries(value) {
589
+ if (!Array.isArray(value) || value.length > MAX_VAULT_ENTRIES) return [];
590
+ const projected = [];
591
+ for (const entry of value) {
592
+ const safe = vaultEntry(entry);
593
+ if (!safe) return [];
594
+ projected.push(safe);
595
+ }
596
+ return projected;
597
+ }
598
+
599
+ function vaultEntry(value) {
600
+ if (!record(value)
601
+ || typeof value.id !== "string" || !VAULT_ID.test(value.id)
602
+ || !vaultText(value.name, 120)
603
+ || !Number.isSafeInteger(value.created_at)
604
+ || value.created_at < 0) return undefined;
605
+ const common = { id: value.id, name: value.name, created_at: value.created_at };
606
+ if (value.kind === "login"
607
+ && exactKeys(value, ["id", "kind", "name", "created_at", "username"])
608
+ && vaultText(value.username, 512)) {
609
+ return { ...common, kind: "login", username: value.username };
610
+ }
611
+ if (value.kind === "card"
612
+ && exactKeys(value, ["id", "kind", "name", "created_at", "last4"])
613
+ && typeof value.last4 === "string" && /^[0-9]{4}$/.test(value.last4)) {
614
+ return { ...common, kind: "card", last4: value.last4 };
615
+ }
616
+ if (value.kind === "address") {
617
+ const hasLine2 = Object.prototype.hasOwnProperty.call(value, "address_line_2");
618
+ if (!exactKeys(value, [
619
+ "id", "kind", "name", "created_at", "address_line_1",
620
+ ...(hasLine2 ? ["address_line_2"] : []),
621
+ "city", "state", "zip", "country",
622
+ ])
623
+ || !vaultText(value.address_line_1, 256)
624
+ || (hasLine2 && !vaultText(value.address_line_2, 256))
625
+ || !vaultText(value.city, 120)
626
+ || !vaultText(value.state, 120)
627
+ || !vaultText(value.zip, 32)
628
+ || !vaultText(value.country, 120)) return undefined;
629
+ return {
630
+ ...common,
631
+ kind: "address",
632
+ address_line_1: value.address_line_1,
633
+ ...(hasLine2 ? { address_line_2: value.address_line_2 } : {}),
634
+ city: value.city,
635
+ state: value.state,
636
+ zip: value.zip,
637
+ country: value.country,
638
+ };
639
+ }
640
+ if (value.kind === "phone"
641
+ && exactKeys(value, ["id", "kind", "name", "created_at", "phone_number"])
642
+ && vaultText(value.phone_number, 64)) {
643
+ return { ...common, kind: "phone", phone_number: value.phone_number };
644
+ }
645
+ return undefined;
646
+ }
647
+
648
+ function exactKeys(value, expected) {
649
+ const keys = Object.keys(value);
650
+ return keys.length === expected.length && keys.every((key) => expected.includes(key));
651
+ }
652
+
653
+ function vaultText(value, maxBytes) {
654
+ return typeof value === "string" && value.length > 0 && value.trim() === value
655
+ && !/[\u0000-\u001f\u007f]/.test(value)
656
+ && new TextEncoder().encode(value).byteLength <= maxBytes;
657
+ }
658
+
659
+ function identity(value) {
660
+ if (!record(value)) return {};
661
+ const hasTempoAddress = typeof value.tempoAddress === "string";
662
+ const hasHostPrincipal = validHostPrincipal(value.hostPrincipal);
663
+ if (hasTempoAddress === hasHostPrincipal) return {};
664
+ if (hasTempoAddress) return { tempoAddress: value.tempoAddress };
665
+ if (hasHostPrincipal) {
666
+ return { hostPrincipal: { kind: "host", id: value.hostPrincipal.id } };
667
+ }
668
+ return {};
669
+ }
670
+
671
+ function stablecoins(value) {
672
+ if (!Array.isArray(value)) return [];
673
+ return value.filter((asset) => record(asset)
674
+ && typeof asset.token === "string"
675
+ && typeof asset.symbol === "string"
676
+ && typeof asset.balance === "string"
677
+ && Number.isSafeInteger(asset.decimals)
678
+ ).map(({ token, symbol, balance, decimals }) => ({ token, symbol, balance, decimals }));
679
+ }
680
+
681
+ function authorizations(value) {
682
+ if (!Array.isArray(value)) return [];
683
+ return value.filter(validAuthorization).map((authorization) => ({
684
+ appId: authorization.appId,
685
+ permission: authorization.permission,
686
+ status: authorization.status,
687
+ expiresAt: authorization.expiresAt,
688
+ capabilities: [...authorization.capabilities],
689
+ connectors: [...authorization.connectors],
690
+ ...(authorization.connectorConnections === undefined ? {} : {
691
+ connectorConnections: Object.fromEntries(Object.entries(
692
+ authorization.connectorConnections,
693
+ ).map(([connector, ids]) => [connector, [...ids]])),
694
+ }),
695
+ ...(authorization.authority === "hosted" ? { authority: "hosted" } : {
696
+ accessKey: {
697
+ id: authorization.accessKey.id,
698
+ expiry: authorization.accessKey.expiry,
699
+ limits: authorization.accessKey.limits.map((limit) => ({
700
+ token: limit.token,
701
+ symbol: limit.symbol,
702
+ limit: limit.limit,
703
+ ...(limit.period === undefined ? {} : { period: limit.period }),
704
+ })),
705
+ scopes: authorization.accessKey.scopes.map((scope) => ({
706
+ address: scope.address,
707
+ ...(scope.selector === undefined ? {} : { selector: scope.selector }),
708
+ ...(scope.recipients === undefined ? {} : { recipients: [...scope.recipients] }),
709
+ })),
710
+ },
711
+ spend: {
712
+ token: authorization.spend.token,
713
+ symbol: authorization.spend.symbol,
714
+ spent: authorization.spend.spent,
715
+ limit: authorization.spend.limit,
716
+ period: authorization.spend.period,
717
+ maxPerRequest: authorization.spend.maxPerRequest,
718
+ },
719
+ }),
720
+ }));
721
+ }
722
+
723
+ function validAuthorization(value) {
724
+ return record(value)
725
+ && typeof value.appId === "string"
726
+ && typeof value.permission === "string"
727
+ && ["active", "revoked", "expired"].includes(value.status)
728
+ && Number.isSafeInteger(value.expiresAt)
729
+ && stringArray(value.capabilities)
730
+ && Array.isArray(value.connectors)
731
+ && value.connectors.every((connector) => CONNECTOR_IDS.includes(connector))
732
+ && validConnectorConnections(value.connectorConnections, value.connectors)
733
+ && ((value.authority === "hosted"
734
+ && value.accessKey === undefined
735
+ && value.spend === undefined)
736
+ || (value.authority === undefined
737
+ && validAccessKey(value.accessKey)
738
+ && validSpend(value.spend)));
739
+ }
740
+
741
+ function validHostPrincipal(value) {
742
+ return record(value)
743
+ && value.kind === "host"
744
+ && typeof value.id === "string"
745
+ && HOST_PRINCIPAL_ID.test(value.id)
746
+ && Object.keys(value).every((key) => key === "kind" || key === "id");
747
+ }
748
+
749
+ function validConnectorConnections(value, granted) {
750
+ if (value === undefined) return true;
751
+ if (!record(value)) return false;
752
+ return Object.entries(value).every(([connector, ids]) => (
753
+ CONNECTOR_CONNECTION_IDS.includes(connector)
754
+ && granted.includes(connector)
755
+ && Array.isArray(ids)
756
+ && ids.length <= 64
757
+ && ids.every((id) => typeof id === "string" && CONNECTION_ID.test(id))
758
+ && new Set(ids).size === ids.length
759
+ ));
760
+ }
761
+
762
+ function validAccessKey(value) {
763
+ return record(value)
764
+ && typeof value.id === "string"
765
+ && Number.isSafeInteger(value.expiry)
766
+ && Array.isArray(value.limits)
767
+ && value.limits.every((limit) => record(limit)
768
+ && typeof limit.token === "string"
769
+ && typeof limit.symbol === "string"
770
+ && typeof limit.limit === "string"
771
+ && (limit.period === undefined || Number.isSafeInteger(limit.period)))
772
+ && Array.isArray(value.scopes)
773
+ && value.scopes.every((scope) => record(scope)
774
+ && typeof scope.address === "string"
775
+ && (scope.selector === undefined || typeof scope.selector === "string")
776
+ && (scope.recipients === undefined || stringArray(scope.recipients)));
777
+ }
778
+
779
+ function validSpend(value) {
780
+ return record(value)
781
+ && typeof value.token === "string"
782
+ && typeof value.symbol === "string"
783
+ && typeof value.spent === "string"
784
+ && typeof value.limit === "string"
785
+ && Number.isSafeInteger(value.period)
786
+ && typeof value.maxPerRequest === "string";
787
+ }
788
+
789
+ function stringArray(value) {
790
+ return Array.isArray(value) && value.every((item) => typeof item === "string");
791
+ }
792
+
793
+ function record(value) {
794
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
795
+ }