export interface PaginatedResponse { data: T[] pagination: { page: number; page_size: number; total?: number } } export interface Recipient { name: string address: string } export interface ApiMessageSummary { id: string message_id: string thread_id?: string account_id: string subject: string from: Recipient[] to: Recipient[] date: string snippet: string flags: string[] labels: string[] has_attachments: boolean } export interface MessageAuthInfo { mailed_by?: string signed_by?: string dkim_pass?: boolean tls?: boolean list_unsubscribe?: string } export interface ApiMessageFull extends ApiMessageSummary { cc?: Recipient[] reply_to?: Recipient[] auth_info?: MessageAuthInfo body_text?: string body_html?: string in_reply_to?: string references?: string } export interface ApiMailAccount { id: string name: string email: string provider: string imap_host: string smtp_host: string is_active: boolean last_sync_at?: string created_at: string } export interface ApiMailAccountDetail extends ApiMailAccount { imap_port: number imap_tls: boolean smtp_port: number smtp_tls: boolean auth_type: 'password' | 'oauth2' | string username: string oauth_provider?: string } export interface ApiOutboxMessage { id: string account_id: string status: 'draft' | 'queued' | 'scheduled' | 'sending' | 'sent' | 'failed' | 'cancelled' to: Recipient[] cc?: Recipient[] bcc?: Recipient[] subject: string body_html: string scheduled_at?: string created_at: string } export interface MessageSearchFilter { q?: string from?: string label?: string account_id?: string date_from?: string date_to?: string has_attachment?: boolean } export interface ApiContact { uid: string full_name: string email?: string phone?: string org?: string path?: string etag?: string raw_vcard?: string } export interface ApiContactSyncResponse { sync_token: string contacts: ApiContact[] deleted: string[] } export interface ApiFolder { id: string account_id: string name: string remote_name: string folder_type: 'inbox' | 'sent' | 'drafts' | 'trash' | 'archive' | 'spam' | 'custom' message_count: number unread_count: number } export interface ApiUnifiedFolder { id: string name: string color: string sort_order?: number scope: 'global' | 'account' account_id?: string parent_id?: string created_at?: string updated_at?: string } export interface ApiLabel { id: string name: string color: string sort_order?: number created_at: string } export interface ApiMailSignature { id: string name: string html: string sort_order?: number created_at?: string updated_at?: string } export interface ApiIdentity { id: string account_id: string email: string name: string is_default: boolean signature_html?: string default_signature_id?: string reply_to_addrs?: string[] } export interface CreateMailSignaturePayload { name: string html: string } export interface ApiMailNotificationSettings { desktop_new_mail: boolean desktop_mentions: boolean email_digest: boolean sound_enabled: boolean } export interface ApiMailSettings { density: 'default' | 'normal' | 'compact' theme_mode: 'light' | 'dark' | 'system' background_id: string inbox_sort: 'default' | 'important' | 'unread' | 'starred' reading_pane: 'none' | 'right' | 'below' conversation_mode: boolean notifications?: ApiMailNotificationSettings updated_at?: string } export interface ApiRule { id: string name: string priority: number conditions: unknown actions: unknown workflow?: unknown rule_kind?: 'rule' | 'function' is_active: boolean match_count?: number account_id?: string } export interface ApiWebhook { id: string name: string url: string method: string headers?: Record body_template?: string max_retries?: number is_active?: boolean } export interface ApiTokenPermissionGrant { resource: string read: boolean write: boolean } export interface ApiTokenMailScope { all_accounts: boolean account_ids: string[] } export interface ApiTokenDriveScope { all_folders: boolean folder_paths: string[] } export interface ApiToken { id: string name: string token_prefix: string permissions: ApiTokenPermissionGrant[] mail_scope: ApiTokenMailScope drive_scope: ApiTokenDriveScope created_at: string last_used_at?: string expires_at?: string } export interface ApiTokenCreated extends ApiToken { token: string } export interface CreateApiTokenPayload { name: string permissions: ApiTokenPermissionGrant[] mail_scope: ApiTokenMailScope drive_scope: ApiTokenDriveScope expires_at?: string } export interface MailAccountTestResult { ok: boolean imap_ok: boolean imap_error?: string smtp_ok: boolean smtp_error?: string } export interface MailOAuthProvidersResponse { providers: string[] } export interface MailAccountDiscoverResult { email: string domain: string provider_id: string provider_name: string source: 'preset' | 'mx' | 'autoconfig' | 'guess' | string confidence: 'high' | 'medium' | 'low' | string imap_host: string imap_port: number imap_tls: boolean smtp_host: string smtp_port: number smtp_tls: boolean username_hint: 'email' | 'local' | string auth_methods: string[] notes?: string[] } export interface CreateMailAccountPayload { name: string email: string provider?: string imap_host: string imap_port?: number imap_tls?: boolean smtp_host: string smtp_port?: number smtp_tls?: boolean username: string password: string } export interface UpdateMailAccountPayload { name: string email: string provider?: string imap_host: string imap_port: number imap_tls: boolean smtp_host: string smtp_port: number smtp_tls: boolean username: string /** Vide = conserver le mot de passe actuel */ password?: string } export interface CreateIdentityPayload { email: string name: string is_default?: boolean signature_html?: string default_signature_id?: string reply_to_addrs?: string[] } export interface MailListResponse { accounts?: T[] labels?: T[] folders?: T[] rules?: T[] webhooks?: T[] pagination?: { page: number; page_size: number; total?: number } } export type WsEventType = 'mail.created' | 'mail.updated' | 'mail.deleted' | 'outbox.updated' | 'contact.updated' | 'ws.ping' | 'ws.pong' export interface WsMailPayload { message_id: string account_id: string } export interface WsContactPayload { contact_id: string account_id?: string } export interface WsOutboxPayload { account_id: string } export interface WsEvent { type: WsEventType seq?: number payload?: WsMailPayload | WsContactPayload | WsOutboxPayload | Record } export interface ApiError { code: string message: string details?: unknown } export type DriveFileType = "file" | "directory" export interface DriveFileInfo { path: string name: string type: DriveFileType size: number mime_type: string last_modified: string etag: string is_favorite: boolean is_shared?: boolean /** Suite app d’origine (ultimail, ultimeet, …) — métadonnée ultid, pas le chemin NC. */ source?: string } export interface DriveListResponse { files: DriveFileInfo[] pagination?: { page: number page_size: number total?: number } } export interface DriveQuota { used: number free: number total: number relative: number } export interface DriveShare { id: string path: string share_type: number permissions: number url: string internal_url?: string access_mode?: "public" | "internal" | "user" | "email" expires_at?: string created_at?: string share_with?: string share_with_displayname?: string owner_id?: string owner_displayname?: string file_owner_id?: string file_owner_displayname?: string note?: string item_type?: string has_password?: boolean label?: string token?: string } export interface ShareRecipientLookup { email: string registered: boolean }