from datetime import datetime from typing import Any, Optional from pydantic import BaseModel, ConfigDict, Field class BaseSchema(BaseModel): model_config = ConfigDict(from_attributes=True) # === Developer === class DeveloperOut(BaseSchema): id: int name: str avatar_url: Optional[str] = None verified: bool # === Category === class CategoryOut(BaseSchema): slug: str name: str description: Optional[str] = None icon: Optional[str] = None class CategoryListResponse(BaseModel): items: list[CategoryOut] # === Version === class VersionInfo(BaseSchema): version: str release_notes: Optional[str] = None min_client_version: Optional[str] = None published_at: Optional[datetime] = None size_bytes: Optional[int] = None class ManifestOut(BaseModel): pages: Optional[list[dict[str, Any]]] = None commands: Optional[list[dict[str, Any]]] = None permissions: Optional[list[dict[str, Any]]] = None # === App === class AppSummary(BaseSchema): app_uid: str name: str type: str icon_url: Optional[str] = None short_description: Optional[str] = None categories: list[CategoryOut] = Field(default_factory=list) developer: Optional[DeveloperOut] = None current_version: Optional[VersionInfo] = None download_count: int = 0 is_featured: bool = False publish_time: Optional[datetime] = None class AppDetail(AppSummary): description: Optional[str] = None homepage_url: Optional[str] = None manifest: Optional[ManifestOut] = None class AppListResponse(BaseModel): items: list[AppSummary] total: int page: int page_size: int # === Download === class DownloadInfo(BaseModel): app_uid: str version: str url: Optional[str] = None checksum_sha256: Optional[str] = None size_bytes: Optional[int] = None # === Error === class ErrorResponse(BaseModel): code: str message: str