6cc797f915
- Retain login state in remote browser profiles (don't delete on disconnect)
- Add GET /api/browser-sessions/{id}/clipboard for clipboard sync
- Add POST /api/browser-sessions/{id}/autofill-login for manual credential fill
- Add DELETE /api/browser-sessions/profiles/{custom_page_id} for login clear
- Add balance tracking with configurable divisor (balance_divisor)
- Health check on session reuse, idle TTL eviction, background cleanup
- Add first-frame watchdog (10s timeout) to prevent infinite loading
- Reconnect browser on active=true when session was closed
- UI: uniform text-only inline buttons (websites + upstreams pages)
- Fix page switch race with closingRemoteSessionPromise
92 lines
2.3 KiB
Python
92 lines
2.3 KiB
Python
from datetime import datetime
|
|
from typing import Optional, Any
|
|
from pydantic import BaseModel
|
|
|
|
|
|
class AuthConfigBearer(BaseModel):
|
|
token: str = ""
|
|
|
|
|
|
class AuthConfigApiKey(BaseModel):
|
|
key: str = ""
|
|
header: str = "Authorization"
|
|
|
|
|
|
class AuthConfigLoginPassword(BaseModel):
|
|
email: str = ""
|
|
password: str = ""
|
|
login_path: str = "/auth/login"
|
|
|
|
|
|
class UpstreamCreate(BaseModel):
|
|
name: str
|
|
base_url: str
|
|
api_prefix: str = "/api/v1"
|
|
auth_type: str = "login_password" # none | bearer | api_key | login_password
|
|
auth_config: dict[str, Any] = {}
|
|
rate_endpoint: str = "/groups/rates"
|
|
groups_endpoint: str = "/groups/available"
|
|
enabled: bool = True
|
|
check_interval_seconds: int = 600
|
|
timeout_seconds: int = 30
|
|
balance_endpoint: str = ""
|
|
balance_response_path: str = ""
|
|
balance_divisor: float = 1.0
|
|
|
|
|
|
class UpstreamUpdate(BaseModel):
|
|
name: Optional[str] = None
|
|
base_url: Optional[str] = None
|
|
api_prefix: Optional[str] = None
|
|
auth_type: Optional[str] = None
|
|
auth_config: Optional[dict[str, Any]] = None
|
|
rate_endpoint: Optional[str] = None
|
|
groups_endpoint: Optional[str] = None
|
|
enabled: Optional[bool] = None
|
|
check_interval_seconds: Optional[int] = None
|
|
timeout_seconds: Optional[int] = None
|
|
balance_endpoint: Optional[str] = None
|
|
balance_response_path: Optional[str] = None
|
|
balance_divisor: Optional[float] = None
|
|
|
|
|
|
class UpstreamResponse(BaseModel):
|
|
id: int
|
|
name: str
|
|
base_url: str
|
|
api_prefix: str
|
|
auth_type: str
|
|
auth_config_masked: dict[str, Any] # secrets replaced with ***
|
|
rate_endpoint: str
|
|
groups_endpoint: str
|
|
enabled: bool
|
|
check_interval_seconds: int
|
|
timeout_seconds: int
|
|
last_status: str
|
|
last_checked_at: Optional[datetime]
|
|
last_error: Optional[str]
|
|
balance: Optional[float] = None
|
|
balance_updated_at: Optional[datetime] = None
|
|
balance_endpoint: str = ""
|
|
balance_response_path: str = ""
|
|
balance_divisor: float = 1.0
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
model_config = {"from_attributes": True}
|
|
|
|
|
|
class SnapshotResponse(BaseModel):
|
|
id: int
|
|
upstream_id: int
|
|
snapshot: dict[str, Any]
|
|
captured_at: datetime
|
|
|
|
model_config = {"from_attributes": True}
|
|
|
|
|
|
class TestResult(BaseModel):
|
|
success: bool
|
|
message: str
|
|
detail: Optional[str] = None
|