Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/Java/Openclaw/extensions/browser/src/browser/routes/   (KI Agentensystem Version 22©)  Datei vom 26.3.2026 mit Größe 10 kB image not shown  

Quelle  tabs.ts

  Sprache: JAVA
 

Spracherkennung für: .ts vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

import { resolveBrowserNavigationProxyMode } from "../browser-proxy-mode.js";
import {
  BrowserProfileUnavailableError,
  BrowserTabNotFoundError,
  BrowserTargetAmbiguousError,
} from "../errors.js";
import {
  assertBrowserNavigationAllowed,
  assertBrowserNavigationResultAllowed,
  withBrowserNavigationPolicy,
} from "../navigation-guard.js";
import type { BrowserRouteContext, ProfileContext } from "../server-context.js";
import { resolveTargetIdFromTabs } from "../target-id.js";
import type { BrowserRequest, BrowserResponse, BrowserRouteRegistrar } from "./types.js";
import {
  asyncBrowserRoute,
  getProfileContext,
  jsonError,
  toNumber,
  toStringOrEmpty,
} from "./utils.js";

function resolveTabsProfileContext(
  req: BrowserRequest,
  res: BrowserResponse,
  ctx: BrowserRouteContext,
) {
  const profileCtx = getProfileContext(req, ctx);
  if ("error" in profileCtx) {
    jsonError(res, profileCtx.status, profileCtx.error);
    return null;
  }
  return profileCtx;
}

function browserNavigationPolicyForProfile(ctx: BrowserRouteContext, profileCtx: ProfileContext) {
  return withBrowserNavigationPolicy(ctx.state().resolved.ssrfPolicy, {
    browserProxyMode: resolveBrowserNavigationProxyMode({
      resolved: ctx.state().resolved,
      profile: profileCtx.profile,
    }),
  });
}

function handleTabsRouteError(
  ctx: BrowserRouteContext,
  res: BrowserResponse,
  err: unknown,
  opts?: { mapTabError?: boolean },
) {
  if (opts?.mapTabError) {
    const mapped = ctx.mapTabError(err);
    if (mapped) {
      return jsonError(res, mapped.status, mapped.message);
    }
  }
  return jsonError(res, 500, String(err));
}

async function withTabsProfileRoute(params: {
  req: BrowserRequest;
  res: BrowserResponse;
  ctx: BrowserRouteContext;
  mapTabError?: boolean;
  run: (profileCtx: ProfileContext) => Promise<void>;
}) {
  const profileCtx = resolveTabsProfileContext(params.req, params.res, params.ctx);
  if (!profileCtx) {
    return;
  }
  try {
    await params.run(profileCtx);
  } catch (err) {
    handleTabsRouteError(params.ctx, params.res, err, { mapTabError: params.mapTabError });
  }
}

async function ensureBrowserRunning(profileCtx: ProfileContext, res: BrowserResponse) {
  if (!(await profileCtx.isReachable(300))) {
    jsonError(
      res,
      new BrowserProfileUnavailableError("browser not running").status,
      "browser not running",
    );
    return false;
  }
  return true;
}

async function redactBlockedTabUrls(params: {
  tabs: Awaited<ReturnType<ProfileContext["listTabs"]>>;
  ssrfPolicy: ReturnType<BrowserRouteContext["state"]>["resolved"]["ssrfPolicy"];
}): Promise<Awaited<ReturnType<ProfileContext["listTabs"]>>> {
  const ssrfPolicyOpts = withBrowserNavigationPolicy(params.ssrfPolicy);
  if (!ssrfPolicyOpts.ssrfPolicy) {
    return params.tabs;
  }

  const redactedTabs: Awaited<ReturnType<ProfileContext["listTabs"]>> = [];
  for (const tab of params.tabs) {
    try {
      await assertBrowserNavigationResultAllowed({
        url: tab.url,
        ...ssrfPolicyOpts,
      });
      redactedTabs.push(tab);
    } catch {
      // Hide blocked URLs while preserving tab identity for safe operations.
      redactedTabs.push({
        ...tab,
        url: "",
      });
    }
  }
  return redactedTabs;
}

function resolveIndexedTab(
  tabs: Awaited<ReturnType<ProfileContext["listTabs"]>>,
  index: number | undefined,
) {
  return typeof index === "number" ? tabs[index] : tabs.at(0);
}

function parseRequiredTargetId(res: BrowserResponse, rawTargetId: unknown): string | null {
  const targetId = toStringOrEmpty(rawTargetId);
  if (!targetId) {
    jsonError(res, 400, "targetId is required");
    return null;
  }
  return targetId;
}

function readOptionalTabLabel(body: unknown): string | undefined {
  const label = toStringOrEmpty((body as { label?: unknown })?.label);
  return label || undefined;
}

async function runTabTargetMutation(params: {
  req: BrowserRequest;
  res: BrowserResponse;
  ctx: BrowserRouteContext;
  targetId: string;
  mutate: (profileCtx: ProfileContext, targetId: string) => Promise<void>;
}) {
  await withTabsProfileRoute({
    req: params.req,
    res: params.res,
    ctx: params.ctx,
    mapTabError: true,
    run: async (profileCtx) => {
      if (!(await ensureBrowserRunning(profileCtx, params.res))) {
        return;
      }
      await params.mutate(profileCtx, params.targetId);
      params.res.json({ ok: true });
    },
  });
}

export function registerBrowserTabRoutes(app: BrowserRouteRegistrar, ctx: BrowserRouteContext) {
  app.get(
    "/tabs",
    asyncBrowserRoute(async (req, res) => {
      await withTabsProfileRoute({
        req,
        res,
        ctx,
        run: async (profileCtx) => {
          const reachable = await profileCtx.isReachable(300);
          if (!reachable) {
            return res.json({ running: false, tabs: [] as unknown[] });
          }
          const tabs = await redactBlockedTabUrls({
            tabs: await profileCtx.listTabs(),
            ssrfPolicy: ctx.state().resolved.ssrfPolicy,
          });
          res.json({ running: true, tabs });
        },
      });
    }),
  );

  app.post(
    "/tabs/open",
    asyncBrowserRoute(async (req, res) => {
      const url = toStringOrEmpty((req.body as { url?: unknown })?.url);
      const label = readOptionalTabLabel(req.body);
      if (!url) {
        return jsonError(res, 400, "url is required");
      }

      await withTabsProfileRoute({
        req,
        res,
        ctx,
        mapTabError: true,
        run: async (profileCtx) => {
          await assertBrowserNavigationAllowed({
            url,
            ...browserNavigationPolicyForProfile(ctx, profileCtx),
          });
          await profileCtx.ensureBrowserAvailable();
          const tab = await profileCtx.openTab(url, { label });
          res.json(tab);
        },
      });
    }),
  );

  app.post(
    "/tabs/focus",
    asyncBrowserRoute(async (req, res) => {
      const targetId = parseRequiredTargetId(res, (req.body as { targetId?: unknown })?.targetId);
      if (!targetId) {
        return;
      }
      await runTabTargetMutation({
        req,
        res,
        ctx,
        targetId,
        mutate: async (profileCtx, id) => {
          const tabs = await profileCtx.listTabs();
          const resolved = resolveTargetIdFromTabs(id, tabs);
          if (!resolved.ok) {
            if (resolved.reason === "ambiguous") {
              throw new BrowserTargetAmbiguousError();
            }
            throw new BrowserTabNotFoundError({ input: id });
          }
          const tab = tabs.find((currentTab) => currentTab.targetId === resolved.targetId);
          if (!tab) {
            throw new BrowserTabNotFoundError({ input: id });
          }
          const ssrfPolicyOpts = browserNavigationPolicyForProfile(ctx, profileCtx);
          if (ssrfPolicyOpts.ssrfPolicy) {
            await assertBrowserNavigationResultAllowed({
              url: tab.url,
              ...ssrfPolicyOpts,
            });
          }
          await profileCtx.focusTab(resolved.targetId);
        },
      });
    }),
  );

  app.delete(
    "/tabs/:targetId",
    asyncBrowserRoute(async (req, res) => {
      const targetId = parseRequiredTargetId(res, req.params.targetId);
      if (!targetId) {
        return;
      }
      await runTabTargetMutation({
        req,
        res,
        ctx,
        targetId,
        mutate: async (profileCtx, id) => {
          await profileCtx.closeTab(id);
        },
      });
    }),
  );

  app.post(
    "/tabs/action",
    asyncBrowserRoute(async (req, res) => {
      const action = toStringOrEmpty((req.body as { action?: unknown })?.action);
      const index = toNumber((req.body as { index?: unknown })?.index);

      await withTabsProfileRoute({
        req,
        res,
        ctx,
        mapTabError: true,
        run: async (profileCtx) => {
          if (action === "list") {
            const reachable = await profileCtx.isReachable(300);
            if (!reachable) {
              return res.json({ ok: true, tabs: [] as unknown[] });
            }
            const tabs = await redactBlockedTabUrls({
              tabs: await profileCtx.listTabs(),
              ssrfPolicy: ctx.state().resolved.ssrfPolicy,
            });
            return res.json({ ok: true, tabs });
          }

          if (action === "new") {
            await profileCtx.ensureBrowserAvailable();
            const tab = await profileCtx.openTab("about:blank", {
              label: readOptionalTabLabel(req.body),
            });
            return res.json({ ok: true, tab });
          }

          if (action === "label") {
            if (!(await ensureBrowserRunning(profileCtx, res))) {
              return;
            }
            const targetId = parseRequiredTargetId(
              res,
              (req.body as { targetId?: unknown })?.targetId,
            );
            if (!targetId) {
              return;
            }
            const label = readOptionalTabLabel(req.body);
            if (!label) {
              return jsonError(res, 400, "label is required");
            }
            const tab = await profileCtx.labelTab(targetId, label);
            return res.json({ ok: true, tab });
          }

          if (action === "close") {
            if (!(await ensureBrowserRunning(profileCtx, res))) {
              return;
            }
            const tabs = await profileCtx.listTabs();
            const target = resolveIndexedTab(tabs, index);
            if (!target) {
              throw new BrowserTabNotFoundError();
            }
            await profileCtx.closeTab(target.targetId);
            return res.json({ ok: true, targetId: target.targetId });
          }

          if (action === "select") {
            if (typeof index !== "number") {
              return jsonError(res, 400, "index is required");
            }
            if (!(await ensureBrowserRunning(profileCtx, res))) {
              return;
            }
            const tabs = await profileCtx.listTabs();
            const target = tabs[index];
            if (!target) {
              throw new BrowserTabNotFoundError();
            }
            const ssrfPolicyOpts = browserNavigationPolicyForProfile(ctx, profileCtx);
            if (ssrfPolicyOpts.ssrfPolicy) {
              await assertBrowserNavigationResultAllowed({
                url: target.url,
                ...ssrfPolicyOpts,
              });
            }
            await profileCtx.focusTab(target.targetId);
            return res.json({ ok: true, targetId: target.targetId });
          }

          return jsonError(res, 400, "unknown tab action");
        },
      });
    }),
  );
}

¤ Dauer der Verarbeitung: 0.19 Sekunden  (vorverarbeitet am  2026-04-27) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.