Files
donutbrowser/src/types.ts
T
2026-08-03 07:57:45 +04:00

648 lines
16 KiB
TypeScript

import type { CookieBotSchedule } from "@/lib/cookie-bot";
import type { RemoteSessionState } from "@/lib/remote-sessions";
export interface ProxySettings {
proxy_type: string;
host: string;
port: number;
username?: string;
password?: string;
vless_uri?: string;
}
export interface TableSortingSettings {
column: string; // "name", "note", "status"
direction: string; // "asc" or "desc"
}
export interface BrowserProfile {
id: string; // UUID of the profile
name: string;
browser: string;
version: string;
proxy_id?: string; // Reference to stored proxy
vpn_id?: string; // Reference to stored VPN config
launch_hook?: string;
process_id?: number;
last_launch?: number;
release_type: string;
wayfern_config?: WayfernConfig; // Wayfern configuration
group_id?: string; // Reference to profile group
tags?: string[];
note?: string; // User note
window_color?: string; // Per-profile window frame color "#RRGGBB"; auto-derived from the id when unset
sync_mode?: SyncMode;
encryption_salt?: string;
last_sync?: number; // Timestamp of last successful sync (epoch seconds)
host_os?: string; // OS where profile was created ("macos", "windows", "linux")
ephemeral?: boolean;
clear_on_close?: boolean;
extension_group_id?: string;
proxy_bypass_rules?: string[];
created_by_id?: string;
created_by_email?: string;
/** Profile creation timestamp (epoch seconds, UTC). Undefined for legacy
* profiles created before this field existed. */
created_at?: number;
dns_blocklist?: string;
password_protected?: boolean;
}
export interface Extension {
id: string;
name: string;
file_name: string;
file_type: string;
browser_compatibility: string[];
created_at: number;
updated_at: number;
sync_enabled?: boolean;
last_sync?: number;
version?: string;
description?: string;
author?: string;
homepage_url?: string;
}
export interface ExtensionGroup {
id: string;
name: string;
extension_ids: string[];
created_at: number;
updated_at: number;
sync_enabled?: boolean;
last_sync?: number;
}
export type SyncMode = "Disabled" | "Regular" | "Encrypted";
export type SyncStatus = "Disabled" | "Syncing" | "Synced" | "Error";
export interface SyncSettings {
sync_server_url?: string;
sync_token?: string;
}
/**
* Capability/limit set derived from the plan by the backend. Features are gated
* on these flags instead of a single "is paid?" check, so a plan like the future
* "starter" tier (cross-OS fingerprints + cloud backup, no automation) is just
* data. Mirrors `apps/backend/src/plans/entitlements.ts`. Resolve via
* `getEntitlements()` — the desktop populates it, but it stays optional for
* safety on older state.
*/
export interface Entitlements {
active: boolean;
browserAutomation: boolean;
crossOsFingerprints: boolean;
cloudBackup: boolean;
teamCollaboration: boolean;
/** Overnight profile warming on a leased remote host. */
cookieBot: boolean;
profileLimit: number;
requestsPerHour: number;
/**
* Per-seat monthly allowance for remote sessions. Reporting only: the
* spendable figure is whatever `get_remote_hours_quota` returns, because a
* team pools this across its seats and only the server knows the seat count.
*/
remoteBrowserHours: number;
}
/**
* What a backend older than the cookie-bot release actually sends. Read it
* through `getEntitlements()`, which fills the gap — never off `CloudUser`
* directly, or a paying customer's Cookie Bot silently reads `false`.
*/
export type ServerEntitlements = Omit<
Entitlements,
"cookieBot" | "remoteBrowserHours"
> &
Partial<Pick<Entitlements, "cookieBot" | "remoteBrowserHours">>;
export interface CloudUser {
id: string;
email: string;
plan: string;
planPeriod: string | null;
subscriptionStatus: string;
profileLimit: number;
cloudProfilesUsed: number;
proxyBandwidthLimitMb: number;
proxyBandwidthUsedMb: number;
proxyBandwidthExtraMb: number;
teamId?: string;
teamName?: string;
teamRole?: string;
// This device's position among the user's active devices (oldest = 1).
// Ordinal 1 / isPrimaryDevice === true is the only device that can run
// browser automation. Optional: older backends omit them.
deviceOrdinal?: number | null;
deviceCount?: number | null;
isPrimaryDevice?: boolean | null;
// Plan-derived capabilities. The desktop resolves this before handing CloudUser
// to the UI; optional to stay safe on older cached state.
entitlements?: ServerEntitlements;
}
/**
* Cookie Bot and remote-session wire types. Defined next to the transport that
* owns them (`src/lib/cookie-bot.ts`, `src/lib/remote-sessions.ts`) and
* re-exported here so a component reads one module. Type-only, so nothing is
* pulled into the bundle.
*/
export type {
CookieBotConflict,
CookieBotPreset,
CookieBotPresetList,
CookieBotRun,
CookieBotRunPage,
CookieBotRunStarted,
CookieBotSchedule,
CookieBotScheduleInput,
CookieBotScheduleList,
CookieBotScheduleSaved,
CookieBotScope,
CookieBotUsage,
CookieBotUsageMember,
CookieBotUsageProfile,
RemoteHoursMember,
RemoteHoursQuota,
} from "@/lib/cookie-bot";
export type {
RemoteSessionPhase,
RemoteSessionSnapshot,
RemoteSessionState,
} from "@/lib/remote-sessions";
/** Where a profile stands with the bot, as one row of the profile table reads it. */
export interface ProfileBotState {
/** The stored enrolment, or null when the profile is not enrolled. */
schedule: CookieBotSchedule | null;
/** A remote session for this profile that has not closed yet. */
liveSession: RemoteSessionState | null;
}
export interface ProfileLockInfo {
profileId: string;
lockedBy: string;
lockedByEmail: string;
lockedAt: string;
expiresAt?: string;
}
export interface CloudAuthState {
user: CloudUser;
logged_in_at: string;
}
export interface ProfileSyncStatusEvent {
profile_id: string;
status: "disabled" | "syncing" | "synced" | "error" | "pending";
}
export interface ProxyCheckResult {
ip: string;
city?: string;
country?: string;
country_code?: string;
timestamp: number;
is_valid: boolean;
}
export function isSyncEnabled(profile: BrowserProfile): boolean {
return profile.sync_mode != null && profile.sync_mode !== "Disabled";
}
export const CLOUD_PROXY_ID = "cloud-included-proxy";
export interface StoredProxy {
id: string;
name: string;
proxy_settings: ProxySettings;
sync_enabled?: boolean;
last_sync?: number;
is_cloud_managed?: boolean;
is_cloud_derived?: boolean;
geo_country?: string;
geo_state?: string;
geo_region?: string;
geo_city?: string;
geo_isp?: string;
}
export interface LocationItem {
code: string;
name: string;
}
export interface ProfileGroup {
id: string;
name: string;
sync_enabled?: boolean;
last_sync?: number;
}
export interface GroupWithCount {
id: string;
name: string;
count: number;
sync_enabled?: boolean;
last_sync?: number;
}
export interface DetectedProfile {
browser: string;
name: string;
path: string;
description: string;
mapped_browser: string;
}
export interface ImportProfileItem {
source_path: string;
browser_type?: string;
new_profile_name: string;
/** Mutually exclusive with `vpn_id`; the importer rejects setting both. */
proxy_id?: string | null;
vpn_id?: string | null;
}
export interface ProfileImportItemResult {
name: string;
source_path: string;
status: "imported" | "skipped" | "failed";
profile_id: string | null;
error: string | null;
}
export interface ProfileImportBatchResult {
imported_count: number;
skipped_count: number;
failed_count: number;
results: ProfileImportItemResult[];
}
export interface ArchiveScanResult {
extracted_dir: string;
profiles: DetectedProfile[];
}
export interface ProfileImportProgress {
total: number;
completed: number;
index: number;
name: string;
status: "importing" | "imported" | "skipped" | "failed";
}
export interface BrowserReleaseTypes {
stable?: string;
}
export interface AppUpdateInfo {
current_version: string;
new_version: string;
release_notes: string;
download_url: string;
is_nightly: boolean;
published_at: string;
manual_update_required: boolean;
release_page_url?: string;
repo_update: boolean;
/** URL of the release's SHA256SUMS.txt; downloads are verified against it. */
checksums_url?: string | null;
/** GitHub-computed digest of the chosen asset ("sha256:<hex>"). */
asset_digest?: string | null;
}
export interface AppUpdateProgress {
stage: string; // "downloading", "extracting", "installing", "completed"
percentage?: number;
speed?: string; // MB/s
eta?: string; // estimated time remaining
message: string;
}
export type WayfernOS = "windows" | "macos" | "linux" | "android" | "ios";
export interface WayfernConfig {
proxy?: string;
screen_max_width?: number;
screen_max_height?: number;
screen_min_width?: number;
screen_min_height?: number;
geoip?: string | boolean; // For compatibility with shared config form
block_images?: boolean; // For compatibility with shared config form
block_webrtc?: boolean;
block_webgl?: boolean;
executable_path?: string;
fingerprint?: string; // JSON string of the complete fingerprint config
randomize_fingerprint_on_launch?: boolean; // Generate new fingerprint on every launch
os?: WayfernOS; // Operating system for fingerprint generation
geo_proxy_signature?: string; // Internal: routing the fingerprint's location was computed for
}
// Wayfern fingerprint config - matches the C++ FingerprintData structure
export interface WayfernFingerprintConfig {
// User agent and platform
userAgent?: string;
platform?: string;
platformVersion?: string;
brand?: string;
brandVersion?: string;
// Hardware
hardwareConcurrency?: number;
maxTouchPoints?: number;
deviceMemory?: number;
// Screen
screenWidth?: number;
screenHeight?: number;
screenAvailWidth?: number;
screenAvailHeight?: number;
screenColorDepth?: number;
screenPixelDepth?: number;
devicePixelRatio?: number;
// Window
windowOuterWidth?: number;
windowOuterHeight?: number;
windowInnerWidth?: number;
windowInnerHeight?: number;
screenX?: number;
screenY?: number;
// Language
language?: string;
languages?: string[];
// Browser features
doNotTrack?: string;
cookieEnabled?: boolean;
webdriver?: boolean;
pdfViewerEnabled?: boolean;
// WebGL
webglVendor?: string;
webglRenderer?: string;
webglVersion?: string;
webglShadingLanguageVersion?: string;
webglParameters?: string; // JSON string
webgl2Parameters?: string; // JSON string
webglShaderPrecisionFormats?: string; // JSON string
webgl2ShaderPrecisionFormats?: string; // JSON string
// Timezone and geolocation
timezone?: string;
timezoneOffset?: number;
latitude?: number;
longitude?: number;
accuracy?: number;
// Media queries / preferences
prefersReducedMotion?: boolean;
prefersDarkMode?: boolean;
prefersContrast?: string;
prefersReducedData?: boolean;
// Color/HDR
colorGamutSrgb?: boolean;
colorGamutP3?: boolean;
colorGamutRec2020?: boolean;
hdrSupport?: boolean;
// Audio
audioSampleRate?: number;
audioMaxChannelCount?: number;
// Storage
localStorage?: boolean;
sessionStorage?: boolean;
indexedDb?: boolean;
// Canvas
canvasNoiseSeed?: string;
// Fonts, plugins, mime types (JSON strings)
fonts?: string; // JSON array string
plugins?: string; // JSON array string
mimeTypes?: string; // JSON array string
// Battery (optional)
batteryCharging?: boolean;
batteryChargingTime?: number;
batteryDischargingTime?: number;
batteryLevel?: number;
// Voices
voices?: string; // JSON array string
// Vendor info
vendor?: string;
vendorSub?: string;
productSub?: string;
// Network (optional)
connectionEffectiveType?: string;
connectionDownlink?: number;
connectionRtt?: number;
// Performance
performanceMemory?: number;
}
export interface WayfernLaunchResult {
id: string;
processId?: number;
profilePath?: string;
url?: string;
cdp_port?: number;
}
// Synchronizer types
export interface SyncFollowerState {
profile_id: string;
profile_name: string;
failed_at_url: string | null;
}
export interface SyncSessionInfo {
id: string;
leader_profile_id: string;
leader_profile_name: string;
followers: SyncFollowerState[];
}
// Traffic stats types
export interface BandwidthDataPoint {
timestamp: number;
bytes_sent: number;
bytes_received: number;
}
export interface DomainAccess {
domain: string;
request_count: number;
bytes_sent: number;
bytes_received: number;
first_access: number;
last_access: number;
}
export interface TrafficStats {
proxy_id: string;
profile_id?: string;
session_start: number;
last_update: number;
total_bytes_sent: number;
total_bytes_received: number;
total_requests: number;
bandwidth_history: BandwidthDataPoint[];
domains: Record<string, DomainAccess>;
unique_ips: string[];
}
export interface TrafficSnapshot {
profile_id?: string;
session_start: number;
last_update: number;
total_bytes_sent: number;
total_bytes_received: number;
total_requests: number;
current_bytes_sent: number;
current_bytes_received: number;
recent_bandwidth: BandwidthDataPoint[];
}
export interface FilteredTrafficStats {
profile_id?: string;
session_start: number;
last_update: number;
total_bytes_sent: number;
total_bytes_received: number;
total_requests: number;
bandwidth_history: BandwidthDataPoint[];
period_bytes_sent: number;
period_bytes_received: number;
period_requests: number;
domains: Record<string, DomainAccess>;
unique_ips: string[];
}
// Cookie copy types
export interface UnifiedCookie {
name: string;
value: string;
domain: string;
path: string;
expires: number;
is_secure: boolean;
is_http_only: boolean;
same_site: number;
creation_time: number;
last_accessed: number;
}
export interface DomainCookies {
domain: string;
cookies: UnifiedCookie[];
cookie_count: number;
}
export interface CookieReadResult {
profile_id: string;
browser_type: string;
domains: DomainCookies[];
total_count: number;
}
export interface SelectedCookie {
domain: string;
name: string;
}
export interface CookieCopyRequest {
source_profile_id: string;
target_profile_ids: string[];
selected_cookies: SelectedCookie[];
}
export interface CookieCopyResult {
target_profile_id: string;
cookies_copied: number;
cookies_replaced: number;
errors: string[];
}
// Proxy import/export types
export interface ProxyExportData {
version: string;
proxies: ExportedProxy[];
exported_at: string;
source: string;
}
export interface ExportedProxy {
name: string;
type: string;
host: string;
port: number;
username?: string;
password?: string;
}
export interface ProxyImportResult {
imported_count: number;
skipped_count: number;
errors: string[];
proxies: StoredProxy[];
}
export interface ParsedProxyLine {
proxy_type: string;
host: string;
port: number;
username?: string;
password?: string;
vless_uri?: string;
original_line: string;
}
export type ProxyParseResult =
| ({ status: "parsed" } & ParsedProxyLine)
| { status: "ambiguous"; line: string; possible_formats: string[] }
| { status: "invalid"; line: string; reason: string };
// VPN types
export type VpnType = "WireGuard";
export interface VpnConfig {
id: string;
name: string;
vpn_type: VpnType;
config_data: string; // Raw config content (may be empty in list view)
created_at: number;
last_used?: number;
sync_enabled?: boolean;
last_sync?: number;
}
export interface VpnImportResult {
success: boolean;
vpn_id?: string;
vpn_type?: VpnType;
name: string;
error?: string;
}
export interface VpnStatus {
connected: boolean;
vpn_id: string;
connected_at?: number;
bytes_sent?: number;
bytes_received?: number;
last_handshake?: number;
}