import type { Command } from "commander"; import { danger } from "../globals.js"; import { defaultRuntime } from "../runtime.js"; import { callBrowserRequest, type BrowserParentOpts } from "./browser-cli-shared.js"; import { inheritOptionFromParent } from "./command-options.js"; function resolveUrl(opts: { url?: string }, command: Command): string | undefined { if (typeof opts.url === "string" && opts.url.trim()) { return opts.url.trim(); } const inherited = inheritOptionFromParent(command, "url"); if (typeof inherited === "string" && inherited.trim()) { return inherited.trim(); } return undefined; } function resolveTargetId(rawTargetId: unknown, command: Command): string | undefined { const local = typeof rawTargetId === "string" ? rawTargetId.trim() : ""; if (local) { return local; } const inherited = inheritOptionFromParent(command, "targetId"); if (typeof inherited !== "string") { return undefined; } const trimmed = inherited.trim(); return trimmed ? trimmed : undefined; } async function runMutationRequest(params: { parent: BrowserParentOpts; request: Parameters[1]; successMessage: string; }) { try { const result = await callBrowserRequest(params.parent, params.request, { timeoutMs: 20000 }); if (params.parent?.json) { defaultRuntime.log(JSON.stringify(result, null, 2)); return; } defaultRuntime.log(params.successMessage); } catch (err) { defaultRuntime.error(danger(String(err))); defaultRuntime.exit(1); } } export function registerBrowserCookiesAndStorageCommands( browser: Command, parentOpts: (cmd: Command) => BrowserParentOpts, ) { const cookies = browser.command("cookies").description("Read/write cookies"); cookies .option("--target-id ", "CDP target id (or unique prefix)") .action(async (opts, cmd) => { const parent = parentOpts(cmd); const profile = parent?.browserProfile; const targetId = resolveTargetId(opts.targetId, cmd); try { const result = await callBrowserRequest<{ cookies?: unknown[] }>( parent, { method: "GET", path: "/cookies", query: { targetId, profile, }, }, { timeoutMs: 20000 }, ); if (parent?.json) { defaultRuntime.log(JSON.stringify(result, null, 2)); return; } defaultRuntime.log(JSON.stringify(result.cookies ?? [], null, 2)); } catch (err) { defaultRuntime.error(danger(String(err))); defaultRuntime.exit(1); } }); cookies .command("set") .description("Set a cookie (requires --url or domain+path)") .argument("", "Cookie name") .argument("", "Cookie value") .option("--url ", "Cookie URL scope (recommended)") .option("--target-id ", "CDP target id (or unique prefix)") .action(async (name: string, value: string, opts, cmd) => { const parent = parentOpts(cmd); const profile = parent?.browserProfile; const targetId = resolveTargetId(opts.targetId, cmd); const url = resolveUrl(opts, cmd); if (!url) { defaultRuntime.error(danger("Missing required --url option for cookies set")); defaultRuntime.exit(1); return; } await runMutationRequest({ parent, request: { method: "POST", path: "/cookies/set", query: profile ? { profile } : undefined, body: { targetId, cookie: { name, value, url }, }, }, successMessage: `cookie set: ${name}`, }); }); cookies .command("clear") .description("Clear all cookies") .option("--target-id ", "CDP target id (or unique prefix)") .action(async (opts, cmd) => { const parent = parentOpts(cmd); const profile = parent?.browserProfile; const targetId = resolveTargetId(opts.targetId, cmd); await runMutationRequest({ parent, request: { method: "POST", path: "/cookies/clear", query: profile ? { profile } : undefined, body: { targetId, }, }, successMessage: "cookies cleared", }); }); const storage = browser.command("storage").description("Read/write localStorage/sessionStorage"); function registerStorageKind(kind: "local" | "session") { const cmd = storage.command(kind).description(`${kind}Storage commands`); cmd .command("get") .description(`Get ${kind}Storage (all keys or one key)`) .argument("[key]", "Key (optional)") .option("--target-id ", "CDP target id (or unique prefix)") .action(async (key: string | undefined, opts, cmd2) => { const parent = parentOpts(cmd2); const profile = parent?.browserProfile; const targetId = resolveTargetId(opts.targetId, cmd2); try { const result = await callBrowserRequest<{ values?: Record }>( parent, { method: "GET", path: `/storage/${kind}`, query: { key: key?.trim() || undefined, targetId, profile, }, }, { timeoutMs: 20000 }, ); if (parent?.json) { defaultRuntime.log(JSON.stringify(result, null, 2)); return; } defaultRuntime.log(JSON.stringify(result.values ?? {}, null, 2)); } catch (err) { defaultRuntime.error(danger(String(err))); defaultRuntime.exit(1); } }); cmd .command("set") .description(`Set a ${kind}Storage key`) .argument("", "Key") .argument("", "Value") .option("--target-id ", "CDP target id (or unique prefix)") .action(async (key: string, value: string, opts, cmd2) => { const parent = parentOpts(cmd2); const profile = parent?.browserProfile; const targetId = resolveTargetId(opts.targetId, cmd2); await runMutationRequest({ parent, request: { method: "POST", path: `/storage/${kind}/set`, query: profile ? { profile } : undefined, body: { key, value, targetId, }, }, successMessage: `${kind}Storage set: ${key}`, }); }); cmd .command("clear") .description(`Clear all ${kind}Storage keys`) .option("--target-id ", "CDP target id (or unique prefix)") .action(async (opts, cmd2) => { const parent = parentOpts(cmd2); const profile = parent?.browserProfile; const targetId = resolveTargetId(opts.targetId, cmd2); await runMutationRequest({ parent, request: { method: "POST", path: `/storage/${kind}/clear`, query: profile ? { profile } : undefined, body: { targetId, }, }, successMessage: `${kind}Storage cleared`, }); }); } registerStorageKind("local"); registerStorageKind("session"); }