import type { Email, Mailbox, StateChange, AccountStates, Thread, Identity, EmailAddress, ContactCard, AddressBook, VacationResponse, Calendar, CalendarEvent, CalendarEventFilter, CalendarTask, FileNode } from "./types"; import type { SieveScript, SieveCapabilities } from "./sieve-types"; /** * Interface defining the public JMAP client contract. * * Both the real `JMAPClient` (network-backed) and `DemoJMAPClient` * (in-memory/browser-only) implement this interface so that stores * and UI code never need to know which one is active. */ export interface IJMAPClient { // ── Connection lifecycle ────────────────────────────────────── connect(): Promise; disconnect(): void; reconnect(): Promise; ping(): Promise; // ── Session / auth accessors ────────────────────────────────── getServerUrl(): string; getAuthHeader(): string; updateAccessToken(token: string): void; getAccountId(): string; getUsername(): string; // ── Capabilities ────────────────────────────────────────────── getCapabilities(): Record; getMaxSizeUpload(): number; getMaxCallsInRequest(): number; getMaxObjectsInGet(): number; getEventSourceUrl(): string | null; supportsEmailSubmission(): boolean; supportsQuota(): boolean; supportsVacationResponse(): boolean; supportsContacts(): boolean; supportsCalendars(): boolean; supportsSieve(): boolean; supportsFiles(): boolean; // ── Push / state ────────────────────────────────────────────── setupPushNotifications(): boolean; closePushNotifications(): void; onConnectionChange(callback: (connected: boolean) => void): void; onStateChange(callback: (change: StateChange) => void): void; getLastStates(): AccountStates; setLastStates(states: AccountStates): void; // ── Quota ───────────────────────────────────────────────────── getQuota(): Promise<{ used: number; total: number } | null>; // ── Mailboxes ───────────────────────────────────────────────── getMailboxes(): Promise; getAllMailboxes(): Promise; createMailbox(name: string, parentId?: string): Promise; updateMailbox(mailboxId: string, changes: { name?: string; parentId?: string | null; role?: string | null; sortOrder?: number }): Promise; deleteMailbox(mailboxId: string): Promise; // ── Emails ──────────────────────────────────────────────────── getEmails(mailboxId?: string, accountId?: string, limit?: number, position?: number, hasKeyword?: string): Promise<{ emails: Email[]; hasMore: boolean; total: number }>; getEmailsInMailbox(mailboxId: string): Promise; getEmail(emailId: string, accountId?: string): Promise; getTagCounts(tagIds: string[]): Promise>; searchEmails(query: string, mailboxId?: string, accountId?: string, limit?: number, position?: number): Promise<{ emails: Email[]; hasMore: boolean; total: number }>; advancedSearchEmails( filter: Record, accountId?: string, limit?: number, position?: number, ): Promise<{ emails: Email[]; hasMore: boolean; total: number }>; // ── Email mutations ─────────────────────────────────────────── markAsRead(emailId: string, read?: boolean, accountId?: string): Promise; batchMarkAsRead(emailIds: string[], read?: boolean): Promise; toggleStar(emailId: string, starred: boolean): Promise; updateEmailKeywords(emailId: string, keywords: Record): Promise; migrateKeyword(oldKeyword: string, newKeyword: string): Promise; deleteEmail(emailId: string): Promise; moveToTrash(emailId: string, trashMailboxId: string, accountId?: string): Promise; batchDeleteEmails(emailIds: string[]): Promise; batchMoveEmails(emailIds: string[], toMailboxId: string): Promise; moveEmail(emailId: string, toMailboxId: string, accountId?: string): Promise; emptyMailbox(mailboxId: string): Promise; markAsSpam(emailId: string, accountId?: string): Promise; undoSpam(emailId: string, originalMailboxId: string, accountId?: string): Promise; // ── Threads ─────────────────────────────────────────────────── getThread(threadId: string, accountId?: string): Promise; getThreadEmails(threadId: string, accountId?: string): Promise; // ── Compose / Send ──────────────────────────────────────────── createDraft( to: string[], subject: string, body: string, cc?: string[], bcc?: string[], identityId?: string, fromEmail?: string, draftId?: string, attachments?: Array<{ blobId: string; name: string; type: string; size: number }>, fromName?: string, ): Promise; sendEmail( to: string[], subject: string, body: string, cc?: string[], bcc?: string[], identityId?: string, fromEmail?: string, draftId?: string, fromName?: string, htmlBody?: string, attachments?: Array<{ blobId: string; name: string; type: string; size: number }>, ): Promise; sendImipReply(opts: { organizerEmail: string; organizerName?: string; attendeeEmail: string; attendeeName?: string; uid: string; summary?: string; dtStart?: string; dtEnd?: string; timeZone?: string; isAllDay?: boolean; sequence?: number; status: 'ACCEPTED' | 'TENTATIVE' | 'DECLINED'; identityId?: string; }): Promise; sendImipInvitation(event: CalendarEvent): Promise; sendImipCancellation(event: CalendarEvent): Promise; // ── Blobs ───────────────────────────────────────────────────── uploadBlob(file: File): Promise<{ blobId: string; size: number; type: string }>; getBlobDownloadUrl(blobId: string, name?: string, type?: string): string; fetchBlob(blobId: string, name?: string, type?: string): Promise; fetchBlobAsObjectUrl(blobId: string, name?: string, type?: string): Promise; fetchBlobArrayBuffer(blobId: string, name?: string, type?: string): Promise; downloadBlob(blobId: string, name?: string, type?: string): Promise; // ── Identities ──────────────────────────────────────────────── getIdentities(): Promise; createIdentity( name: string, email: string, replyTo?: EmailAddress[] | null, bcc?: EmailAddress[] | null, htmlSignature?: string, textSignature?: string, ): Promise; updateIdentity( identityId: string, updates: { name?: string; replyTo?: EmailAddress[] | null; bcc?: EmailAddress[] | null; htmlSignature?: string; textSignature?: string; }, ): Promise; deleteIdentity(identityId: string): Promise; // ── Vacation ────────────────────────────────────────────────── getVacationResponse(): Promise; setVacationResponse(updates: Partial): Promise; // ── Contacts ────────────────────────────────────────────────── getContactsAccountId(): string; getAddressBooks(): Promise; getAllAddressBooks(): Promise; getContacts(addressBookId?: string): Promise; getAllContacts(): Promise; getContact(contactId: string, accountId?: string): Promise; createContact(contact: Partial, targetAccountId?: string): Promise; updateContact(contactId: string, updates: Partial, targetAccountId?: string): Promise; deleteContact(contactId: string, targetAccountId?: string): Promise; searchContacts(query: string): Promise; // ── Calendars ───────────────────────────────────────────────── getCalendarsAccountId(): string; getCalendars(): Promise; getAllCalendars(): Promise; createCalendar(calendar: Partial, targetAccountId?: string): Promise; updateCalendar(calendarId: string, updates: Partial, targetAccountId?: string): Promise; deleteCalendar(calendarId: string, targetAccountId?: string): Promise; getCalendarEvents(calendarIds?: string[], targetAccountId?: string): Promise; getCalendarEvent(id: string, targetAccountId?: string): Promise; createCalendarEvent(event: Partial, sendSchedulingMessages?: boolean, targetAccountId?: string): Promise; updateCalendarEvent( eventId: string, updates: Partial, sendSchedulingMessages?: boolean, targetAccountId?: string, ): Promise; deleteCalendarEvent(eventId: string, sendSchedulingMessages?: boolean, targetAccountId?: string): Promise; batchDeleteCalendarEvents(eventIds: string[], targetAccountId?: string): Promise<{ destroyed: string[]; notDestroyed: string[] }>; queryCalendarEvents(filter: CalendarEventFilter, sort?: Array<{ property: string; isAscending: boolean }>, limit?: number, targetAccountId?: string): Promise; queryAllCalendarEvents(filter: CalendarEventFilter, sort?: Array<{ property: string; isAscending: boolean }>, limit?: number): Promise; parseCalendarEvents(accountId: string, blobId: string): Promise[]>; // ── Calendar Tasks ──────────────────────────────────────────── getCalendarTasks(calendarIds?: string[], targetAccountId?: string): Promise; createCalendarTask(task: Partial, targetAccountId?: string): Promise; updateCalendarTask(taskId: string, updates: Partial, targetAccountId?: string): Promise; deleteCalendarTask(taskId: string, targetAccountId?: string): Promise; // ── Sieve / Filters ────────────────────────────────────────── getSieveAccountId(): string; getSieveCapabilities(): SieveCapabilities | null; getSieveScripts(): Promise; getSieveScriptContent(blobId: string): Promise; createSieveScript(name: string, content: string, activate?: boolean): Promise; updateSieveScript(scriptId: string, content: string, activate?: boolean): Promise; deleteSieveScript(scriptId: string): Promise; validateSieveScript(content: string): Promise<{ isValid: boolean; errors?: string[] }>; // ── Files (WebDAV / FileNode) ───────────────────────────────── getFilesAccountId(): string; probeFileNodeSupport(): Promise; listFileNodes(parentId: string | null): Promise; getFileNodes(ids: string[] | null, properties?: string[]): Promise; createFileDirectory(name: string, parentId: string | null): Promise; createFileNode(name: string, blobId: string, type: string, size: number, parentId: string | null): Promise; updateFileNode(id: string, updates: Partial>): Promise; destroyFileNodes(ids: string[]): Promise<{ destroyed: string[]; notDestroyed: string[] }>; copyFileNode(id: string, newName: string, parentId: string | null): Promise; // ── S/MIME raw-email helpers ────────────────────────────────── importRawEmail(blob: Blob, mailboxIds: Record, keywords?: Record): Promise; submitEmail(emailId: string, identityId: string): Promise; sendRawEmail(blob: Blob, identityId: string, sentMailboxId: string, draftMailboxId?: string): Promise; }