/** * rInbox Automerge document schemas. * * Granularity: one Automerge document per mailbox. * DocId format: {space}:inbox:mailboxes:{mailboxId} * * IMAP sync stays server-side — Automerge holds thread/comment state. */ import type { DocSchema } from '../../shared/local-first/document'; // ── Document types ── export interface MailboxMember { id: string; mailboxId: string; userId: string; role: string; joinedAt: number; } export interface ThreadComment { id: string; threadId: string; authorId: string; body: string; mentions: string[]; createdAt: number; } export interface ThreadItem { id: string; mailboxId: string; messageId: string | null; subject: string; fromAddress: string | null; fromName: string | null; toAddresses: string[]; ccAddresses: string[]; bodyText: string; bodyHtml: string; tags: string[]; status: string; isRead: boolean; isStarred: boolean; assignedTo: string | null; hasAttachments: boolean; receivedAt: number; createdAt: number; comments: ThreadComment[]; // Threading (RFC 5322) inReplyTo: string | null; references: string[]; direction: 'inbound' | 'outbound'; parentThreadId: string | null; } export interface ApprovalSignature { id: string; approvalId: string; signerId: string; vote: string; signedAt: number; } export interface ApprovalItem { id: string; mailboxId: string; threadId: string | null; authorId: string; subject: string; bodyText: string; bodyHtml: string; toAddresses: string[]; ccAddresses: string[]; status: string; requiredSignatures: number; safeTxHash: string | null; createdAt: number; resolvedAt: number; signatures: ApprovalSignature[]; // Reply/forward context inReplyTo: string | null; references: string[]; replyType: 'reply' | 'reply-all' | 'forward' | 'new'; } // ── Personal Inbox ── export interface PersonalInbox { id: string; ownerDid: string; label: string; email: string; imapHost: string; imapPort: number; smtpHost: string; smtpPort: number; lastSyncAt: number; status: 'active' | 'error' | 'paused'; } // ── Agent Inbox ── export interface AgentRule { match: { field: 'from' | 'subject' | 'body'; pattern: string }; action: 'reply' | 'forward' | 'tag' | 'assign'; value?: string; } export interface AgentInbox { id: string; spaceSlug: string; name: string; email: string; personality: string; autoReply: boolean; autoClassify: boolean; rules: AgentRule[]; } export interface MailboxMeta { id: string; workspaceId: string | null; slug: string; name: string; email: string; description: string; visibility: string; ownerDid: string; safeAddress: string | null; safeChainId: number | null; approvalThreshold: number; createdAt: number; } export interface MailboxDoc { meta: { module: string; collection: string; version: number; spaceSlug: string; createdAt: number; }; mailbox: MailboxMeta; members: MailboxMember[]; threads: Record; approvals: Record; personalInboxes: Record; agentInboxes: Record; } // ── Schema registration ── export const mailboxSchema: DocSchema = { module: 'inbox', collection: 'mailboxes', version: 2, init: (): MailboxDoc => ({ meta: { module: 'inbox', collection: 'mailboxes', version: 2, spaceSlug: '', createdAt: Date.now(), }, mailbox: { id: '', workspaceId: null, slug: '', name: '', email: '', description: '', visibility: 'private', ownerDid: '', safeAddress: null, safeChainId: null, approvalThreshold: 1, createdAt: Date.now(), }, members: [], threads: {}, approvals: {}, personalInboxes: {}, agentInboxes: {}, }), }; // ── Helpers ── export function mailboxDocId(space: string, mailboxId: string) { return `${space}:inbox:mailboxes:${mailboxId}` as const; }