chore: migrate to oxlint and oxfmt

Co-authored-by: Christoph Nakazawa <christoph.pojer@gmail.com>
This commit is contained in:
Peter Steinberger
2026-01-14 14:31:43 +00:00
parent 912ebffc63
commit c379191f80
1480 changed files with 28608 additions and 43547 deletions

View File

@@ -21,12 +21,7 @@ export function isActKind(value: unknown): value is ActKind {
}
export type ClickButton = "left" | "right" | "middle";
export type ClickModifier =
| "Alt"
| "Control"
| "ControlOrMeta"
| "Meta"
| "Shift";
export type ClickModifier = "Alt" | "Control" | "ControlOrMeta" | "Meta" | "Shift";
const ALLOWED_CLICK_MODIFIERS = new Set<ClickModifier>([
"Alt",
@@ -45,9 +40,7 @@ export function parseClickModifiers(raw: string[]): {
modifiers?: ClickModifier[];
error?: string;
} {
const invalid = raw.filter(
(m) => !ALLOWED_CLICK_MODIFIERS.has(m as ClickModifier),
);
const invalid = raw.filter((m) => !ALLOWED_CLICK_MODIFIERS.has(m as ClickModifier));
if (invalid.length) {
return { error: "modifiers must be Alt|Control|ControlOrMeta|Meta|Shift" };
}

View File

@@ -15,18 +15,9 @@ import {
resolveProfileContext,
SELECTOR_UNSUPPORTED_MESSAGE,
} from "./agent.shared.js";
import {
jsonError,
toBoolean,
toNumber,
toStringArray,
toStringOrEmpty,
} from "./utils.js";
import { jsonError, toBoolean, toNumber, toStringArray, toStringOrEmpty } from "./utils.js";
export function registerBrowserAgentActRoutes(
app: express.Express,
ctx: BrowserRouteContext,
) {
export function registerBrowserAgentActRoutes(app: express.Express, ctx: BrowserRouteContext) {
app.post("/act", async (req, res) => {
const profileCtx = resolveProfileContext(req, res, ctx);
if (!profileCtx) return;
@@ -55,8 +46,7 @@ export function registerBrowserAgentActRoutes(
const timeoutMs = toNumber(body.timeoutMs);
const buttonRaw = toStringOrEmpty(body.button) || "";
const button = buttonRaw ? parseClickButton(buttonRaw) : undefined;
if (buttonRaw && !button)
return jsonError(res, 400, "button must be left|right|middle");
if (buttonRaw && !button) return jsonError(res, 400, "button must be left|right|middle");
const modifiersRaw = toStringArray(body.modifiers) ?? [];
const parsedModifiers = parseClickModifiers(modifiersRaw);
@@ -79,8 +69,7 @@ export function registerBrowserAgentActRoutes(
case "type": {
const ref = toStringOrEmpty(body.ref);
if (!ref) return jsonError(res, 400, "ref is required");
if (typeof body.text !== "string")
return jsonError(res, 400, "text is required");
if (typeof body.text !== "string") return jsonError(res, 400, "text is required");
const text = body.text;
const submit = toBoolean(body.submit) ?? false;
const slowly = toBoolean(body.slowly) ?? false;
@@ -125,9 +114,7 @@ export function registerBrowserAgentActRoutes(
const ref = toStringOrEmpty(body.ref);
if (!ref) return jsonError(res, 400, "ref is required");
const timeoutMs = toNumber(body.timeoutMs);
const scrollRequest: Parameters<
typeof pw.scrollIntoViewViaPlaywright
>[0] = {
const scrollRequest: Parameters<typeof pw.scrollIntoViewViaPlaywright>[0] = {
cdpUrl,
targetId: tab.targetId,
ref,
@@ -139,8 +126,7 @@ export function registerBrowserAgentActRoutes(
case "drag": {
const startRef = toStringOrEmpty(body.startRef);
const endRef = toStringOrEmpty(body.endRef);
if (!startRef || !endRef)
return jsonError(res, 400, "startRef and endRef are required");
if (!startRef || !endRef) return jsonError(res, 400, "startRef and endRef are required");
const timeoutMs = toNumber(body.timeoutMs);
await pw.dragViaPlaywright({
cdpUrl,
@@ -154,8 +140,7 @@ export function registerBrowserAgentActRoutes(
case "select": {
const ref = toStringOrEmpty(body.ref);
const values = toStringArray(body.values);
if (!ref || !values?.length)
return jsonError(res, 400, "ref and values are required");
if (!ref || !values?.length) return jsonError(res, 400, "ref and values are required");
const timeoutMs = toNumber(body.timeoutMs);
await pw.selectOptionViaPlaywright({
cdpUrl,
@@ -199,8 +184,7 @@ export function registerBrowserAgentActRoutes(
case "resize": {
const width = toNumber(body.width);
const height = toNumber(body.height);
if (!width || !height)
return jsonError(res, 400, "width and height are required");
if (!width || !height) return jsonError(res, 400, "width and height are required");
await pw.resizeViewportViaPlaywright({
cdpUrl,
targetId: tab.targetId,
@@ -300,11 +284,7 @@ export function registerBrowserAgentActRoutes(
if (!pw) return;
if (inputRef || element) {
if (ref) {
return jsonError(
res,
400,
"ref cannot be combined with inputRef/element",
);
return jsonError(res, 400, "ref cannot be combined with inputRef/element");
}
await pw.setInputFilesViaPlaywright({
cdpUrl: profileCtx.profile.cdpUrl,

View File

@@ -5,23 +5,14 @@ import path from "node:path";
import type express from "express";
import type { BrowserRouteContext } from "../server-context.js";
import {
handleRouteError,
readBody,
requirePwAi,
resolveProfileContext,
} from "./agent.shared.js";
import { handleRouteError, readBody, requirePwAi, resolveProfileContext } from "./agent.shared.js";
import { toBoolean, toStringOrEmpty } from "./utils.js";
export function registerBrowserAgentDebugRoutes(
app: express.Express,
ctx: BrowserRouteContext,
) {
export function registerBrowserAgentDebugRoutes(app: express.Express, ctx: BrowserRouteContext) {
app.get("/console", async (req, res) => {
const profileCtx = resolveProfileContext(req, res, ctx);
if (!profileCtx) return;
const targetId =
typeof req.query.targetId === "string" ? req.query.targetId.trim() : "";
const targetId = typeof req.query.targetId === "string" ? req.query.targetId.trim() : "";
const level = typeof req.query.level === "string" ? req.query.level : "";
try {
@@ -42,8 +33,7 @@ export function registerBrowserAgentDebugRoutes(
app.get("/errors", async (req, res) => {
const profileCtx = resolveProfileContext(req, res, ctx);
if (!profileCtx) return;
const targetId =
typeof req.query.targetId === "string" ? req.query.targetId.trim() : "";
const targetId = typeof req.query.targetId === "string" ? req.query.targetId.trim() : "";
const clear = toBoolean(req.query.clear) ?? false;
try {
@@ -64,8 +54,7 @@ export function registerBrowserAgentDebugRoutes(
app.get("/requests", async (req, res) => {
const profileCtx = resolveProfileContext(req, res, ctx);
if (!profileCtx) return;
const targetId =
typeof req.query.targetId === "string" ? req.query.targetId.trim() : "";
const targetId = typeof req.query.targetId === "string" ? req.query.targetId.trim() : "";
const filter = typeof req.query.filter === "string" ? req.query.filter : "";
const clear = toBoolean(req.query.clear) ?? false;

View File

@@ -19,11 +19,7 @@ export function readBody(req: express.Request): Record<string, unknown> {
return body;
}
export function handleRouteError(
ctx: BrowserRouteContext,
res: express.Response,
err: unknown,
) {
export function handleRouteError(ctx: BrowserRouteContext, res: express.Response, err: unknown) {
const mapped = ctx.mapTabError(err);
if (mapped) return jsonError(res, mapped.status, mapped.message);
jsonError(res, 500, String(err));

View File

@@ -20,10 +20,7 @@ import {
} from "./agent.shared.js";
import { jsonError, toBoolean, toNumber, toStringOrEmpty } from "./utils.js";
export function registerBrowserAgentSnapshotRoutes(
app: express.Express,
ctx: BrowserRouteContext,
) {
export function registerBrowserAgentSnapshotRoutes(app: express.Express, ctx: BrowserRouteContext) {
app.post("/navigate", async (req, res) => {
const profileCtx = resolveProfileContext(req, res, ctx);
if (!profileCtx) return;
@@ -88,11 +85,7 @@ export function registerBrowserAgentSnapshotRoutes(
const type = body.type === "jpeg" ? "jpeg" : "png";
if (fullPage && (ref || element)) {
return jsonError(
res,
400,
"fullPage is not supported for element screenshots",
);
return jsonError(res, 400, "fullPage is not supported for element screenshots");
}
try {
@@ -144,8 +137,7 @@ export function registerBrowserAgentSnapshotRoutes(
app.get("/snapshot", async (req, res) => {
const profileCtx = resolveProfileContext(req, res, ctx);
if (!profileCtx) return;
const targetId =
typeof req.query.targetId === "string" ? req.query.targetId.trim() : "";
const targetId = typeof req.query.targetId === "string" ? req.query.targetId.trim() : "";
const format =
req.query.format === "aria"
? "aria"
@@ -154,26 +146,17 @@ export function registerBrowserAgentSnapshotRoutes(
: (await getPwAiModule())
? "ai"
: "aria";
const limitRaw =
typeof req.query.limit === "string" ? Number(req.query.limit) : undefined;
const limitRaw = typeof req.query.limit === "string" ? Number(req.query.limit) : undefined;
const hasMaxChars = Object.hasOwn(req.query, "maxChars");
const maxCharsRaw =
typeof req.query.maxChars === "string"
? Number(req.query.maxChars)
: undefined;
typeof req.query.maxChars === "string" ? Number(req.query.maxChars) : undefined;
const limit = Number.isFinite(limitRaw) ? limitRaw : undefined;
const maxChars =
typeof maxCharsRaw === "number" &&
Number.isFinite(maxCharsRaw) &&
maxCharsRaw > 0
typeof maxCharsRaw === "number" && Number.isFinite(maxCharsRaw) && maxCharsRaw > 0
? Math.floor(maxCharsRaw)
: undefined;
const resolvedMaxChars =
format === "ai"
? hasMaxChars
? maxChars
: DEFAULT_AI_SNAPSHOT_MAX_CHARS
: undefined;
format === "ai" ? (hasMaxChars ? maxChars : DEFAULT_AI_SNAPSHOT_MAX_CHARS) : undefined;
const interactive = toBoolean(req.query.interactive);
const compact = toBoolean(req.query.compact);
const depth = toNumber(req.query.depth);
@@ -208,9 +191,7 @@ export function registerBrowserAgentSnapshotRoutes(
.snapshotAiViaPlaywright({
cdpUrl: profileCtx.profile.cdpUrl,
targetId: tab.targetId,
...(typeof resolvedMaxChars === "number"
? { maxChars: resolvedMaxChars }
: {}),
...(typeof resolvedMaxChars === "number" ? { maxChars: resolvedMaxChars } : {}),
})
.catch(async (err) => {
// Public-API fallback when Playwright's private _snapshotForAI is missing.

View File

@@ -1,23 +1,14 @@
import type express from "express";
import type { BrowserRouteContext } from "../server-context.js";
import {
handleRouteError,
readBody,
requirePwAi,
resolveProfileContext,
} from "./agent.shared.js";
import { handleRouteError, readBody, requirePwAi, resolveProfileContext } from "./agent.shared.js";
import { jsonError, toBoolean, toNumber, toStringOrEmpty } from "./utils.js";
export function registerBrowserAgentStorageRoutes(
app: express.Express,
ctx: BrowserRouteContext,
) {
export function registerBrowserAgentStorageRoutes(app: express.Express, ctx: BrowserRouteContext) {
app.get("/cookies", async (req, res) => {
const profileCtx = resolveProfileContext(req, res, ctx);
if (!profileCtx) return;
const targetId =
typeof req.query.targetId === "string" ? req.query.targetId.trim() : "";
const targetId = typeof req.query.targetId === "string" ? req.query.targetId.trim() : "";
try {
const tab = await profileCtx.ensureTabAvailable(targetId || undefined);
const pw = await requirePwAi(res, "cookies");
@@ -38,9 +29,7 @@ export function registerBrowserAgentStorageRoutes(
const body = readBody(req);
const targetId = toStringOrEmpty(body.targetId) || undefined;
const cookie =
body.cookie &&
typeof body.cookie === "object" &&
!Array.isArray(body.cookie)
body.cookie && typeof body.cookie === "object" && !Array.isArray(body.cookie)
? (body.cookie as Record<string, unknown>)
: null;
if (!cookie) return jsonError(res, 400, "cookie is required");
@@ -61,9 +50,7 @@ export function registerBrowserAgentStorageRoutes(
httpOnly: toBoolean(cookie.httpOnly) ?? undefined,
secure: toBoolean(cookie.secure) ?? undefined,
sameSite:
cookie.sameSite === "Lax" ||
cookie.sameSite === "None" ||
cookie.sameSite === "Strict"
cookie.sameSite === "Lax" || cookie.sameSite === "None" || cookie.sameSite === "Strict"
? (cookie.sameSite as "Lax" | "None" | "Strict")
: undefined,
},
@@ -99,8 +86,7 @@ export function registerBrowserAgentStorageRoutes(
const kind = toStringOrEmpty(req.params.kind);
if (kind !== "local" && kind !== "session")
return jsonError(res, 400, "kind must be local|session");
const targetId =
typeof req.query.targetId === "string" ? req.query.targetId.trim() : "";
const targetId = typeof req.query.targetId === "string" ? req.query.targetId.trim() : "";
const key = typeof req.query.key === "string" ? req.query.key : "";
try {
const tab = await profileCtx.ensureTabAvailable(targetId || undefined);
@@ -175,8 +161,7 @@ export function registerBrowserAgentStorageRoutes(
const body = readBody(req);
const targetId = toStringOrEmpty(body.targetId) || undefined;
const offline = toBoolean(body.offline);
if (offline === undefined)
return jsonError(res, 400, "offline is required");
if (offline === undefined) return jsonError(res, 400, "offline is required");
try {
const tab = await profileCtx.ensureTabAvailable(targetId);
const pw = await requirePwAi(res, "offline");
@@ -198,9 +183,7 @@ export function registerBrowserAgentStorageRoutes(
const body = readBody(req);
const targetId = toStringOrEmpty(body.targetId) || undefined;
const headers =
body.headers &&
typeof body.headers === "object" &&
!Array.isArray(body.headers)
body.headers && typeof body.headers === "object" && !Array.isArray(body.headers)
? (body.headers as Record<string, unknown>)
: null;
if (!headers) return jsonError(res, 400, "headers is required");
@@ -230,8 +213,7 @@ export function registerBrowserAgentStorageRoutes(
const targetId = toStringOrEmpty(body.targetId) || undefined;
const clear = toBoolean(body.clear) ?? false;
const username = toStringOrEmpty(body.username) || undefined;
const password =
typeof body.password === "string" ? body.password : undefined;
const password = typeof body.password === "string" ? body.password : undefined;
try {
const tab = await profileCtx.ensureTabAvailable(targetId);
const pw = await requirePwAi(res, "http credentials");
@@ -285,19 +267,13 @@ export function registerBrowserAgentStorageRoutes(
const targetId = toStringOrEmpty(body.targetId) || undefined;
const schemeRaw = toStringOrEmpty(body.colorScheme);
const colorScheme =
schemeRaw === "dark" ||
schemeRaw === "light" ||
schemeRaw === "no-preference"
schemeRaw === "dark" || schemeRaw === "light" || schemeRaw === "no-preference"
? (schemeRaw as "dark" | "light" | "no-preference")
: schemeRaw === "none"
? null
: undefined;
if (colorScheme === undefined)
return jsonError(
res,
400,
"colorScheme must be dark|light|no-preference|none",
);
return jsonError(res, 400, "colorScheme must be dark|light|no-preference|none");
try {
const tab = await profileCtx.ensureTabAvailable(targetId);
const pw = await requirePwAi(res, "media emulation");

View File

@@ -6,10 +6,7 @@ import { registerBrowserAgentDebugRoutes } from "./agent.debug.js";
import { registerBrowserAgentSnapshotRoutes } from "./agent.snapshot.js";
import { registerBrowserAgentStorageRoutes } from "./agent.storage.js";
export function registerBrowserAgentRoutes(
app: express.Express,
ctx: BrowserRouteContext,
) {
export function registerBrowserAgentRoutes(app: express.Express, ctx: BrowserRouteContext) {
registerBrowserAgentSnapshotRoutes(app, ctx);
registerBrowserAgentActRoutes(app, ctx);
registerBrowserAgentDebugRoutes(app, ctx);

View File

@@ -4,10 +4,7 @@ import { createBrowserProfilesService } from "../profiles-service.js";
import type { BrowserRouteContext } from "../server-context.js";
import { getProfileContext, jsonError, toStringOrEmpty } from "./utils.js";
export function registerBrowserBasicRoutes(
app: express.Express,
ctx: BrowserRouteContext,
) {
export function registerBrowserBasicRoutes(app: express.Express, ctx: BrowserRouteContext) {
// List all profiles with their status
app.get("/profiles", async (_req, res) => {
try {

View File

@@ -5,10 +5,7 @@ import { registerBrowserAgentRoutes } from "./agent.js";
import { registerBrowserBasicRoutes } from "./basic.js";
import { registerBrowserTabRoutes } from "./tabs.js";
export function registerBrowserRoutes(
app: express.Express,
ctx: BrowserRouteContext,
) {
export function registerBrowserRoutes(app: express.Express, ctx: BrowserRouteContext) {
registerBrowserBasicRoutes(app, ctx);
registerBrowserTabRoutes(app, ctx);
registerBrowserAgentRoutes(app, ctx);

View File

@@ -1,25 +1,15 @@
import type express from "express";
import type { BrowserRouteContext } from "../server-context.js";
import {
getProfileContext,
jsonError,
toNumber,
toStringOrEmpty,
} from "./utils.js";
import { getProfileContext, jsonError, toNumber, toStringOrEmpty } from "./utils.js";
export function registerBrowserTabRoutes(
app: express.Express,
ctx: BrowserRouteContext,
) {
export function registerBrowserTabRoutes(app: express.Express, ctx: BrowserRouteContext) {
app.get("/tabs", async (req, res) => {
const profileCtx = getProfileContext(req, ctx);
if ("error" in profileCtx)
return jsonError(res, profileCtx.status, profileCtx.error);
if ("error" in profileCtx) return jsonError(res, profileCtx.status, profileCtx.error);
try {
const reachable = await profileCtx.isReachable(300);
if (!reachable)
return res.json({ running: false, tabs: [] as unknown[] });
if (!reachable) return res.json({ running: false, tabs: [] as unknown[] });
const tabs = await profileCtx.listTabs();
res.json({ running: true, tabs });
} catch (err) {
@@ -29,8 +19,7 @@ export function registerBrowserTabRoutes(
app.post("/tabs/open", async (req, res) => {
const profileCtx = getProfileContext(req, ctx);
if ("error" in profileCtx)
return jsonError(res, profileCtx.status, profileCtx.error);
if ("error" in profileCtx) return jsonError(res, profileCtx.status, profileCtx.error);
const url = toStringOrEmpty((req.body as { url?: unknown })?.url);
if (!url) return jsonError(res, 400, "url is required");
try {
@@ -44,15 +33,11 @@ export function registerBrowserTabRoutes(
app.post("/tabs/focus", async (req, res) => {
const profileCtx = getProfileContext(req, ctx);
if ("error" in profileCtx)
return jsonError(res, profileCtx.status, profileCtx.error);
const targetId = toStringOrEmpty(
(req.body as { targetId?: unknown })?.targetId,
);
if ("error" in profileCtx) return jsonError(res, profileCtx.status, profileCtx.error);
const targetId = toStringOrEmpty((req.body as { targetId?: unknown })?.targetId);
if (!targetId) return jsonError(res, 400, "targetId is required");
try {
if (!(await profileCtx.isReachable(300)))
return jsonError(res, 409, "browser not running");
if (!(await profileCtx.isReachable(300))) return jsonError(res, 409, "browser not running");
await profileCtx.focusTab(targetId);
res.json({ ok: true });
} catch (err) {
@@ -64,13 +49,11 @@ export function registerBrowserTabRoutes(
app.delete("/tabs/:targetId", async (req, res) => {
const profileCtx = getProfileContext(req, ctx);
if ("error" in profileCtx)
return jsonError(res, profileCtx.status, profileCtx.error);
if ("error" in profileCtx) return jsonError(res, profileCtx.status, profileCtx.error);
const targetId = toStringOrEmpty(req.params.targetId);
if (!targetId) return jsonError(res, 400, "targetId is required");
try {
if (!(await profileCtx.isReachable(300)))
return jsonError(res, 409, "browser not running");
if (!(await profileCtx.isReachable(300))) return jsonError(res, 409, "browser not running");
await profileCtx.closeTab(targetId);
res.json({ ok: true });
} catch (err) {
@@ -82,8 +65,7 @@ export function registerBrowserTabRoutes(
app.post("/tabs/action", async (req, res) => {
const profileCtx = getProfileContext(req, ctx);
if ("error" in profileCtx)
return jsonError(res, profileCtx.status, profileCtx.error);
if ("error" in profileCtx) return jsonError(res, profileCtx.status, profileCtx.error);
const action = toStringOrEmpty((req.body as { action?: unknown })?.action);
const index = toNumber((req.body as { index?: unknown })?.index);
try {
@@ -109,8 +91,7 @@ export function registerBrowserTabRoutes(
}
if (action === "select") {
if (typeof index !== "number")
return jsonError(res, 400, "index is required");
if (typeof index !== "number") return jsonError(res, 400, "index is required");
const tabs = await profileCtx.listTabs();
const target = tabs[index];
if (!target) return jsonError(res, 404, "tab not found");

View File

@@ -32,11 +32,7 @@ export function getProfileContext(
}
}
export function jsonError(
res: express.Response,
status: number,
message: string,
) {
export function jsonError(res: express.Response, status: number, message: string) {
res.status(status).json({ error: message });
}