diff --git a/src/canvas-host/a2ui-shared.ts b/src/canvas-host/a2ui-shared.ts new file mode 100644 index 00000000000..ee1897292ef --- /dev/null +++ b/src/canvas-host/a2ui-shared.ts @@ -0,0 +1,72 @@ +import { lowercasePreservingWhitespace } from "../shared/string-coerce.js"; + +export const A2UI_PATH = "/__openclaw__/a2ui"; + +export const CANVAS_HOST_PATH = "/__openclaw__/canvas"; + +export const CANVAS_WS_PATH = "/__openclaw__/ws"; + +export function isA2uiPath(pathname: string): boolean { + return pathname === A2UI_PATH || pathname.startsWith(`${A2UI_PATH}/`); +} + +export function injectCanvasLiveReload(html: string): string { + const snippet = ` + +`.trim(); + + const idx = lowercasePreservingWhitespace(html).lastIndexOf(""); + if (idx >= 0) { + return `${html.slice(0, idx)}\n${snippet}\n${html.slice(idx)}`; + } + return `${html}\n${snippet}\n`; +} diff --git a/src/canvas-host/a2ui.ts b/src/canvas-host/a2ui.ts index f81d20d5bd1..4b5bb5d3c53 100644 --- a/src/canvas-host/a2ui.ts +++ b/src/canvas-host/a2ui.ts @@ -4,13 +4,16 @@ import path from "node:path"; import { fileURLToPath } from "node:url"; import { detectMime } from "../media/mime.js"; import { lowercasePreservingWhitespace } from "../shared/string-coerce.js"; +import { A2UI_PATH, injectCanvasLiveReload, isA2uiPath } from "./a2ui-shared.js"; import { resolveFileWithinRoot } from "./file-resolver.js"; -export const A2UI_PATH = "/__openclaw__/a2ui"; - -export const CANVAS_HOST_PATH = "/__openclaw__/canvas"; - -export const CANVAS_WS_PATH = "/__openclaw__/ws"; +export { + A2UI_PATH, + CANVAS_HOST_PATH, + CANVAS_WS_PATH, + injectCanvasLiveReload, + isA2uiPath, +} from "./a2ui-shared.js"; let cachedA2uiRootReal: string | null | undefined; let resolvingA2uiRoot: Promise | null = null; @@ -79,67 +82,6 @@ async function resolveA2uiRootReal(): Promise { return resolvingA2uiRoot; } -export function injectCanvasLiveReload(html: string): string { - const snippet = ` - -`.trim(); - - const idx = lowercasePreservingWhitespace(html).lastIndexOf(""); - if (idx >= 0) { - return `${html.slice(0, idx)}\n${snippet}\n${html.slice(idx)}`; - } - return `${html}\n${snippet}\n`; -} - export async function handleA2uiHttpRequest( req: IncomingMessage, res: ServerResponse, @@ -150,8 +92,7 @@ export async function handleA2uiHttpRequest( } const url = new URL(urlRaw, "http://localhost"); - const basePath = - url.pathname === A2UI_PATH || url.pathname.startsWith(`${A2UI_PATH}/`) ? A2UI_PATH : undefined; + const basePath = isA2uiPath(url.pathname) ? A2UI_PATH : undefined; if (!basePath) { return false; } diff --git a/src/canvas-host/server.test.ts b/src/canvas-host/server.test.ts index 364b10a83ee..8f6e2ff8ba4 100644 --- a/src/canvas-host/server.test.ts +++ b/src/canvas-host/server.test.ts @@ -9,9 +9,8 @@ import { A2UI_PATH, CANVAS_HOST_PATH, CANVAS_WS_PATH, - handleA2uiHttpRequest, injectCanvasLiveReload, -} from "./a2ui.js"; +} from "./a2ui-shared.js"; type MockWatcher = { on: (event: string, cb: (...args: unknown[]) => void) => MockWatcher; @@ -106,6 +105,7 @@ async function captureHandlerResponse( } async function captureA2uiResponse(url: string, method = "GET"): Promise { + const { handleA2uiHttpRequest } = await import("./a2ui.js"); return await captureHttpResponse(handleA2uiHttpRequest, url, method); } diff --git a/src/canvas-host/server.ts b/src/canvas-host/server.ts index 9e6f84fe1c0..ac69eed01f4 100644 --- a/src/canvas-host/server.ts +++ b/src/canvas-host/server.ts @@ -20,9 +20,9 @@ import { ensureDir, resolveUserPath } from "../utils.js"; import { CANVAS_HOST_PATH, CANVAS_WS_PATH, - handleA2uiHttpRequest, injectCanvasLiveReload, -} from "./a2ui.js"; + isA2uiPath, +} from "./a2ui-shared.js"; import { normalizeUrlPath, resolveFileWithinRoot } from "./file-resolver.js"; type ChokidarWatch = typeof import("chokidar").watch; @@ -469,8 +469,11 @@ export async function startCanvasHost(opts: CanvasHostServerOpts): Promise { - if (await handleA2uiHttpRequest(req, res)) { - return; + if (req.url && isA2uiPath(new URL(req.url, "http://localhost").pathname)) { + const { handleA2uiHttpRequest } = await import("./a2ui.js"); + if (await handleA2uiHttpRequest(req, res)) { + return; + } } if (await handler.handleHttpRequest(req, res)) { return;