From a0c3339c757ba0e2fc82ee687555a02372464752 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Thu, 19 Feb 2026 12:52:18 -0600 Subject: [PATCH] refactor(tlon): simplify probeAccount to direct /~/name request No channel needed - just authenticate and GET /~/name. Removes UrbitChannelClient, keeping only UrbitSSEClient for monitor. --- extensions/tlon/src/channel.ts | 20 ++- extensions/tlon/src/urbit/channel-client.ts | 157 -------------------- 2 files changed, 15 insertions(+), 162 deletions(-) delete mode 100644 extensions/tlon/src/urbit/channel-client.ts diff --git a/extensions/tlon/src/channel.ts b/extensions/tlon/src/channel.ts index c431e2b6621..6b7dd5cc4cb 100644 --- a/extensions/tlon/src/channel.ts +++ b/extensions/tlon/src/channel.ts @@ -17,8 +17,8 @@ import { tlonOnboardingAdapter } from "./onboarding.js"; import { formatTargetHint, normalizeShip, parseTlonTarget } from "./targets.js"; import { resolveTlonAccount, listTlonAccountIds } from "./types.js"; import { authenticate } from "./urbit/auth.js"; -import { UrbitChannelClient } from "./urbit/channel-client.js"; import { ssrfPolicyFromAllowPrivateNetwork } from "./urbit/context.js"; +import { urbitFetch } from "./urbit/fetch.js"; import { buildMediaStory, sendDm, @@ -446,15 +446,25 @@ export const tlonPlugin: ChannelPlugin = { try { const ssrfPolicy = ssrfPolicyFromAllowPrivateNetwork(account.allowPrivateNetwork); const cookie = await authenticate(account.url, account.code, { ssrfPolicy }); - const api = new UrbitChannelClient(account.url, cookie, { - ship: account.ship.replace(/^~/, ""), + // Simple probe - just verify we can reach /~/name + const { response, release } = await urbitFetch({ + baseUrl: account.url, + path: "/~/name", + init: { + method: "GET", + headers: { Cookie: cookie }, + }, ssrfPolicy, + timeoutMs: 30_000, + auditContext: "tlon-probe-account", }); try { - await api.getOurName(); + if (!response.ok) { + return { ok: false, error: `Name request failed: ${response.status}` }; + } return { ok: true }; } finally { - await api.close(); + await release(); } } catch (error) { return { ok: false, error: (error as { message?: string })?.message ?? String(error) }; diff --git a/extensions/tlon/src/urbit/channel-client.ts b/extensions/tlon/src/urbit/channel-client.ts deleted file mode 100644 index fb8af656a6f..00000000000 --- a/extensions/tlon/src/urbit/channel-client.ts +++ /dev/null @@ -1,157 +0,0 @@ -import type { LookupFn, SsrFPolicy } from "openclaw/plugin-sdk"; -import { ensureUrbitChannelOpen, pokeUrbitChannel, scryUrbitPath } from "./channel-ops.js"; -import { getUrbitContext, normalizeUrbitCookie } from "./context.js"; -import { urbitFetch } from "./fetch.js"; - -export type UrbitChannelClientOptions = { - ship?: string; - ssrfPolicy?: SsrFPolicy; - lookupFn?: LookupFn; - fetchImpl?: (input: RequestInfo | URL, init?: RequestInit) => Promise; -}; - -export class UrbitChannelClient { - readonly baseUrl: string; - readonly cookie: string; - readonly ship: string; - readonly ssrfPolicy?: SsrFPolicy; - readonly lookupFn?: LookupFn; - readonly fetchImpl?: (input: RequestInfo | URL, init?: RequestInit) => Promise; - - private channelId: string | null = null; - - constructor(url: string, cookie: string, options: UrbitChannelClientOptions = {}) { - const ctx = getUrbitContext(url, options.ship); - this.baseUrl = ctx.baseUrl; - this.cookie = normalizeUrbitCookie(cookie); - this.ship = ctx.ship; - this.ssrfPolicy = options.ssrfPolicy; - this.lookupFn = options.lookupFn; - this.fetchImpl = options.fetchImpl; - } - - private get channelPath(): string { - const id = this.channelId; - if (!id) { - throw new Error("Channel not opened"); - } - return `/~/channel/${id}`; - } - - async open(): Promise { - if (this.channelId) { - return; - } - - const channelId = `${Math.floor(Date.now() / 1000)}-${Math.random().toString(36).substring(2, 8)}`; - this.channelId = channelId; - - try { - await ensureUrbitChannelOpen( - { - baseUrl: this.baseUrl, - cookie: this.cookie, - ship: this.ship, - channelId, - ssrfPolicy: this.ssrfPolicy, - lookupFn: this.lookupFn, - fetchImpl: this.fetchImpl, - }, - { - createBody: [], - createAuditContext: "tlon-urbit-channel-open", - }, - ); - } catch (error) { - this.channelId = null; - throw error; - } - } - - async poke(params: { app: string; mark: string; json: unknown }): Promise { - await this.open(); - const channelId = this.channelId; - if (!channelId) { - throw new Error("Channel not opened"); - } - return await pokeUrbitChannel( - { - baseUrl: this.baseUrl, - cookie: this.cookie, - ship: this.ship, - channelId, - ssrfPolicy: this.ssrfPolicy, - lookupFn: this.lookupFn, - fetchImpl: this.fetchImpl, - }, - { ...params, auditContext: "tlon-urbit-poke" }, - ); - } - - async scry(path: string): Promise { - return await scryUrbitPath( - { - baseUrl: this.baseUrl, - cookie: this.cookie, - ssrfPolicy: this.ssrfPolicy, - lookupFn: this.lookupFn, - fetchImpl: this.fetchImpl, - }, - { path, auditContext: "tlon-urbit-scry" }, - ); - } - - async getOurName(): Promise { - const { response, release } = await urbitFetch({ - baseUrl: this.baseUrl, - path: "/~/name", - init: { - method: "GET", - headers: { Cookie: this.cookie }, - }, - ssrfPolicy: this.ssrfPolicy, - lookupFn: this.lookupFn, - fetchImpl: this.fetchImpl, - timeoutMs: 30_000, - auditContext: "tlon-urbit-name", - }); - - try { - if (!response.ok) { - throw new Error(`Name request failed: ${response.status}`); - } - const text = await response.text(); - return text.trim(); - } finally { - await release(); - } - } - - async close(): Promise { - if (!this.channelId) { - return; - } - const channelPath = this.channelPath; - this.channelId = null; - - try { - const { response, release } = await urbitFetch({ - baseUrl: this.baseUrl, - path: channelPath, - init: { method: "DELETE", headers: { Cookie: this.cookie } }, - ssrfPolicy: this.ssrfPolicy, - lookupFn: this.lookupFn, - fetchImpl: this.fetchImpl, - timeoutMs: 30_000, - auditContext: "tlon-urbit-channel-close", - }); - try { - void response.body?.cancel(); - } finally { - await release(); - } - } catch { - // ignore cleanup errors - } - } -}