docs: document browser route handlers

This commit is contained in:
Peter Steinberger
2026-06-04 07:29:19 -04:00
parent ce56fc176a
commit 7fe6c16f03
6 changed files with 56 additions and 0 deletions

View File

@@ -1,3 +1,9 @@
/**
* Browser agent action route registration and existing-session execution.
*
* Dispatches normalized actions to either Playwright-backed OpenClaw browser
* control or Chrome MCP existing-session operations with navigation guards.
*/
import { formatErrorMessage } from "../../infra/errors.js";
import {
clickChromeMcpElement,
@@ -350,6 +356,7 @@ function getExistingSessionUnsupportedMessage(action: BrowserActRequest): string
throw new Error("Unsupported browser act kind");
}
/** Register browser action endpoints, including hook and download subroutes. */
export function registerBrowserAgentActRoutes(
app: BrowserRouteRegistrar,
ctx: BrowserRouteContext,

View File

@@ -1,3 +1,9 @@
/**
* Browser debug and trace routes.
*
* Exposes console messages, page errors, network requests, dialog state, and
* Playwright tracing scoped to the selected browser tab.
*/
import crypto from "node:crypto";
import path from "node:path";
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
@@ -44,6 +50,7 @@ async function sendPlaywrightDebugCollection(params: {
});
}
/** Register browser debug endpoints on the control server. */
export function registerBrowserAgentDebugRoutes(
app: BrowserRouteRegistrar,
ctx: BrowserRouteContext,

View File

@@ -1,3 +1,9 @@
/**
* Shared browser route helpers.
*
* Centralizes body/query parsing, profile resolution, error mapping, Playwright
* availability checks, and tab-context guards for route modules.
*/
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
import { resolveBrowserNavigationProxyMode } from "../browser-proxy-mode.js";
import { toBrowserErrorResponse } from "../errors.js";
@@ -21,6 +27,7 @@ export const SELECTOR_UNSUPPORTED_MESSAGE = [
"This is more reliable for modern SPAs.",
].join("\n");
/** Return a safe object body for routes that accept JSON payloads. */
export function readBody(req: BrowserRequest): Record<string, unknown> {
const body = req.body as Record<string, unknown> | undefined;
if (!body || typeof body !== "object" || Array.isArray(body)) {
@@ -29,16 +36,19 @@ export function readBody(req: BrowserRequest): Record<string, unknown> {
return body;
}
/** Read an optional targetId from a request body. */
export function resolveTargetIdFromBody(body: Record<string, unknown>): string | undefined {
const targetId = normalizeOptionalString(body.targetId) ?? "";
return targetId || undefined;
}
/** Read an optional targetId from a query object. */
export function resolveTargetIdFromQuery(query: Record<string, unknown>): string | undefined {
const targetId = normalizeOptionalString(query.targetId) ?? "";
return targetId || undefined;
}
/** Map route-level browser errors to HTTP JSON responses. */
export function handleRouteError(ctx: BrowserRouteContext, res: BrowserResponse, err: unknown) {
const mapped = ctx.mapTabError(err);
if (mapped) {
@@ -51,6 +61,7 @@ export function handleRouteError(ctx: BrowserRouteContext, res: BrowserResponse,
jsonError(res, 500, String(err));
}
/** Resolve the requested browser profile and respond with JSON on failure. */
export function resolveProfileContext(
req: BrowserRequest,
res: BrowserResponse,
@@ -64,6 +75,7 @@ export function resolveProfileContext(
return profileCtx;
}
/** Build navigation guard policy for a profile and current resolved config. */
export function browserNavigationPolicyForProfile(
ctx: BrowserRouteContext,
profileCtx: ProfileContext,
@@ -76,10 +88,12 @@ export function browserNavigationPolicyForProfile(
});
}
/** Load the optional Playwright bridge module in soft-fail mode. */
export async function getPwAiModule(): Promise<PwAiModule | null> {
return await getPwAiModuleBase({ mode: "soft" });
}
/** Require Playwright support for a route feature, returning a 501 when absent. */
export async function requirePwAi(
res: BrowserResponse,
feature: string,
@@ -124,6 +138,7 @@ type RouteWithTabParams<T> = {
run: (ctx: RouteTabContext) => Promise<T>;
};
/** Resolve profile and tab context, optionally enforcing current URL policy. */
export async function withRouteTabContext<T>(
params: RouteWithTabParams<T>,
): Promise<T | undefined> {
@@ -198,6 +213,7 @@ type RouteWithPwParams<T> = {
run: (ctx: RouteTabPwContext) => Promise<T>;
};
/** Resolve profile, tab, and Playwright context for Playwright-only routes. */
export async function withPlaywrightRouteContext<T>(
params: RouteWithPwParams<T>,
): Promise<T | undefined> {

View File

@@ -1,3 +1,9 @@
/**
* Snapshot planning for browser route handlers.
*
* Resolves requested snapshot mode, format, limits, refs, labels, and driver
* choice before the route talks to Playwright or Chrome MCP.
*/
import {
parseStrictNonNegativeInteger,
parseStrictPositiveInteger,
@@ -34,6 +40,7 @@ type BrowserSnapshotPlan = {
wantsRoleSnapshot: boolean;
};
/** Resolve a normalized snapshot plan from query parameters and profile caps. */
export function resolveSnapshotPlan(params: {
profile: ResolvedBrowserProfile;
query: Record<string, unknown>;

View File

@@ -1,3 +1,9 @@
/**
* Browser snapshot, navigation, and screenshot routes.
*
* Handles profile-aware snapshot generation across Playwright and Chrome MCP,
* navigation policy checks, media storage, and screenshot normalization.
*/
import path from "node:path";
import { ensureMediaDir, saveMediaBuffer } from "../../media/store.js";
import { captureScreenshot, snapshotAria, snapshotRoleViaCdp } from "../cdp.js";
@@ -253,6 +259,7 @@ function browserStateResponseFields(state: unknown): { browserState?: unknown }
return hasObservableBrowserState(state) ? { browserState: state } : {};
}
/** Register snapshot, screenshot, and navigation endpoints. */
export function registerBrowserAgentSnapshotRoutes(
app: BrowserRouteRegistrar,
ctx: BrowserRouteContext,

View File

@@ -1,3 +1,9 @@
/**
* Browser storage and context mutation routes.
*
* Parses and applies cookies, local/session storage, geolocation, permissions,
* and related browser-context mutations for the selected profile/tab.
*/
import {
normalizeOptionalString,
readStringValue,
@@ -36,6 +42,7 @@ type CookieSetOptions = {
sameSite?: "Lax" | "None" | "Strict";
};
/** Parse the supported browser storage bucket names. */
export function parseStorageKind(raw: string): StorageKind | null {
if (raw === "local" || raw === "session") {
return raw;
@@ -43,6 +50,7 @@ export function parseStorageKind(raw: string): StorageKind | null {
return null;
}
/** Parse an optional storage mutation request from a route body. */
export function parseStorageMutationRequest(
kindParam: unknown,
body: Record<string, unknown>,
@@ -53,6 +61,7 @@ export function parseStorageMutationRequest(
};
}
/** Parse a required storage mutation request and throw on invalid input. */
export function parseRequiredStorageMutationRequest(
kindParam: unknown,
body: Record<string, unknown>,
@@ -104,6 +113,7 @@ function assertRange(
return value;
}
/** Parse cookie options accepted by browser storage mutation routes. */
export function parseCookieSetOptions(cookie: Record<string, unknown>): CookieSetOptions {
return {
name: toStringOrEmpty(cookie.name),
@@ -121,6 +131,7 @@ export function parseCookieSetOptions(cookie: Record<string, unknown>): CookieSe
};
}
/** Parse geolocation override options accepted by context mutation routes. */
export function parseGeolocationOptions(body: Record<string, unknown>): GeolocationOptions {
const clear = toBoolean(body.clear) ?? false;
const origin = toStringOrEmpty(body.origin) || undefined;
@@ -149,6 +160,7 @@ export function parseGeolocationOptions(body: Record<string, unknown>): Geolocat
return { clear, latitude, longitude, accuracy, origin };
}
/** Register storage and browser-context mutation endpoints. */
export function registerBrowserAgentStorageRoutes(
app: BrowserRouteRegistrar,
ctx: BrowserRouteContext,