from __future__ import annotations from datetime import datetime from typing import Literal from pydantic import BaseModel, Field, field_validator INSTANCE_PATTERN = r"^[a-z0-9](?:[a-z0-9-]{0,38}[a-z0-9])?$" class Resources(BaseModel): storage: str = "1Gi" cpu_limit: str = "300m" memory_limit: str = "1536Mi" class AccountBase(BaseModel): instance_id: str = Field(pattern=INSTANCE_PATTERN, max_length=40) display_name: str = Field(min_length=1, max_length=80) api_id: int = Field(gt=0) api_hash: str = Field(min_length=16, max_length=128) resources: Resources = Field(default_factory=Resources) @field_validator("display_name", "api_hash") @classmethod def strip_text(cls, value: str) -> str: return value.strip() class PhoneStart(AccountBase): phone: str = Field(min_length=7, max_length=32) @field_validator("phone") @classmethod def normalize_phone(cls, value: str) -> str: value = value.strip() if not value.startswith("+"): raise ValueError("phone must use international format") return value class StringSessionStart(AccountBase): session_string: str = Field(min_length=32) class CodeSubmit(BaseModel): code: str = Field(min_length=3, max_length=12) @field_validator("code") @classmethod def normalize_code(cls, value: str) -> str: return "".join(value.split()) class PasswordSubmit(BaseModel): password: str = Field(min_length=1, max_length=256) class DeleteRequest(BaseModel): confirmation: str delete_data: bool = False class InstanceSummary(BaseModel): instance_id: str display_name: str namespace: str deployment: str pod: str | None = None status: Literal["running", "stopped", "pending", "error"] reason: str | None = None ready: bool = False restarts: int = 0 pvc: str | None = None storage: str | None = None image: str cpu_limit: str | None = None memory_limit: str | None = None cpu_usage: str | None = None memory_usage: str | None = None updated_at: datetime | None = None legacy: bool = False deletable: bool = True class AuthResult(BaseModel): status: Literal["code_required", "password_required", "ready"] flow_id: str | None = None instance: InstanceSummary | None = None