@stage-labs/metro 0.1.0-beta.20 → 0.1.0-beta.201

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 (442) hide show
  1. package/dist/api.js +9 -101
  2. package/dist/claude-settings.js +40 -0
  3. package/dist/claude.js +163 -0
  4. package/dist/cli.js +50 -109
  5. package/dist/control.js +47 -75
  6. package/dist/hold.js +211 -0
  7. package/dist/local.js +43 -0
  8. package/dist/mcp-config.js +25 -0
  9. package/dist/node-name.js +71 -0
  10. package/dist/onboarding.js +44 -0
  11. package/dist/provider-flags.js +9 -0
  12. package/dist/route.js +58 -0
  13. package/dist/runtime-install.js +97 -0
  14. package/dist/runtime.js +32 -52
  15. package/dist/serve.js +158 -0
  16. package/dist/service.js +243 -0
  17. package/dist/tail.js +119 -0
  18. package/dist/update.js +13 -1
  19. package/package.json +1 -22
  20. package/runtime/marketplace/.claude-plugin/marketplace.json +12 -0
  21. package/runtime/marketplace/plugin/.claude-plugin/plugin.json +17 -0
  22. package/runtime/marketplace/plugin/.mcp.json +1 -0
  23. package/runtime/marketplace/plugin/bin/guard.mjs +71 -0
  24. package/runtime/marketplace/plugin/bin/metro-plugin.mjs +30 -0
  25. package/runtime/marketplace/plugin/bin/policy.mjs +97 -0
  26. package/runtime/marketplace/plugin/bin/session-start.mjs +31 -0
  27. package/runtime/marketplace/plugin/hooks/hooks.json +25 -0
  28. package/runtime/marketplace/plugin/orchestrator.md +24 -0
  29. package/runtime/node_modules/@metro-labs/core/package.json +47 -0
  30. package/runtime/node_modules/@metro-labs/core/src/endpoints.ts +7 -0
  31. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/events.ts +8 -6
  32. package/runtime/node_modules/@metro-labs/core/src/identity.ts +7 -0
  33. package/runtime/node_modules/@metro-labs/{mcp/src/db → core/src}/ids.ts +5 -0
  34. package/runtime/node_modules/@metro-labs/core/src/is-record.ts +2 -0
  35. package/runtime/node_modules/@metro-labs/{mcp/src/stations → core/src}/lines.ts +12 -3
  36. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/protocol.ts +7 -4
  37. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/secure-fs.ts +17 -0
  38. package/runtime/node_modules/@metro-labs/core/src/station-names.ts +13 -0
  39. package/runtime/node_modules/@metro-labs/core/src/stations/account-files.ts +41 -0
  40. package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/account-store.ts +4 -24
  41. package/runtime/node_modules/@metro-labs/core/src/stations/profile.ts +58 -0
  42. package/runtime/node_modules/@metro-labs/core/src/stations/sender-profile.ts +64 -0
  43. package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/station-runtime.ts +3 -6
  44. package/runtime/node_modules/@metro-labs/core/src/stations/train-boot.ts +42 -0
  45. package/runtime/node_modules/@metro-labs/core/src/stations/train-events.ts +89 -0
  46. package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/types.ts +16 -0
  47. package/runtime/node_modules/@metro-labs/core/src/tickets.ts +37 -0
  48. package/runtime/node_modules/@metro-labs/core/src/version.ts +2 -0
  49. package/runtime/node_modules/@metro-labs/daemon/package.json +48 -0
  50. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/agent-fs.ts +134 -0
  51. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/files-api.ts +12 -0
  52. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/files.ts +119 -0
  53. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/home-fs.ts +113 -0
  54. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/job-env.ts +51 -0
  55. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/provision.ts +99 -0
  56. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedule-detail.ts +100 -0
  57. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedules-api.ts +27 -0
  58. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedules.ts +252 -0
  59. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/unit-files.ts +61 -0
  60. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/user.ts +91 -0
  61. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/view.ts +87 -0
  62. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-attach.ts +19 -0
  63. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-lookups.ts +55 -0
  64. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-routes.ts +76 -0
  65. package/runtime/node_modules/@metro-labs/daemon/src/agents/accounts-api.ts +357 -0
  66. package/runtime/node_modules/@metro-labs/daemon/src/agents/admin.ts +30 -0
  67. package/runtime/node_modules/@metro-labs/daemon/src/agents/allowlist.ts +59 -0
  68. package/runtime/node_modules/@metro-labs/daemon/src/agents/api.ts +131 -0
  69. package/runtime/node_modules/@metro-labs/daemon/src/agents/bundle.ts +132 -0
  70. package/runtime/node_modules/@metro-labs/daemon/src/agents/file-admin.ts +305 -0
  71. package/runtime/node_modules/@metro-labs/daemon/src/agents/files.ts +168 -0
  72. package/runtime/node_modules/@metro-labs/{mcp/src/db/key-map.ts → daemon/src/agents/keys.ts} +1 -11
  73. package/runtime/node_modules/@metro-labs/{mcp/src/db/agent-map.ts → daemon/src/agents/map.ts} +58 -1
  74. package/runtime/node_modules/@metro-labs/daemon/src/agents/policy-route.ts +27 -0
  75. package/runtime/node_modules/@metro-labs/{mcp/src/db/agent-scope.ts → daemon/src/agents/scope.ts} +2 -2
  76. package/runtime/node_modules/@metro-labs/daemon/src/agents/sender-cards.ts +86 -0
  77. package/runtime/node_modules/@metro-labs/daemon/src/agents/senders.ts +38 -0
  78. package/runtime/node_modules/@metro-labs/daemon/src/approvals/api.ts +55 -0
  79. package/runtime/node_modules/@metro-labs/daemon/src/approvals/needs.ts +2 -0
  80. package/runtime/node_modules/@metro-labs/daemon/src/approvals/pending.ts +149 -0
  81. package/runtime/node_modules/@metro-labs/daemon/src/approvals/preview.ts +66 -0
  82. package/runtime/node_modules/@metro-labs/daemon/src/boot/boot.ts +221 -0
  83. package/runtime/node_modules/@metro-labs/daemon/src/boot/connect-hint.ts +39 -0
  84. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/boot}/crash-guard.ts +1 -1
  85. package/runtime/node_modules/@metro-labs/daemon/src/boot/local-owner.ts +21 -0
  86. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/boot}/paths.ts +6 -34
  87. package/runtime/node_modules/@metro-labs/daemon/src/channels/addressed.ts +26 -0
  88. package/runtime/node_modules/@metro-labs/daemon/src/channels/dedupe.ts +12 -0
  89. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/inbound.ts +47 -44
  90. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/media-note.ts +9 -4
  91. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/pending.ts +4 -1
  92. package/runtime/node_modules/@metro-labs/daemon/src/channels/react-note.ts +13 -0
  93. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/relay.ts +2 -2
  94. package/runtime/node_modules/@metro-labs/daemon/src/channels/reply-id.ts +1 -0
  95. package/runtime/node_modules/@metro-labs/daemon/src/claude/api.ts +355 -0
  96. package/runtime/node_modules/@metro-labs/daemon/src/claude/files.ts +359 -0
  97. package/runtime/node_modules/@metro-labs/daemon/src/claude/login.ts +208 -0
  98. package/runtime/node_modules/@metro-labs/daemon/src/claude/memory.ts +82 -0
  99. package/runtime/node_modules/@metro-labs/daemon/src/claude/onboarding.ts +60 -0
  100. package/runtime/node_modules/@metro-labs/daemon/src/claude/plugin-install.ts +149 -0
  101. package/runtime/node_modules/@metro-labs/daemon/src/claude/session-files.ts +75 -0
  102. package/runtime/node_modules/@metro-labs/daemon/src/claude/session.ts +283 -0
  103. package/runtime/node_modules/@metro-labs/daemon/src/claude/settings.ts +109 -0
  104. package/runtime/node_modules/@metro-labs/daemon/src/claude/setup.ts +271 -0
  105. package/runtime/node_modules/@metro-labs/daemon/src/claude/skills.ts +120 -0
  106. package/runtime/node_modules/@metro-labs/daemon/src/claude/version.ts +113 -0
  107. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-api.ts → daemon/src/connectors/api.ts} +77 -109
  108. package/runtime/node_modules/@metro-labs/{mcp/src/db/connector-config.ts → daemon/src/connectors/config.ts} +55 -26
  109. package/runtime/node_modules/@metro-labs/daemon/src/connectors/gates.ts +72 -0
  110. package/runtime/node_modules/@metro-labs/daemon/src/connectors/health.ts +18 -0
  111. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/connectors}/oauth-client.ts +14 -17
  112. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/connectors}/oauth-discovery.ts +28 -13
  113. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-oauth-routes.ts → daemon/src/connectors/oauth-routes.ts} +30 -29
  114. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-oauth.ts → daemon/src/connectors/oauth.ts} +61 -22
  115. package/runtime/node_modules/@metro-labs/daemon/src/connectors/plugin-sync.ts +131 -0
  116. package/runtime/node_modules/@metro-labs/daemon/src/connectors/reach.ts +27 -0
  117. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay-policy.ts +90 -0
  118. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay-target.ts +29 -0
  119. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay.ts +348 -0
  120. package/runtime/node_modules/@metro-labs/daemon/src/connectors/store.ts +358 -0
  121. package/runtime/node_modules/@metro-labs/daemon/src/connectors/tools.ts +81 -0
  122. package/runtime/node_modules/@metro-labs/daemon/src/connectors/url.ts +37 -0
  123. package/runtime/node_modules/@metro-labs/daemon/src/connectors/verify.ts +106 -0
  124. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-grant.ts +4 -4
  125. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-owner.ts +3 -3
  126. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-reaper.ts +174 -0
  127. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-serve.ts +11 -12
  128. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/upload-api.ts +10 -27
  129. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/upload-store.ts +2 -2
  130. package/runtime/node_modules/@metro-labs/daemon/src/gateway/bedrock.ts +233 -0
  131. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-auth.ts +208 -0
  132. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-device.ts +91 -0
  133. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-stream.ts +173 -0
  134. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-translate.ts +194 -0
  135. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex.ts +137 -0
  136. package/runtime/node_modules/@metro-labs/daemon/src/gateway/effort.ts +77 -0
  137. package/runtime/node_modules/@metro-labs/daemon/src/gateway/eventstream.ts +123 -0
  138. package/runtime/node_modules/@metro-labs/daemon/src/gateway/forward.ts +237 -0
  139. package/runtime/node_modules/@metro-labs/daemon/src/gateway/frames.ts +118 -0
  140. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gateway.ts +274 -0
  141. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-auth.ts +160 -0
  142. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-client.ts +46 -0
  143. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-setup.ts +150 -0
  144. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-stream.ts +139 -0
  145. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-translate.ts +223 -0
  146. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini.ts +208 -0
  147. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-api.ts +199 -0
  148. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-config.ts +299 -0
  149. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-signin.ts +193 -0
  150. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-store.ts +70 -0
  151. package/runtime/node_modules/@metro-labs/daemon/src/gateway/openrouter.ts +90 -0
  152. package/runtime/node_modules/@metro-labs/daemon/src/gateway/pkce.ts +36 -0
  153. package/runtime/node_modules/@metro-labs/daemon/src/gateway/provider-models.ts +66 -0
  154. package/runtime/node_modules/@metro-labs/daemon/src/gateway/served.ts +18 -0
  155. package/runtime/node_modules/@metro-labs/daemon/src/gateway/subscription.ts +120 -0
  156. package/runtime/node_modules/@metro-labs/daemon/src/gateway/text.ts +15 -0
  157. package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage.ts +244 -0
  158. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/accounts.ts +59 -18
  159. package/runtime/node_modules/@metro-labs/daemon/src/mcp/attachment-schema.ts +91 -0
  160. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/call-tools.ts +43 -20
  161. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/ctx.ts +4 -4
  162. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/event-store.ts +15 -16
  163. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/group-tools.ts +2 -2
  164. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/index.ts +24 -79
  165. package/runtime/node_modules/@metro-labs/daemon/src/mcp/instructions.ts +19 -0
  166. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/member-tools.ts +2 -2
  167. package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-prompt.ts +87 -0
  168. package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-relay.ts +79 -0
  169. package/runtime/node_modules/@metro-labs/daemon/src/mcp/policy-gate.ts +83 -0
  170. package/runtime/node_modules/@metro-labs/daemon/src/mcp/policy-snapshot.ts +79 -0
  171. package/runtime/node_modules/@metro-labs/daemon/src/mcp/profile-lookup.ts +60 -0
  172. package/runtime/node_modules/@metro-labs/daemon/src/mcp/profile-tool.ts +96 -0
  173. package/runtime/node_modules/@metro-labs/daemon/src/mcp/read-tool.ts +87 -0
  174. package/runtime/node_modules/@metro-labs/daemon/src/mcp/request-identity.ts +46 -0
  175. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session-slot.ts +48 -0
  176. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/session.ts +33 -42
  177. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-catalog.ts +88 -0
  178. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-def.ts +9 -0
  179. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/tool-dispatch.ts +53 -40
  180. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/tool-schemas.ts +55 -119
  181. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/upload-tool.ts +6 -11
  182. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/api.ts +43 -0
  183. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/helper-script.ts +126 -0
  184. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/move.ts +165 -0
  185. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/privilege.ts +48 -0
  186. package/runtime/node_modules/@metro-labs/daemon/src/monitor/api.ts +132 -0
  187. package/runtime/node_modules/@metro-labs/daemon/src/net/tunnel.ts +316 -0
  188. package/runtime/node_modules/@metro-labs/daemon/src/policy/policy.ts +118 -0
  189. package/runtime/node_modules/@metro-labs/daemon/src/routes/bearer.ts +35 -0
  190. package/runtime/node_modules/@metro-labs/daemon/src/routes/body.ts +24 -0
  191. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/routes}/http.ts +59 -51
  192. package/runtime/node_modules/@metro-labs/daemon/src/routes/local-mode.ts +208 -0
  193. package/runtime/node_modules/@metro-labs/daemon/src/routes/session-apis.ts +71 -0
  194. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/session-api.ts → daemon/src/routes/session.ts} +9 -7
  195. package/runtime/node_modules/@metro-labs/daemon/src/routes/threema-callback.ts +103 -0
  196. package/runtime/node_modules/@metro-labs/daemon/src/server/control.ts +39 -0
  197. package/runtime/node_modules/@metro-labs/daemon/src/server/machine.ts +58 -0
  198. package/runtime/node_modules/@metro-labs/daemon/src/server/owner.ts +26 -0
  199. package/runtime/node_modules/@metro-labs/daemon/src/server/update.ts +90 -0
  200. package/runtime/node_modules/@metro-labs/daemon/src/server.ts +2 -0
  201. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-driver.ts +42 -0
  202. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-inline.ts +29 -1
  203. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-interactive.ts +9 -36
  204. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-outlook.ts +63 -0
  205. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-resolve.ts +38 -13
  206. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/attach-session.ts +30 -20
  207. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-xmtp.ts +2 -2
  208. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach.ts +75 -9
  209. package/runtime/node_modules/@metro-labs/daemon/src/stations/materialize.ts +265 -0
  210. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/registry.ts +22 -6
  211. package/runtime/node_modules/@metro-labs/daemon/src/stations/runtime-deps.ts +82 -0
  212. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/supervisor-io.ts +2 -2
  213. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/supervisor.ts +5 -8
  214. package/runtime/node_modules/@metro-labs/daemon/src/stations/threema-callbacks.ts +32 -0
  215. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/train-call.ts +1 -1
  216. package/runtime/node_modules/@metro-labs/daemon/src/stations/webhook-endpoints.ts +51 -0
  217. package/runtime/node_modules/@metro-labs/daemon/src/terminal/api.ts +84 -0
  218. package/runtime/node_modules/@metro-labs/daemon/src/terminal/socket.ts +124 -0
  219. package/runtime/node_modules/@metro-labs/daemon/src/terminal/tickets.ts +15 -0
  220. package/runtime/node_modules/@metro-labs/daemon/src/vault/api.ts +45 -0
  221. package/runtime/node_modules/@metro-labs/daemon/src/vault/config.ts +51 -0
  222. package/runtime/node_modules/@metro-labs/daemon/src/vault/firewall.ts +48 -0
  223. package/runtime/node_modules/@metro-labs/daemon/src/vault/index.ts +96 -0
  224. package/runtime/node_modules/@metro-labs/daemon/src/vault/install.ts +56 -0
  225. package/runtime/node_modules/@metro-labs/daemon/src/vault/paths.ts +26 -0
  226. package/runtime/node_modules/@metro-labs/daemon/src/vault/proxy.ts +148 -0
  227. package/runtime/node_modules/@metro-labs/daemon/src/vault/store.ts +130 -0
  228. package/runtime/node_modules/@metro-labs/daemon/src/vault/trust.ts +61 -0
  229. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/package.json +3 -5
  230. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/accounts.ts +11 -13
  231. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/actions.ts +6 -154
  232. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/attachments.ts +3 -3
  233. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/format.ts +28 -64
  234. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/group-actions.ts +1 -1
  235. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/group.ts +2 -2
  236. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/index.ts +14 -19
  237. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/members.ts +2 -2
  238. package/runtime/node_modules/@metro-labs/discord-bot/src/profile.ts +68 -0
  239. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/send-files.ts +1 -1
  240. package/runtime/node_modules/@metro-labs/discord-bot/src/station.ts +22 -0
  241. package/runtime/node_modules/@metro-labs/discord-bot/src/wire.ts +1 -0
  242. package/runtime/node_modules/@metro-labs/http/package.json +29 -0
  243. package/runtime/node_modules/@metro-labs/http/src/api-http.ts +138 -0
  244. package/runtime/node_modules/@metro-labs/http/src/mode-api.ts +32 -0
  245. package/runtime/node_modules/@metro-labs/http/src/return-to.ts +21 -0
  246. package/runtime/node_modules/@metro-labs/http/src/workos-token.ts +149 -0
  247. package/runtime/node_modules/@metro-labs/{telegram-user → outlook}/package.json +2 -5
  248. package/runtime/node_modules/@metro-labs/outlook/src/accounts.ts +107 -0
  249. package/runtime/node_modules/@metro-labs/outlook/src/actions.ts +20 -0
  250. package/runtime/node_modules/@metro-labs/outlook/src/attachments.ts +97 -0
  251. package/runtime/node_modules/@metro-labs/outlook/src/auth.ts +150 -0
  252. package/runtime/node_modules/@metro-labs/outlook/src/browser.ts +53 -0
  253. package/runtime/node_modules/@metro-labs/outlook/src/config.ts +36 -0
  254. package/runtime/node_modules/@metro-labs/outlook/src/format.ts +141 -0
  255. package/runtime/node_modules/@metro-labs/outlook/src/graph.ts +60 -0
  256. package/runtime/node_modules/@metro-labs/outlook/src/html.ts +72 -0
  257. package/runtime/node_modules/@metro-labs/outlook/src/inbound.ts +104 -0
  258. package/runtime/node_modules/@metro-labs/outlook/src/index.ts +12 -0
  259. package/runtime/node_modules/@metro-labs/outlook/src/login.ts +150 -0
  260. package/runtime/node_modules/@metro-labs/outlook/src/me.ts +41 -0
  261. package/runtime/node_modules/@metro-labs/outlook/src/outbound.ts +116 -0
  262. package/runtime/node_modules/@metro-labs/outlook/src/query.ts +119 -0
  263. package/runtime/node_modules/@metro-labs/outlook/src/state.ts +43 -0
  264. package/runtime/node_modules/@metro-labs/outlook/src/station.ts +15 -0
  265. package/runtime/node_modules/@metro-labs/outlook/src/trust.ts +70 -0
  266. package/runtime/node_modules/@metro-labs/telegram/package.json +3 -2
  267. package/runtime/node_modules/@metro-labs/telegram/src/accounts.ts +48 -88
  268. package/runtime/node_modules/@metro-labs/telegram/src/actions.ts +214 -253
  269. package/runtime/node_modules/@metro-labs/telegram/src/attachments.ts +67 -108
  270. package/runtime/node_modules/@metro-labs/{telegram-user → telegram}/src/client.ts +6 -6
  271. package/runtime/node_modules/@metro-labs/telegram/src/format.ts +102 -146
  272. package/runtime/node_modules/@metro-labs/{telegram-user → telegram}/src/group.ts +4 -4
  273. package/runtime/node_modules/@metro-labs/{telegram-user → telegram}/src/history.ts +1 -1
  274. package/runtime/node_modules/@metro-labs/telegram/src/inbound.ts +57 -0
  275. package/runtime/node_modules/@metro-labs/telegram/src/index.ts +6 -102
  276. package/runtime/node_modules/@metro-labs/{telegram-user → telegram}/src/login.ts +20 -20
  277. package/runtime/node_modules/@metro-labs/telegram/src/media-actions.ts +65 -151
  278. package/runtime/node_modules/@metro-labs/telegram/src/members.ts +61 -33
  279. package/runtime/node_modules/@metro-labs/{telegram-user → telegram}/src/normalize.ts +1 -1
  280. package/runtime/node_modules/@metro-labs/telegram/src/profile.ts +70 -0
  281. package/runtime/node_modules/@metro-labs/{telegram-user → telegram}/src/reactions.ts +2 -2
  282. package/runtime/node_modules/@metro-labs/telegram/src/station.ts +11 -1
  283. package/runtime/node_modules/@metro-labs/telegram/src/types.ts +5 -47
  284. package/runtime/node_modules/@metro-labs/telegram/src/wire.ts +1 -3
  285. package/runtime/node_modules/@metro-labs/telegram-bot/package.json +25 -0
  286. package/runtime/node_modules/@metro-labs/telegram-bot/src/accounts.ts +119 -0
  287. package/runtime/node_modules/@metro-labs/telegram-bot/src/actions.ts +246 -0
  288. package/runtime/node_modules/@metro-labs/telegram-bot/src/attachments.ts +128 -0
  289. package/runtime/node_modules/@metro-labs/telegram-bot/src/format.ts +173 -0
  290. package/runtime/node_modules/@metro-labs/telegram-bot/src/index.ts +103 -0
  291. package/runtime/node_modules/@metro-labs/telegram-bot/src/media-actions.ts +95 -0
  292. package/runtime/node_modules/@metro-labs/telegram-bot/src/members.ts +47 -0
  293. package/runtime/node_modules/@metro-labs/telegram-bot/src/profile.ts +65 -0
  294. package/runtime/node_modules/@metro-labs/telegram-bot/src/station.ts +20 -0
  295. package/runtime/node_modules/@metro-labs/telegram-bot/src/types.ts +56 -0
  296. package/runtime/node_modules/@metro-labs/telegram-bot/src/wire.ts +1 -0
  297. package/runtime/node_modules/@metro-labs/threema/package.json +26 -0
  298. package/runtime/node_modules/@metro-labs/threema/src/accounts.ts +106 -0
  299. package/runtime/node_modules/@metro-labs/threema/src/actions.ts +134 -0
  300. package/runtime/node_modules/@metro-labs/threema/src/api.ts +152 -0
  301. package/runtime/node_modules/@metro-labs/threema/src/crypto.ts +100 -0
  302. package/runtime/node_modules/@metro-labs/threema/src/files.ts +58 -0
  303. package/runtime/node_modules/@metro-labs/threema/src/format.ts +169 -0
  304. package/runtime/node_modules/@metro-labs/threema/src/groups.ts +96 -0
  305. package/runtime/node_modules/@metro-labs/threema/src/ids.ts +21 -0
  306. package/runtime/node_modules/@metro-labs/threema/src/inbound.ts +89 -0
  307. package/runtime/node_modules/@metro-labs/threema/src/index.ts +24 -0
  308. package/runtime/node_modules/@metro-labs/threema/src/messages.ts +264 -0
  309. package/runtime/node_modules/@metro-labs/threema/src/outbound.ts +160 -0
  310. package/runtime/node_modules/@metro-labs/threema/src/station.ts +13 -0
  311. package/runtime/node_modules/@metro-labs/threema/src/verify.ts +117 -0
  312. package/runtime/node_modules/@metro-labs/webhook/package.json +1 -1
  313. package/runtime/node_modules/@metro-labs/webhook/src/station.ts +5 -8
  314. package/runtime/node_modules/@metro-labs/whatsapp/package.json +1 -3
  315. package/runtime/node_modules/@metro-labs/whatsapp/src/accounts.ts +1 -2
  316. package/runtime/node_modules/@metro-labs/whatsapp/src/ack.ts +1 -1
  317. package/runtime/node_modules/@metro-labs/whatsapp/src/actions.ts +40 -5
  318. package/runtime/node_modules/@metro-labs/whatsapp/src/attachments.ts +2 -2
  319. package/runtime/node_modules/@metro-labs/whatsapp/src/auth-state.ts +1 -1
  320. package/runtime/node_modules/@metro-labs/whatsapp/src/client.ts +74 -4
  321. package/runtime/node_modules/@metro-labs/whatsapp/src/format.ts +7 -56
  322. package/runtime/node_modules/@metro-labs/whatsapp/src/inbound.ts +10 -27
  323. package/runtime/node_modules/@metro-labs/whatsapp/src/index.ts +4 -37
  324. package/runtime/node_modules/@metro-labs/whatsapp/src/keys.ts +1 -1
  325. package/runtime/node_modules/@metro-labs/whatsapp/src/login.ts +1 -1
  326. package/runtime/node_modules/@metro-labs/whatsapp/src/media.ts +1 -1
  327. package/runtime/node_modules/@metro-labs/whatsapp/src/names.ts +28 -0
  328. package/runtime/node_modules/@metro-labs/whatsapp/src/normalize.ts +1 -1
  329. package/runtime/node_modules/@metro-labs/whatsapp/src/parse.ts +44 -0
  330. package/runtime/node_modules/@metro-labs/whatsapp/src/resolve.ts +52 -0
  331. package/runtime/node_modules/@metro-labs/whatsapp/src/station.ts +8 -1
  332. package/runtime/node_modules/@metro-labs/whatsapp/src/token-store.ts +5 -9
  333. package/runtime/node_modules/@metro-labs/whatsapp/src/types.ts +0 -1
  334. package/runtime/node_modules/@metro-labs/whatsapp/src/wire.ts +1 -5
  335. package/runtime/node_modules/@metro-labs/xmtp/package.json +3 -2
  336. package/runtime/node_modules/@metro-labs/xmtp/src/accounts.ts +9 -8
  337. package/runtime/node_modules/@metro-labs/xmtp/src/actions-close.ts +1 -1
  338. package/runtime/node_modules/@metro-labs/xmtp/src/actions-conv.ts +3 -201
  339. package/runtime/node_modules/@metro-labs/xmtp/src/actions-meta.ts +3 -42
  340. package/runtime/node_modules/@metro-labs/xmtp/src/actions.ts +12 -143
  341. package/runtime/node_modules/@metro-labs/xmtp/src/attachments.ts +3 -3
  342. package/runtime/node_modules/@metro-labs/xmtp/src/conv-helpers.ts +3 -3
  343. package/runtime/node_modules/@metro-labs/xmtp/src/emit-payloads.ts +7 -24
  344. package/runtime/node_modules/@metro-labs/xmtp/src/emit.ts +7 -16
  345. package/runtime/node_modules/@metro-labs/xmtp/src/group-members.ts +1 -1
  346. package/runtime/node_modules/@metro-labs/xmtp/src/group.ts +2 -2
  347. package/runtime/node_modules/@metro-labs/xmtp/src/identity.ts +30 -16
  348. package/runtime/node_modules/@metro-labs/xmtp/src/index.ts +11 -14
  349. package/runtime/node_modules/@metro-labs/xmtp/src/labels.ts +1 -19
  350. package/runtime/node_modules/@metro-labs/xmtp/src/member-args.ts +1 -1
  351. package/runtime/node_modules/@metro-labs/xmtp/src/names.ts +61 -0
  352. package/runtime/node_modules/@metro-labs/xmtp/src/profile.ts +153 -0
  353. package/runtime/node_modules/@metro-labs/xmtp/src/sender.ts +112 -0
  354. package/runtime/node_modules/@metro-labs/xmtp/src/smart.ts +72 -0
  355. package/runtime/node_modules/@metro-labs/xmtp/src/station.ts +5 -1
  356. package/runtime/node_modules/@metro-labs/xmtp/src/tools-handlers.ts +3 -50
  357. package/runtime/node_modules/@metro-labs/xmtp/src/tools.ts +30 -44
  358. package/runtime/node_modules/@metro-labs/xmtp/src/transcribe.ts +4 -6
  359. package/runtime/node_modules/@metro-labs/xmtp/src/verify.ts +19 -5
  360. package/runtime/node_modules/@metro-labs/xmtp/src/wire.ts +15 -3
  361. package/runtime/runtime.json +1 -1
  362. package/runtime/server.ts +1 -0
  363. package/runtime/stations.json +37 -0
  364. package/dist/prompt.js +0 -10
  365. package/dist/store.js +0 -70
  366. package/runtime/node_modules/@metro-labs/discord/src/station.ts +0 -19
  367. package/runtime/node_modules/@metro-labs/discord/src/voice-speak.ts +0 -195
  368. package/runtime/node_modules/@metro-labs/discord/src/voice-transcribe.ts +0 -292
  369. package/runtime/node_modules/@metro-labs/discord/src/voice.ts +0 -197
  370. package/runtime/node_modules/@metro-labs/discord/src/wire.ts +0 -5
  371. package/runtime/node_modules/@metro-labs/mcp/package.json +0 -66
  372. package/runtime/node_modules/@metro-labs/mcp/src/channels/dedupe.ts +0 -24
  373. package/runtime/node_modules/@metro-labs/mcp/src/daemon/account-api.ts +0 -311
  374. package/runtime/node_modules/@metro-labs/mcp/src/daemon/agent-api.ts +0 -335
  375. package/runtime/node_modules/@metro-labs/mcp/src/daemon/api-http.ts +0 -129
  376. package/runtime/node_modules/@metro-labs/mcp/src/daemon/boot.ts +0 -322
  377. package/runtime/node_modules/@metro-labs/mcp/src/daemon/cli-pair-api.ts +0 -111
  378. package/runtime/node_modules/@metro-labs/mcp/src/daemon/cli-pair.ts +0 -20
  379. package/runtime/node_modules/@metro-labs/mcp/src/daemon/collection-api.ts +0 -202
  380. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-json.ts +0 -31
  381. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-tools.ts +0 -100
  382. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-url.ts +0 -57
  383. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-verify.ts +0 -333
  384. package/runtime/node_modules/@metro-labs/mcp/src/daemon/google-auth.ts +0 -164
  385. package/runtime/node_modules/@metro-labs/mcp/src/daemon/google-oauth.ts +0 -208
  386. package/runtime/node_modules/@metro-labs/mcp/src/daemon/identity.ts +0 -79
  387. package/runtime/node_modules/@metro-labs/mcp/src/daemon/oauth-pending.ts +0 -65
  388. package/runtime/node_modules/@metro-labs/mcp/src/daemon/pair-codes.ts +0 -58
  389. package/runtime/node_modules/@metro-labs/mcp/src/daemon/project-api.ts +0 -214
  390. package/runtime/node_modules/@metro-labs/mcp/src/daemon/run-api.ts +0 -125
  391. package/runtime/node_modules/@metro-labs/mcp/src/daemon/run-pair.ts +0 -18
  392. package/runtime/node_modules/@metro-labs/mcp/src/daemon/runtime-source.ts +0 -105
  393. package/runtime/node_modules/@metro-labs/mcp/src/daemon/session-apis.ts +0 -41
  394. package/runtime/node_modules/@metro-labs/mcp/src/daemon/session.ts +0 -218
  395. package/runtime/node_modules/@metro-labs/mcp/src/daemon/tunnel.ts +0 -169
  396. package/runtime/node_modules/@metro-labs/mcp/src/db/account-attach.ts +0 -91
  397. package/runtime/node_modules/@metro-labs/mcp/src/db/agent-admin.ts +0 -215
  398. package/runtime/node_modules/@metro-labs/mcp/src/db/client.ts +0 -37
  399. package/runtime/node_modules/@metro-labs/mcp/src/db/connector-collections.ts +0 -218
  400. package/runtime/node_modules/@metro-labs/mcp/src/db/connectors.ts +0 -329
  401. package/runtime/node_modules/@metro-labs/mcp/src/db/materialize.ts +0 -340
  402. package/runtime/node_modules/@metro-labs/mcp/src/db/projects.ts +0 -300
  403. package/runtime/node_modules/@metro-labs/mcp/src/db/runtime-admin.ts +0 -28
  404. package/runtime/node_modules/@metro-labs/mcp/src/db/runtimes.ts +0 -105
  405. package/runtime/node_modules/@metro-labs/mcp/src/db/schema.ts +0 -131
  406. package/runtime/node_modules/@metro-labs/mcp/src/db/token-carry.ts +0 -45
  407. package/runtime/node_modules/@metro-labs/mcp/src/db/users.ts +0 -57
  408. package/runtime/node_modules/@metro-labs/mcp/src/db/whatsapp-login.ts +0 -18
  409. package/runtime/node_modules/@metro-labs/mcp/src/mcp/channel-owner.ts +0 -29
  410. package/runtime/node_modules/@metro-labs/mcp/src/mcp/frame-scope.ts +0 -21
  411. package/runtime/node_modules/@metro-labs/mcp/src/mcp/permission-relay.ts +0 -66
  412. package/runtime/node_modules/@metro-labs/mcp/src/mcp/request-identity.ts +0 -73
  413. package/runtime/node_modules/@metro-labs/mcp/src/mcp/session-registry.ts +0 -172
  414. package/runtime/node_modules/@metro-labs/mcp/src/mcp/session-route.ts +0 -43
  415. package/runtime/node_modules/@metro-labs/mcp/src/monitor/api.ts +0 -240
  416. package/runtime/node_modules/@metro-labs/mcp/src/server.ts +0 -2
  417. package/runtime/node_modules/@metro-labs/telegram-user/src/accounts.ts +0 -81
  418. package/runtime/node_modules/@metro-labs/telegram-user/src/actions.ts +0 -254
  419. package/runtime/node_modules/@metro-labs/telegram-user/src/attachments.ts +0 -87
  420. package/runtime/node_modules/@metro-labs/telegram-user/src/format.ts +0 -141
  421. package/runtime/node_modules/@metro-labs/telegram-user/src/inbound.ts +0 -78
  422. package/runtime/node_modules/@metro-labs/telegram-user/src/index.ts +0 -46
  423. package/runtime/node_modules/@metro-labs/telegram-user/src/media-actions.ts +0 -80
  424. package/runtime/node_modules/@metro-labs/telegram-user/src/members.ts +0 -75
  425. package/runtime/node_modules/@metro-labs/telegram-user/src/station.ts +0 -24
  426. package/runtime/node_modules/@metro-labs/telegram-user/src/types.ts +0 -7
  427. package/runtime/node_modules/@metro-labs/telegram-user/src/wire.ts +0 -1
  428. package/runtime/node_modules/@metro-labs/xmtp/src/actions-push.ts +0 -87
  429. package/runtime/node_modules/@metro-labs/xmtp/src/emit-core.ts +0 -55
  430. package/runtime/node_modules/@metro-labs/xmtp/src/push.ts +0 -349
  431. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/log.ts +0 -0
  432. /package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/attachments.ts +0 -0
  433. /package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/messaging-normalize.ts +0 -0
  434. /package/runtime/node_modules/@metro-labs/{mcp/src/mcp → core/src}/str.ts +0 -0
  435. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/train-error.ts +0 -0
  436. /package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/webhook-note.ts +0 -0
  437. /package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/raw-get-stream.ts +0 -0
  438. /package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/api-base.ts +0 -0
  439. /package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/verify.ts +0 -0
  440. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → http/src}/api-error.ts +0 -0
  441. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → http/src}/cors.ts +0 -0
  442. /package/runtime/node_modules/@metro-labs/{telegram → telegram-bot}/src/verify.ts +0 -0
@@ -1,31 +1,31 @@
1
1
  import type { IncomingMessage, ServerResponse } from 'node:http';
2
- import { errMsg, log } from './log.js';
2
+ import { log } from '@metro-labs/core/log';
3
+ import { healthOf } from './health.js';
4
+ import type { RemoteTool } from './tools.js';
5
+ import { normalizePolicy, type ToolPolicy } from '../policy/policy.js';
3
6
  import {
4
7
  apiFailure,
5
8
  apiSession,
6
- projectParam,
7
9
  bodyField,
8
10
  cors,
9
11
  readJsonBody,
10
12
  sendJson,
11
- type ApiSession,
12
- } from './api-http.js';
13
- import { parseId } from '../db/ids.js';
14
- import type { ConnectorCollectionRow } from '../db/connector-collections.js';
13
+ } from '@metro-labs/http/api-http';
14
+ import { parseId } from '@metro-labs/core/ids';
15
15
  import {
16
16
  handleCallback,
17
17
  handleConnect,
18
18
  hostOf,
19
19
  startOAuth,
20
20
  type OAuthRouteDeps,
21
- } from './connector-oauth-routes.js';
22
- import { ConnectorUnauthorized } from './connector-verify.js';
21
+ } from './oauth-routes.js';
22
+ import { ConnectorUnauthorized } from './verify.js';
23
23
  import type {
24
24
  Connector,
25
25
  ConnectorCheck,
26
26
  ConnectorInput,
27
27
  DeletedConnector,
28
- } from '../db/connectors.js';
28
+ } from './store.js';
29
29
 
30
30
  const PREFIX = '/api/connectors';
31
31
 
@@ -33,50 +33,14 @@ const asText = (value: unknown): string =>
33
33
  typeof value === 'string' ? value : '';
34
34
 
35
35
  export interface ConnectorApiDeps extends OAuthRouteDeps {
36
- listConnectors: (email: string, project: string) => Promise<Connector[]>;
37
- freshConnectorsByIds: (ids: string[]) => Promise<Connector[]>;
38
- listCollections: (
39
- email: string,
40
- project: string,
41
- ) => Promise<ConnectorCollectionRow[]>;
42
- getCollection: (email: string, id: string) => Promise<ConnectorCollectionRow>;
43
- createCollection: (
44
- email: string,
45
- project: string,
46
- name: string,
47
- ) => Promise<ConnectorCollectionRow>;
48
- renameCollection: (
49
- email: string,
50
- id: string,
51
- name: string,
52
- ) => Promise<ConnectorCollectionRow>;
53
- deleteCollection: (
54
- email: string,
55
- id: string,
56
- ) => Promise<{ id: string; name: string }>;
57
- addToCollection: (
58
- email: string,
59
- id: string,
60
- connectorId: string,
61
- ) => Promise<ConnectorCollectionRow>;
62
- removeFromCollection: (
63
- email: string,
64
- id: string,
65
- connectorId: string,
66
- ) => Promise<ConnectorCollectionRow>;
67
- createConnector: (
68
- email: string,
69
- project: string,
70
- input: ConnectorInput,
71
- ) => Promise<Connector>;
72
- verifyConnector: (email: string, id: string) => Promise<ConnectorCheck>;
73
- disconnectConnector: (email: string, id: string) => Promise<Connector>;
74
- renameConnector: (
75
- email: string,
76
- id: string,
77
- name: string,
78
- ) => Promise<Connector>;
79
- deleteConnector: (email: string, id: string) => Promise<DeletedConnector>;
36
+ listConnectors: () => Promise<Connector[]>;
37
+ createConnector: (input: ConnectorInput) => Promise<Connector>;
38
+ verifyConnector: (id: string) => Promise<ConnectorCheck>;
39
+ connectorTools: (id: string) => Promise<RemoteTool[]>;
40
+ disconnectConnector: (id: string) => Promise<Connector>;
41
+ renameConnector: (id: string, name: string) => Promise<Connector>;
42
+ deleteConnector: (id: string) => Promise<DeletedConnector>;
43
+ setConnectorPolicy: (id: string, policy: ToolPolicy) => Promise<Connector>;
80
44
  }
81
45
 
82
46
  type Routable =
@@ -84,9 +48,11 @@ type Routable =
84
48
  | { kind: 'callback' }
85
49
  | { kind: 'connector'; id: string }
86
50
  | { kind: 'verify'; id: string }
51
+ | { kind: 'tools'; id: string }
87
52
  | { kind: 'connect'; id: string }
88
53
  | { kind: 'disconnect'; id: string }
89
- | { kind: 'rename'; id: string };
54
+ | { kind: 'rename'; id: string }
55
+ | { kind: 'policy'; id: string };
90
56
 
91
57
  type Target = Routable | { kind: 'unknown' } | null;
92
58
 
@@ -95,9 +61,11 @@ function subTarget(id: string, rest: string[]): Target {
95
61
  if (rest.length > 1) return { kind: 'unknown' };
96
62
  const head = rest[0];
97
63
  if (head === 'verify') return { kind: 'verify', id };
64
+ if (head === 'tools') return { kind: 'tools', id };
98
65
  if (head === 'connect') return { kind: 'connect', id };
99
66
  if (head === 'disconnect') return { kind: 'disconnect', id };
100
67
  if (head === 'rename') return { kind: 'rename', id };
68
+ if (head === 'policy') return { kind: 'policy', id };
101
69
  return { kind: 'unknown' };
102
70
  }
103
71
 
@@ -112,20 +80,18 @@ function target(path: string): Target {
112
80
  return id === null ? { kind: 'unknown' } : subTarget(id, segments.slice(1));
113
81
  }
114
82
 
115
- function connectorPayload(
116
- row: Connector,
117
- detail = false,
118
- ): Record<string, unknown> {
119
- const { catalog, ...summary } = row.verified;
83
+ function connectorPayload(row: Connector): Record<string, unknown> {
120
84
  return {
121
85
  id: row.id,
122
86
  name: row.name,
123
87
  url: row.url,
124
- transport: row.transport,
125
88
  auth: row.auth,
126
89
  header: row.header,
90
+ clientId: row.client?.clientId ?? null,
127
91
  signIn: row.signIn,
128
- verified: detail ? { ...summary, catalog } : summary,
92
+ verified: row.verified,
93
+ policy: row.policy,
94
+ health: healthOf(row.id),
129
95
  };
130
96
  }
131
97
 
@@ -133,14 +99,8 @@ async function handleList(
133
99
  req: IncomingMessage,
134
100
  res: ServerResponse,
135
101
  deps: ConnectorApiDeps,
136
- session: ApiSession,
137
102
  ): Promise<void> {
138
- const project = projectParam(req);
139
- if (project === null) {
140
- sendJson(req, res, 400, { error: 'a project is required' });
141
- return;
142
- }
143
- const rows = await deps.listConnectors(session.email, project);
103
+ const rows = await deps.listConnectors();
144
104
  sendJson(req, res, 200, {
145
105
  connectors: rows.map((row) => connectorPayload(row)),
146
106
  });
@@ -150,21 +110,17 @@ async function handleCreate(
150
110
  req: IncomingMessage,
151
111
  res: ServerResponse,
152
112
  deps: ConnectorApiDeps,
153
- session: ApiSession,
154
113
  ): Promise<void> {
155
114
  const body = await readJsonBody(req);
156
- const project = projectParam(req);
157
- if (project === null) {
158
- sendJson(req, res, 400, { error: 'a project is required' });
159
- return;
160
- }
161
115
  const offered = asText(bodyField(body, 'value')).trim() !== '';
162
116
  try {
163
- const created = await deps.createConnector(session.email, project, {
117
+ const created = await deps.createConnector({
164
118
  name: bodyField(body, 'name'),
165
119
  url: bodyField(body, 'url'),
166
120
  header: bodyField(body, 'header'),
167
121
  value: bodyField(body, 'value'),
122
+ clientId: bodyField(body, 'clientId'),
123
+ clientSecret: bodyField(body, 'clientSecret'),
168
124
  });
169
125
  log.info(
170
126
  { id: created.id, name: created.name, host: hostOf(created.url) },
@@ -173,7 +129,7 @@ async function handleCreate(
173
129
  sendJson(req, res, 201, connectorPayload(created));
174
130
  } catch (err) {
175
131
  if (offered || !(err instanceof ConnectorUnauthorized)) throw err;
176
- await startOAuth(req, res, deps, session, project, body, (row) =>
132
+ await startOAuth(req, res, deps, body, (row) =>
177
133
  connectorPayload(row),
178
134
  );
179
135
  }
@@ -183,10 +139,9 @@ async function handleVerify(
183
139
  req: IncomingMessage,
184
140
  res: ServerResponse,
185
141
  deps: ConnectorApiDeps,
186
- session: ApiSession,
187
142
  id: string,
188
143
  ): Promise<void> {
189
- const check = await deps.verifyConnector(session.email, id);
144
+ const check = await deps.verifyConnector(id);
190
145
  log.info(
191
146
  { id: check.id, name: check.name, ok: check.ok },
192
147
  'connector-api: re-verified connector',
@@ -198,10 +153,9 @@ async function handleDisconnect(
198
153
  req: IncomingMessage,
199
154
  res: ServerResponse,
200
155
  deps: ConnectorApiDeps,
201
- session: ApiSession,
202
156
  id: string,
203
157
  ): Promise<void> {
204
- const row = await deps.disconnectConnector(session.email, id);
158
+ const row = await deps.disconnectConnector(id);
205
159
  log.info(
206
160
  { id: row.id, name: row.name },
207
161
  'connector-api: signed the connector out',
@@ -213,10 +167,9 @@ async function handleDelete(
213
167
  req: IncomingMessage,
214
168
  res: ServerResponse,
215
169
  deps: ConnectorApiDeps,
216
- session: ApiSession,
217
170
  id: string,
218
171
  ): Promise<void> {
219
- const gone = await deps.deleteConnector(session.email, id);
172
+ const gone = await deps.deleteConnector(id);
220
173
  log.info(
221
174
  { id: gone.id, name: gone.name },
222
175
  'connector-api: deleted connector',
@@ -228,22 +181,20 @@ async function handleConnector(
228
181
  req: IncomingMessage,
229
182
  res: ServerResponse,
230
183
  deps: ConnectorApiDeps,
231
- session: ApiSession,
232
184
  id: string,
233
185
  ): Promise<void> {
234
186
  if (req.method !== 'GET') {
235
- await handleDelete(req, res, deps, session, id);
187
+ await handleDelete(req, res, deps, id);
236
188
  return;
237
189
  }
238
- const row = await deps.getConnector(session.email, id);
239
- sendJson(req, res, 200, connectorPayload(row, true));
190
+ const row = await deps.getConnector(id);
191
+ sendJson(req, res, 200, connectorPayload(row));
240
192
  }
241
193
 
242
194
  async function handleRename(
243
195
  req: IncomingMessage,
244
196
  res: ServerResponse,
245
197
  deps: ConnectorApiDeps,
246
- session: ApiSession,
247
198
  id: string,
248
199
  ): Promise<void> {
249
200
  const name = bodyField(await readJsonBody(req), 'name');
@@ -251,32 +202,48 @@ async function handleRename(
251
202
  sendJson(req, res, 400, { error: 'name is required' });
252
203
  return;
253
204
  }
254
- const row = await deps.renameConnector(session.email, id, name);
205
+ const row = await deps.renameConnector(id, name);
255
206
  log.info({ id: row.id, name: row.name }, 'connector-api: renamed connector');
256
207
  sendJson(req, res, 200, connectorPayload(row));
257
208
  }
258
209
 
210
+ async function handlePolicy(
211
+ req: IncomingMessage,
212
+ res: ServerResponse,
213
+ deps: ConnectorApiDeps,
214
+ id: string,
215
+ ): Promise<void> {
216
+ const policy = normalizePolicy(bodyField(await readJsonBody(req), 'policy'));
217
+ const row = await deps.setConnectorPolicy(id, policy);
218
+ log.info({ id: row.id, name: row.name, policy: row.policy }, 'connector-api: tool policy set');
219
+ sendJson(req, res, 200, connectorPayload(row));
220
+ }
221
+
222
+ type ById = Exclude<Routable['kind'], 'collection' | 'callback'>;
223
+
224
+ const BY_ID: Record<ById, (req: IncomingMessage, res: ServerResponse, deps: ConnectorApiDeps, id: string) => Promise<void>> = {
225
+ verify: handleVerify,
226
+ tools: async (req, res, deps, id) => {
227
+ sendJson(req, res, 200, { tools: await deps.connectorTools(id) });
228
+ },
229
+ connect: handleConnect,
230
+ disconnect: handleDisconnect,
231
+ rename: handleRename,
232
+ policy: handlePolicy,
233
+ connector: handleConnector,
234
+ };
235
+
259
236
  async function route(
260
237
  req: IncomingMessage,
261
238
  res: ServerResponse,
262
239
  deps: ConnectorApiDeps,
263
- session: ApiSession,
264
240
  tgt: Routable,
265
241
  ): Promise<void> {
266
242
  try {
267
243
  if (tgt.kind === 'callback') return;
268
- if (tgt.kind === 'verify')
269
- await handleVerify(req, res, deps, session, tgt.id);
270
- else if (tgt.kind === 'connect')
271
- await handleConnect(req, res, deps, session, tgt.id);
272
- else if (tgt.kind === 'disconnect')
273
- await handleDisconnect(req, res, deps, session, tgt.id);
274
- else if (tgt.kind === 'rename')
275
- await handleRename(req, res, deps, session, tgt.id);
276
- else if (tgt.kind === 'connector')
277
- await handleConnector(req, res, deps, session, tgt.id);
278
- else if (req.method === 'GET') await handleList(req, res, deps, session);
279
- else await handleCreate(req, res, deps, session);
244
+ if (tgt.kind !== 'collection') await BY_ID[tgt.kind](req, res, deps, tgt.id);
245
+ else if (req.method === 'GET') await handleList(req, res, deps);
246
+ else await handleCreate(req, res, deps);
280
247
  } catch (err) {
281
248
  apiFailure(req, res, err, 'connector-api');
282
249
  }
@@ -287,12 +254,14 @@ const ALLOWED: Record<Routable['kind'], string[]> = {
287
254
  callback: ['GET'],
288
255
  connector: ['GET', 'DELETE'],
289
256
  verify: ['POST'],
257
+ tools: ['GET'],
290
258
  connect: ['POST'],
291
259
  disconnect: ['POST'],
292
260
  rename: ['POST'],
261
+ policy: ['PUT'],
293
262
  };
294
263
 
295
- function dispatch(
264
+ async function dispatch(
296
265
  req: IncomingMessage,
297
266
  res: ServerResponse,
298
267
  deps: ConnectorApiDeps,
@@ -300,14 +269,14 @@ function dispatch(
300
269
  ): Promise<void> {
301
270
  if (tgt.kind === 'callback') {
302
271
  handleCallback(req, res, deps);
303
- return Promise.resolve();
272
+ return;
304
273
  }
305
- const session = apiSession(req);
274
+ const session = await apiSession(req);
306
275
  if (!session) {
307
276
  sendJson(req, res, 401, { error: 'unauthorized' });
308
- return Promise.resolve();
277
+ return;
309
278
  }
310
- return route(req, res, deps, session, tgt);
279
+ await route(req, res, deps, tgt);
311
280
  }
312
281
 
313
282
  export function handleConnectorApiRequest(
@@ -330,9 +299,8 @@ export function handleConnectorApiRequest(
330
299
  return true;
331
300
  }
332
301
  dispatch(req, res, deps, tgt).catch((err: unknown) => {
333
- log.warn({ err: errMsg(err) }, 'connector-api: unhandled error');
334
- if (!res.headersSent)
335
- sendJson(req, res, 500, { error: 'connector api failed' });
302
+ if (res.headersSent) return;
303
+ apiFailure(req, res, err, 'connector-api');
336
304
  });
337
305
  return true;
338
306
  }
@@ -1,14 +1,19 @@
1
- import { ApiError } from '../daemon/api-error.js';
1
+ import { ApiError } from '@metro-labs/http/api-error';
2
2
  import type {
3
3
  ConnectorAuth,
4
4
  VerifiedRecord,
5
5
  VerifiedServer,
6
- } from '../daemon/connector-verify.js';
7
- import { readStoredTools } from '../daemon/connector-tools.js';
6
+ } from './verify.js';
7
+ import type { OAuthClient } from './oauth-client.js';
8
+ import { isRecord } from '@metro-labs/core/is-record';
9
+ import type { ToolGroup } from '@metro-labs/core/stations/types';
10
+ import { parsePolicy, type ToolPolicy } from '../policy/policy.js';
8
11
 
9
12
  const CONNECTOR_NAME_MAX = 64;
10
13
  const HEADER_NAME_RE = /^[A-Za-z0-9!#$%&'*+.^_`|~-]{1,64}$/;
11
14
  const HEADER_VALUE_RE = /^[\x20-\x7e]{1,4096}$/;
15
+ const CLIENT_ID_RE = /^[\x21-\x7e]{1,256}$/;
16
+ const CLIENT_SECRET_RE = /^[\x21-\x7e]{1,1024}$/;
12
17
  const DEFAULT_HEADER = 'Authorization';
13
18
 
14
19
  export class ConnectorError extends ApiError {}
@@ -20,10 +25,9 @@ export interface ConnectorConfig {
20
25
  createdAt: string;
21
26
  verified: VerifiedRecord;
22
27
  oauth: boolean;
23
- }
24
-
25
- function isRecord(value: unknown): value is Record<string, unknown> {
26
- return typeof value === 'object' && value !== null && !Array.isArray(value);
28
+ client: OAuthClient | null;
29
+ policy?: ToolPolicy;
30
+ toolGroups?: Record<string, ToolGroup>;
27
31
  }
28
32
 
29
33
  function text(value: unknown): string {
@@ -74,6 +78,30 @@ export function connectorAuth(
74
78
  return { kind: 'header', name, value };
75
79
  }
76
80
 
81
+ export function connectorClient(
82
+ rawId: unknown,
83
+ rawSecret: unknown,
84
+ ): OAuthClient | null {
85
+ const clientId = text(rawId).trim();
86
+ const clientSecret = text(rawSecret).trim();
87
+ if (clientId === '' && clientSecret === '') return null;
88
+ if (clientId === '')
89
+ throw new ConnectorError('a client secret needs the client ID it belongs to', 400);
90
+ if (!CLIENT_ID_RE.test(clientId))
91
+ throw new ConnectorError('that is not a client ID Metro can send', 400);
92
+ if (clientSecret !== '' && !CLIENT_SECRET_RE.test(clientSecret))
93
+ throw new ConnectorError('that client secret is not sendable', 400);
94
+ return { clientId, ...(clientSecret === '' ? {} : { clientSecret }) };
95
+ }
96
+
97
+ function readClient(raw: unknown): OAuthClient | null {
98
+ if (!isRecord(raw)) return null;
99
+ const clientId = text(raw.clientId);
100
+ if (clientId === '') return null;
101
+ const clientSecret = text(raw.clientSecret);
102
+ return { clientId, ...(clientSecret === '' ? {} : { clientSecret }) };
103
+ }
104
+
77
105
  function readOAuth(raw: Record<string, unknown>): ConnectorAuth {
78
106
  const accessToken = text(raw.accessToken);
79
107
  const clientId = text(raw.clientId);
@@ -82,6 +110,7 @@ function readOAuth(raw: Record<string, unknown>): ConnectorAuth {
82
110
  return { kind: 'none' };
83
111
  const refreshToken = text(raw.refreshToken);
84
112
  const clientSecret = text(raw.clientSecret);
113
+ const scope = text(raw.scope);
85
114
  return {
86
115
  kind: 'oauth',
87
116
  accessToken,
@@ -90,6 +119,7 @@ function readOAuth(raw: Record<string, unknown>): ConnectorAuth {
90
119
  issuer: text(raw.issuer),
91
120
  ...(refreshToken === '' ? {} : { refreshToken }),
92
121
  ...(clientSecret === '' ? {} : { clientSecret }),
122
+ ...(scope === '' ? {} : { scope }),
93
123
  ...(typeof raw.expiresAt === 'number' ? { expiresAt: raw.expiresAt } : {}),
94
124
  };
95
125
  }
@@ -106,26 +136,33 @@ function readAuth(raw: unknown): ConnectorAuth {
106
136
 
107
137
  function readVerified(raw: unknown): VerifiedRecord {
108
138
  const record = isRecord(raw) ? raw : {};
109
- const catalog = readStoredTools(record.catalog);
110
- return {
111
- at: text(record.at),
112
- server: text(record.server),
113
- version: text(record.version),
114
- protocol: text(record.protocol),
115
- icon: text(record.icon),
116
- tools: typeof record.tools === 'number' ? record.tools : 0,
117
- catalog,
118
- };
139
+ return { at: text(record.at), server: text(record.server) };
140
+ }
141
+
142
+ const TOOL_NAME_MAX = 128;
143
+ const TOOL_GROUPS_MAX = 1000;
144
+
145
+ export function readToolGroups(raw: unknown): Record<string, ToolGroup> | undefined {
146
+ if (!isRecord(raw)) return undefined;
147
+ const kept = Object.entries(raw)
148
+ .filter((entry): entry is [string, ToolGroup] => entry[0].length <= TOOL_NAME_MAX && (entry[1] === 'read' || entry[1] === 'write'))
149
+ .slice(0, TOOL_GROUPS_MAX);
150
+ return kept.length > 0 ? Object.fromEntries(kept) : undefined;
119
151
  }
120
152
 
121
153
  export function readConfig(raw: unknown): ConnectorConfig {
122
154
  const record = isRecord(raw) ? raw : {};
123
155
  const auth = readAuth(record.auth);
156
+ const policy = parsePolicy(record.policy, 'connectors.json');
157
+ const toolGroups = readToolGroups(record.toolGroups);
124
158
  return {
125
159
  auth,
126
160
  createdAt: text(record.createdAt),
127
161
  verified: readVerified(record.verified),
128
162
  oauth: record.oauth === true || auth.kind === 'oauth',
163
+ client: readClient(record.client),
164
+ ...(policy === undefined || Object.keys(policy).length === 0 ? {} : { policy }),
165
+ ...(toolGroups === undefined ? {} : { toolGroups }),
129
166
  };
130
167
  }
131
168
 
@@ -135,13 +172,5 @@ export function signInState(config: ConnectorConfig): ConnectorSignIn {
135
172
  }
136
173
 
137
174
  export function stamp(server: VerifiedServer): VerifiedRecord {
138
- return {
139
- at: new Date().toISOString(),
140
- server: server.server,
141
- version: server.version,
142
- protocol: server.protocol,
143
- icon: server.icon,
144
- tools: server.tools,
145
- catalog: server.catalog,
146
- };
175
+ return { at: new Date().toISOString(), server: server.server };
147
176
  }
@@ -0,0 +1,72 @@
1
+ import type { ToolGroup } from '@metro-labs/core/stations/types';
2
+ import { policyFor, setPolicies, type PolicyTarget, type ToolPolicy } from '../policy/policy.js';
3
+ import { serverKeysOf } from './plugin-sync.js';
4
+ import { takeGrant } from '../approvals/pending.js';
5
+ import { NEEDS_APPROVAL } from '../approvals/needs.js';
6
+
7
+ interface GateRow {
8
+ id: string;
9
+ name: string;
10
+ config: { policy?: ToolPolicy; toolGroups?: Record<string, ToolGroup> };
11
+ }
12
+
13
+ export interface ConnectorGate {
14
+ id: string;
15
+ name: string;
16
+ server: string;
17
+ policy: ToolPolicy;
18
+ tools: Record<string, ToolGroup>;
19
+ }
20
+
21
+ let gates: ConnectorGate[] = [];
22
+
23
+ const normalized = (name: string): string => name.replace(/[^a-zA-Z0-9_-]/g, '_');
24
+
25
+ export function registerConnectors(rows: readonly GateRow[]): void {
26
+ const keys = serverKeysOf([...rows]);
27
+ gates = rows.map((row) => ({
28
+ id: row.id,
29
+ name: row.name,
30
+ server: keys.get(row.id) ?? '',
31
+ policy: row.config.policy ?? {},
32
+ tools: row.config.toolGroups ?? {},
33
+ }));
34
+ const entries = rows.flatMap((row): [PolicyTarget, ToolPolicy][] =>
35
+ row.config.policy === undefined ? [] : [[{ kind: 'connector', id: row.id }, row.config.policy]],
36
+ );
37
+ setPolicies('connector', entries);
38
+ }
39
+
40
+ export const connectorGates = (): readonly ConnectorGate[] => gates;
41
+
42
+ export const toolGroupOf = (gate: ConnectorGate, tool: string): ToolGroup => (gate.tools[tool] === 'read' ? 'read' : 'write');
43
+
44
+ const promptFor = (connectorId: string, tool: string) => (asked: string): boolean => {
45
+ const found = connectorToolOf(asked);
46
+ return found?.gate.id === connectorId && found.tool === tool;
47
+ };
48
+
49
+ export function blockedReason(connectorId: string, tool: string, args: Record<string, unknown> = {}): string | null {
50
+ const gate = gates.find((g) => g.id === connectorId);
51
+ if (gate === undefined) return null;
52
+ const access = policyFor({ kind: 'connector', id: connectorId }, { name: tool, group: toolGroupOf(gate, tool) });
53
+ if (access === 'deny') return `Blocked by the owner's policy for ${gate.name} (${tool}).`;
54
+ if (access === 'allow' || takeGrant(promptFor(connectorId, tool), args)) return null;
55
+ return NEEDS_APPROVAL(gate.name, tool);
56
+ }
57
+
58
+ function prefixesOf(gate: ConnectorGate): string[] {
59
+ return [`mcp__plugin_metro_${gate.server}__`, `mcp__${gate.server}__`, `mcp__${normalized(`metro.box ${gate.name}`)}__`];
60
+ }
61
+
62
+ export function connectorToolOf(toolName: string): { gate: ConnectorGate; tool: string } | undefined {
63
+ if (toolName.startsWith('mcp__metro__')) return undefined;
64
+ for (const gate of gates)
65
+ for (const prefix of prefixesOf(gate))
66
+ if (toolName.startsWith(prefix) && toolName.length > prefix.length) {
67
+ const called = toolName.slice(prefix.length);
68
+ const known = [...Object.keys(gate.tools), ...Object.keys(gate.policy.tools ?? {})];
69
+ return { gate, tool: known.find((name) => name === called) ?? known.find((name) => normalized(name) === called) ?? called };
70
+ }
71
+ return undefined;
72
+ }
@@ -0,0 +1,18 @@
1
+ export interface ConnectorHealth {
2
+ ok: boolean;
3
+ reason: string | null;
4
+ at: string;
5
+ }
6
+
7
+ const seen = new Map<string, ConnectorHealth>();
8
+
9
+ export function noteHealth(id: string, ok: boolean, reason: string | null = null): void {
10
+ seen.set(id, { ok, reason: ok ? null : reason, at: new Date().toISOString() });
11
+ }
12
+
13
+ export const healthOf = (id: string): ConnectorHealth | null => seen.get(id) ?? null;
14
+
15
+ export function forgetHealth(id?: string): void {
16
+ if (id === undefined) seen.clear();
17
+ else seen.delete(id);
18
+ }
@@ -1,9 +1,8 @@
1
1
  import { createHash, randomBytes } from 'node:crypto';
2
- import {
3
- ConnectorVerifyError,
4
- type OAuthTokens,
5
- } from './connector-verify.js';
2
+ import { whyUnreachable } from './reach.js';
3
+ import { refused, type OAuthTokens } from './verify.js';
6
4
  import type { OAuthServer } from './oauth-discovery.js';
5
+ import { isRecord } from '@metro-labs/core/is-record';
7
6
 
8
7
  const TOKEN_TIMEOUT_MS = 15_000;
9
8
  const CLIENT_NAME = 'Metro';
@@ -13,14 +12,6 @@ export interface OAuthClient {
13
12
  clientSecret?: string;
14
13
  }
15
14
 
16
- function refused(message: string): ConnectorVerifyError {
17
- return new ConnectorVerifyError(message, 400);
18
- }
19
-
20
- function isRecord(value: unknown): value is Record<string, unknown> {
21
- return typeof value === 'object' && value !== null && !Array.isArray(value);
22
- }
23
-
24
15
  export function newVerifier(): string {
25
16
  return randomBytes(32).toString('base64url');
26
17
  }
@@ -35,7 +26,9 @@ export async function registerClient(
35
26
  ): Promise<OAuthClient> {
36
27
  if (server.registrationEndpoint === null)
37
28
  throw refused(
38
- 'That server requires OAuth but does not accept client registration, so Metro cannot sign in to it.',
29
+ 'That server signs in with OAuth but registers no clients on its own. ' +
30
+ `Register an app with it yourself, with ${redirectUri} as its redirect URL, ` +
31
+ "and add the connector again with that app's client ID.",
39
32
  );
40
33
  let res: Response;
41
34
  try {
@@ -52,8 +45,8 @@ export async function registerClient(
52
45
  token_endpoint_auth_method: 'none',
53
46
  }),
54
47
  });
55
- } catch {
56
- throw refused('Metro could not reach that server to register.');
48
+ } catch (err) {
49
+ throw refused(`Metro could not reach that server to register: ${whyUnreachable(err)}`);
57
50
  }
58
51
  const body: unknown = await res.json().catch(() => null);
59
52
  if (!res.ok || !isRecord(body) || typeof body.client_id !== 'string')
@@ -83,6 +76,8 @@ export function authorizeUrl(input: AuthorizeInput): string {
83
76
  url.searchParams.set('code_challenge', challengeOf(input.verifier));
84
77
  url.searchParams.set('code_challenge_method', 'S256');
85
78
  url.searchParams.set('resource', input.resource);
79
+ if (input.server.scopes.length > 0)
80
+ url.searchParams.set('scope', input.server.scopes.join(' '));
86
81
  return url.toString();
87
82
  }
88
83
 
@@ -125,8 +120,8 @@ async function postToken(
125
120
  },
126
121
  body: params.toString(),
127
122
  });
128
- } catch {
129
- throw refused('Metro could not reach that server to finish signing in.');
123
+ } catch (err) {
124
+ throw refused(`Metro could not reach that server to finish signing in: ${whyUnreachable(err)}`);
130
125
  }
131
126
  const body: unknown = await res.json().catch(() => null);
132
127
  if (!res.ok || !isRecord(body))
@@ -153,10 +148,12 @@ export function refreshTokens(
153
148
  client: OAuthClient,
154
149
  refreshToken: string,
155
150
  resource: string,
151
+ scope?: string,
156
152
  ): Promise<OAuthTokens> {
157
153
  return postToken(server, client, {
158
154
  grant_type: 'refresh_token',
159
155
  refresh_token: refreshToken,
160
156
  resource,
157
+ ...(scope === undefined ? {} : { scope }),
161
158
  });
162
159
  }