From 7d294a7cab1ad4a79dbef5991116cc97bdbd0a25 Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Tue, 17 Mar 2026 04:46:47 -0700 Subject: [PATCH] feat: [US-003] - Add browser type definitions (DTOs and errors) Co-Authored-By: Claude Opus 4.6 (1M context) --- .../sandbox-agent/src/browser_errors.rs | 167 +++++ .../sandbox-agent/src/browser_types.rs | 578 ++++++++++++++++++ server/packages/sandbox-agent/src/lib.rs | 2 + 3 files changed, 747 insertions(+) create mode 100644 server/packages/sandbox-agent/src/browser_errors.rs create mode 100644 server/packages/sandbox-agent/src/browser_types.rs diff --git a/server/packages/sandbox-agent/src/browser_errors.rs b/server/packages/sandbox-agent/src/browser_errors.rs new file mode 100644 index 0000000..27c3b64 --- /dev/null +++ b/server/packages/sandbox-agent/src/browser_errors.rs @@ -0,0 +1,167 @@ +use sandbox_agent_error::ProblemDetails; +use serde_json::{Map, Value}; + +use crate::desktop_types::DesktopErrorInfo; + +#[derive(Debug, Clone)] +pub struct BrowserProblem { + status: u16, + title: &'static str, + code: &'static str, + message: String, +} + +impl BrowserProblem { + // 409 - browser is not running + pub fn not_active() -> Self { + Self::new( + 409, + "Browser Not Active", + "browser/not-active", + "The browser is not running. Call POST /v1/browser/start first.", + ) + } + + // 409 - browser is already running + pub fn already_active() -> Self { + Self::new( + 409, + "Browser Already Active", + "browser/already-active", + "The browser is already running. Stop it first with POST /v1/browser/stop.", + ) + } + + // 409 - desktop mode is active, cannot start browser + pub fn desktop_conflict() -> Self { + Self::new( + 409, + "Desktop Conflict", + "browser/desktop-conflict", + "The desktop runtime is currently active. Browser and desktop modes are mutually exclusive.", + ) + } + + // 424 - missing dependencies + pub fn install_required(message: impl Into) -> Self { + Self::new( + 424, + "Browser Install Required", + "browser/install-required", + message, + ) + } + + // 500 - startup sequence failed + pub fn start_failed(message: impl Into) -> Self { + Self::new(500, "Browser Start Failed", "browser/start-failed", message) + } + + // 502 - CDP communication error + pub fn cdp_error(message: impl Into) -> Self { + Self::new(502, "CDP Error", "browser/cdp-error", message) + } + + // 504 - operation timed out + pub fn timeout(message: impl Into) -> Self { + Self::new(504, "Browser Timeout", "browser/timeout", message) + } + + // 404 - tab/context/element not found + pub fn not_found(message: impl Into) -> Self { + Self::new(404, "Not Found", "browser/not-found", message) + } + + // 400 - bad CSS selector + pub fn invalid_selector(message: impl Into) -> Self { + Self::new(400, "Invalid Selector", "browser/invalid-selector", message) + } + + pub fn to_problem_details(&self) -> ProblemDetails { + let mut extensions = Map::new(); + extensions.insert("code".to_string(), Value::String(self.code.to_string())); + + ProblemDetails { + type_: format!("tag:sandboxagent.dev,2025:{}", self.code), + title: self.title.to_string(), + status: self.status, + detail: Some(self.message.clone()), + instance: None, + extensions, + } + } + + pub fn to_error_info(&self) -> DesktopErrorInfo { + DesktopErrorInfo { + code: self.code.to_string(), + message: self.message.clone(), + } + } + + pub fn code(&self) -> &'static str { + self.code + } + + fn new( + status: u16, + title: &'static str, + code: &'static str, + message: impl Into, + ) -> Self { + Self { + status, + title, + code, + message: message.into(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn not_active_produces_correct_problem_details() { + let problem = BrowserProblem::not_active(); + let details = problem.to_problem_details(); + assert_eq!(details.status, 409); + assert_eq!( + details.type_, + "tag:sandboxagent.dev,2025:browser/not-active" + ); + assert_eq!(details.title, "Browser Not Active"); + assert!(details.detail.unwrap().contains("not running")); + } + + #[test] + fn cdp_error_includes_custom_message() { + let problem = BrowserProblem::cdp_error("connection refused"); + let details = problem.to_problem_details(); + assert_eq!(details.status, 502); + assert_eq!(details.detail.unwrap(), "connection refused"); + assert_eq!( + details.extensions.get("code"), + Some(&Value::String("browser/cdp-error".to_string())) + ); + } + + #[test] + fn install_required_uses_424_status() { + let problem = BrowserProblem::install_required("chromium not found"); + let details = problem.to_problem_details(); + assert_eq!(details.status, 424); + assert_eq!( + details.type_, + "tag:sandboxagent.dev,2025:browser/install-required" + ); + } + + #[test] + fn to_error_info_returns_code_and_message() { + let problem = BrowserProblem::timeout("CDP poll timed out after 15s"); + let info = problem.to_error_info(); + assert_eq!(info.code, "browser/timeout"); + assert_eq!(info.message, "CDP poll timed out after 15s"); + } +} diff --git a/server/packages/sandbox-agent/src/browser_types.rs b/server/packages/sandbox-agent/src/browser_types.rs new file mode 100644 index 0000000..29a6588 --- /dev/null +++ b/server/packages/sandbox-agent/src/browser_types.rs @@ -0,0 +1,578 @@ +use std::collections::HashMap; + +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use utoipa::{IntoParams, ToSchema}; + +use crate::desktop_types::{DesktopErrorInfo, DesktopProcessInfo, DesktopResolution}; + +// --------------------------------------------------------------------------- +// State +// --------------------------------------------------------------------------- + +#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, ToSchema, PartialEq, Eq)] +#[serde(rename_all = "snake_case")] +pub enum BrowserState { + Inactive, + InstallRequired, + Starting, + Active, + Stopping, + Failed, +} + +// --------------------------------------------------------------------------- +// Lifecycle +// --------------------------------------------------------------------------- + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema, IntoParams, Default)] +#[serde(rename_all = "camelCase")] +pub struct BrowserStartRequest { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub width: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub dpi: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub headless: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub context_id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub stream_video_codec: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub stream_audio_codec: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub stream_frame_rate: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub webrtc_port_range: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub recording_fps: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct BrowserStatusResponse { + pub state: BrowserState, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub display: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub resolution: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub started_at: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub cdp_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub url: Option, + #[serde(default)] + pub missing_dependencies: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub install_command: Option, + #[serde(default)] + pub processes: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub last_error: Option, +} + +// --------------------------------------------------------------------------- +// Navigation +// --------------------------------------------------------------------------- + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct BrowserNavigateRequest { + pub url: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub wait_until: Option, +} + +#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, ToSchema, PartialEq, Eq)] +#[serde(rename_all = "lowercase")] +pub enum BrowserNavigateWaitUntil { + Load, + Domcontentloaded, + Networkidle, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct BrowserPageInfo { + pub url: String, + pub title: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub status: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema, Default)] +#[serde(rename_all = "camelCase")] +pub struct BrowserReloadRequest { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub ignore_cache: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct BrowserWaitRequest { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub selector: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub timeout: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub state: Option, +} + +#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, ToSchema, PartialEq, Eq)] +#[serde(rename_all = "lowercase")] +pub enum BrowserWaitState { + Visible, + Hidden, + Attached, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct BrowserWaitResponse { + pub found: bool, +} + +// --------------------------------------------------------------------------- +// Tabs +// --------------------------------------------------------------------------- + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct BrowserTabInfo { + pub id: String, + pub url: String, + pub title: String, + pub active: bool, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct BrowserTabListResponse { + pub tabs: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema, Default)] +#[serde(rename_all = "camelCase")] +pub struct BrowserCreateTabRequest { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub url: Option, +} + +// --------------------------------------------------------------------------- +// Screenshots & PDF +// --------------------------------------------------------------------------- + +#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, ToSchema, PartialEq, Eq)] +#[serde(rename_all = "lowercase")] +pub enum BrowserScreenshotFormat { + Png, + Jpeg, + Webp, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema, IntoParams, Default)] +#[serde(rename_all = "camelCase")] +pub struct BrowserScreenshotQuery { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub format: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub quality: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub full_page: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub selector: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema, IntoParams, Default)] +#[serde(rename_all = "camelCase")] +pub struct BrowserPdfQuery { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub format: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub landscape: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub print_background: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub scale: Option, +} + +#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, ToSchema, PartialEq, Eq)] +#[serde(rename_all = "lowercase")] +pub enum BrowserPdfFormat { + A4, + Letter, + Legal, +} + +// --------------------------------------------------------------------------- +// Content extraction +// --------------------------------------------------------------------------- + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema, IntoParams, Default)] +#[serde(rename_all = "camelCase")] +pub struct BrowserContentQuery { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub selector: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct BrowserContentResponse { + pub html: String, + pub url: String, + pub title: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct BrowserMarkdownResponse { + pub markdown: String, + pub url: String, + pub title: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct BrowserLinkInfo { + pub href: String, + pub text: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct BrowserLinksResponse { + pub links: Vec, + pub url: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct BrowserSnapshotResponse { + pub snapshot: String, + pub url: String, + pub title: String, +} + +// --------------------------------------------------------------------------- +// Scrape +// --------------------------------------------------------------------------- + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct BrowserScrapeRequest { + pub selectors: HashMap, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub url: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct BrowserScrapeResponse { + pub data: HashMap>, + pub url: String, + pub title: String, +} + +// --------------------------------------------------------------------------- +// Execute +// --------------------------------------------------------------------------- + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct BrowserExecuteRequest { + pub expression: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub await_promise: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct BrowserExecuteResponse { + pub result: Value, + #[serde(rename = "type")] + pub type_: String, +} + +// --------------------------------------------------------------------------- +// Interaction +// --------------------------------------------------------------------------- + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct BrowserClickRequest { + pub selector: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub button: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub click_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub timeout: Option, +} + +#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, ToSchema, PartialEq, Eq)] +#[serde(rename_all = "lowercase")] +pub enum BrowserMouseButton { + Left, + Right, + Middle, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct BrowserTypeRequest { + pub selector: String, + pub text: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub delay: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub clear: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct BrowserSelectRequest { + pub selector: String, + pub value: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct BrowserHoverRequest { + pub selector: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct BrowserScrollRequest { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub selector: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub x: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub y: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct BrowserUploadRequest { + pub selector: String, + pub path: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct BrowserDialogRequest { + pub accept: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub text: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct BrowserActionResponse { + pub ok: bool, +} + +// --------------------------------------------------------------------------- +// Console monitoring +// --------------------------------------------------------------------------- + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema, IntoParams, Default)] +#[serde(rename_all = "camelCase")] +pub struct BrowserConsoleQuery { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub level: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub limit: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct BrowserConsoleMessage { + pub level: String, + pub text: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub line: Option, + pub timestamp: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct BrowserConsoleResponse { + pub messages: Vec, +} + +// --------------------------------------------------------------------------- +// Network monitoring +// --------------------------------------------------------------------------- + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema, IntoParams, Default)] +#[serde(rename_all = "camelCase")] +pub struct BrowserNetworkQuery { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub url_pattern: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct BrowserNetworkRequest { + pub url: String, + pub method: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub status: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub response_size: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub duration: Option, + pub timestamp: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct BrowserNetworkResponse { + pub requests: Vec, +} + +// --------------------------------------------------------------------------- +// Crawling +// --------------------------------------------------------------------------- + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct BrowserCrawlRequest { + pub url: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub max_pages: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub max_depth: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub allowed_domains: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub extract: Option, +} + +#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, ToSchema, PartialEq, Eq)] +#[serde(rename_all = "lowercase")] +pub enum BrowserCrawlExtract { + Markdown, + Html, + Text, + Links, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct BrowserCrawlPage { + pub url: String, + pub title: String, + pub content: String, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub links: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub status: Option, + pub depth: u32, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct BrowserCrawlResponse { + pub pages: Vec, + pub total_pages: u32, + pub truncated: bool, +} + +// --------------------------------------------------------------------------- +// Contexts (persistent profiles) +// --------------------------------------------------------------------------- + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct BrowserContextInfo { + pub id: String, + pub name: String, + pub created_at: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub size_bytes: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct BrowserContextListResponse { + pub contexts: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct BrowserContextCreateRequest { + pub name: String, +} + +// --------------------------------------------------------------------------- +// Cookies +// --------------------------------------------------------------------------- + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema, IntoParams, Default)] +#[serde(rename_all = "camelCase")] +pub struct BrowserCookiesQuery { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub url: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct BrowserCookie { + pub name: String, + pub value: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub domain: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub path: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub expires: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub http_only: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub secure: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub same_site: Option, +} + +#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, ToSchema, PartialEq, Eq)] +pub enum BrowserCookieSameSite { + Strict, + Lax, + None, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct BrowserCookiesResponse { + pub cookies: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct BrowserSetCookiesRequest { + pub cookies: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema, IntoParams, Default)] +#[serde(rename_all = "camelCase")] +pub struct BrowserDeleteCookiesQuery { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub domain: Option, +} diff --git a/server/packages/sandbox-agent/src/lib.rs b/server/packages/sandbox-agent/src/lib.rs index faa1d52..32b4427 100644 --- a/server/packages/sandbox-agent/src/lib.rs +++ b/server/packages/sandbox-agent/src/lib.rs @@ -1,7 +1,9 @@ //! Sandbox agent core utilities. mod acp_proxy_runtime; +mod browser_errors; mod browser_install; +pub mod browser_types; pub mod cli; pub mod daemon; mod desktop_errors;