@stage-labs/metro 0.1.0-beta.21 → 0.1.0-beta.211
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.
- package/dist/api.js +9 -101
- package/dist/claude-settings.js +40 -0
- package/dist/claude.js +152 -0
- package/dist/cli.js +52 -109
- package/dist/control.js +47 -75
- package/dist/hold.js +210 -0
- package/dist/local.js +43 -0
- package/dist/mcp-config.js +25 -0
- package/dist/node-name.js +71 -0
- package/dist/onboarding.js +44 -0
- package/dist/provider-flags.js +9 -0
- package/dist/route.js +58 -0
- package/dist/runtime-install.js +96 -0
- package/dist/runtime.js +29 -52
- package/dist/serve.js +157 -0
- package/dist/service.js +304 -0
- package/dist/tail.js +119 -0
- package/dist/update.js +13 -1
- package/package.json +2 -23
- package/runtime/marketplace/.claude-plugin/marketplace.json +12 -0
- package/runtime/marketplace/plugin/.claude-plugin/plugin.json +17 -0
- package/runtime/marketplace/plugin/.mcp.json +1 -0
- package/runtime/marketplace/plugin/bin/guard.mjs +71 -0
- package/runtime/marketplace/plugin/bin/metro-plugin.mjs +30 -0
- package/runtime/marketplace/plugin/bin/policy.mjs +97 -0
- package/runtime/marketplace/plugin/bin/session-start.mjs +31 -0
- package/runtime/marketplace/plugin/hooks/hooks.json +25 -0
- package/runtime/marketplace/plugin/orchestrator.md +26 -0
- package/runtime/node_modules/@metro-labs/core/package.json +47 -0
- package/runtime/node_modules/@metro-labs/core/src/endpoints.ts +7 -0
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/events.ts +11 -7
- package/runtime/node_modules/@metro-labs/{mcp/src/db → core/src}/ids.ts +5 -0
- package/runtime/node_modules/@metro-labs/core/src/is-record.ts +2 -0
- package/runtime/node_modules/@metro-labs/{mcp/src/stations → core/src}/lines.ts +24 -28
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/protocol.ts +7 -4
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/secure-fs.ts +17 -0
- package/runtime/node_modules/@metro-labs/core/src/station-names.ts +13 -0
- package/runtime/node_modules/@metro-labs/core/src/stations/account-files.ts +41 -0
- package/runtime/node_modules/@metro-labs/core/src/stations/account-store.ts +83 -0
- package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/attachments.ts +0 -1
- package/runtime/node_modules/@metro-labs/core/src/stations/messaging-normalize.ts +16 -0
- package/runtime/node_modules/@metro-labs/core/src/stations/profile.ts +58 -0
- package/runtime/node_modules/@metro-labs/core/src/stations/sender-profile.ts +64 -0
- package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/station-runtime.ts +6 -11
- package/runtime/node_modules/@metro-labs/core/src/stations/train-boot.ts +42 -0
- package/runtime/node_modules/@metro-labs/core/src/stations/train-events.ts +84 -0
- package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/types.ts +18 -1
- package/runtime/node_modules/@metro-labs/core/src/tickets.ts +37 -0
- package/runtime/node_modules/@metro-labs/core/src/version.ts +2 -0
- package/runtime/node_modules/@metro-labs/daemon/package.json +48 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/agent-fs.ts +134 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/files-api.ts +12 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/files.ts +89 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/home-fs.ts +113 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/job-env.ts +51 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/provision.ts +80 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedule-detail.ts +99 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedules-api.ts +27 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedules.ts +144 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/unit-files.ts +37 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/user.ts +89 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/view.ts +87 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/account-attach.ts +19 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/account-lookups.ts +55 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/account-routes.ts +76 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/accounts-api.ts +357 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/admin.ts +30 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/allowlist.ts +59 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/api.ts +131 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/bundle.ts +132 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/file-admin.ts +305 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/files.ts +142 -0
- package/runtime/node_modules/@metro-labs/{mcp/src/db/key-map.ts → daemon/src/agents/keys.ts} +1 -11
- package/runtime/node_modules/@metro-labs/{mcp/src/db/agent-map.ts → daemon/src/agents/map.ts} +58 -1
- package/runtime/node_modules/@metro-labs/daemon/src/agents/policy-route.ts +27 -0
- package/runtime/node_modules/@metro-labs/{mcp/src/db/agent-scope.ts → daemon/src/agents/scope.ts} +2 -2
- package/runtime/node_modules/@metro-labs/daemon/src/agents/sender-cards.ts +94 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/senders.ts +38 -0
- package/runtime/node_modules/@metro-labs/daemon/src/approvals/api.ts +55 -0
- package/runtime/node_modules/@metro-labs/daemon/src/approvals/pending.ts +150 -0
- package/runtime/node_modules/@metro-labs/daemon/src/approvals/preview.ts +66 -0
- package/runtime/node_modules/@metro-labs/daemon/src/boot/boot.ts +218 -0
- package/runtime/node_modules/@metro-labs/daemon/src/boot/connect-hint.ts +36 -0
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/boot}/crash-guard.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/boot/local-owner.ts +21 -0
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/boot}/paths.ts +6 -34
- package/runtime/node_modules/@metro-labs/daemon/src/channels/addressed.ts +26 -0
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/inbound.ts +70 -45
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/media-note.ts +11 -7
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/pending.ts +4 -1
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/relay.ts +2 -2
- package/runtime/node_modules/@metro-labs/daemon/src/claude/api.ts +355 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/files.ts +359 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/login.ts +208 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/memory.ts +32 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/onboarding.ts +60 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/plugin-install.ts +149 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/session-files.ts +75 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/session.ts +313 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/settings.ts +109 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/setup.ts +273 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/skills.ts +120 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/version.ts +113 -0
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-api.ts → daemon/src/connectors/api.ts} +79 -113
- package/runtime/node_modules/@metro-labs/{mcp/src/db/connector-config.ts → daemon/src/connectors/config.ts} +67 -41
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/gates.ts +72 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/health.ts +18 -0
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/connectors}/oauth-client.ts +14 -17
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/connectors}/oauth-discovery.ts +33 -20
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-oauth-routes.ts → daemon/src/connectors/oauth-routes.ts} +30 -32
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-oauth.ts → daemon/src/connectors/oauth.ts} +61 -22
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/plugin-sync.ts +131 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/reach.ts +27 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay-policy.ts +90 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay.ts +347 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/store.ts +385 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/tools.ts +81 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/url.ts +37 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/verify.ts +106 -0
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-grant.ts +4 -4
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-owner.ts +3 -3
- package/runtime/node_modules/@metro-labs/daemon/src/files/attach-reaper.ts +174 -0
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-serve.ts +12 -13
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/upload-api.ts +10 -27
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/upload-store.ts +4 -4
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/bedrock.ts +233 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-auth.ts +208 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-device.ts +91 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-stream.ts +173 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-translate.ts +195 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-version.ts +44 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex.ts +128 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/effort.ts +77 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/eventstream.ts +123 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/forward.ts +237 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/frames.ts +118 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/gateway.ts +274 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-auth.ts +160 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-client.ts +46 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-setup.ts +150 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-stream.ts +139 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-translate.ts +224 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini.ts +208 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-api.ts +199 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-config.ts +278 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-signin.ts +193 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-store.ts +70 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/openrouter.ts +90 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/pkce.ts +36 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/provider-models.ts +66 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/served.ts +18 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/subscription.ts +120 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/text.ts +14 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage.ts +244 -0
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/accounts.ts +28 -17
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/attachment-schema.ts +91 -0
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/call-tools.ts +49 -20
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/ctx.ts +4 -4
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/event-store.ts +15 -16
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/group-tools.ts +2 -2
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/index.ts +24 -79
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/instructions.ts +19 -0
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/member-tools.ts +2 -2
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-prompt.ts +87 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-relay.ts +79 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/policy-gate.ts +82 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/policy-snapshot.ts +79 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/profile-lookup.ts +60 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/profile-tool.ts +96 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/read-tool.ts +87 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/request-identity.ts +46 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/session-slot.ts +48 -0
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/session.ts +33 -42
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-catalog.ts +88 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-def.ts +9 -0
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/tool-dispatch.ts +53 -40
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/tool-schemas.ts +68 -119
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/upload-tool.ts +6 -11
- package/runtime/node_modules/@metro-labs/daemon/src/metro-user/helper-script.ts +126 -0
- package/runtime/node_modules/@metro-labs/daemon/src/metro-user/install.ts +37 -0
- package/runtime/node_modules/@metro-labs/daemon/src/metro-user/privilege.ts +48 -0
- package/runtime/node_modules/@metro-labs/daemon/src/monitor/api.ts +132 -0
- package/runtime/node_modules/@metro-labs/daemon/src/net/tunnel.ts +316 -0
- package/runtime/node_modules/@metro-labs/daemon/src/policy/policy.ts +118 -0
- package/runtime/node_modules/@metro-labs/daemon/src/routes/bearer.ts +35 -0
- package/runtime/node_modules/@metro-labs/daemon/src/routes/body.ts +24 -0
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/routes}/http.ts +59 -51
- package/runtime/node_modules/@metro-labs/daemon/src/routes/local-mode.ts +205 -0
- package/runtime/node_modules/@metro-labs/daemon/src/routes/session-apis.ts +66 -0
- package/runtime/node_modules/@metro-labs/daemon/src/routes/session.ts +29 -0
- package/runtime/node_modules/@metro-labs/daemon/src/routes/threema-callback.ts +103 -0
- package/runtime/node_modules/@metro-labs/daemon/src/server/control.ts +39 -0
- package/runtime/node_modules/@metro-labs/daemon/src/server/machine.ts +58 -0
- package/runtime/node_modules/@metro-labs/daemon/src/server/owner.ts +26 -0
- package/runtime/node_modules/@metro-labs/daemon/src/server/update.ts +90 -0
- package/runtime/node_modules/@metro-labs/daemon/src/server.ts +2 -0
- package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-driver.ts +42 -0
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-inline.ts +29 -1
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-interactive.ts +9 -36
- package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-outlook.ts +63 -0
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-resolve.ts +38 -13
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/attach-session.ts +32 -22
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-xmtp.ts +8 -9
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach.ts +75 -9
- package/runtime/node_modules/@metro-labs/daemon/src/stations/materialize.ts +265 -0
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/registry.ts +22 -6
- package/runtime/node_modules/@metro-labs/daemon/src/stations/runtime-deps.ts +82 -0
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/supervisor-io.ts +3 -3
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/supervisor.ts +6 -9
- package/runtime/node_modules/@metro-labs/daemon/src/stations/threema-callbacks.ts +32 -0
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/train-call.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/stations/webhook-endpoints.ts +51 -0
- package/runtime/node_modules/@metro-labs/daemon/src/terminal/api.ts +84 -0
- package/runtime/node_modules/@metro-labs/daemon/src/terminal/socket.ts +124 -0
- package/runtime/node_modules/@metro-labs/daemon/src/terminal/tickets.ts +15 -0
- package/runtime/node_modules/@metro-labs/daemon/src/vault/api.ts +45 -0
- package/runtime/node_modules/@metro-labs/daemon/src/vault/config.ts +51 -0
- package/runtime/node_modules/@metro-labs/daemon/src/vault/firewall.ts +9 -0
- package/runtime/node_modules/@metro-labs/daemon/src/vault/index.ts +96 -0
- package/runtime/node_modules/@metro-labs/daemon/src/vault/install.ts +56 -0
- package/runtime/node_modules/@metro-labs/daemon/src/vault/paths.ts +26 -0
- package/runtime/node_modules/@metro-labs/daemon/src/vault/proxy.ts +147 -0
- package/runtime/node_modules/@metro-labs/daemon/src/vault/store.ts +129 -0
- package/runtime/node_modules/@metro-labs/daemon/src/vault/trust.ts +44 -0
- package/runtime/node_modules/@metro-labs/{discord → discord-bot}/package.json +3 -5
- package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/accounts.ts +8 -28
- package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/actions.ts +19 -187
- package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/attachments.ts +3 -3
- package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/format.ts +31 -72
- package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/group-actions.ts +2 -2
- package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/group.ts +2 -2
- package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/index.ts +15 -21
- package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/members.ts +2 -2
- package/runtime/node_modules/@metro-labs/discord-bot/src/profile.ts +68 -0
- package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/send-files.ts +12 -13
- package/runtime/node_modules/@metro-labs/discord-bot/src/station.ts +23 -0
- package/runtime/node_modules/@metro-labs/http/package.json +29 -0
- package/runtime/node_modules/@metro-labs/http/src/api-http.ts +135 -0
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon/session-api.ts → http/src/mode-api.ts} +13 -9
- package/runtime/node_modules/@metro-labs/http/src/return-to.ts +21 -0
- package/runtime/node_modules/@metro-labs/http/src/workos-token.ts +149 -0
- package/runtime/node_modules/@metro-labs/{telegram-user → outlook}/package.json +2 -5
- package/runtime/node_modules/@metro-labs/outlook/src/accounts.ts +93 -0
- package/runtime/node_modules/@metro-labs/outlook/src/actions.ts +14 -0
- package/runtime/node_modules/@metro-labs/outlook/src/attachments.ts +97 -0
- package/runtime/node_modules/@metro-labs/outlook/src/auth.ts +150 -0
- package/runtime/node_modules/@metro-labs/outlook/src/browser.ts +53 -0
- package/runtime/node_modules/@metro-labs/outlook/src/config.ts +36 -0
- package/runtime/node_modules/@metro-labs/outlook/src/format.ts +140 -0
- package/runtime/node_modules/@metro-labs/outlook/src/graph.ts +60 -0
- package/runtime/node_modules/@metro-labs/outlook/src/html.ts +72 -0
- package/runtime/node_modules/@metro-labs/outlook/src/inbound.ts +104 -0
- package/runtime/node_modules/@metro-labs/outlook/src/index.ts +12 -0
- package/runtime/node_modules/@metro-labs/outlook/src/login.ts +150 -0
- package/runtime/node_modules/@metro-labs/outlook/src/me.ts +41 -0
- package/runtime/node_modules/@metro-labs/outlook/src/outbound.ts +116 -0
- package/runtime/node_modules/@metro-labs/outlook/src/query.ts +119 -0
- package/runtime/node_modules/@metro-labs/outlook/src/state.ts +43 -0
- package/runtime/node_modules/@metro-labs/outlook/src/station.ts +15 -0
- package/runtime/node_modules/@metro-labs/outlook/src/trust.ts +70 -0
- package/runtime/node_modules/@metro-labs/telegram/package.json +3 -2
- package/runtime/node_modules/@metro-labs/telegram/src/accounts.ts +38 -96
- package/runtime/node_modules/@metro-labs/telegram/src/actions.ts +214 -253
- package/runtime/node_modules/@metro-labs/telegram/src/attachments.ts +67 -108
- package/runtime/node_modules/@metro-labs/{telegram-user → telegram}/src/client.ts +6 -6
- package/runtime/node_modules/@metro-labs/telegram/src/format.ts +101 -147
- package/runtime/node_modules/@metro-labs/{telegram-user → telegram}/src/group.ts +4 -4
- package/runtime/node_modules/@metro-labs/{telegram-user → telegram}/src/history.ts +1 -1
- package/runtime/node_modules/@metro-labs/telegram/src/inbound.ts +57 -0
- package/runtime/node_modules/@metro-labs/telegram/src/index.ts +6 -102
- package/runtime/node_modules/@metro-labs/{telegram-user → telegram}/src/login.ts +20 -20
- package/runtime/node_modules/@metro-labs/telegram/src/media-actions.ts +64 -151
- package/runtime/node_modules/@metro-labs/telegram/src/members.ts +61 -33
- package/runtime/node_modules/@metro-labs/telegram/src/profile.ts +70 -0
- package/runtime/node_modules/@metro-labs/{telegram-user → telegram}/src/reactions.ts +3 -3
- package/runtime/node_modules/@metro-labs/telegram/src/station.ts +11 -1
- package/runtime/node_modules/@metro-labs/telegram/src/types.ts +5 -47
- package/runtime/node_modules/@metro-labs/telegram-bot/package.json +25 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/accounts.ts +86 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/actions.ts +240 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/attachments.ts +128 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/format.ts +170 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/index.ts +103 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/media-actions.ts +90 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/members.ts +47 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/profile.ts +85 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/station.ts +21 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/types.ts +56 -0
- package/runtime/node_modules/@metro-labs/threema/package.json +26 -0
- package/runtime/node_modules/@metro-labs/threema/src/accounts.ts +95 -0
- package/runtime/node_modules/@metro-labs/threema/src/actions.ts +124 -0
- package/runtime/node_modules/@metro-labs/threema/src/api.ts +152 -0
- package/runtime/node_modules/@metro-labs/threema/src/crypto.ts +100 -0
- package/runtime/node_modules/@metro-labs/threema/src/files.ts +47 -0
- package/runtime/node_modules/@metro-labs/threema/src/format.ts +164 -0
- package/runtime/node_modules/@metro-labs/threema/src/groups.ts +96 -0
- package/runtime/node_modules/@metro-labs/threema/src/ids.ts +21 -0
- package/runtime/node_modules/@metro-labs/threema/src/inbound.ts +89 -0
- package/runtime/node_modules/@metro-labs/threema/src/index.ts +24 -0
- package/runtime/node_modules/@metro-labs/threema/src/messages.ts +264 -0
- package/runtime/node_modules/@metro-labs/threema/src/outbound.ts +160 -0
- package/runtime/node_modules/@metro-labs/threema/src/station.ts +13 -0
- package/runtime/node_modules/@metro-labs/threema/src/verify.ts +117 -0
- package/runtime/node_modules/@metro-labs/webhook/package.json +1 -1
- package/runtime/node_modules/@metro-labs/webhook/src/station.ts +5 -8
- package/runtime/node_modules/@metro-labs/whatsapp/package.json +2 -5
- package/runtime/node_modules/@metro-labs/whatsapp/src/accounts.ts +6 -28
- package/runtime/node_modules/@metro-labs/whatsapp/src/ack.ts +1 -1
- package/runtime/node_modules/@metro-labs/whatsapp/src/actions.ts +54 -11
- package/runtime/node_modules/@metro-labs/whatsapp/src/attachments.ts +2 -2
- package/runtime/node_modules/@metro-labs/whatsapp/src/auth-state.ts +1 -1
- package/runtime/node_modules/@metro-labs/whatsapp/src/client.ts +86 -4
- package/runtime/node_modules/@metro-labs/whatsapp/src/format.ts +7 -58
- package/runtime/node_modules/@metro-labs/whatsapp/src/inbound.ts +11 -28
- package/runtime/node_modules/@metro-labs/whatsapp/src/index.ts +4 -37
- package/runtime/node_modules/@metro-labs/whatsapp/src/keys.ts +1 -1
- package/runtime/node_modules/@metro-labs/whatsapp/src/login.ts +1 -1
- package/runtime/node_modules/@metro-labs/whatsapp/src/media.ts +1 -1
- package/runtime/node_modules/@metro-labs/whatsapp/src/names.ts +75 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/parse.ts +44 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/resolve.ts +52 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/station.ts +16 -1
- package/runtime/node_modules/@metro-labs/whatsapp/src/token-store.ts +5 -9
- package/runtime/node_modules/@metro-labs/whatsapp/src/types.ts +0 -1
- package/runtime/node_modules/@metro-labs/xmtp/package.json +3 -2
- package/runtime/node_modules/@metro-labs/xmtp/src/accounts.ts +10 -20
- package/runtime/node_modules/@metro-labs/xmtp/src/actions-close.ts +2 -2
- package/runtime/node_modules/@metro-labs/xmtp/src/actions-conv.ts +15 -204
- package/runtime/node_modules/@metro-labs/xmtp/src/actions-meta.ts +4 -43
- package/runtime/node_modules/@metro-labs/xmtp/src/actions.ts +41 -219
- package/runtime/node_modules/@metro-labs/xmtp/src/attachments.ts +3 -3
- package/runtime/node_modules/@metro-labs/xmtp/src/conv-helpers.ts +3 -3
- package/runtime/node_modules/@metro-labs/xmtp/src/emit-payloads.ts +7 -24
- package/runtime/node_modules/@metro-labs/xmtp/src/emit.ts +8 -18
- package/runtime/node_modules/@metro-labs/xmtp/src/group-members.ts +1 -1
- package/runtime/node_modules/@metro-labs/xmtp/src/group.ts +2 -2
- package/runtime/node_modules/@metro-labs/xmtp/src/identity.ts +30 -16
- package/runtime/node_modules/@metro-labs/xmtp/src/index.ts +12 -20
- package/runtime/node_modules/@metro-labs/xmtp/src/labels.ts +1 -19
- package/runtime/node_modules/@metro-labs/xmtp/src/member-args.ts +1 -1
- package/runtime/node_modules/@metro-labs/xmtp/src/names.ts +61 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/profile.ts +153 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/sender.ts +112 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/smart.ts +72 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/station.ts +5 -1
- package/runtime/node_modules/@metro-labs/xmtp/src/tools-handlers.ts +4 -51
- package/runtime/node_modules/@metro-labs/xmtp/src/tools.ts +30 -44
- package/runtime/node_modules/@metro-labs/xmtp/src/transcribe.ts +4 -6
- package/runtime/node_modules/@metro-labs/xmtp/src/verify.ts +19 -5
- package/runtime/node_modules/@metro-labs/xmtp/src/wire.ts +14 -4
- package/runtime/runtime.json +1 -1
- package/runtime/server.ts +1 -0
- package/runtime/stations.json +37 -0
- package/dist/prompt.js +0 -10
- package/dist/store.js +0 -70
- package/runtime/node_modules/@metro-labs/discord/src/station.ts +0 -19
- package/runtime/node_modules/@metro-labs/discord/src/voice-speak.ts +0 -195
- package/runtime/node_modules/@metro-labs/discord/src/voice-transcribe.ts +0 -292
- package/runtime/node_modules/@metro-labs/discord/src/voice.ts +0 -197
- package/runtime/node_modules/@metro-labs/discord/src/wire.ts +0 -5
- package/runtime/node_modules/@metro-labs/mcp/package.json +0 -66
- package/runtime/node_modules/@metro-labs/mcp/src/channels/dedupe.ts +0 -24
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/account-api.ts +0 -311
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/agent-api.ts +0 -335
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/api-http.ts +0 -129
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/boot.ts +0 -322
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/cli-pair-api.ts +0 -111
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/cli-pair.ts +0 -20
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/collection-api.ts +0 -202
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-json.ts +0 -31
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-tools.ts +0 -100
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-url.ts +0 -57
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-verify.ts +0 -333
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/google-auth.ts +0 -164
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/google-oauth.ts +0 -208
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/identity.ts +0 -79
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/oauth-pending.ts +0 -65
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/pair-codes.ts +0 -58
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/project-api.ts +0 -214
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/run-api.ts +0 -125
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/run-pair.ts +0 -18
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/runtime-source.ts +0 -105
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/session-apis.ts +0 -41
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/session.ts +0 -218
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/tunnel.ts +0 -169
- package/runtime/node_modules/@metro-labs/mcp/src/db/account-attach.ts +0 -91
- package/runtime/node_modules/@metro-labs/mcp/src/db/agent-admin.ts +0 -215
- package/runtime/node_modules/@metro-labs/mcp/src/db/client.ts +0 -37
- package/runtime/node_modules/@metro-labs/mcp/src/db/connector-collections.ts +0 -218
- package/runtime/node_modules/@metro-labs/mcp/src/db/connectors.ts +0 -329
- package/runtime/node_modules/@metro-labs/mcp/src/db/materialize.ts +0 -364
- package/runtime/node_modules/@metro-labs/mcp/src/db/projects.ts +0 -300
- package/runtime/node_modules/@metro-labs/mcp/src/db/runtime-admin.ts +0 -31
- package/runtime/node_modules/@metro-labs/mcp/src/db/runtimes.ts +0 -105
- package/runtime/node_modules/@metro-labs/mcp/src/db/schema.ts +0 -131
- package/runtime/node_modules/@metro-labs/mcp/src/db/token-carry.ts +0 -45
- package/runtime/node_modules/@metro-labs/mcp/src/db/users.ts +0 -57
- package/runtime/node_modules/@metro-labs/mcp/src/db/whatsapp-login.ts +0 -18
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/channel-owner.ts +0 -29
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/frame-scope.ts +0 -21
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/permission-relay.ts +0 -66
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/request-identity.ts +0 -73
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/session-registry.ts +0 -172
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/session-route.ts +0 -43
- package/runtime/node_modules/@metro-labs/mcp/src/monitor/api.ts +0 -240
- package/runtime/node_modules/@metro-labs/mcp/src/server.ts +0 -2
- package/runtime/node_modules/@metro-labs/mcp/src/stations/account-store.ts +0 -80
- package/runtime/node_modules/@metro-labs/mcp/src/stations/messaging-normalize.ts +0 -88
- package/runtime/node_modules/@metro-labs/telegram/src/wire.ts +0 -3
- package/runtime/node_modules/@metro-labs/telegram-user/src/accounts.ts +0 -81
- package/runtime/node_modules/@metro-labs/telegram-user/src/actions.ts +0 -254
- package/runtime/node_modules/@metro-labs/telegram-user/src/attachments.ts +0 -87
- package/runtime/node_modules/@metro-labs/telegram-user/src/format.ts +0 -141
- package/runtime/node_modules/@metro-labs/telegram-user/src/inbound.ts +0 -78
- package/runtime/node_modules/@metro-labs/telegram-user/src/index.ts +0 -46
- package/runtime/node_modules/@metro-labs/telegram-user/src/media-actions.ts +0 -80
- package/runtime/node_modules/@metro-labs/telegram-user/src/members.ts +0 -75
- package/runtime/node_modules/@metro-labs/telegram-user/src/normalize.ts +0 -22
- package/runtime/node_modules/@metro-labs/telegram-user/src/station.ts +0 -24
- package/runtime/node_modules/@metro-labs/telegram-user/src/types.ts +0 -7
- package/runtime/node_modules/@metro-labs/telegram-user/src/wire.ts +0 -1
- package/runtime/node_modules/@metro-labs/whatsapp/src/normalize.ts +0 -22
- package/runtime/node_modules/@metro-labs/whatsapp/src/wire.ts +0 -5
- package/runtime/node_modules/@metro-labs/xmtp/src/actions-push.ts +0 -87
- package/runtime/node_modules/@metro-labs/xmtp/src/emit-core.ts +0 -55
- package/runtime/node_modules/@metro-labs/xmtp/src/push.ts +0 -349
- /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/log.ts +0 -0
- /package/runtime/node_modules/@metro-labs/{mcp/src/mcp → core/src}/str.ts +0 -0
- /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/train-error.ts +0 -0
- /package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/webhook-note.ts +0 -0
- /package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/raw-get-stream.ts +0 -0
- /package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/api-base.ts +0 -0
- /package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/verify.ts +0 -0
- /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → http/src}/api-error.ts +0 -0
- /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → http/src}/cors.ts +0 -0
- /package/runtime/node_modules/@metro-labs/{telegram → telegram-bot}/src/verify.ts +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { errMsg } from '@metro-labs/
|
|
1
|
+
import { errMsg } from '@metro-labs/core/log';
|
|
2
2
|
import { ConsentState, type DecodedMessage } from '@xmtp/node-sdk';
|
|
3
3
|
import {
|
|
4
4
|
accounts,
|
|
@@ -6,10 +6,12 @@ import {
|
|
|
6
6
|
loadAccounts,
|
|
7
7
|
type Account,
|
|
8
8
|
} from './accounts.js';
|
|
9
|
-
import { emitInbound
|
|
9
|
+
import { emitInbound } from '@metro-labs/core/stations/train-events';
|
|
10
|
+
import { announceAccounts } from '@metro-labs/core/stations/train-boot';
|
|
11
|
+
import { envelope } from './emit.js';
|
|
10
12
|
import { groupNameFor } from './conv-helpers.js';
|
|
11
|
-
import {
|
|
12
|
-
import { readCalls } from '@metro-labs/
|
|
13
|
+
import { senderFieldsNow } from './sender.js';
|
|
14
|
+
import { readCalls } from '@metro-labs/core/trains/protocol';
|
|
13
15
|
import { handleCall } from './actions.js';
|
|
14
16
|
|
|
15
17
|
readCalls('xmtp', handleCall);
|
|
@@ -59,21 +61,15 @@ async function handleStreamMessage(
|
|
|
59
61
|
const { id } = acct.cfg;
|
|
60
62
|
if (msg.senderInboxId === acct.client.inboxId) return;
|
|
61
63
|
if (SILENT_TYPES.has(msg.contentType?.typeId ?? '')) return;
|
|
62
|
-
if (handleControlDm(id, msg)) return;
|
|
63
64
|
const conv = await acct.client.conversations.getConversationById(
|
|
64
65
|
msg.conversationId,
|
|
65
66
|
);
|
|
66
67
|
if (!conv) return;
|
|
67
68
|
const env = envelope(id, msg, conv);
|
|
69
|
+
Object.assign(env, senderFieldsNow(acct, msg.senderInboxId));
|
|
68
70
|
const name = await groupNameFor(msg.conversationId, conv);
|
|
69
|
-
if (name)
|
|
70
|
-
env.line_name = name;
|
|
71
|
-
env.lineName = name;
|
|
72
|
-
const p = (env.payload ?? {}) as Record<string, unknown>;
|
|
73
|
-
env.payload = { ...p, lineName: name };
|
|
74
|
-
}
|
|
71
|
+
if (name) env.line_name = name;
|
|
75
72
|
emitInbound(id, env);
|
|
76
|
-
pushInbound(id, env, msg, conv);
|
|
77
73
|
}
|
|
78
74
|
|
|
79
75
|
async function runAccount(acct: Account): Promise<void> {
|
|
@@ -88,7 +84,9 @@ async function runAccount(acct: Account): Promise<void> {
|
|
|
88
84
|
});
|
|
89
85
|
for await (const msg of stream) {
|
|
90
86
|
if (!msg) continue;
|
|
91
|
-
await handleStreamMessage(acct, msg)
|
|
87
|
+
await handleStreamMessage(acct, msg).catch((err: unknown) => {
|
|
88
|
+
process.stderr.write(`xmtp[${id}] one message failed and was skipped: ${errMsg(err)}\n`);
|
|
89
|
+
});
|
|
92
90
|
}
|
|
93
91
|
} catch (err) {
|
|
94
92
|
process.stderr.write(
|
|
@@ -109,13 +107,7 @@ for (const cfg of cfgs) {
|
|
|
109
107
|
);
|
|
110
108
|
}
|
|
111
109
|
}
|
|
112
|
-
|
|
113
|
-
process.stderr.write('xmtp: no accounts booted, exiting\n');
|
|
114
|
-
process.exit(2);
|
|
115
|
-
}
|
|
116
|
-
process.stderr.write(
|
|
117
|
-
`xmtp train ready — ${accounts.size} account(s): ${[...accounts.keys()].join(', ')}\n`,
|
|
118
|
-
);
|
|
110
|
+
announceAccounts('xmtp', accounts.keys());
|
|
119
111
|
|
|
120
112
|
for (const acct of accounts.values())
|
|
121
113
|
runAccount(acct).catch((err: unknown) => {
|
|
@@ -11,7 +11,7 @@ export interface GroupLike {
|
|
|
11
11
|
const MAX_LABELS = 16;
|
|
12
12
|
const MAX_LABEL_LEN = 24;
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
function cleanLabels(raw: unknown): string[] {
|
|
15
15
|
if (!Array.isArray(raw)) return [];
|
|
16
16
|
const out: string[] = [];
|
|
17
17
|
const seen = new Set<string>();
|
|
@@ -41,24 +41,6 @@ function parseAppDataObject(
|
|
|
41
41
|
return {};
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
export function labelsBlob(
|
|
45
|
-
existingAppData: string | undefined,
|
|
46
|
-
labels: string[],
|
|
47
|
-
github?: string,
|
|
48
|
-
): string {
|
|
49
|
-
const existing = parseAppDataObject(existingAppData);
|
|
50
|
-
const blob: Record<string, unknown> = {
|
|
51
|
-
...existing,
|
|
52
|
-
v: 1,
|
|
53
|
-
labels: cleanLabels(labels),
|
|
54
|
-
};
|
|
55
|
-
if (typeof github === 'string') {
|
|
56
|
-
if (github.trim()) blob.github = github.trim();
|
|
57
|
-
else delete blob.github;
|
|
58
|
-
}
|
|
59
|
-
return JSON.stringify(blob);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
44
|
function trimmedString(v: unknown): string | undefined {
|
|
63
45
|
return typeof v === 'string' && v.trim() ? v.trim() : undefined;
|
|
64
46
|
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { TrainError } from '@metro-labs/core/train-error';
|
|
2
|
+
|
|
3
|
+
export const STAGE_NAMES_PARENT = 'stage.base.eth';
|
|
4
|
+
export const STAGE_PROXY = 'https://proxy.stage.box';
|
|
5
|
+
const LABEL_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
6
|
+
const MIN = 6;
|
|
7
|
+
const MAX = 32;
|
|
8
|
+
const HEADERS = { 'content-type': 'application/json', 'x-stage-client': '1' };
|
|
9
|
+
|
|
10
|
+
export const proxyBase = (): string => process.env.METRO_STAGE_PROXY ?? STAGE_PROXY;
|
|
11
|
+
|
|
12
|
+
export const stageNameOf = (label: string): string => `${label}.${STAGE_NAMES_PARENT}`;
|
|
13
|
+
|
|
14
|
+
export function parseLabel(raw: unknown): string {
|
|
15
|
+
const label = typeof raw === 'string' ? raw.trim().toLowerCase() : '';
|
|
16
|
+
if (label.length < MIN) throw new TrainError('bad_request', `a name needs at least ${String(MIN)} characters`);
|
|
17
|
+
if (label.length > MAX) throw new TrainError('bad_request', `a name can have at most ${String(MAX)} characters`);
|
|
18
|
+
if (!LABEL_RE.test(label)) throw new TrainError('bad_request', 'a name is lowercase letters, digits and single inner hyphens');
|
|
19
|
+
return label;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const claimMessage = (label: string, address: string, issuedAt: number): string =>
|
|
23
|
+
`Claim ${stageNameOf(label)} for ${address.toLowerCase()} at ${String(issuedAt)}`;
|
|
24
|
+
|
|
25
|
+
async function ask(path: string, init: RequestInit, fetchImpl: typeof fetch): Promise<Record<string, unknown>> {
|
|
26
|
+
let res: Response;
|
|
27
|
+
try {
|
|
28
|
+
res = await fetchImpl(`${proxyBase()}/names/${path}`, { ...init, headers: HEADERS, signal: AbortSignal.timeout(30_000) });
|
|
29
|
+
} catch (err) {
|
|
30
|
+
throw new TrainError('names_unreachable', `could not reach the stage name service: ${err instanceof Error ? err.message : String(err)}`);
|
|
31
|
+
}
|
|
32
|
+
const body: unknown = await res.json().catch(() => null);
|
|
33
|
+
const record = typeof body === 'object' && body !== null ? (body as Record<string, unknown>) : {};
|
|
34
|
+
if (!res.ok) throw new TrainError('names_refused', typeof record.error === 'string' ? record.error : `the stage name service answered ${String(res.status)}`);
|
|
35
|
+
return record;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export async function nameOf(address: string, fetchImpl: typeof fetch = fetch): Promise<string | null> {
|
|
39
|
+
const body = await ask(`status?address=${encodeURIComponent(address)}`, {}, fetchImpl);
|
|
40
|
+
return typeof body.name === 'string' && body.name !== '' ? body.name : null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export async function checkLabel(label: string, fetchImpl: typeof fetch = fetch): Promise<void> {
|
|
44
|
+
const body = await ask(`check?label=${encodeURIComponent(label)}`, {}, fetchImpl);
|
|
45
|
+
if (body.valid !== true) throw new TrainError('bad_request', typeof body.reason === 'string' ? body.reason : `${stageNameOf(label)} is not a valid name`);
|
|
46
|
+
if (body.available !== true) throw new TrainError('name_taken', `${stageNameOf(label)} is already taken`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function claimName(
|
|
50
|
+
label: string,
|
|
51
|
+
address: string,
|
|
52
|
+
sign: (message: string) => Promise<string>,
|
|
53
|
+
fetchImpl: typeof fetch = fetch,
|
|
54
|
+
now = Date.now(),
|
|
55
|
+
): Promise<string> {
|
|
56
|
+
await checkLabel(label, fetchImpl);
|
|
57
|
+
const signature = await sign(claimMessage(label, address, now));
|
|
58
|
+
const body = await ask('claim', { method: 'POST', body: JSON.stringify({ label, address, issuedAt: now, signature }) }, fetchImpl);
|
|
59
|
+
if (typeof body.name !== 'string' || body.name === '') throw new TrainError('names_refused', 'the stage name service issued no name');
|
|
60
|
+
return body.name;
|
|
61
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { encodeFunctionData, encodePacked, keccak256, namehash, stringToBytes, type Hex } from 'viem';
|
|
3
|
+
import { normalize } from 'viem/ens';
|
|
4
|
+
import { TrainError } from '@metro-labs/core/train-error';
|
|
5
|
+
import {
|
|
6
|
+
assertImage,
|
|
7
|
+
fieldsOf,
|
|
8
|
+
parseProfileChange,
|
|
9
|
+
type ProfileApplied,
|
|
10
|
+
type ProfileAvatar,
|
|
11
|
+
type ProfileChange,
|
|
12
|
+
} from '@metro-labs/core/stations/profile';
|
|
13
|
+
import { accountForCall } from './accounts.js';
|
|
14
|
+
import { claimName, nameOf, parseLabel } from './names.js';
|
|
15
|
+
import { sendSponsored, type SmartAccount } from './smart.js';
|
|
16
|
+
import { respond } from '@metro-labs/core/stations/station-runtime';
|
|
17
|
+
|
|
18
|
+
export const BASENAME_REGISTRY = '0xB94704422c2a1E396835A571837Aa5AE53285a95' as const;
|
|
19
|
+
export const BASENAME_L2_RESOLVER = '0xC6d566A56A1aFf6508b41f6c90ff131615583BCD' as const;
|
|
20
|
+
export const BASENAME_REVERSE_REGISTRAR = '0x79EA96012eEa67A83431F1701B3dFf7e37F9E282' as const;
|
|
21
|
+
export const PINEAPPLE_UPLOAD_URL = 'https://pineapple.fyi/upload';
|
|
22
|
+
const STAMP_CLEAR_URL = 'https://stamp.fyi/clear/';
|
|
23
|
+
const ZERO = '0x0000000000000000000000000000000000000000';
|
|
24
|
+
const TEXT_KEYS = { name: 'name', bio: 'description', avatar: 'avatar' } as const;
|
|
25
|
+
|
|
26
|
+
export const REGISTRY_ABI = [
|
|
27
|
+
{ name: 'resolver', type: 'function', stateMutability: 'view', inputs: [{ name: 'node', type: 'bytes32' }], outputs: [{ name: '', type: 'address' }] },
|
|
28
|
+
] as const;
|
|
29
|
+
|
|
30
|
+
const RESOLVER_ABI = [
|
|
31
|
+
{
|
|
32
|
+
name: 'setText',
|
|
33
|
+
type: 'function',
|
|
34
|
+
stateMutability: 'nonpayable',
|
|
35
|
+
inputs: [{ name: 'node', type: 'bytes32' }, { name: 'key', type: 'string' }, { name: 'value', type: 'string' }],
|
|
36
|
+
outputs: [],
|
|
37
|
+
},
|
|
38
|
+
{ name: 'multicall', type: 'function', stateMutability: 'nonpayable', inputs: [{ name: 'data', type: 'bytes[]' }], outputs: [{ name: 'results', type: 'bytes[]' }] },
|
|
39
|
+
] as const;
|
|
40
|
+
|
|
41
|
+
const REVERSE_ABI = [
|
|
42
|
+
{ name: 'setName', type: 'function', stateMutability: 'nonpayable', inputs: [{ name: 'name', type: 'string' }], outputs: [{ name: '', type: 'bytes32' }] },
|
|
43
|
+
] as const;
|
|
44
|
+
|
|
45
|
+
export const NAME_ABI = [
|
|
46
|
+
{ name: 'name', type: 'function', stateMutability: 'view', inputs: [{ name: 'node', type: 'bytes32' }], outputs: [{ name: '', type: 'string' }] },
|
|
47
|
+
] as const;
|
|
48
|
+
|
|
49
|
+
const BASE_REVERSE_ROOT = namehash('80002105.reverse');
|
|
50
|
+
|
|
51
|
+
type Args = Record<string, unknown>;
|
|
52
|
+
|
|
53
|
+
const NO_NAME = 'this XMTP account has no name yet, so it has no profile: claim a <label>.stage.base.eth name on its channel page first';
|
|
54
|
+
const NOT_SMART = 'this XMTP account was attached before names existed and cannot hold one; attach XMTP again to get an account that can';
|
|
55
|
+
|
|
56
|
+
export async function pinAvatar(avatar: ProfileAvatar, fetchImpl: typeof fetch = fetch): Promise<string> {
|
|
57
|
+
assertImage(avatar);
|
|
58
|
+
const form = new FormData();
|
|
59
|
+
form.append('file', new Blob([await readFile(avatar.path)], { type: avatar.mime }), avatar.name);
|
|
60
|
+
const res = await fetchImpl(PINEAPPLE_UPLOAD_URL, { method: 'POST', body: form, signal: AbortSignal.timeout(60_000) });
|
|
61
|
+
const body = (await res.json().catch(() => ({}))) as { result?: { cid?: string }; error?: { message?: string } };
|
|
62
|
+
if (!res.ok) throw new TrainError('avatar_upload', `the image upload answered ${String(res.status)}`);
|
|
63
|
+
if (typeof body.error?.message === 'string') throw new TrainError('avatar_upload', body.error.message);
|
|
64
|
+
if (typeof body.result?.cid !== 'string' || body.result.cid === '') throw new TrainError('avatar_upload', 'the image upload returned no CID');
|
|
65
|
+
return `ipfs://${body.result.cid}`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export const encodePrimaryName = (name: string): Hex => encodeFunctionData({ abi: REVERSE_ABI, functionName: 'setName', args: [name] });
|
|
69
|
+
|
|
70
|
+
export const reverseNodeOf = (address: string): Hex =>
|
|
71
|
+
keccak256(encodePacked(['bytes32', 'bytes32'], [BASE_REVERSE_ROOT, keccak256(stringToBytes(address.slice(2).toLowerCase()))]));
|
|
72
|
+
|
|
73
|
+
async function resolverOf(smart: SmartAccount, node: Hex): Promise<Hex> {
|
|
74
|
+
const found: Hex = await smart.publicClient.readContract({ address: BASENAME_REGISTRY, abi: REGISTRY_ABI, functionName: 'resolver', args: [node] });
|
|
75
|
+
return found === ZERO ? BASENAME_L2_RESOLVER : found;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export async function primaryNameOf(smart: SmartAccount): Promise<string | null> {
|
|
79
|
+
const node = reverseNodeOf(smart.address);
|
|
80
|
+
const found = await smart.publicClient.readContract({ address: await resolverOf(smart, node), abi: NAME_ABI, functionName: 'name', args: [node] }).catch(() => '');
|
|
81
|
+
return found === '' ? null : found;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export async function setPrimaryName(smart: SmartAccount, name: string): Promise<boolean> {
|
|
85
|
+
try {
|
|
86
|
+
await sendSponsored(smart, BASENAME_REVERSE_REGISTRAR, encodePrimaryName(name));
|
|
87
|
+
return true;
|
|
88
|
+
} catch (err) {
|
|
89
|
+
process.stderr.write(`xmtp: the name ${name} is claimed but not set as the primary name of ${smart.address}: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function encodeTextRecords(name: string, records: Record<string, string>): Hex {
|
|
95
|
+
const node = namehash(normalize(name));
|
|
96
|
+
const calls = Object.entries(records).map(([key, value]) => encodeFunctionData({ abi: RESOLVER_ABI, functionName: 'setText', args: [node, key, value] }));
|
|
97
|
+
return encodeFunctionData({ abi: RESOLVER_ABI, functionName: 'multicall', args: [calls] });
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const resolverFor = (smart: SmartAccount, name: string): Promise<Hex> => resolverOf(smart, namehash(normalize(name)));
|
|
101
|
+
|
|
102
|
+
async function recordsFor(change: ProfileChange, fetchImpl: typeof fetch): Promise<Record<string, string>> {
|
|
103
|
+
const records: Record<string, string> = {};
|
|
104
|
+
if (change.name !== undefined) records[TEXT_KEYS.name] = change.name;
|
|
105
|
+
if (change.bio !== undefined) records[TEXT_KEYS.bio] = change.bio;
|
|
106
|
+
if (change.avatar !== undefined) records[TEXT_KEYS.avatar] = await pinAvatar(change.avatar, fetchImpl);
|
|
107
|
+
return records;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export async function writeProfile(smart: SmartAccount, name: string, change: ProfileChange, fetchImpl: typeof fetch = fetch): Promise<Hex> {
|
|
111
|
+
const records = await recordsFor(change, fetchImpl);
|
|
112
|
+
const hash = await sendSponsored(smart, await resolverFor(smart, name), encodeTextRecords(name, records));
|
|
113
|
+
const id = smart.address.toLowerCase();
|
|
114
|
+
await Promise.all([fetchImpl(`${STAMP_CLEAR_URL}address/${id}`), fetchImpl(`${STAMP_CLEAR_URL}avatar/eth:${id}`)]).catch(() => undefined);
|
|
115
|
+
return hash;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const smartOf = (args: Args): { accountId: string; address: string; smart: SmartAccount } => {
|
|
119
|
+
const acct = accountForCall(args);
|
|
120
|
+
if (acct.smart === null) throw new TrainError('no_name', NOT_SMART);
|
|
121
|
+
return { accountId: acct.cfg.id, address: acct.address, smart: acct.smart };
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export async function setProfile(id: string, args: Args): Promise<void> {
|
|
125
|
+
const { accountId, address, smart } = smartOf(args);
|
|
126
|
+
const change = parseProfileChange(args);
|
|
127
|
+
const name = await nameOf(address);
|
|
128
|
+
if (name === null) throw new TrainError('no_name', NO_NAME);
|
|
129
|
+
const tx = await writeProfile(smart, name, change);
|
|
130
|
+
const result: ProfileApplied & { name: string; tx: string } = { account: accountId, applied: fieldsOf(change), name, tx };
|
|
131
|
+
respond(id, { result });
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export async function claimNameAction(id: string, args: Args): Promise<void> {
|
|
135
|
+
const { accountId, address, smart } = smartOf(args);
|
|
136
|
+
const held = await nameOf(address);
|
|
137
|
+
if (held !== null) throw new TrainError('name_held', `this account already holds ${held}`);
|
|
138
|
+
const name = await claimName(parseLabel(args.label), address, (message) => smart.signMessage(message));
|
|
139
|
+
const primary = await setPrimaryName(smart, name);
|
|
140
|
+
respond(id, { result: { account: accountId, name, primary } });
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export async function ensurePrimaryName(smart: SmartAccount, name: string): Promise<boolean> {
|
|
144
|
+
if ((await primaryNameOf(smart)) === name) return true;
|
|
145
|
+
return setPrimaryName(smart, name);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export async function nameAction(id: string, args: Args): Promise<void> {
|
|
149
|
+
const acct = accountForCall(args);
|
|
150
|
+
const name = acct.smart === null ? null : await nameOf(acct.address);
|
|
151
|
+
const primary = acct.smart !== null && name !== null ? await ensurePrimaryName(acct.smart, name) : false;
|
|
152
|
+
respond(id, { result: { account: acct.cfg.id, name, primary, canClaim: acct.smart !== null && name === null } });
|
|
153
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { createPublicClient, http, namehash, type Hex } from 'viem';
|
|
2
|
+
import { base } from 'viem/chains';
|
|
3
|
+
import { normalize } from 'viem/ens';
|
|
4
|
+
import { makeProfileCache, type SenderProfile as Profile } from '@metro-labs/core/stations/sender-profile';
|
|
5
|
+
import { respond } from '@metro-labs/core/stations/station-runtime';
|
|
6
|
+
import { TrainError } from '@metro-labs/core/train-error';
|
|
7
|
+
import { accountForCall, accounts, type Account } from './accounts.js';
|
|
8
|
+
import { resolveAddresses } from './conv-helpers.js';
|
|
9
|
+
import { nameOf } from './names.js';
|
|
10
|
+
import { BASENAME_L2_RESOLVER, BASENAME_REGISTRY, NAME_ABI, REGISTRY_ABI, reverseNodeOf } from './profile.js';
|
|
11
|
+
|
|
12
|
+
export interface SenderProfile {
|
|
13
|
+
address: string;
|
|
14
|
+
name: string | null;
|
|
15
|
+
displayName: string | null;
|
|
16
|
+
about: string | null;
|
|
17
|
+
avatar: string | null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const BASE_RPC = 'https://rpc.brovider.xyz/8453';
|
|
21
|
+
const ZERO = '0x0000000000000000000000000000000000000000';
|
|
22
|
+
const AVATAR_RE = /^(https?:\/\/|ipfs:\/\/|data:image\/)/i;
|
|
23
|
+
|
|
24
|
+
const TEXT_ABI = [
|
|
25
|
+
{ name: 'addr', type: 'function', stateMutability: 'view', inputs: [{ name: 'node', type: 'bytes32' }], outputs: [{ name: '', type: 'address' }] },
|
|
26
|
+
{
|
|
27
|
+
name: 'text',
|
|
28
|
+
type: 'function',
|
|
29
|
+
stateMutability: 'view',
|
|
30
|
+
inputs: [{ name: 'node', type: 'bytes32' }, { name: 'key', type: 'string' }],
|
|
31
|
+
outputs: [{ name: '', type: 'string' }],
|
|
32
|
+
},
|
|
33
|
+
] as const;
|
|
34
|
+
|
|
35
|
+
export const baseRpc = (): string => process.env.METRO_BASE_RPC ?? BASE_RPC;
|
|
36
|
+
|
|
37
|
+
const makeReader = (rpc: string) => createPublicClient({ chain: base, transport: http(rpc), batch: { multicall: true } });
|
|
38
|
+
|
|
39
|
+
export type Reader = ReturnType<typeof makeReader>;
|
|
40
|
+
|
|
41
|
+
let reader: Reader | null = null;
|
|
42
|
+
const readerFor = (): Reader => (reader ??= makeReader(baseRpc()));
|
|
43
|
+
|
|
44
|
+
const trimmed = (v: string): string | null => (v.trim() === '' ? null : v.trim());
|
|
45
|
+
|
|
46
|
+
async function resolverOf(client: Reader, node: Hex): Promise<Hex> {
|
|
47
|
+
const found: Hex = await client.readContract({ address: BASENAME_REGISTRY, abi: REGISTRY_ABI, functionName: 'resolver', args: [node] });
|
|
48
|
+
return found === ZERO ? BASENAME_L2_RESOLVER : found;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function primaryName(client: Reader, address: string): Promise<string | null> {
|
|
52
|
+
const node = reverseNodeOf(address);
|
|
53
|
+
const found = await client.readContract({ address: await resolverOf(client, node), abi: NAME_ABI, functionName: 'name', args: [node] });
|
|
54
|
+
return found === '' ? null : found;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function recordsOf(client: Reader, name: string, address: string): Promise<SenderProfile | null> {
|
|
58
|
+
const node = namehash(normalize(name));
|
|
59
|
+
const resolver = { address: await resolverOf(client, node), abi: TEXT_ABI } as const;
|
|
60
|
+
const text = (key: string): Promise<string> => client.readContract({ ...resolver, functionName: 'text', args: [node, key] });
|
|
61
|
+
const [forward, displayName, about, avatar] = await Promise.all([
|
|
62
|
+
client.readContract({ ...resolver, functionName: 'addr', args: [node] }),
|
|
63
|
+
text('name'),
|
|
64
|
+
text('description'),
|
|
65
|
+
text('avatar'),
|
|
66
|
+
]);
|
|
67
|
+
if (forward.toLowerCase() !== address.toLowerCase()) return null;
|
|
68
|
+
return { address, name, displayName: trimmed(displayName), about: trimmed(about), avatar: AVATAR_RE.test(avatar.trim()) ? avatar.trim() : null };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export async function profileOf(address: string, client: Reader = readerFor(), fetchImpl: typeof fetch = fetch): Promise<SenderProfile> {
|
|
72
|
+
const bare: SenderProfile = { address, name: null, displayName: null, about: null, avatar: null };
|
|
73
|
+
const name = (await primaryName(client, address)) ?? (await nameOf(address, fetchImpl));
|
|
74
|
+
if (name === null) return bare;
|
|
75
|
+
return (await recordsOf(client, name, address)) ?? bare;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const key = (acct: Account, inboxId: string): string => `${acct.cfg.id}:${inboxId}`;
|
|
79
|
+
|
|
80
|
+
const senders = makeProfileCache<SenderProfile>(
|
|
81
|
+
async (k) => {
|
|
82
|
+
const [accountId, inboxId] = k.split(':', 2) as [string, string];
|
|
83
|
+
const acct = accounts.get(accountId);
|
|
84
|
+
if (acct === undefined) return null;
|
|
85
|
+
const address = (await resolveAddresses(acct, [inboxId]))[inboxId];
|
|
86
|
+
return address === undefined ? null : profileOf(address);
|
|
87
|
+
},
|
|
88
|
+
{ onError: (k, err) => process.stderr.write(`xmtp: could not resolve the sender ${k}: ${err instanceof Error ? err.message : String(err)}\n`) },
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
export const senderFields = (p: SenderProfile | null): Record<string, string> =>
|
|
92
|
+
p === null ? {} : { from_name: p.name ?? p.address, ...(p.displayName === null ? {} : { from_display_name: p.displayName }) };
|
|
93
|
+
|
|
94
|
+
export const senderFieldsNow = (acct: Account, inboxId: string): Record<string, string> => senderFields(senders.peek(key(acct, inboxId)));
|
|
95
|
+
|
|
96
|
+
export const senderProfile = (acct: Account, inboxId: string): Promise<SenderProfile | null> => senders.get(key(acct, inboxId));
|
|
97
|
+
|
|
98
|
+
export const profileView = (inboxId: string, p: SenderProfile | null): Profile => ({
|
|
99
|
+
id: inboxId,
|
|
100
|
+
...(p === null ? {} : { address: p.address }),
|
|
101
|
+
...(p?.name == null ? {} : { name: p.name }),
|
|
102
|
+
...(p?.displayName == null ? {} : { display_name: p.displayName }),
|
|
103
|
+
...(p?.about == null ? {} : { about: p.about }),
|
|
104
|
+
...(p?.avatar == null ? {} : { avatar: p.avatar }),
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
export async function profileAction(id: string, args: Record<string, unknown>): Promise<void> {
|
|
108
|
+
const user = typeof args.user === 'string' ? args.user.trim() : '';
|
|
109
|
+
if (user === '') throw new TrainError('xmtp_user_required', 'profile needs the inbox id of the person', { retryable: false });
|
|
110
|
+
const acct = accountForCall({ account: typeof args.account === 'string' ? args.account : undefined });
|
|
111
|
+
respond(id, { result: profileView(user, await senderProfile(acct, user)) });
|
|
112
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { createPublicClient, http, type Hex } from 'viem';
|
|
2
|
+
import { privateKeyToAccount } from 'viem/accounts';
|
|
3
|
+
import { base } from 'viem/chains';
|
|
4
|
+
import {
|
|
5
|
+
createKernelAccount,
|
|
6
|
+
createKernelAccountClient,
|
|
7
|
+
createZeroDevPaymasterClient,
|
|
8
|
+
getUserOperationGasPrice,
|
|
9
|
+
type KernelAccountClient,
|
|
10
|
+
} from '@zerodev/sdk';
|
|
11
|
+
import { getEntryPoint, KERNEL_V3_1 } from '@zerodev/sdk/constants';
|
|
12
|
+
import { signerToEcdsaValidator } from '@zerodev/ecdsa-validator';
|
|
13
|
+
|
|
14
|
+
export const SMART_CHAIN_ID = 8453;
|
|
15
|
+
const STAGE_ZERODEV_PROJECT = 'c107f734-f7bb-48c1-a5d2-ceb3f70a42f6';
|
|
16
|
+
const ENTRY_POINT = getEntryPoint('0.7');
|
|
17
|
+
|
|
18
|
+
export const zerodevRpc = (): string =>
|
|
19
|
+
`https://rpc.zerodev.app/api/v3/${process.env.METRO_ZERODEV_PROJECT ?? STAGE_ZERODEV_PROJECT}/chain/${String(SMART_CHAIN_ID)}`;
|
|
20
|
+
|
|
21
|
+
export const makePublicClient = (rpc: string) => createPublicClient({ chain: base, transport: http(rpc) });
|
|
22
|
+
|
|
23
|
+
export type BaseClient = ReturnType<typeof makePublicClient>;
|
|
24
|
+
|
|
25
|
+
export interface SmartAccount {
|
|
26
|
+
address: Hex;
|
|
27
|
+
publicClient: BaseClient;
|
|
28
|
+
client: () => KernelAccountClient;
|
|
29
|
+
signMessage: (message: string) => Promise<Hex>;
|
|
30
|
+
deployed: () => Promise<boolean>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function smartAccountFor(privateKey: string, rpc = zerodevRpc()): Promise<SmartAccount> {
|
|
34
|
+
const owner = privateKeyToAccount(privateKey as Hex);
|
|
35
|
+
const publicClient = makePublicClient(rpc);
|
|
36
|
+
const validator = await signerToEcdsaValidator(publicClient, { signer: owner, entryPoint: ENTRY_POINT, kernelVersion: KERNEL_V3_1 });
|
|
37
|
+
const account = await createKernelAccount(publicClient, { plugins: { sudo: validator }, entryPoint: ENTRY_POINT, kernelVersion: KERNEL_V3_1, index: 0n });
|
|
38
|
+
const paymaster = createZeroDevPaymasterClient({ chain: base, transport: http(rpc) });
|
|
39
|
+
const client = (): KernelAccountClient =>
|
|
40
|
+
createKernelAccountClient({
|
|
41
|
+
account,
|
|
42
|
+
chain: base,
|
|
43
|
+
bundlerTransport: http(rpc),
|
|
44
|
+
client: publicClient,
|
|
45
|
+
paymaster: { getPaymasterData: (userOperation) => paymaster.sponsorUserOperation({ userOperation }) },
|
|
46
|
+
userOperation: { estimateFeesPerGas: ({ bundlerClient }) => getUserOperationGasPrice(bundlerClient) },
|
|
47
|
+
});
|
|
48
|
+
return {
|
|
49
|
+
address: account.address,
|
|
50
|
+
publicClient,
|
|
51
|
+
client,
|
|
52
|
+
signMessage: (message) => account.signMessage({ message }),
|
|
53
|
+
deployed: async () => {
|
|
54
|
+
const code = await publicClient.getCode({ address: account.address });
|
|
55
|
+
return code !== undefined && code !== '0x';
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export async function sendSponsored(smart: SmartAccount, to: Hex, data: Hex): Promise<Hex> {
|
|
61
|
+
const client = smart.client();
|
|
62
|
+
const hash = await client.sendTransaction({ to, data, value: 0n } as Parameters<typeof client.sendTransaction>[0]);
|
|
63
|
+
const receipt = await smart.publicClient.waitForTransactionReceipt({ hash });
|
|
64
|
+
if (receipt.status !== 'success') throw new Error(`the Base transaction ${hash} reverted`);
|
|
65
|
+
return hash;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export async function ensureDeployed(smart: SmartAccount): Promise<boolean> {
|
|
69
|
+
if (await smart.deployed()) return false;
|
|
70
|
+
await sendSponsored(smart, smart.address, '0x');
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { GroupOp, Station, Verb } from '@metro-labs/
|
|
1
|
+
import type { GroupOp, Station, Verb } from '@metro-labs/core/stations/types';
|
|
2
|
+
import { PROFILE_FIELDS, type ProfileField } from '@metro-labs/core/stations/profile';
|
|
2
3
|
import { XMTP_TOOLS, xmtpSendAttachments } from './tools.js';
|
|
3
4
|
|
|
4
5
|
export const xmtpStation: Station = {
|
|
@@ -8,6 +9,9 @@ export const xmtpStation: Station = {
|
|
|
8
9
|
messageVerbs: new Set<Verb>(['send', 'reply', 'react', 'unreact', 'read']),
|
|
9
10
|
groupOps: new Set<GroupOp>(['create_group', 'add_members', 'remove_members']),
|
|
10
11
|
attachmentMode: 'native',
|
|
12
|
+
profileFields: new Set<ProfileField>(PROFILE_FIELDS),
|
|
13
|
+
readsProfiles: true,
|
|
14
|
+
claimsName: true,
|
|
11
15
|
sendAttachments: xmtpSendAttachments,
|
|
12
16
|
tools: XMTP_TOOLS,
|
|
13
17
|
};
|
|
@@ -1,61 +1,14 @@
|
|
|
1
|
-
import type { CanonicalAttachment, ToolContext } from '@metro-labs/
|
|
2
|
-
import { TrainError } from '@metro-labs/
|
|
1
|
+
import type { CanonicalAttachment, ToolContext } from '@metro-labs/core/stations/types';
|
|
2
|
+
import { TrainError } from '@metro-labs/core/train-error';
|
|
3
3
|
import {
|
|
4
4
|
guessMime,
|
|
5
5
|
isImageMime,
|
|
6
6
|
isImageExt,
|
|
7
7
|
kindOf,
|
|
8
|
-
} from '@metro-labs/
|
|
8
|
+
} from '@metro-labs/core/stations/attachments';
|
|
9
9
|
|
|
10
10
|
export const str = (v: unknown): string => (typeof v === 'string' ? v : '');
|
|
11
11
|
|
|
12
|
-
function strList(value: unknown): string[] {
|
|
13
|
-
return (value as unknown[] | undefined)?.map(String).filter(Boolean) ?? [];
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
interface CreatedGroup {
|
|
17
|
-
line?: string;
|
|
18
|
-
id?: string;
|
|
19
|
-
account?: string;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
async function applyCreateLabels(
|
|
23
|
-
line: string,
|
|
24
|
-
labels: string[],
|
|
25
|
-
ctx: ToolContext,
|
|
26
|
-
): Promise<unknown> {
|
|
27
|
-
if (!labels.length) return undefined;
|
|
28
|
-
return ctx.call('updateChannelMeta', { line, appData: { labels } });
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export async function createChannel(
|
|
32
|
-
a: Record<string, unknown>,
|
|
33
|
-
ctx: ToolContext,
|
|
34
|
-
) {
|
|
35
|
-
const addresses = strList(a.addresses);
|
|
36
|
-
const channelName = str(a.name);
|
|
37
|
-
const labels = strList(a.labels);
|
|
38
|
-
const account = str(a.account) || undefined;
|
|
39
|
-
if (!addresses.length)
|
|
40
|
-
return ctx.err('create_channel requires a non-empty `addresses` array');
|
|
41
|
-
if (!channelName) return ctx.err('create_channel requires `name`');
|
|
42
|
-
const groupArgs: Record<string, unknown> = { addresses, name: channelName };
|
|
43
|
-
if (account) groupArgs.account = account;
|
|
44
|
-
const { result } = (await ctx.call('newGroup', groupArgs)) as {
|
|
45
|
-
result: CreatedGroup | null;
|
|
46
|
-
};
|
|
47
|
-
const newLine = result?.line ?? '';
|
|
48
|
-
const labelResult = newLine.length
|
|
49
|
-
? await applyCreateLabels(newLine, labels, ctx)
|
|
50
|
-
: undefined;
|
|
51
|
-
return ctx.okJson({
|
|
52
|
-
line: newLine,
|
|
53
|
-
convId: result?.id,
|
|
54
|
-
account: result?.account,
|
|
55
|
-
labels: labelResult,
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
|
|
59
12
|
export async function setChannelMetadata(
|
|
60
13
|
a: Record<string, unknown>,
|
|
61
14
|
ctx: ToolContext,
|
|
@@ -112,7 +65,7 @@ export async function xmtpSendAttachments(
|
|
|
112
65
|
): Promise<string[]> {
|
|
113
66
|
const sent: string[] = [];
|
|
114
67
|
for (const a of atts) {
|
|
115
|
-
const src = a.path ??
|
|
68
|
+
const src = a.path ?? '';
|
|
116
69
|
if (!src) continue;
|
|
117
70
|
const mime = a.mime ?? guessMime(src);
|
|
118
71
|
if (isImageMime(mime) || isImageExt(src)) {
|