@stage-labs/metro 0.1.0-beta.13 → 0.1.0-beta.131

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 (329) hide show
  1. package/dist/api.js +14 -0
  2. package/dist/claude-settings.js +40 -0
  3. package/dist/claude.js +176 -0
  4. package/dist/cli.js +101 -0
  5. package/dist/control.js +74 -0
  6. package/dist/hold.js +211 -0
  7. package/dist/local.js +93 -0
  8. package/dist/mcp-config.js +25 -0
  9. package/dist/node-name.js +71 -0
  10. package/dist/onboarding.js +43 -0
  11. package/dist/plugin.js +120 -0
  12. package/dist/provider-flags.js +9 -0
  13. package/dist/route.js +38 -0
  14. package/dist/runtime-install.js +97 -0
  15. package/dist/runtime.js +74 -0
  16. package/dist/serve.js +150 -0
  17. package/dist/service.js +242 -0
  18. package/dist/tail.js +119 -0
  19. package/dist/update.js +45 -0
  20. package/dist/version.js +97 -0
  21. package/package.json +14 -27
  22. package/runtime/marketplace/.claude-plugin/marketplace.json +12 -0
  23. package/runtime/marketplace/plugin/.claude-plugin/plugin.json +18 -0
  24. package/runtime/marketplace/plugin/.mcp.json +1 -0
  25. package/runtime/marketplace/plugin/bin/guard.mjs +55 -0
  26. package/runtime/marketplace/plugin/bin/metro-plugin.mjs +122 -0
  27. package/runtime/marketplace/plugin/bin/session-start.mjs +31 -0
  28. package/runtime/marketplace/plugin/hooks/hooks.json +25 -0
  29. package/runtime/marketplace/plugin/orchestrator.md +16 -0
  30. package/runtime/marketplace/plugin/skills/refresh/SKILL.md +15 -0
  31. package/runtime/node_modules/@metro-labs/core/package.json +43 -0
  32. package/runtime/node_modules/@metro-labs/core/src/address.ts +6 -0
  33. package/runtime/node_modules/@metro-labs/core/src/endpoints.ts +7 -0
  34. package/runtime/node_modules/@metro-labs/core/src/events.ts +120 -0
  35. package/runtime/node_modules/@metro-labs/core/src/identity.ts +7 -0
  36. package/runtime/node_modules/@metro-labs/core/src/ids.ts +21 -0
  37. package/runtime/node_modules/@metro-labs/core/src/is-record.ts +2 -0
  38. package/runtime/node_modules/@metro-labs/core/src/lines.ts +87 -0
  39. package/runtime/node_modules/@metro-labs/core/src/log.ts +42 -0
  40. package/runtime/node_modules/@metro-labs/core/src/protocol.ts +226 -0
  41. package/runtime/node_modules/@metro-labs/core/src/secure-fs.ts +57 -0
  42. package/runtime/node_modules/@metro-labs/core/src/station-names.ts +13 -0
  43. package/runtime/node_modules/@metro-labs/core/src/stations/account-store.ts +60 -0
  44. package/runtime/node_modules/@metro-labs/core/src/stations/attachments.ts +196 -0
  45. package/runtime/node_modules/@metro-labs/core/src/stations/messaging-normalize.ts +88 -0
  46. package/runtime/node_modules/@metro-labs/core/src/stations/station-runtime.ts +64 -0
  47. package/runtime/node_modules/@metro-labs/core/src/stations/types.ts +108 -0
  48. package/runtime/node_modules/@metro-labs/core/src/str.ts +5 -0
  49. package/runtime/node_modules/@metro-labs/core/src/train-error.ts +53 -0
  50. package/runtime/node_modules/@metro-labs/core/src/version.ts +2 -0
  51. package/runtime/node_modules/@metro-labs/daemon/package.json +48 -0
  52. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-attach.ts +19 -0
  53. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-routes.ts +70 -0
  54. package/runtime/node_modules/@metro-labs/daemon/src/agents/accounts-api.ts +365 -0
  55. package/runtime/node_modules/@metro-labs/daemon/src/agents/admin.ts +43 -0
  56. package/runtime/node_modules/@metro-labs/daemon/src/agents/allowlist.ts +37 -0
  57. package/runtime/node_modules/@metro-labs/daemon/src/agents/api.ts +300 -0
  58. package/runtime/node_modules/@metro-labs/daemon/src/agents/bundle.ts +122 -0
  59. package/runtime/node_modules/@metro-labs/daemon/src/agents/file-admin.ts +371 -0
  60. package/runtime/node_modules/@metro-labs/daemon/src/agents/files.ts +155 -0
  61. package/runtime/node_modules/@metro-labs/daemon/src/agents/keys.ts +45 -0
  62. package/runtime/node_modules/@metro-labs/daemon/src/agents/map.ts +95 -0
  63. package/runtime/node_modules/@metro-labs/daemon/src/agents/scope.ts +64 -0
  64. package/runtime/node_modules/@metro-labs/daemon/src/agents/seed.ts +33 -0
  65. package/runtime/node_modules/@metro-labs/daemon/src/agents/senders.ts +38 -0
  66. package/runtime/node_modules/@metro-labs/daemon/src/boot/boot.ts +209 -0
  67. package/runtime/node_modules/@metro-labs/daemon/src/boot/connect-hint.ts +39 -0
  68. package/runtime/node_modules/@metro-labs/daemon/src/boot/crash-guard.ts +49 -0
  69. package/runtime/node_modules/@metro-labs/daemon/src/boot/local-owner.ts +14 -0
  70. package/runtime/node_modules/@metro-labs/daemon/src/boot/paths.ts +106 -0
  71. package/runtime/node_modules/@metro-labs/daemon/src/channels/addressed.ts +25 -0
  72. package/runtime/node_modules/@metro-labs/daemon/src/channels/dedupe.ts +24 -0
  73. package/runtime/node_modules/@metro-labs/daemon/src/channels/inbound.ts +377 -0
  74. package/runtime/node_modules/@metro-labs/daemon/src/channels/media-note.ts +85 -0
  75. package/runtime/node_modules/@metro-labs/daemon/src/channels/pending.ts +75 -0
  76. package/runtime/node_modules/@metro-labs/daemon/src/channels/relay.ts +129 -0
  77. package/runtime/node_modules/@metro-labs/daemon/src/channels/webhook-note.ts +51 -0
  78. package/runtime/node_modules/@metro-labs/daemon/src/claude/api.ts +309 -0
  79. package/runtime/node_modules/@metro-labs/daemon/src/claude/files.ts +358 -0
  80. package/runtime/node_modules/@metro-labs/daemon/src/claude/login.ts +169 -0
  81. package/runtime/node_modules/@metro-labs/daemon/src/claude/onboarding.ts +56 -0
  82. package/runtime/node_modules/@metro-labs/daemon/src/claude/plugin-install.ts +140 -0
  83. package/runtime/node_modules/@metro-labs/daemon/src/claude/session-files.ts +90 -0
  84. package/runtime/node_modules/@metro-labs/daemon/src/claude/session.ts +253 -0
  85. package/runtime/node_modules/@metro-labs/daemon/src/claude/settings.ts +117 -0
  86. package/runtime/node_modules/@metro-labs/daemon/src/claude/setup.ts +239 -0
  87. package/runtime/node_modules/@metro-labs/daemon/src/claude/skills.ts +154 -0
  88. package/runtime/node_modules/@metro-labs/daemon/src/claude/version.ts +109 -0
  89. package/runtime/node_modules/@metro-labs/daemon/src/connectors/api.ts +310 -0
  90. package/runtime/node_modules/@metro-labs/daemon/src/connectors/cli-api.ts +63 -0
  91. package/runtime/node_modules/@metro-labs/daemon/src/connectors/config.ts +175 -0
  92. package/runtime/node_modules/@metro-labs/daemon/src/connectors/json.ts +21 -0
  93. package/runtime/node_modules/@metro-labs/daemon/src/connectors/model.ts +77 -0
  94. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-client.ts +166 -0
  95. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-discovery.ts +139 -0
  96. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-pending.ts +65 -0
  97. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-routes.ts +171 -0
  98. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth.ts +155 -0
  99. package/runtime/node_modules/@metro-labs/daemon/src/connectors/plugin-sync.ts +122 -0
  100. package/runtime/node_modules/@metro-labs/daemon/src/connectors/reach.ts +27 -0
  101. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay-target.ts +39 -0
  102. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay.ts +296 -0
  103. package/runtime/node_modules/@metro-labs/daemon/src/connectors/store.ts +286 -0
  104. package/runtime/node_modules/@metro-labs/daemon/src/connectors/tools.ts +98 -0
  105. package/runtime/node_modules/@metro-labs/daemon/src/connectors/url.ts +70 -0
  106. package/runtime/node_modules/@metro-labs/daemon/src/connectors/verify.ts +332 -0
  107. package/runtime/node_modules/@metro-labs/daemon/src/connectors/watch.ts +54 -0
  108. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-grant.ts +99 -0
  109. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-owner.ts +32 -0
  110. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-serve.ts +121 -0
  111. package/runtime/node_modules/@metro-labs/daemon/src/files/upload-api.ts +294 -0
  112. package/runtime/node_modules/@metro-labs/daemon/src/files/upload-store.ts +181 -0
  113. package/runtime/node_modules/@metro-labs/daemon/src/gateway/bedrock.ts +259 -0
  114. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-auth.ts +231 -0
  115. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-device.ts +91 -0
  116. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-stream.ts +288 -0
  117. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-translate.ts +203 -0
  118. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex.ts +231 -0
  119. package/runtime/node_modules/@metro-labs/daemon/src/gateway/eventstream.ts +123 -0
  120. package/runtime/node_modules/@metro-labs/daemon/src/gateway/forward.ts +187 -0
  121. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gateway.ts +229 -0
  122. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-api.ts +269 -0
  123. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-config.ts +207 -0
  124. package/runtime/node_modules/@metro-labs/daemon/src/gateway/openrouter.ts +90 -0
  125. package/runtime/node_modules/@metro-labs/daemon/src/gateway/provider-models.ts +65 -0
  126. package/runtime/node_modules/@metro-labs/daemon/src/gateway/served.ts +17 -0
  127. package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage.ts +229 -0
  128. package/runtime/node_modules/@metro-labs/daemon/src/mcp/accounts.ts +151 -0
  129. package/runtime/node_modules/@metro-labs/daemon/src/mcp/call-tools.ts +216 -0
  130. package/runtime/node_modules/@metro-labs/daemon/src/mcp/channel-owner.ts +29 -0
  131. package/runtime/node_modules/@metro-labs/daemon/src/mcp/ctx.ts +62 -0
  132. package/runtime/node_modules/@metro-labs/daemon/src/mcp/event-store.ts +91 -0
  133. package/runtime/node_modules/@metro-labs/daemon/src/mcp/frame-scope.ts +21 -0
  134. package/runtime/node_modules/@metro-labs/daemon/src/mcp/group-tools.ts +129 -0
  135. package/runtime/node_modules/@metro-labs/daemon/src/mcp/index.ts +191 -0
  136. package/runtime/node_modules/@metro-labs/daemon/src/mcp/member-tools.ts +72 -0
  137. package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-relay.ts +66 -0
  138. package/runtime/node_modules/@metro-labs/daemon/src/mcp/raw-get-stream.ts +207 -0
  139. package/runtime/node_modules/@metro-labs/daemon/src/mcp/request-identity.ts +47 -0
  140. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session-registry.ts +172 -0
  141. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session-route.ts +43 -0
  142. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session.ts +215 -0
  143. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-dispatch.ts +215 -0
  144. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-schemas.ts +400 -0
  145. package/runtime/node_modules/@metro-labs/daemon/src/mcp/upload-tool.ts +66 -0
  146. package/runtime/node_modules/@metro-labs/daemon/src/monitor/api.ts +237 -0
  147. package/runtime/node_modules/@metro-labs/daemon/src/net/tunnel.ts +389 -0
  148. package/runtime/node_modules/@metro-labs/daemon/src/routes/body.ts +24 -0
  149. package/runtime/node_modules/@metro-labs/daemon/src/routes/http.ts +372 -0
  150. package/runtime/node_modules/@metro-labs/daemon/src/routes/identity.ts +54 -0
  151. package/runtime/node_modules/@metro-labs/daemon/src/routes/local-mode.ts +223 -0
  152. package/runtime/node_modules/@metro-labs/daemon/src/routes/session-apis.ts +60 -0
  153. package/runtime/node_modules/@metro-labs/daemon/src/routes/session.ts +29 -0
  154. package/runtime/node_modules/@metro-labs/daemon/src/routes/threema-callback.ts +103 -0
  155. package/runtime/node_modules/@metro-labs/daemon/src/server/control.ts +64 -0
  156. package/runtime/node_modules/@metro-labs/daemon/src/server/machine.ts +61 -0
  157. package/runtime/node_modules/@metro-labs/daemon/src/server/update.ts +116 -0
  158. package/runtime/node_modules/@metro-labs/daemon/src/server.ts +2 -0
  159. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-inline.ts +100 -0
  160. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-interactive.ts +161 -0
  161. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-resolve.ts +202 -0
  162. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-session.ts +280 -0
  163. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-xmtp.ts +111 -0
  164. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach.ts +248 -0
  165. package/runtime/node_modules/@metro-labs/daemon/src/stations/materialize.ts +261 -0
  166. package/runtime/node_modules/@metro-labs/daemon/src/stations/registry.ts +37 -0
  167. package/runtime/node_modules/@metro-labs/daemon/src/stations/runtime-deps.ts +82 -0
  168. package/runtime/node_modules/@metro-labs/daemon/src/stations/supervisor-io.ts +97 -0
  169. package/runtime/node_modules/@metro-labs/daemon/src/stations/supervisor.ts +320 -0
  170. package/runtime/node_modules/@metro-labs/daemon/src/stations/threema-callbacks.ts +32 -0
  171. package/runtime/node_modules/@metro-labs/daemon/src/stations/train-call.ts +22 -0
  172. package/runtime/node_modules/@metro-labs/daemon/src/terminal/api.ts +96 -0
  173. package/runtime/node_modules/@metro-labs/daemon/src/terminal/socket.ts +123 -0
  174. package/runtime/node_modules/@metro-labs/daemon/src/terminal/tickets.ts +40 -0
  175. package/runtime/node_modules/@metro-labs/discord-bot/package.json +28 -0
  176. package/runtime/node_modules/@metro-labs/discord-bot/src/accounts.ts +118 -0
  177. package/runtime/node_modules/@metro-labs/discord-bot/src/actions.ts +388 -0
  178. package/runtime/node_modules/@metro-labs/discord-bot/src/api-base.ts +1 -0
  179. package/runtime/node_modules/@metro-labs/discord-bot/src/attachments.ts +29 -0
  180. package/runtime/node_modules/@metro-labs/discord-bot/src/format.ts +220 -0
  181. package/runtime/node_modules/@metro-labs/discord-bot/src/group-actions.ts +50 -0
  182. package/runtime/node_modules/@metro-labs/discord-bot/src/group.ts +115 -0
  183. package/runtime/node_modules/@metro-labs/discord-bot/src/index.ts +127 -0
  184. package/runtime/node_modules/@metro-labs/discord-bot/src/members.ts +215 -0
  185. package/runtime/node_modules/@metro-labs/discord-bot/src/send-files.ts +43 -0
  186. package/runtime/node_modules/@metro-labs/discord-bot/src/station.ts +19 -0
  187. package/runtime/node_modules/@metro-labs/discord-bot/src/verify.ts +82 -0
  188. package/runtime/node_modules/@metro-labs/discord-bot/src/voice-speak.ts +195 -0
  189. package/runtime/node_modules/@metro-labs/discord-bot/src/voice-transcribe.ts +292 -0
  190. package/runtime/node_modules/@metro-labs/discord-bot/src/voice.ts +197 -0
  191. package/runtime/node_modules/@metro-labs/discord-bot/src/wire.ts +5 -0
  192. package/runtime/node_modules/@metro-labs/http/package.json +33 -0
  193. package/runtime/node_modules/@metro-labs/http/src/api-error.ts +8 -0
  194. package/runtime/node_modules/@metro-labs/http/src/api-http.ts +95 -0
  195. package/runtime/node_modules/@metro-labs/http/src/cors.ts +29 -0
  196. package/runtime/node_modules/@metro-labs/http/src/identity-key.ts +33 -0
  197. package/runtime/node_modules/@metro-labs/http/src/identity-registry.ts +13 -0
  198. package/runtime/node_modules/@metro-labs/http/src/mode-api.ts +32 -0
  199. package/runtime/node_modules/@metro-labs/http/src/return-to.ts +21 -0
  200. package/runtime/node_modules/@metro-labs/http/src/signed-identity.ts +36 -0
  201. package/runtime/node_modules/@metro-labs/telegram/package.json +26 -0
  202. package/runtime/node_modules/@metro-labs/telegram/src/accounts.ts +80 -0
  203. package/runtime/node_modules/@metro-labs/telegram/src/actions.ts +254 -0
  204. package/runtime/node_modules/@metro-labs/telegram/src/attachments.ts +87 -0
  205. package/runtime/node_modules/@metro-labs/telegram/src/client.ts +77 -0
  206. package/runtime/node_modules/@metro-labs/telegram/src/format.ts +156 -0
  207. package/runtime/node_modules/@metro-labs/telegram/src/group.ts +261 -0
  208. package/runtime/node_modules/@metro-labs/telegram/src/history.ts +52 -0
  209. package/runtime/node_modules/@metro-labs/telegram/src/inbound.ts +78 -0
  210. package/runtime/node_modules/@metro-labs/telegram/src/index.ts +46 -0
  211. package/runtime/node_modules/@metro-labs/telegram/src/login.ts +166 -0
  212. package/runtime/node_modules/@metro-labs/telegram/src/media-actions.ts +80 -0
  213. package/runtime/node_modules/@metro-labs/telegram/src/members.ts +75 -0
  214. package/runtime/node_modules/@metro-labs/telegram/src/normalize.ts +22 -0
  215. package/runtime/node_modules/@metro-labs/telegram/src/reactions.ts +167 -0
  216. package/runtime/node_modules/@metro-labs/telegram/src/station.ts +24 -0
  217. package/runtime/node_modules/@metro-labs/telegram/src/types.ts +7 -0
  218. package/runtime/node_modules/@metro-labs/telegram/src/wire.ts +1 -0
  219. package/runtime/node_modules/@metro-labs/telegram-bot/package.json +25 -0
  220. package/runtime/node_modules/@metro-labs/telegram-bot/src/accounts.ts +120 -0
  221. package/runtime/node_modules/@metro-labs/telegram-bot/src/actions.ts +295 -0
  222. package/runtime/node_modules/@metro-labs/telegram-bot/src/attachments.ts +128 -0
  223. package/runtime/node_modules/@metro-labs/telegram-bot/src/format.ts +201 -0
  224. package/runtime/node_modules/@metro-labs/telegram-bot/src/index.ts +109 -0
  225. package/runtime/node_modules/@metro-labs/telegram-bot/src/media-actions.ts +166 -0
  226. package/runtime/node_modules/@metro-labs/telegram-bot/src/members.ts +47 -0
  227. package/runtime/node_modules/@metro-labs/telegram-bot/src/station.ts +17 -0
  228. package/runtime/node_modules/@metro-labs/telegram-bot/src/types.ts +58 -0
  229. package/runtime/node_modules/@metro-labs/telegram-bot/src/verify.ts +38 -0
  230. package/runtime/node_modules/@metro-labs/telegram-bot/src/wire.ts +3 -0
  231. package/runtime/node_modules/@metro-labs/threema/package.json +26 -0
  232. package/runtime/node_modules/@metro-labs/threema/src/accounts.ts +100 -0
  233. package/runtime/node_modules/@metro-labs/threema/src/actions.ts +219 -0
  234. package/runtime/node_modules/@metro-labs/threema/src/api.ts +130 -0
  235. package/runtime/node_modules/@metro-labs/threema/src/crypto.ts +132 -0
  236. package/runtime/node_modules/@metro-labs/threema/src/format.ts +123 -0
  237. package/runtime/node_modules/@metro-labs/threema/src/ids.ts +21 -0
  238. package/runtime/node_modules/@metro-labs/threema/src/index.ts +29 -0
  239. package/runtime/node_modules/@metro-labs/threema/src/station.ts +10 -0
  240. package/runtime/node_modules/@metro-labs/threema/src/verify.ts +117 -0
  241. package/runtime/node_modules/@metro-labs/webhook/package.json +23 -0
  242. package/runtime/node_modules/@metro-labs/webhook/src/station.ts +37 -0
  243. package/runtime/node_modules/@metro-labs/whatsapp/package.json +27 -0
  244. package/runtime/node_modules/@metro-labs/whatsapp/src/accounts.ts +66 -0
  245. package/runtime/node_modules/@metro-labs/whatsapp/src/ack.ts +101 -0
  246. package/runtime/node_modules/@metro-labs/whatsapp/src/actions.ts +190 -0
  247. package/runtime/node_modules/@metro-labs/whatsapp/src/attachments.ts +72 -0
  248. package/runtime/node_modules/@metro-labs/whatsapp/src/auth-state.ts +129 -0
  249. package/runtime/node_modules/@metro-labs/whatsapp/src/client.ts +347 -0
  250. package/runtime/node_modules/@metro-labs/whatsapp/src/delivery.ts +49 -0
  251. package/runtime/node_modules/@metro-labs/whatsapp/src/format.ts +138 -0
  252. package/runtime/node_modules/@metro-labs/whatsapp/src/inbound.ts +57 -0
  253. package/runtime/node_modules/@metro-labs/whatsapp/src/index.ts +40 -0
  254. package/runtime/node_modules/@metro-labs/whatsapp/src/keys.ts +59 -0
  255. package/runtime/node_modules/@metro-labs/whatsapp/src/logger.ts +60 -0
  256. package/runtime/node_modules/@metro-labs/whatsapp/src/login.ts +176 -0
  257. package/runtime/node_modules/@metro-labs/whatsapp/src/media.ts +84 -0
  258. package/runtime/node_modules/@metro-labs/whatsapp/src/normalize.ts +22 -0
  259. package/runtime/node_modules/@metro-labs/whatsapp/src/outbox.ts +38 -0
  260. package/runtime/node_modules/@metro-labs/whatsapp/src/parse.ts +185 -0
  261. package/runtime/node_modules/@metro-labs/whatsapp/src/resolve.ts +52 -0
  262. package/runtime/node_modules/@metro-labs/whatsapp/src/station.ts +18 -0
  263. package/runtime/node_modules/@metro-labs/whatsapp/src/token-store.ts +98 -0
  264. package/runtime/node_modules/@metro-labs/whatsapp/src/types.ts +6 -0
  265. package/runtime/node_modules/@metro-labs/whatsapp/src/wire.ts +5 -0
  266. package/runtime/node_modules/@metro-labs/xmtp/package.json +33 -0
  267. package/runtime/node_modules/@metro-labs/xmtp/src/accounts.ts +112 -0
  268. package/runtime/node_modules/@metro-labs/xmtp/src/actions-close.ts +110 -0
  269. package/runtime/node_modules/@metro-labs/xmtp/src/actions-conv.ts +299 -0
  270. package/runtime/node_modules/@metro-labs/xmtp/src/actions-meta.ts +157 -0
  271. package/runtime/node_modules/@metro-labs/xmtp/src/actions-push.ts +87 -0
  272. package/runtime/node_modules/@metro-labs/xmtp/src/actions.ts +375 -0
  273. package/runtime/node_modules/@metro-labs/xmtp/src/attachments.ts +107 -0
  274. package/runtime/node_modules/@metro-labs/xmtp/src/codecs.ts +171 -0
  275. package/runtime/node_modules/@metro-labs/xmtp/src/conv-helpers.ts +239 -0
  276. package/runtime/node_modules/@metro-labs/xmtp/src/emit-core.ts +55 -0
  277. package/runtime/node_modules/@metro-labs/xmtp/src/emit-payloads.ts +335 -0
  278. package/runtime/node_modules/@metro-labs/xmtp/src/emit.ts +80 -0
  279. package/runtime/node_modules/@metro-labs/xmtp/src/group-members.ts +34 -0
  280. package/runtime/node_modules/@metro-labs/xmtp/src/group.ts +56 -0
  281. package/runtime/node_modules/@metro-labs/xmtp/src/identity.ts +33 -0
  282. package/runtime/node_modules/@metro-labs/xmtp/src/index.ts +125 -0
  283. package/runtime/node_modules/@metro-labs/xmtp/src/labels.ts +157 -0
  284. package/runtime/node_modules/@metro-labs/xmtp/src/member-args.ts +40 -0
  285. package/runtime/node_modules/@metro-labs/xmtp/src/push.ts +349 -0
  286. package/runtime/node_modules/@metro-labs/xmtp/src/station.ts +13 -0
  287. package/runtime/node_modules/@metro-labs/xmtp/src/tools-handlers.ts +126 -0
  288. package/runtime/node_modules/@metro-labs/xmtp/src/tools.ts +212 -0
  289. package/runtime/node_modules/@metro-labs/xmtp/src/transcribe.ts +90 -0
  290. package/runtime/node_modules/@metro-labs/xmtp/src/verify.ts +84 -0
  291. package/runtime/node_modules/@metro-labs/xmtp/src/wire.ts +53 -0
  292. package/runtime/runtime.json +3 -0
  293. package/runtime/server.ts +1 -0
  294. package/runtime/stations.json +39 -0
  295. package/runtime/trains/.keep +0 -0
  296. package/LICENSE +0 -21
  297. package/README.md +0 -252
  298. package/dist/broker.js +0 -202
  299. package/dist/cache.js +0 -69
  300. package/dist/cli/actions.js +0 -206
  301. package/dist/cli/config.js +0 -185
  302. package/dist/cli/index.js +0 -188
  303. package/dist/cli/skill.js +0 -62
  304. package/dist/cli/tail.js +0 -164
  305. package/dist/cli/util.js +0 -72
  306. package/dist/cli/webhook.js +0 -81
  307. package/dist/codex-rc.js +0 -245
  308. package/dist/dispatcher.js +0 -128
  309. package/dist/history.js +0 -121
  310. package/dist/ipc.js +0 -72
  311. package/dist/log.js +0 -15
  312. package/dist/monitor.js +0 -194
  313. package/dist/paths.js +0 -68
  314. package/dist/registry.js +0 -48
  315. package/dist/stations/claude.js +0 -45
  316. package/dist/stations/codex.js +0 -68
  317. package/dist/stations/discord.js +0 -216
  318. package/dist/stations/index.js +0 -129
  319. package/dist/stations/telegram-md.js +0 -34
  320. package/dist/stations/telegram-upload.js +0 -113
  321. package/dist/stations/telegram.js +0 -234
  322. package/dist/stations/webhook.js +0 -103
  323. package/dist/tunnel.js +0 -64
  324. package/dist/webhooks.js +0 -41
  325. package/docs/broker.md +0 -214
  326. package/docs/monitor.md +0 -163
  327. package/docs/uri-scheme.md +0 -124
  328. package/docs/users.md +0 -226
  329. package/skills/metro/SKILL.md +0 -256
@@ -0,0 +1,375 @@
1
+ import { ReactionAction, ReactionSchema } from '@xmtp/node-sdk';
2
+ import type { Reply } from '@xmtp/node-bindings';
3
+ import {
4
+ AttachmentCodec,
5
+ type Attachment,
6
+ } from '@xmtp/content-type-remote-attachment';
7
+ import {
8
+ WalletSendCallsCodec,
9
+ type WalletSendCallsParams,
10
+ } from '@xmtp/content-type-wallet-send-calls';
11
+ import { toHex } from 'viem';
12
+ import { convOf } from './accounts.js';
13
+ import { resolveMsgId, respond } from './wire.js';
14
+ import { emitOutbound } from './emit.js';
15
+ import {
16
+ PollCodec,
17
+ buildPollContent,
18
+ SignatureRequestCodec,
19
+ type SignatureRequestContent,
20
+ } from './codecs.js';
21
+ import { convHandlers } from './actions-conv.js';
22
+ import { normalizeXmtp } from '@metro-labs/core/stations/messaging-normalize';
23
+ import { TrainError } from '@metro-labs/core/train-error';
24
+ import { makeStation, type CallMsg } from '@metro-labs/core/stations/station-runtime';
25
+
26
+ type Args = Record<string, unknown>;
27
+
28
+ const noConv = (line: string): TrainError =>
29
+ new TrainError('NOT_FOUND', `conversation not found for ${line}`);
30
+ const badArgs = (message: string): TrainError =>
31
+ new TrainError('INVALID_ARGS', message);
32
+
33
+ async function send(id: string, args: Args): Promise<void> {
34
+ const { line, text } = args as { line: string; text: string };
35
+ const { acct, conv } = await convOf(line);
36
+ if (!conv) throw noConv(line);
37
+ const messageId = await conv.sendText(text);
38
+ emitOutbound(acct.cfg.id, line, messageId, text);
39
+ respond(id, { result: { messageId } });
40
+ }
41
+
42
+ async function ask(id: string, args: Args): Promise<void> {
43
+ const { line, pollId } = args as { line: string; pollId?: string };
44
+ const { acct, conv } = await convOf(line);
45
+ if (!conv) throw noConv(line);
46
+ const fallbackId = `poll_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
47
+ const mintedId =
48
+ pollId ??
49
+ (typeof crypto?.randomUUID === 'function'
50
+ ? crypto.randomUUID()
51
+ : fallbackId);
52
+ const { poll, title } = buildPollContent(args, mintedId);
53
+ const sentId = await conv.send(new PollCodec().encode(poll));
54
+ emitOutbound(acct.cfg.id, line, sentId, `📊 Poll: ${title}`);
55
+ respond(id, { result: { messageId: sentId, pollId: mintedId } });
56
+ }
57
+
58
+ async function react(id: string, args: Args): Promise<void> {
59
+ const {
60
+ line,
61
+ messageId,
62
+ emoji,
63
+ action: reactAction,
64
+ schema: reactSchema,
65
+ } = args as {
66
+ line: string;
67
+ messageId: string;
68
+ emoji: string;
69
+ action?: 'added' | 'removed';
70
+ schema?: string;
71
+ referenceInboxId?: string;
72
+ };
73
+ const { acct, conv } = await convOf(line);
74
+ if (!conv) throw noConv(line);
75
+ const xmtpMsgId = resolveMsgId(messageId);
76
+ let refInbox = (args as { referenceInboxId?: string }).referenceInboxId;
77
+ if (!refInbox) {
78
+ const recent = await conv.messages({ limit: 200, direction: 1 });
79
+ refInbox = recent.find((m) => m.id === xmtpMsgId)?.senderInboxId;
80
+ if (!refInbox)
81
+ throw new TrainError(
82
+ 'NOT_FOUND',
83
+ `could not resolve referenceInboxId for ${xmtpMsgId}`,
84
+ );
85
+ }
86
+ const schemaEnum =
87
+ reactSchema === 'custom'
88
+ ? ReactionSchema.Custom
89
+ : reactSchema === 'shortcode'
90
+ ? ReactionSchema.Shortcode
91
+ : ReactionSchema.Unicode;
92
+ const sentId = await conv.sendReaction({
93
+ reference: xmtpMsgId,
94
+ referenceInboxId: refInbox,
95
+ action:
96
+ reactAction === 'removed' ? ReactionAction.Removed : ReactionAction.Added,
97
+ content: emoji,
98
+ schema: schemaEnum,
99
+ });
100
+ emitOutbound(
101
+ acct.cfg.id,
102
+ line,
103
+ sentId,
104
+ `[react ${emoji}${reactAction === 'removed' ? ' (removed)' : ''}]`,
105
+ { type: 'react', emoji, targetId: xmtpMsgId },
106
+ );
107
+ respond(id, { result: { messageId: sentId } });
108
+ }
109
+
110
+ async function reply(id: string, args: Args): Promise<void> {
111
+ const { line, replyTo, text } = args as {
112
+ line: string;
113
+ replyTo: string;
114
+ text: string;
115
+ };
116
+ const { acct, conv } = await convOf(line);
117
+ if (!conv) throw noConv(line);
118
+ const { encodeText } = await import('@xmtp/node-bindings');
119
+ const xmtpReplyTo = resolveMsgId(replyTo);
120
+ const sentId = await conv.sendReply({
121
+ reference: xmtpReplyTo,
122
+ content: encodeText(text),
123
+ contentType: {
124
+ authorityId: 'xmtp.org',
125
+ typeId: 'text',
126
+ versionMajor: 1,
127
+ versionMinor: 0,
128
+ },
129
+ } as unknown as Reply);
130
+ emitOutbound(acct.cfg.id, line, sentId, text, {
131
+ type: 'reply',
132
+ replyTo: xmtpReplyTo,
133
+ });
134
+ respond(id, { result: { messageId: sentId } });
135
+ }
136
+
137
+ async function sendAttachment(id: string, args: Args): Promise<void> {
138
+ const { line, name, mime, dataB64 } = args as {
139
+ line: string;
140
+ name: string;
141
+ mime: string;
142
+ dataB64: string;
143
+ };
144
+ const { acct, conv } = await convOf(line);
145
+ if (!conv) throw noConv(line);
146
+ const sentId = await conv.sendAttachment({
147
+ filename: name,
148
+ mimeType: mime,
149
+ content: new Uint8Array(Buffer.from(dataB64, 'base64')),
150
+ });
151
+ emitOutbound(acct.cfg.id, line, sentId, `[${mime.split('/')[0]}: ${name}]`);
152
+ respond(id, { result: { messageId: sentId } });
153
+ }
154
+
155
+ const IMG_MIME_BY_EXT: Record<string, string> = {
156
+ jpg: 'image/jpeg',
157
+ jpeg: 'image/jpeg',
158
+ gif: 'image/gif',
159
+ webp: 'image/webp',
160
+ };
161
+
162
+ async function loadImageBytes(
163
+ path: string | undefined,
164
+ dataB64: string | undefined,
165
+ ): Promise<Uint8Array> {
166
+ if (path) {
167
+ const { readFileSync } = await import('node:fs');
168
+ return new Uint8Array(readFileSync(path));
169
+ }
170
+ if (dataB64) return new Uint8Array(Buffer.from(dataB64, 'base64'));
171
+ throw badArgs('sendImage requires path or dataB64');
172
+ }
173
+
174
+ function imageMime(
175
+ mimeType: string | undefined,
176
+ filename: string | undefined,
177
+ path: string | undefined,
178
+ ): string {
179
+ if (mimeType) return mimeType;
180
+ const ext = (filename ?? path ?? '').toLowerCase().split('.').pop() ?? '';
181
+ return IMG_MIME_BY_EXT[ext] ?? 'image/png';
182
+ }
183
+
184
+ function imageFilename(
185
+ filename: string | undefined,
186
+ path: string | undefined,
187
+ ): string {
188
+ if (filename) return filename;
189
+ const baseName = path ? path.split('/').pop() : undefined;
190
+ return baseName != null && baseName !== '' ? baseName : 'image.png';
191
+ }
192
+
193
+ async function sendImage(id: string, args: Args): Promise<void> {
194
+ const { line, path, dataB64, filename, mimeType } = args as {
195
+ line: string;
196
+ path?: string;
197
+ dataB64?: string;
198
+ filename?: string;
199
+ mimeType?: string;
200
+ };
201
+ const { acct, conv } = await convOf(line);
202
+ if (!conv) throw noConv(line);
203
+ const bytes = await loadImageBytes(path, dataB64);
204
+ const mime = imageMime(mimeType, filename, path);
205
+ const fname = imageFilename(filename, path);
206
+ const attachment: Attachment = {
207
+ filename: fname,
208
+ mimeType: mime,
209
+ data: bytes,
210
+ };
211
+ const sentId = await conv.send(new AttachmentCodec().encode(attachment));
212
+ emitOutbound(acct.cfg.id, line, sentId, `[${mime.split('/')[0]}: ${fname}]`);
213
+ respond(id, { result: { messageId: sentId } });
214
+ }
215
+
216
+ interface TxRequestArgs {
217
+ to: string;
218
+ amountEth?: number;
219
+ data?: string;
220
+ note?: string;
221
+ chainId?: number;
222
+ }
223
+
224
+ function validateTxAmount(amountEth: number | undefined, hasData: boolean): void {
225
+ if (!hasData && (typeof amountEth !== 'number' || !(amountEth > 0))) {
226
+ throw badArgs(
227
+ 'sendTxRequest requires a positive `amountEth` (or `data` for a contract call)',
228
+ );
229
+ }
230
+ if (amountEth != null && (typeof amountEth !== 'number' || amountEth < 0)) {
231
+ throw badArgs('sendTxRequest `amountEth` must be a non-negative number');
232
+ }
233
+ }
234
+
235
+ function validateTxRequest(a: TxRequestArgs): boolean {
236
+ const { to, amountEth, data } = a;
237
+ if (!to || typeof to !== 'string' || !/^0x[0-9a-fA-F]{40}$/.test(to)) {
238
+ throw badArgs('sendTxRequest requires a valid 0x `to` address');
239
+ }
240
+ const hasData = data != null;
241
+ if (
242
+ hasData &&
243
+ (typeof data !== 'string' || !/^0x([0-9a-fA-F]{2})*$/.test(data))
244
+ ) {
245
+ throw badArgs('sendTxRequest `data` must be 0x-prefixed hex calldata');
246
+ }
247
+ validateTxAmount(amountEth, hasData);
248
+ return hasData;
249
+ }
250
+
251
+ function buildTxContent(
252
+ a: TxRequestArgs,
253
+ from: string,
254
+ hasData: boolean,
255
+ ): WalletSendCallsParams {
256
+ const { to, amountEth, data, note, chainId } = a;
257
+ const weiHex = amountEth
258
+ ? '0x' + BigInt(Math.round(amountEth * 1e18)).toString(16)
259
+ : '0x0';
260
+ return {
261
+ version: '1.0',
262
+ chainId: toHex(chainId ?? 1),
263
+ from: from as `0x${string}`,
264
+ calls: [
265
+ {
266
+ to: to as `0x${string}`,
267
+ value: weiHex as `0x${string}`,
268
+ ...(hasData ? { data: data as `0x${string}` } : {}),
269
+ metadata: {
270
+ description: note ?? (hasData ? 'Contract call' : 'Payment request'),
271
+ transactionType: 'transfer',
272
+ },
273
+ },
274
+ ],
275
+ };
276
+ }
277
+
278
+ function txRequestLabel(a: TxRequestArgs, hasData: boolean): string {
279
+ const { amountEth, note } = a;
280
+ return hasData
281
+ ? `📝 ${note ?? 'Contract call'}${amountEth ? ` (${amountEth} ETH)` : ''}`
282
+ : `💸 ${note ?? 'Payment request'} (${amountEth} ETH)`;
283
+ }
284
+
285
+ async function sendTxRequest(id: string, args: Args): Promise<void> {
286
+ const { line } = args as { line: string };
287
+ const txArgs = args as Args & TxRequestArgs;
288
+ const { acct, conv } = await convOf(line);
289
+ if (!conv) throw noConv(line);
290
+ const hasData = validateTxRequest(txArgs);
291
+ const content = buildTxContent(txArgs, acct.address, hasData);
292
+ const sentId = await conv.send(new WalletSendCallsCodec().encode(content));
293
+ emitOutbound(acct.cfg.id, line, sentId, txRequestLabel(txArgs, hasData));
294
+ respond(id, { result: { messageId: sentId } });
295
+ }
296
+
297
+ async function sendSignatureRequest(id: string, args: Args): Promise<void> {
298
+ const { line, kind, eip712, message, description } = args as {
299
+ line: string;
300
+ kind?: 'eip712' | 'personal';
301
+ eip712?: unknown;
302
+ message?: string;
303
+ description?: string;
304
+ };
305
+ const { acct, conv } = await convOf(line);
306
+ if (!conv) throw noConv(line);
307
+ const k: 'eip712' | 'personal' = kind === 'eip712' ? 'eip712' : 'personal';
308
+ if (k === 'eip712' && !eip712)
309
+ throw badArgs(
310
+ 'sendSignatureRequest eip712 requires an `eip712` typed-data object',
311
+ );
312
+ if (k === 'personal' && (!message || typeof message !== 'string')) {
313
+ throw badArgs('sendSignatureRequest personal requires a `message` string');
314
+ }
315
+ const content: SignatureRequestContent = {
316
+ id: 'sig_' + Date.now().toString(36),
317
+ kind: k,
318
+ ...(k === 'eip712' ? { eip712 } : { message }),
319
+ description,
320
+ };
321
+ const sentId = await conv.send(new SignatureRequestCodec().encode(content));
322
+ emitOutbound(
323
+ acct.cfg.id,
324
+ line,
325
+ sentId,
326
+ `✍️ ${description ?? 'Signature request'}`,
327
+ );
328
+ respond(id, { result: { messageId: sentId } });
329
+ }
330
+
331
+ async function accountsAction(id: string): Promise<void> {
332
+ const { accounts } = await import('./accounts.js');
333
+ respond(id, {
334
+ result: {
335
+ accounts: [...accounts.values()].map((a) => ({
336
+ id: a.cfg.id,
337
+ handle: a.address,
338
+ url: `https://stage.box/#/${a.address}`,
339
+ address: a.address,
340
+ inboxId: a.inboxId,
341
+ env: 'production',
342
+ owner: a.cfg.owner ?? null,
343
+ keySource: 'privateKey',
344
+ })),
345
+ },
346
+ });
347
+ }
348
+
349
+ function unsupportedVerb(id: string, verb: string): Promise<void> {
350
+ respond(id, { error: `unsupported verb '${verb}' on xmtp` });
351
+ return Promise.resolve();
352
+ }
353
+
354
+ const handlers: Record<string, (id: string, args: Args) => Promise<void>> = {
355
+ accounts: (id) => accountsAction(id),
356
+ send,
357
+ ask,
358
+ sendPoll: ask,
359
+ react,
360
+ reply,
361
+ sendAttachment,
362
+ sendImage,
363
+ sendTxRequest,
364
+ sendSignatureRequest,
365
+ edit: (id) => unsupportedVerb(id, 'edit'),
366
+ delete: (id) => unsupportedVerb(id, 'delete'),
367
+ ...convHandlers,
368
+ };
369
+
370
+ export type { CallMsg };
371
+
372
+ export const handleCall = makeStation({
373
+ handlers,
374
+ normalize: normalizeXmtp,
375
+ });
@@ -0,0 +1,107 @@
1
+ import {
2
+ AttachmentCodec,
3
+ RemoteAttachmentCodec,
4
+ ContentTypeAttachment,
5
+ } from '@xmtp/content-type-remote-attachment';
6
+ import {
7
+ saveBufferToCache,
8
+ assertAttachmentSize,
9
+ } from '@metro-labs/core/stations/attachments';
10
+ import type { SavedAttachment } from '@metro-labs/core/stations/attachments';
11
+ import { errMsg } from '@metro-labs/core/log';
12
+
13
+ export type { SavedAttachment };
14
+
15
+ export const REMOTE_FETCH_ATTEMPTS = 3;
16
+ const REMOTE_FETCH_BACKOFF_MS = 400;
17
+
18
+ const sleep = (ms: number): Promise<void> =>
19
+ new Promise((resolve) => setTimeout(resolve, ms));
20
+
21
+ const attachmentCodec = new AttachmentCodec();
22
+ const loadRegistry = {
23
+ codecFor: (ct: { typeId?: string }) =>
24
+ ct.typeId === ContentTypeAttachment.typeId ? attachmentCodec : undefined,
25
+ };
26
+
27
+ export interface RemoteEntry {
28
+ url: string;
29
+ filename?: string;
30
+ contentDigest?: string;
31
+ nonce?: Uint8Array;
32
+ salt?: Uint8Array;
33
+ secret?: Uint8Array;
34
+ scheme?: string;
35
+ contentLength?: number;
36
+ }
37
+
38
+ export async function saveInlineAttachment(
39
+ a: { filename?: string; mimeType?: string; content: Uint8Array },
40
+ messageId: string,
41
+ index = 0,
42
+ ): Promise<SavedAttachment> {
43
+ return saveBufferToCache(a.content, messageId, index, {
44
+ mime: a.mimeType,
45
+ name: a.filename,
46
+ });
47
+ }
48
+
49
+ function toRemoteDescriptor(r: RemoteEntry): {
50
+ url: string;
51
+ contentDigest: string;
52
+ salt: Uint8Array;
53
+ nonce: Uint8Array;
54
+ secret: Uint8Array;
55
+ scheme: string;
56
+ contentLength: number;
57
+ filename: string;
58
+ } {
59
+ return {
60
+ url: r.url,
61
+ contentDigest: r.contentDigest ?? '',
62
+ salt: r.salt ?? new Uint8Array(),
63
+ nonce: r.nonce ?? new Uint8Array(),
64
+ secret: r.secret ?? new Uint8Array(),
65
+ scheme: r.scheme ?? 'https://',
66
+ contentLength: r.contentLength ?? 0,
67
+ filename: r.filename ?? '',
68
+ };
69
+ }
70
+
71
+ interface DecodedAttachment {
72
+ filename?: string;
73
+ mimeType?: string;
74
+ data: Uint8Array;
75
+ }
76
+
77
+ async function loadRemote(r: RemoteEntry): Promise<DecodedAttachment> {
78
+ let last = '';
79
+ for (let attempt = 1; attempt <= REMOTE_FETCH_ATTEMPTS; attempt += 1) {
80
+ try {
81
+ return await RemoteAttachmentCodec.load<DecodedAttachment>(
82
+ toRemoteDescriptor(r),
83
+ loadRegistry,
84
+ );
85
+ } catch (err) {
86
+ last = errMsg(err);
87
+ if (attempt < REMOTE_FETCH_ATTEMPTS)
88
+ await sleep(REMOTE_FETCH_BACKOFF_MS * attempt);
89
+ }
90
+ }
91
+ throw new Error(
92
+ `xmtp remote attachment fetch failed after ${REMOTE_FETCH_ATTEMPTS} attempts: ${last}`,
93
+ );
94
+ }
95
+
96
+ export async function saveRemoteAttachment(
97
+ r: RemoteEntry,
98
+ messageId: string,
99
+ index = 0,
100
+ ): Promise<SavedAttachment> {
101
+ if (r.contentLength) assertAttachmentSize(r.contentLength);
102
+ const decoded = await loadRemote(r);
103
+ return saveBufferToCache(decoded.data, messageId, index, {
104
+ mime: decoded.mimeType,
105
+ name: decoded.filename ?? r.filename,
106
+ });
107
+ }
@@ -0,0 +1,171 @@
1
+ import type {
2
+ ContentTypeId,
3
+ ContentCodec,
4
+ EncodedContent,
5
+ } from '@xmtp/content-type-primitives';
6
+
7
+ const enc = (o: unknown): Uint8Array =>
8
+ new TextEncoder().encode(JSON.stringify(o));
9
+ const dec = (e: EncodedContent): unknown =>
10
+ JSON.parse(new TextDecoder().decode(e.content));
11
+
12
+ const makeJsonCodec = <T>(
13
+ contentType: ContentTypeId,
14
+ fallbackFn: (c: T) => string,
15
+ ) =>
16
+ class {
17
+ get contentType() {
18
+ return contentType;
19
+ }
20
+ encode(c: T): EncodedContent {
21
+ return {
22
+ type: contentType,
23
+ parameters: {},
24
+ fallback: fallbackFn(c),
25
+ content: enc(c),
26
+ };
27
+ }
28
+ decode(e: EncodedContent): T {
29
+ return dec(e) as T;
30
+ }
31
+ fallback(c: T) {
32
+ return fallbackFn(c);
33
+ }
34
+ shouldPush() {
35
+ return true;
36
+ }
37
+ };
38
+
39
+ export const ContentTypePoll: ContentTypeId = {
40
+ authorityId: 'metro.box',
41
+ typeId: 'poll',
42
+ versionMajor: 1,
43
+ versionMinor: 0,
44
+ };
45
+ export interface PollOption {
46
+ label: string;
47
+ description?: string;
48
+ }
49
+ export interface PollQuestion {
50
+ question: string;
51
+ header?: string;
52
+ multiSelect?: boolean;
53
+ open?: boolean;
54
+ options?: (PollOption | string)[];
55
+ }
56
+ export interface PollContent {
57
+ questions?: PollQuestion[];
58
+ question?: string;
59
+ header?: string;
60
+ multiSelect?: boolean;
61
+ pollId?: string;
62
+ options?: (PollOption | string)[];
63
+ [k: string]: unknown;
64
+ }
65
+ const pollTitle = (c: PollContent): string =>
66
+ c.questions?.[0]?.question ?? c.question ?? 'Poll';
67
+ export const PollCodec = makeJsonCodec<PollContent>(
68
+ ContentTypePoll,
69
+ (c) => `📊 Poll: ${pollTitle(c)}`,
70
+ );
71
+
72
+ const normOpts = (o: (string | PollOption)[]): PollOption[] =>
73
+ o.map((x) =>
74
+ typeof x === 'string'
75
+ ? { label: x }
76
+ : { label: x.label, description: x.description },
77
+ );
78
+
79
+ export function buildPollContent(
80
+ args: Record<string, unknown>,
81
+ pollId: string,
82
+ ): { poll: PollContent; title: string } {
83
+ const { question, options, header, multiSelect, questions } = args as {
84
+ question?: string;
85
+ options?: (string | PollOption)[];
86
+ header?: string;
87
+ multiSelect?: boolean;
88
+ questions?: PollQuestion[];
89
+ };
90
+ if (Array.isArray(questions) && questions.length > 0) {
91
+ const norm: PollQuestion[] = questions.map((q, i) => {
92
+ if (!q || typeof q.question !== 'string' || !q.question)
93
+ throw new Error(`ask questions[${i}] requires a question`);
94
+ const open = q.open === true;
95
+ const opts = Array.isArray(q.options) ? q.options : [];
96
+ if (!open && opts.length === 0)
97
+ throw new Error(
98
+ `ask questions[${i}] requires a non-empty options array (or open:true for free-text)`,
99
+ );
100
+ return {
101
+ question: q.question,
102
+ options: normOpts(opts),
103
+ multiSelect: !!q.multiSelect,
104
+ ...(open ? { open: true } : {}),
105
+ ...(q.header ? { header: q.header } : {}),
106
+ };
107
+ });
108
+ const first = norm[0];
109
+ if (!first) throw new Error('ask requires at least one question');
110
+ return { poll: { questions: norm, pollId }, title: first.question };
111
+ }
112
+ if (!question || typeof question !== 'string')
113
+ throw new Error('ask requires a question (or a questions[] array)');
114
+ if (!Array.isArray(options) || options.length === 0)
115
+ throw new Error('ask requires a non-empty options array');
116
+ return {
117
+ poll: {
118
+ question,
119
+ options: normOpts(options),
120
+ multiSelect: !!multiSelect,
121
+ pollId,
122
+ ...(header ? { header } : {}),
123
+ },
124
+ title: question,
125
+ };
126
+ }
127
+
128
+ export const ContentTypeSignatureRequest: ContentTypeId = {
129
+ authorityId: 'metro.box',
130
+ typeId: 'signatureRequest',
131
+ versionMajor: 1,
132
+ versionMinor: 0,
133
+ };
134
+ export interface SignatureRequestContent {
135
+ id?: string;
136
+ kind?: 'eip712' | 'personal';
137
+ eip712?: unknown;
138
+ message?: string;
139
+ description?: string;
140
+ [k: string]: unknown;
141
+ }
142
+ export const SignatureRequestCodec = makeJsonCodec<SignatureRequestContent>(
143
+ ContentTypeSignatureRequest,
144
+ (c) =>
145
+ c.description
146
+ ? `[Signature request] ${c.description}`
147
+ : '[Signature request]',
148
+ );
149
+
150
+ export const ContentTypeSignatureReference: ContentTypeId = {
151
+ authorityId: 'metro.box',
152
+ typeId: 'signatureReference',
153
+ versionMajor: 1,
154
+ versionMinor: 0,
155
+ };
156
+ export interface SignatureReferenceContent {
157
+ requestId?: string;
158
+ signature: string;
159
+ signer?: string;
160
+ [k: string]: unknown;
161
+ }
162
+ export const SignatureReferenceCodec =
163
+ makeJsonCodec<SignatureReferenceContent>(ContentTypeSignatureReference, (c) =>
164
+ c.signature ? `[Signature] ${c.signature}` : '[Signature]',
165
+ );
166
+
167
+ export const CODECS = (): ContentCodec[] => [
168
+ new PollCodec(),
169
+ new SignatureRequestCodec(),
170
+ new SignatureReferenceCodec(),
171
+ ];