@happyvertical/smrt-messages 0.45.0 → 0.45.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/{Email-BR0NkbZc.js → Email-BIdbpXym.js} +3 -3
- package/dist/chunks/Email-BIdbpXym.js.map +1 -0
- package/dist/chunks/{EmailFolder-DvZODbnW.js → EmailFolder-D0o1z0_T.js} +2 -2
- package/dist/chunks/EmailFolder-D0o1z0_T.js.map +1 -0
- package/dist/chunks/{Message-68WwnJi0.js → Message-BtsJ06xH.js} +3 -3
- package/dist/chunks/Message-BtsJ06xH.js.map +1 -0
- package/dist/chunks/{MessageCollection-Db1A7xHc.js → MessageCollection-CYEFYNMh.js} +2 -2
- package/dist/chunks/{MessageCollection-Db1A7xHc.js.map → MessageCollection-CYEFYNMh.js.map} +1 -1
- package/dist/index.js +12 -12
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +25 -9
- package/dist/smrt-knowledge.json +3 -3
- package/package.json +8 -8
- package/dist/chunks/Email-BR0NkbZc.js.map +0 -1
- package/dist/chunks/EmailFolder-DvZODbnW.js.map +0 -1
- package/dist/chunks/Message-68WwnJi0.js.map +0 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["route"],"sources":["../src/permissions.ts","../src/models/Attachment.ts","../src/collections/AttachmentCollection.ts","../src/models/MessagingEndpoint.ts","../src/collections/MessagingEndpointCollection.ts","../src/models/PersonaMessageRoute.ts","../src/collections/PersonaMessageRouteCollection.ts","../src/models/EmailAccount.ts","../src/collections/EmailAccountCollection.ts","../src/models/EmailAttachment.ts","../src/collections/EmailAttachmentCollection.ts","../src/collections/EmailCollection.ts","../src/collections/EmailFolderCollection.ts","../src/models/Blacklist.ts","../src/collections/BlacklistCollection.ts","../src/models/Whitelist.ts","../src/collections/WhitelistCollection.ts","../src/models/SlackAccount.ts","../src/models/SlackMessage.ts","../src/models/TelegramAccount.ts","../src/models/Tweet.ts","../src/models/TwitterAccount.ts","../src/models/ZulipAccount.ts","../src/senders/EmailSender.ts","../src/services/MessagingSettingsService.ts","../src/services/PersonaMessagingService.ts","../src/index.ts"],"sourcesContent":["import {\n type PermissionDefinition,\n registerPermissionDefinitions,\n} from '@happyvertical/smrt-users';\n\nexport const SEND_MESSAGES_PERMISSION = 'messages.send';\nexport const MANAGE_MESSAGE_ROUTES_PERMISSION = 'messages.manage-routes';\nexport const MANAGE_MESSAGE_CREDENTIALS_PERMISSION =\n 'messages.manage-credentials';\n\nexport const MESSAGING_PERMISSION_DEFINITIONS: PermissionDefinition[] = [\n {\n slug: SEND_MESSAGES_PERMISSION,\n category: 'messages',\n name: 'Send Messages',\n description: 'Allows send on messages',\n },\n {\n slug: MANAGE_MESSAGE_ROUTES_PERMISSION,\n category: 'messages',\n name: 'Manage Message Routes',\n description: 'Manage persona messaging endpoints and route bindings',\n },\n {\n slug: MANAGE_MESSAGE_CREDENTIALS_PERMISSION,\n category: 'messages',\n name: 'Manage Message Credentials',\n description: 'Create accounts and replace write-only provider credentials',\n },\n];\n\nexport interface MessagingPrincipal {\n readonly id?: string;\n readonly tenantId?: string;\n can(slug: string): boolean;\n}\n\nexport function messagingPrincipalFromPermissions(\n permissions: Iterable<string>,\n options: { id?: string; tenantId?: string } = {},\n): MessagingPrincipal {\n const granted = new Set(permissions);\n return {\n ...options,\n can: (slug) => granted.has(slug),\n };\n}\n\nexport function assertMessagingPermission(\n principal: MessagingPrincipal,\n tenantId: string,\n permission: string,\n): void {\n if (principal.tenantId && principal.tenantId !== tenantId) {\n throw new Error('Messaging principal does not belong to this tenant.');\n }\n if (!principal.can(permission)) {\n throw new Error(`Missing required permission '${permission}'.`);\n }\n}\n\nlet registered = false;\n\nexport function ensureMessagingPermissionsRegistered(): void {\n if (registered) return;\n registered = true;\n registerPermissionDefinitions(MESSAGING_PERMISSION_DEFINITIONS);\n}\n","/**\n * Attachment model - Generalized attachment for any message type\n *\n * Uses messageId instead of emailId for cross-type support.\n */\n\nimport {\n foreignKey,\n importOptionalDependency,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { AttachmentOptions } from '../types';\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n api: { include: ['list', 'get', 'create', 'delete'] },\n mcp: { include: ['list', 'get'] },\n cli: true,\n})\nexport class Attachment extends SmrtObject {\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n @foreignKey('Message')\n messageId = '';\n filename = '';\n contentType = '';\n size = 0;\n contentId = ''; // For inline images (<img src=\"cid:...\">)\n contentDisposition: 'attachment' | 'inline' = 'attachment';\n filePath = ''; // External file storage path\n sourceUrl = ''; // For non-email attachments (media URLs, etc.)\n\n // Timestamps\n createdAt = new Date();\n\n constructor(options: AttachmentOptions = {}) {\n super(options);\n\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.messageId !== undefined) this.messageId = options.messageId;\n if (options.filename !== undefined) this.filename = options.filename;\n if (options.contentType !== undefined)\n this.contentType = options.contentType;\n if (options.size !== undefined) this.size = options.size;\n if (options.contentId !== undefined) this.contentId = options.contentId;\n if (options.contentDisposition !== undefined)\n this.contentDisposition = options.contentDisposition;\n if (options.filePath !== undefined) this.filePath = options.filePath;\n if (options.sourceUrl !== undefined) this.sourceUrl = options.sourceUrl;\n if (options.createdAt) this.createdAt = options.createdAt;\n }\n\n /**\n * Get the message this attachment belongs to\n */\n async getMessage() {\n if (!this.messageId) return null;\n\n const { MessageCollection } = await import(\n '../collections/MessageCollection'\n );\n const collection = await MessageCollection.create(this.options);\n\n return await collection.get({ id: this.messageId });\n }\n\n /**\n * Check if attachment is an image\n */\n isImage(): boolean {\n return this.contentType.startsWith('image/');\n }\n\n /**\n * Check if attachment is a PDF\n */\n isPdf(): boolean {\n return this.contentType === 'application/pdf';\n }\n\n /**\n * Check if attachment is inline (embedded in message body)\n */\n isInline(): boolean {\n return this.contentDisposition === 'inline';\n }\n\n /**\n * Get file extension from filename\n */\n getExtension(): string {\n if (!this.filename) return '';\n const parts = this.filename.split('.');\n return parts.length > 1 ? parts[parts.length - 1].toLowerCase() : '';\n }\n\n /**\n * Get human-readable file size\n */\n getFormattedSize(): string {\n const units = ['B', 'KB', 'MB', 'GB'];\n let size = this.size;\n let unitIndex = 0;\n\n while (size >= 1024 && unitIndex < units.length - 1) {\n size /= 1024;\n unitIndex++;\n }\n\n return `${size.toFixed(1)} ${units[unitIndex]}`;\n }\n\n /**\n * Check if file is stored externally\n */\n hasExternalFile(): boolean {\n return !!this.filePath;\n }\n\n /**\n * Read file content (if stored externally)\n *\n * The files SDK is loaded through core's bundler-invisible optional-import\n * boundary so it never enters provider-neutral consumer bundles (#1979).\n * Absence of the SDK at runtime degrades to the existing null contract.\n */\n async readContent(): Promise<Buffer | null> {\n if (!this.filePath) return null;\n\n try {\n const { getFilesystem } = (await importOptionalDependency(\n '@happyvertical/files',\n \"Import '@happyvertical/smrt-core/filesystem' (or '@happyvertical/smrt-assets/filesystem') during server startup to read externally-stored attachments in bundled builds.\",\n )) as typeof import('@happyvertical/files');\n const files = await getFilesystem({ type: 'local' });\n const data = await files.read(this.filePath);\n return data instanceof Buffer ? data : Buffer.from(data);\n } catch {\n return null;\n }\n }\n}\n","/**\n * AttachmentCollection - Generalized attachment collection using messageId\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { queryGlobal, queryWithGlobals } from '@happyvertical/smrt-tenancy';\nimport { Attachment } from '../models/Attachment';\n\nexport class AttachmentCollection extends SmrtCollection<Attachment> {\n static readonly _itemClass = Attachment;\n\n /**\n * Get attachments for a message\n */\n async getByMessage(messageId: string): Promise<Attachment[]> {\n return await this.list({ where: { messageId } });\n }\n\n /**\n * Get attachments by content type\n */\n async getByContentType(contentType: string): Promise<Attachment[]> {\n return await this.list({ where: { contentType } });\n }\n\n /**\n * Get image attachments\n */\n async getImages(messageId?: string): Promise<Attachment[]> {\n const attachments = messageId\n ? await this.getByMessage(messageId)\n : await this.list({});\n\n return attachments.filter((a) => a.isImage());\n }\n\n /**\n * Get PDF attachments\n */\n async getPdfs(messageId?: string): Promise<Attachment[]> {\n const attachments = messageId\n ? await this.getByMessage(messageId)\n : await this.list({});\n\n return attachments.filter((a) => a.isPdf());\n }\n\n /**\n * Get inline attachments (embedded in message body)\n */\n async getInline(messageId: string): Promise<Attachment[]> {\n const attachments = await this.getByMessage(messageId);\n return attachments.filter((a) => a.isInline());\n }\n\n /**\n * Get regular attachments (not inline)\n */\n async getRegular(messageId: string): Promise<Attachment[]> {\n const attachments = await this.getByMessage(messageId);\n return attachments.filter((a) => !a.isInline());\n }\n\n /**\n * Get attachments with external files\n */\n async getWithExternalFiles(): Promise<Attachment[]> {\n const attachments = await this.list({});\n return attachments.filter((a) => a.hasExternalFile());\n }\n\n /**\n * Get total size of attachments for a message\n */\n async getTotalSize(messageId: string): Promise<number> {\n const attachments = await this.getByMessage(messageId);\n return attachments.reduce((sum, a) => sum + a.size, 0);\n }\n\n /**\n * Get largest attachments\n */\n async getLargest(limit = 10): Promise<Attachment[]> {\n const attachments = await this.list({});\n return attachments.sort((a, b) => b.size - a.size).slice(0, limit);\n }\n\n /**\n * Search attachments by filename\n */\n async searchByFilename(query: string): Promise<Attachment[]> {\n const attachments = await this.list({});\n const lowerQuery = query.toLowerCase();\n\n return attachments.filter((a) =>\n a.filename?.toLowerCase().includes(lowerQuery),\n );\n }\n\n /**\n * Get attachments by extension\n */\n async getByExtension(extension: string): Promise<Attachment[]> {\n const attachments = await this.list({});\n const lowerExt = extension.toLowerCase().replace(/^\\./, '');\n\n return attachments.filter((a) => a.getExtension() === lowerExt);\n }\n\n /**\n * Get attachment statistics\n */\n async getStats(): Promise<{\n total: number;\n totalSize: number;\n byType: Record<string, number>;\n inline: number;\n regular: number;\n }> {\n const attachments = await this.list({});\n\n const byType: Record<string, number> = {};\n for (const attachment of attachments) {\n const type = attachment.contentType.split('/')[0] || 'other';\n byType[type] = (byType[type] || 0) + 1;\n }\n\n return {\n total: attachments.length,\n totalSize: attachments.reduce((sum, a) => sum + a.size, 0),\n byType,\n inline: attachments.filter((a) => a.isInline()).length,\n regular: attachments.filter((a) => !a.isInline()).length,\n };\n }\n\n /**\n * Delete all attachments for a message\n */\n async deleteByMessage(messageId: string): Promise<number> {\n const attachments = await this.getByMessage(messageId);\n let count = 0;\n\n for (const attachment of attachments) {\n await attachment.delete();\n count++;\n }\n\n return count;\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Tenant Helper Methods\n // ─────────────────────────────────────────────────────────────────────────\n\n async findByTenant(tenantId: string): Promise<Attachment[]> {\n return this.list({ where: { tenantId } });\n }\n\n // Attachment is @TenantScoped (CTI, own `attachments` table). Under an active\n // tenant context list({ tenantId: null }) throws and unflagged raw SQL is\n // blocked (#1596); route through the raw helpers.\n async findGlobal(): Promise<Attachment[]> {\n return queryGlobal<Attachment>(this);\n }\n\n async findWithGlobals(tenantId: string): Promise<Attachment[]> {\n return queryWithGlobals<Attachment>(\n this,\n tenantId,\n 'Attachment.findWithGlobals',\n );\n }\n}\n","import type { SmrtObjectOptions } from '@happyvertical/smrt-core';\nimport {\n crossPackageRef,\n field,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { MessagingChannel, MessagingEndpointOptions } from '../types.js';\n\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'messaging_endpoints',\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n conflictColumns: ['tenant_id', 'channel', 'label'],\n})\nexport class MessagingEndpoint extends SmrtObject {\n @tenantId()\n tenantId = '';\n\n @crossPackageRef('@happyvertical/smrt-profiles:Profile', { nullable: true })\n profileId: string | null = null;\n\n @field({ required: true })\n label = '';\n\n @field({ required: true })\n channel: MessagingChannel = 'email';\n\n /** Provider-specific destination JSON. Hidden from generated read surfaces. */\n @field({ required: true, sensitive: true })\n address = '{}';\n\n isActive = true;\n verifiedAt: Date | null = null;\n createdAt = new Date();\n updatedAt = new Date();\n\n constructor(options: MessagingEndpointOptions = {}) {\n super(options as SmrtObjectOptions);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.profileId !== undefined) this.profileId = options.profileId;\n if (options.label !== undefined) this.label = options.label;\n if (options.channel !== undefined) this.channel = options.channel;\n if (options.address !== undefined) this.address = options.address;\n if (options.isActive !== undefined) this.isActive = options.isActive;\n if (options.verifiedAt !== undefined) this.verifiedAt = options.verifiedAt;\n if (options.createdAt !== undefined) this.createdAt = options.createdAt;\n if (options.updatedAt !== undefined) this.updatedAt = options.updatedAt;\n }\n\n getAddress<T extends Record<string, unknown> = Record<string, unknown>>(): T {\n try {\n return JSON.parse(this.address) as T;\n } catch {\n return {} as T;\n }\n }\n\n setAddress(address: Record<string, unknown>): void {\n this.address = JSON.stringify(address);\n }\n\n getMaskedAddress(): string {\n const address = this.getAddress();\n const visible =\n address.email ??\n address.chatId ??\n address.to ??\n address.stream ??\n address.phoneNumber;\n if (typeof visible !== 'string' && typeof visible !== 'number')\n return '••••';\n const value = String(visible);\n if (value.includes('@')) {\n const [name, domain] = value.split('@');\n return `${name.slice(0, 2)}•••@${domain}`;\n }\n return value.length <= 4 ? '••••' : `••••${value.slice(-4)}`;\n }\n}\n","import { SmrtCollection } from '@happyvertical/smrt-core';\nimport { MessagingEndpoint } from '../models/MessagingEndpoint.js';\n\nexport class MessagingEndpointCollection extends SmrtCollection<MessagingEndpoint> {\n static readonly _itemClass = MessagingEndpoint;\n}\n","import {\n crossPackageRef,\n field,\n foreignKey,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { PersonaMessageRouteOptions } from '../types.js';\n\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'persona_message_routes',\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n conflictColumns: [\n 'tenant_id',\n 'persona_id',\n 'account_id',\n 'endpoint_id',\n 'purpose',\n ],\n})\nexport class PersonaMessageRoute extends SmrtObject {\n @tenantId()\n tenantId = '';\n\n @crossPackageRef('@happyvertical/smrt-personas:AgentPersona', {\n required: true,\n })\n personaId = '';\n\n @foreignKey('Account', { required: true })\n accountId = '';\n\n @foreignKey('MessagingEndpoint', { required: true })\n endpointId = '';\n\n @field({ required: true })\n purpose = 'default';\n\n priority = 0;\n enabled = true;\n createdAt = new Date();\n updatedAt = new Date();\n\n constructor(options: PersonaMessageRouteOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.personaId !== undefined) this.personaId = options.personaId;\n if (options.accountId !== undefined) this.accountId = options.accountId;\n if (options.endpointId !== undefined) this.endpointId = options.endpointId;\n if (options.purpose !== undefined) this.purpose = options.purpose;\n if (options.priority !== undefined) this.priority = options.priority;\n if (options.enabled !== undefined) this.enabled = options.enabled;\n if (options.createdAt !== undefined) this.createdAt = options.createdAt;\n if (options.updatedAt !== undefined) this.updatedAt = options.updatedAt;\n }\n}\n","import { SmrtCollection } from '@happyvertical/smrt-core';\nimport { PersonaMessageRoute } from '../models/PersonaMessageRoute.js';\n\nexport class PersonaMessageRouteCollection extends SmrtCollection<PersonaMessageRoute> {\n static readonly _itemClass = PersonaMessageRoute;\n\n async forPersona(personaId: string): Promise<PersonaMessageRoute[]> {\n return this.list({ where: { personaId, enabled: true } });\n }\n}\n","/**\n * EmailAccount model - Email account extending the Account STI base\n *\n * Retains email-specific fields and sync capability.\n */\n\nimport type { FetchOptions, GetEmailClientOptions } from '@happyvertical/email';\nimport { smrt } from '@happyvertical/smrt-core';\nimport type {\n EmailAccountOptions,\n MessageSenderInterface,\n ProviderType,\n SyncOptions,\n SyncResult,\n} from '../types';\nimport { Account } from './Account';\n\n@smrt({\n tableStrategy: 'sti',\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n})\nexport class EmailAccount extends Account {\n email = '';\n syncIntervalMinutes = 60;\n\n constructor(options: EmailAccountOptions = {}) {\n super(options);\n\n if (options.email !== undefined) this.email = options.email;\n if (options.providerType !== undefined)\n this.providerType = options.providerType;\n if (options.syncIntervalMinutes !== undefined)\n this.syncIntervalMinutes = options.syncIntervalMinutes;\n this.channelType = 'email';\n }\n\n /**\n * Options for child rows (folders/emails) created during sync: carries the DB\n * connection + tenant context from this account, but strips this account's own\n * identity fields. When this account was hydrated from the DB, `this.options`\n * holds the account row's `id`/`slug`/`_skipLoad`; spreading those into a new\n * child would make every synced row inherit the account's primary key and\n * upsert over each other.\n */\n private childOptions(): Record<string, unknown> {\n const rest = { ...(this.options as Record<string, unknown>) };\n delete rest.id;\n delete rest.slug;\n delete rest._skipLoad;\n return rest;\n }\n\n /**\n * Create a sender for this email account\n */\n override async createSender(): Promise<MessageSenderInterface> {\n const client = await this.createClient();\n await client.connect();\n const { EmailSender } = await import('../senders/EmailSender');\n return new EmailSender(client, this);\n }\n\n /**\n * Create an EmailClient from stored settings\n * Retrieves credentials from smrt-secrets if credentialSecretId is set\n *\n * The client factory comes from the messaging provider registry rather than\n * a direct `@happyvertical/email` import so the email SDK\n * (googleapis/nodemailer) never becomes reachable from provider-neutral\n * consumer bundles (#1979). Server code that uses email accounts must\n * import '@happyvertical/smrt-messages/providers/email' (or\n * '/providers/all') once during startup.\n */\n async createClient() {\n const { getMessagingProvider } = await import('../providers.js');\n const createEmailClient = getMessagingProvider(\n this.providerType,\n )?.createEmailClient;\n if (!createEmailClient) {\n throw new Error(\n `Email provider '${this.providerType}' has no client implementation registered. ` +\n \"Import '@happyvertical/smrt-messages/providers/email' (or '/providers/all') \" +\n 'during server startup to enable outbound email and mailbox sync.',\n );\n }\n const settings: Record<string, unknown> = {\n ...this.getConfiguration(),\n ...((await this.getCredentials()) ?? {}),\n };\n delete settings.email;\n\n return await createEmailClient({\n type: this.providerType as ProviderType,\n ...settings,\n } as GetEmailClientOptions);\n }\n\n /**\n * Sync emails from the email server to the database\n */\n async syncFrom(options: SyncOptions = {}): Promise<SyncResult> {\n const startTime = Date.now();\n const result: SyncResult = {\n folders: [],\n messagesProcessed: 0,\n messagesDownloaded: 0,\n messagesSkipped: 0,\n errors: [],\n duration: 0,\n };\n\n try {\n // Create email client\n const client = await this.createClient();\n await client.connect();\n\n // Get folders to sync\n const foldersToSync = options.folders || ['INBOX'];\n result.folders = foldersToSync;\n\n // Import collections\n const { EmailCollection } = await import(\n '../collections/EmailCollection'\n );\n const { EmailFolderCollection } = await import(\n '../collections/EmailFolderCollection'\n );\n\n const emailCollection = await EmailCollection.create(this.options);\n const folderCollection = await EmailFolderCollection.create(this.options);\n\n if (!this.id) {\n throw new Error(\n 'EmailAccount.syncFrom requires a persisted account (missing id)',\n );\n }\n const accountId = this.id;\n for (const folderName of foldersToSync) {\n try {\n // Ensure folder exists in database\n let folder = await folderCollection.getByPath(accountId, folderName);\n\n if (!folder) {\n // Create folder record\n const { EmailFolder } = await import('./EmailFolder');\n folder = new EmailFolder({\n ...this.childOptions(),\n accountId,\n name: folderName,\n path: folderName,\n });\n // initialize() binds the DB connection; without it save() throws\n // \"Database accessed before initialization\" and sync persists nothing.\n await folder.initialize();\n await folder.save();\n }\n\n // Fetch messages from server\n const fetchOptions: FetchOptions = {\n folder: folderName,\n limit: options.batchSize || 100,\n };\n\n if (options.since) {\n fetchOptions.since = options.since;\n }\n if (options.before) {\n fetchOptions.before = options.before;\n }\n\n const messages = await client.fetch(fetchOptions);\n\n for (const msg of messages) {\n result.messagesProcessed++;\n\n try {\n // Check if message already exists\n const existingEmail = await emailCollection.getByMessageId(\n accountId,\n msg.messageId || '',\n );\n\n if (existingEmail && !options.fullSync) {\n result.messagesSkipped++;\n continue;\n }\n\n // Create or update email record\n const { Email } = await import('./Email');\n let email = existingEmail;\n if (!email) {\n email = new Email({\n ...this.childOptions(),\n accountId,\n });\n // Bind the DB connection before save() (existingEmail is already\n // initialized via the query that loaded it).\n await email.initialize();\n }\n\n // Update fields\n email.messageId = msg.messageId || '';\n email.threadId = msg.threadId || '';\n email.inReplyTo = msg.inReplyTo || '';\n email.fromAddress = msg.from?.address || '';\n email.fromName = msg.from?.name || '';\n email.toAddresses = JSON.stringify(msg.to || []);\n email.ccAddresses = JSON.stringify(msg.cc || []);\n email.bccAddresses = JSON.stringify(msg.bcc || []);\n email.replyToAddress = msg.replyTo?.address || '';\n email.replyToName = msg.replyTo?.name || '';\n email.subject = msg.subject || '';\n email.date = msg.date || null;\n email.textBody = msg.text || '';\n email.htmlBody = msg.html || '';\n email.body = msg.text || '';\n email.folderId = folder.id ?? '';\n email.folderPath = folderName;\n email.labels = JSON.stringify(msg.labels || []);\n email.flags = JSON.stringify(msg.flags || []);\n email.hasAttachments =\n (msg.attachments && msg.attachments.length > 0) || false;\n email.size = msg.size || 0;\n email.headers = JSON.stringify(msg.headers || {});\n email.updatedAt = new Date();\n\n await email.save();\n result.messagesDownloaded++;\n\n // Report progress\n if (options.onProgress) {\n options.onProgress({\n folder: folderName,\n processed: result.messagesProcessed,\n total: messages.length,\n downloaded: result.messagesDownloaded,\n skipped: result.messagesSkipped,\n errors: result.errors.length,\n });\n }\n } catch (error) {\n const err =\n error instanceof Error ? error : new Error(String(error));\n result.errors.push(err);\n if (options.onError) {\n options.onError(err, msg);\n }\n }\n }\n\n // Update folder counts\n const folderId = folder.id ?? '';\n folder.messageCount = await emailCollection.countByFolder(folderId);\n folder.unreadCount =\n await emailCollection.countUnreadByFolder(folderId);\n await folder.save();\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n result.errors.push(err);\n if (options.onError) {\n options.onError(err);\n }\n }\n }\n\n // Update last sync time\n this.lastSyncAt = new Date();\n this.updatedAt = new Date();\n await this.save();\n\n await client.disconnect();\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n result.errors.push(err);\n if (options.onError) {\n options.onError(err);\n }\n }\n\n result.duration = Date.now() - startTime;\n return result;\n }\n\n /**\n * Get all folders for this account\n */\n async getFolders() {\n const { EmailFolderCollection } = await import(\n '../collections/EmailFolderCollection'\n );\n const collection = await EmailFolderCollection.create(this.options);\n\n return await collection.list({ where: { accountId: this.id } });\n }\n\n /**\n * Get all emails for this account\n */\n async getEmails(limit?: number) {\n const { EmailCollection } = await import('../collections/EmailCollection');\n const collection = await EmailCollection.create(this.options);\n\n const options: { where: Record<string, unknown>; limit?: number } = {\n where: { accountId: this.id },\n };\n if (limit) {\n options.limit = limit;\n }\n\n return await collection.list(options);\n }\n\n /**\n * Get unread email count\n */\n async getUnreadCount(): Promise<number> {\n const { EmailCollection } = await import('../collections/EmailCollection');\n const collection = await EmailCollection.create(this.options);\n\n return await collection.countUnreadByAccount(this.id ?? '');\n }\n\n /**\n * Store credentials securely using smrt-secrets (email-specific)\n */\n override async setCredentials(\n credentials: Record<string, unknown>,\n options: {\n description?: string;\n category?: string;\n } = {},\n ): Promise<void> {\n await super.setCredentials(credentials, {\n description: options.description || `Email credentials for ${this.name}`,\n category: options.category || 'email',\n });\n }\n\n /**\n * Sync all active email accounts (for job runner)\n *\n * NOTE: This is a class-wide operation, not per-instance. It syncs ALL active\n * accounts, ignoring `this` instance. It exists as an instance method because\n * the TaskRunner dispatches via `objectType: 'EmailAccount', method: 'syncAll'`\n * which requires an instance method signature.\n */\n async syncAll(\n args?: Record<string, unknown>,\n ): Promise<Map<string, { success: boolean; error?: Error }>> {\n const { EmailAccountCollection } = await import(\n '../collections/EmailAccountCollection'\n );\n const collection = await EmailAccountCollection.create({\n db: this.db,\n });\n return collection.syncAll(args as SyncOptions | undefined);\n }\n\n /**\n * Migrate from plain-text settings to secrets\n */\n async migrateToSecrets(): Promise<void> {\n if (this.credentialSecretId) {\n return;\n }\n\n const settings = this.getSettings();\n if (Object.keys(settings).length === 0) {\n return;\n }\n\n await this.setCredentials(settings, {\n description: `Migrated IMAP credentials for ${this.name}`,\n });\n }\n}\n","/**\n * EmailAccountCollection - Collection manager for EmailAccount objects\n *\n * Extends AccountCollection with email-specific query methods.\n */\n\nimport { queryGlobal, queryWithGlobals } from '@happyvertical/smrt-tenancy';\nimport { EmailAccount } from '../models/EmailAccount';\nimport type {\n EmailAccountSearchFilters,\n ProviderType,\n SyncOptions,\n} from '../types';\nimport { AccountCollection } from './AccountCollection';\n\nexport class EmailAccountCollection extends AccountCollection {\n static override readonly _itemClass = EmailAccount;\n\n /**\n * Get account by email address\n */\n async getByEmail(email: string): Promise<EmailAccount | null> {\n const accounts = await this.list({ where: { email } });\n return (accounts[0] as EmailAccount) || null;\n }\n\n /**\n * Get accounts by email provider type\n */\n async getByEmailProviderType(\n providerType: ProviderType,\n ): Promise<EmailAccount[]> {\n return (await this.list({ where: { providerType } })) as EmailAccount[];\n }\n\n /**\n * Get active email accounts\n */\n override async getActive(): Promise<EmailAccount[]> {\n return (await this.list({ where: { isActive: true } })) as EmailAccount[];\n }\n\n /**\n * Get inactive email accounts\n */\n override async getInactive(): Promise<EmailAccount[]> {\n return (await this.list({ where: { isActive: false } })) as EmailAccount[];\n }\n\n /**\n * Get accounts that need syncing\n */\n async getNeedingSync(maxAgeMinutes = 60): Promise<EmailAccount[]> {\n const allAccounts = await this.getActive();\n const cutoffTime = new Date(Date.now() - maxAgeMinutes * 60 * 1000);\n\n return allAccounts.filter(\n (account) => !account.lastSyncAt || account.lastSyncAt < cutoffTime,\n ) as EmailAccount[];\n }\n\n /**\n * Search email accounts with filters.\n * Alias: `search()` for backward compatibility.\n */\n override async search(\n query: string,\n filters?: EmailAccountSearchFilters,\n ): Promise<EmailAccount[]> {\n return this.searchEmailAccounts(query, filters);\n }\n\n /**\n * Get accounts by email provider type.\n * Alias: `getByProviderType()` for backward compatibility.\n */\n override async getByProviderType(\n providerType: string,\n ): Promise<EmailAccount[]> {\n return this.getByEmailProviderType(providerType as ProviderType);\n }\n\n /**\n * Get email account statistics.\n * Alias: `getStats()` for backward compatibility.\n */\n override async getStats(): Promise<{\n total: number;\n active: number;\n inactive: number;\n byType: Record<string, number>;\n }> {\n const stats = await this.getEmailStats();\n return {\n total: stats.total,\n active: stats.active,\n inactive: stats.inactive,\n byType: stats.byProvider as unknown as Record<string, number>,\n };\n }\n\n /**\n * Search email accounts with filters\n */\n async searchEmailAccounts(\n query: string,\n filters?: EmailAccountSearchFilters,\n ): Promise<EmailAccount[]> {\n let accounts = (await this.list({})) as EmailAccount[];\n\n // Filter by query\n if (query) {\n const lowerQuery = query.toLowerCase();\n accounts = accounts.filter(\n (a) =>\n a.name?.toLowerCase().includes(lowerQuery) ||\n a.email?.toLowerCase().includes(lowerQuery),\n );\n }\n\n // Apply filters\n if (filters) {\n if (filters.providerType) {\n accounts = accounts.filter(\n (a) => a.providerType === filters.providerType,\n );\n }\n if (filters.email) {\n const emailLower = filters.email.toLowerCase();\n accounts = accounts.filter((a) =>\n a.email?.toLowerCase().includes(emailLower),\n );\n }\n if (filters.isActive !== undefined) {\n accounts = accounts.filter((a) => a.isActive === filters.isActive);\n }\n }\n\n return accounts;\n }\n\n /**\n * Sync all active email accounts\n */\n async syncAll(\n options?: SyncOptions,\n ): Promise<Map<string, { success: boolean; error?: Error }>> {\n const results = new Map<string, { success: boolean; error?: Error }>();\n const accounts = await this.getActive();\n\n for (const account of accounts) {\n const ea = account as EmailAccount;\n const accountId = ea.id ?? ea.email ?? 'unknown';\n try {\n await ea.syncFrom(options);\n results.set(accountId, { success: true });\n } catch (error) {\n results.set(accountId, {\n success: false,\n error: error instanceof Error ? error : new Error(String(error)),\n });\n }\n }\n\n return results;\n }\n\n /**\n * Get total unread count across all email accounts\n */\n async getTotalUnreadCount(): Promise<number> {\n const accounts = await this.getActive();\n let total = 0;\n\n for (const account of accounts) {\n total += await (account as EmailAccount).getUnreadCount();\n }\n\n return total;\n }\n\n /**\n * Get email account statistics\n */\n async getEmailStats(): Promise<{\n total: number;\n active: number;\n inactive: number;\n byProvider: Record<ProviderType, number>;\n }> {\n const accounts = (await this.list({})) as EmailAccount[];\n\n const byProvider: Record<ProviderType, number> = {\n smtp: 0,\n imap: 0,\n pop3: 0,\n gmail: 0,\n };\n\n for (const account of accounts) {\n const pt = account.providerType as ProviderType;\n if (pt in byProvider) {\n byProvider[pt]++;\n }\n }\n\n return {\n total: accounts.length,\n active: accounts.filter((a) => a.isActive).length,\n inactive: accounts.filter((a) => !a.isActive).length,\n byProvider,\n };\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Tenant Helper Methods\n // ─────────────────────────────────────────────────────────────────────────\n\n override async findByTenant(tenantId: string): Promise<EmailAccount[]> {\n return this.list({ where: { tenantId } }) as Promise<EmailAccount[]>;\n }\n\n // EmailAccount inherits Account's @TenantScoped recognition (#1596); see\n // EmailCollection for why these route through the raw helpers. They auto-scope\n // to the EmailAccount `_meta_type` (via getStiChildMetaType) so the shared\n // `accounts` table never returns sibling Account subtypes. (#1600)\n override async findGlobal(): Promise<EmailAccount[]> {\n return queryGlobal<EmailAccount>(this);\n }\n\n override async findWithGlobals(tenantId: string): Promise<EmailAccount[]> {\n return queryWithGlobals<EmailAccount>(\n this,\n tenantId,\n 'EmailAccount.findWithGlobals',\n );\n }\n}\n","/**\n * EmailAttachment - Backward-compatible alias for Attachment\n *\n * @deprecated Use Attachment instead. EmailAttachment is preserved for backward compatibility.\n */\n\nimport type { EmailAttachmentOptions } from '../types';\nimport { Attachment } from './Attachment';\n\n/**\n * @deprecated Use Attachment instead\n */\nexport class EmailAttachment extends Attachment {\n /**\n * Legacy emailId field — maps to messageId\n */\n get emailId(): string {\n return this.messageId;\n }\n\n set emailId(value: string) {\n this.messageId = value;\n }\n\n constructor(options: EmailAttachmentOptions = {}) {\n // Map emailId to messageId for backward compat\n const mappedOptions = {\n ...options,\n messageId: options.emailId || options.messageId || '',\n };\n super(mappedOptions);\n }\n\n /**\n * Get the email this attachment belongs to\n * @deprecated Use getMessage() instead\n */\n async getEmail() {\n if (!this.messageId) return null;\n\n const { EmailCollection } = await import('../collections/EmailCollection');\n const collection = await EmailCollection.create(this.options);\n\n return await collection.get({ id: this.messageId });\n }\n}\n","/**\n * EmailAttachmentCollection - Backward-compatible collection for EmailAttachment\n *\n * @deprecated Use AttachmentCollection instead\n */\n\nimport { queryGlobal, queryWithGlobals } from '@happyvertical/smrt-tenancy';\nimport { EmailAttachment } from '../models/EmailAttachment';\nimport { AttachmentCollection } from './AttachmentCollection';\n\n/**\n * @deprecated Use AttachmentCollection instead\n */\nexport class EmailAttachmentCollection extends AttachmentCollection {\n static override readonly _itemClass = EmailAttachment;\n\n /**\n * Get attachments for an email\n * @deprecated Use getByMessage() instead\n */\n async getByEmail(emailId: string): Promise<EmailAttachment[]> {\n return (await this.getByMessage(emailId)) as EmailAttachment[];\n }\n\n /**\n * Get image attachments\n */\n override async getImages(emailId?: string): Promise<EmailAttachment[]> {\n return (await super.getImages(emailId)) as EmailAttachment[];\n }\n\n /**\n * Get PDF attachments\n */\n override async getPdfs(emailId?: string): Promise<EmailAttachment[]> {\n return (await super.getPdfs(emailId)) as EmailAttachment[];\n }\n\n /**\n * Get inline attachments\n */\n override async getInline(emailId: string): Promise<EmailAttachment[]> {\n return (await super.getInline(emailId)) as EmailAttachment[];\n }\n\n /**\n * Get regular attachments\n */\n override async getRegular(emailId: string): Promise<EmailAttachment[]> {\n return (await super.getRegular(emailId)) as EmailAttachment[];\n }\n\n /**\n * Delete all attachments for an email\n * @deprecated Use deleteByMessage() instead\n */\n async deleteByEmail(emailId: string): Promise<number> {\n return await this.deleteByMessage(emailId);\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Tenant Helper Methods\n // ─────────────────────────────────────────────────────────────────────────\n\n override async findByTenant(tenantId: string): Promise<EmailAttachment[]> {\n return this.list({ where: { tenantId } }) as Promise<EmailAttachment[]>;\n }\n\n // EmailAttachment is a CTI subclass of the @TenantScoped Attachment (own\n // `email_attachments` table, no `_meta_type`) and inherits its recognition\n // (#1596); route global / cross-global lookups through the raw helpers.\n override async findGlobal(): Promise<EmailAttachment[]> {\n return queryGlobal<EmailAttachment>(this);\n }\n\n override async findWithGlobals(tenantId: string): Promise<EmailAttachment[]> {\n return queryWithGlobals<EmailAttachment>(\n this,\n tenantId,\n 'EmailAttachment.findWithGlobals',\n );\n }\n}\n","/**\n * EmailCollection - Collection manager for Email objects\n *\n * Extends MessageCollection with email-specific query methods.\n * STI framework auto-filters to Email instances.\n */\n\nimport { queryGlobal, queryWithGlobals } from '@happyvertical/smrt-tenancy';\nimport { Email } from '../models/Email';\nimport type { EmailSearchFilters } from '../types';\nimport { MessageCollection } from './MessageCollection';\n\nexport class EmailCollection extends MessageCollection {\n static override readonly _itemClass = Email;\n\n /**\n * Get email by RFC 822 Message-ID\n */\n async getByMessageId(\n accountId: string,\n messageId: string,\n ): Promise<Email | null> {\n const emails = await this.list({\n where: { accountId, messageId },\n limit: 1,\n });\n return (emails[0] as Email) || null;\n }\n\n /**\n * Get emails by account\n */\n async getByAccount(accountId: string): Promise<Email[]> {\n return (await this.list({ where: { accountId } })) as Email[];\n }\n\n /**\n * Get emails by folder\n */\n async getByFolder(folderId: string): Promise<Email[]> {\n return (await this.list({ where: { folderId } })) as Email[];\n }\n\n /**\n * Get emails by thread\n */\n override async getByThread(threadId: string): Promise<Email[]> {\n return (await this.list({ where: { threadId } })) as Email[];\n }\n\n /**\n * Get unread emails\n */\n override async getUnread(accountId?: string): Promise<Email[]> {\n const where: Record<string, unknown> = { isRead: false };\n if (accountId) {\n where.accountId = accountId;\n }\n return (await this.list({ where })) as Email[];\n }\n\n /**\n * Get flagged emails\n */\n override async getFlagged(accountId?: string): Promise<Email[]> {\n const where: Record<string, unknown> = { isFlagged: true };\n if (accountId) {\n where.accountId = accountId;\n }\n return (await this.list({ where })) as Email[];\n }\n\n /**\n * Get emails with attachments\n */\n async getWithAttachments(accountId?: string): Promise<Email[]> {\n const where: Record<string, unknown> = { hasAttachments: true };\n if (accountId) {\n where.accountId = accountId;\n }\n return (await this.list({ where })) as Email[];\n }\n\n /**\n * Get recent emails\n */\n override async getRecent(limit = 20, accountId?: string): Promise<Email[]> {\n const allEmails = (await this.list({\n where: accountId ? { accountId } : undefined,\n })) as Email[];\n\n return allEmails\n .sort((a, b) => {\n const dateA = a.date?.getTime() || 0;\n const dateB = b.date?.getTime() || 0;\n return dateB - dateA;\n })\n .slice(0, limit);\n }\n\n /**\n * Count emails in a folder\n */\n async countByFolder(folderId: string): Promise<number> {\n const emails = await this.list({ where: { folderId } });\n return emails.length;\n }\n\n /**\n * Count unread emails in a folder\n */\n async countUnreadByFolder(folderId: string): Promise<number> {\n const emails = await this.list({ where: { folderId, isRead: false } });\n return emails.length;\n }\n\n /**\n * Count unread emails for an account\n */\n async countUnreadByAccount(accountId: string): Promise<number> {\n const emails = await this.list({ where: { accountId, isRead: false } });\n return emails.length;\n }\n\n /**\n * Search emails with email-specific filters.\n * Alias: `search()` for backward compatibility.\n */\n override async search(\n query: string,\n filters?: EmailSearchFilters,\n ): Promise<Email[]> {\n return this.searchEmails(query, filters);\n }\n\n /**\n * Search emails with email-specific filters\n */\n async searchEmails(\n query: string,\n filters?: EmailSearchFilters,\n ): Promise<Email[]> {\n let emails = (await this.list({})) as Email[];\n\n // Filter by query\n if (query) {\n const lowerQuery = query.toLowerCase();\n emails = emails.filter(\n (e) =>\n e.subject?.toLowerCase().includes(lowerQuery) ||\n e.textBody?.toLowerCase().includes(lowerQuery) ||\n e.fromAddress?.toLowerCase().includes(lowerQuery) ||\n e.fromName?.toLowerCase().includes(lowerQuery),\n );\n }\n\n // Apply filters\n if (filters) {\n if (filters.accountId) {\n emails = emails.filter((e) => e.accountId === filters.accountId);\n }\n if (filters.folderId) {\n emails = emails.filter((e) => e.folderId === filters.folderId);\n }\n if (filters.threadId) {\n emails = emails.filter((e) => e.threadId === filters.threadId);\n }\n if (filters.from) {\n const fromLower = filters.from.toLowerCase();\n emails = emails.filter(\n (e) =>\n e.fromAddress?.toLowerCase().includes(fromLower) ||\n e.fromName?.toLowerCase().includes(fromLower),\n );\n }\n if (filters.to) {\n const toLower = filters.to.toLowerCase();\n emails = emails.filter((e) =>\n e.toAddresses?.toLowerCase().includes(toLower),\n );\n }\n if (filters.subject) {\n const subjectLower = filters.subject.toLowerCase();\n emails = emails.filter((e) =>\n e.subject?.toLowerCase().includes(subjectLower),\n );\n }\n if (filters.isRead !== undefined) {\n emails = emails.filter((e) => e.isRead === filters.isRead);\n }\n if (filters.isFlagged !== undefined) {\n emails = emails.filter((e) => e.isFlagged === filters.isFlagged);\n }\n if (filters.hasAttachments !== undefined) {\n emails = emails.filter(\n (e) => e.hasAttachments === filters.hasAttachments,\n );\n }\n if (filters.sincDate) {\n emails = emails.filter(\n (e) => e.date && e.date >= (filters.sincDate as Date),\n );\n }\n if (filters.beforeDate) {\n emails = emails.filter(\n (e) => e.date && e.date < (filters.beforeDate as Date),\n );\n }\n }\n\n return emails;\n }\n\n /**\n * Mark all emails in a folder as read\n */\n async markFolderRead(folderId: string): Promise<void> {\n const emails = (await this.getUnread()) as Email[];\n const folderEmails = emails.filter((e) => e.folderId === folderId);\n\n for (const email of folderEmails) {\n await email.markRead();\n }\n }\n\n /**\n * Delete emails by folder\n */\n async deleteByFolder(folderId: string): Promise<number> {\n const emails = await this.getByFolder(folderId);\n let count = 0;\n\n for (const email of emails) {\n await email.delete();\n count++;\n }\n\n return count;\n }\n\n /**\n * Get email statistics for an account\n */\n override async getAccountStats(accountId: string): Promise<{\n total: number;\n unread: number;\n flagged: number;\n withAttachments: number;\n byType: Record<string, number>;\n }> {\n const emails = await this.getByAccount(accountId);\n\n return {\n total: emails.length,\n unread: emails.filter((e) => !e.isRead).length,\n flagged: emails.filter((e) => e.isFlagged).length,\n withAttachments: emails.filter((e) => e.hasAttachments).length,\n byType: { Email: emails.length },\n };\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Tenant Helper Methods\n // ─────────────────────────────────────────────────────────────────────────\n\n override async findByTenant(tenantId: string): Promise<Email[]> {\n return this.list({ where: { tenantId } }) as Promise<Email[]>;\n }\n\n // Now that Email inherits Message's @TenantScoped recognition (#1596), an\n // explicit `tenant_id IS NULL` filter via list() throws and unflagged raw SQL\n // is blocked under an active tenant context — so route global / cross-global\n // lookups through the shared raw helpers. They auto-scope to the Email\n // `_meta_type` (via getStiChildMetaType) so the shared `messages` table never\n // returns sibling Message subtypes. (#1600)\n override async findGlobal(): Promise<Email[]> {\n return queryGlobal<Email>(this);\n }\n\n override async findWithGlobals(tenantId: string): Promise<Email[]> {\n return queryWithGlobals<Email>(this, tenantId, 'Email.findWithGlobals');\n }\n}\n","/**\n * EmailFolderCollection - Collection manager for EmailFolder objects\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { queryGlobal, queryWithGlobals } from '@happyvertical/smrt-tenancy';\nimport { EmailFolder } from '../models/EmailFolder';\nimport type { EmailFolderSearchFilters } from '../types';\n\nexport class EmailFolderCollection extends SmrtCollection<EmailFolder> {\n static readonly _itemClass = EmailFolder;\n\n /**\n * Get folder by path for an account\n */\n async getByPath(\n accountId: string,\n path: string,\n ): Promise<EmailFolder | null> {\n const folders = await this.list({ where: { accountId, path } });\n return folders[0] || null;\n }\n\n /**\n * Get folders by account\n */\n async getByAccount(accountId: string): Promise<EmailFolder[]> {\n return await this.list({ where: { accountId } });\n }\n\n /**\n * Get inbox folder for an account\n */\n async getInbox(accountId: string): Promise<EmailFolder | null> {\n const folders = await this.getByAccount(accountId);\n return folders.find((f) => f.isInbox()) || null;\n }\n\n /**\n * Get sent folder for an account\n */\n async getSent(accountId: string): Promise<EmailFolder | null> {\n const folders = await this.getByAccount(accountId);\n return folders.find((f) => f.isSent()) || null;\n }\n\n /**\n * Get drafts folder for an account\n */\n async getDrafts(accountId: string): Promise<EmailFolder | null> {\n const folders = await this.getByAccount(accountId);\n return folders.find((f) => f.isDrafts()) || null;\n }\n\n /**\n * Get trash folder for an account\n */\n async getTrash(accountId: string): Promise<EmailFolder | null> {\n const folders = await this.getByAccount(accountId);\n return folders.find((f) => f.isTrash()) || null;\n }\n\n /**\n * Get spam folder for an account\n */\n async getSpam(accountId: string): Promise<EmailFolder | null> {\n const folders = await this.getByAccount(accountId);\n return folders.find((f) => f.isSpam()) || null;\n }\n\n /**\n * Get system folders for an account\n */\n async getSystemFolders(accountId: string): Promise<EmailFolder[]> {\n const folders = await this.getByAccount(accountId);\n return folders.filter((f) => f.isSystemFolder());\n }\n\n /**\n * Get user-created folders for an account\n */\n async getUserFolders(accountId: string): Promise<EmailFolder[]> {\n const folders = await this.getByAccount(accountId);\n return folders.filter((f) => !f.isSystemFolder());\n }\n\n /**\n * Get subscribed folders\n */\n async getSubscribed(accountId?: string): Promise<EmailFolder[]> {\n const where: Record<string, unknown> = { subscribed: true };\n if (accountId) {\n where.accountId = accountId;\n }\n return await this.list({ where });\n }\n\n /**\n * Get folders with unread messages\n */\n async getWithUnread(accountId?: string): Promise<EmailFolder[]> {\n const folders = accountId\n ? await this.getByAccount(accountId)\n : await this.list({});\n\n return folders.filter((f) => f.unreadCount > 0);\n }\n\n /**\n * Search folders with filters\n */\n async search(\n query: string,\n filters?: EmailFolderSearchFilters,\n ): Promise<EmailFolder[]> {\n let folders = await this.list({});\n\n // Filter by query\n if (query) {\n const lowerQuery = query.toLowerCase();\n folders = folders.filter(\n (f) =>\n f.name?.toLowerCase().includes(lowerQuery) ||\n f.path?.toLowerCase().includes(lowerQuery),\n );\n }\n\n // Apply filters\n if (filters) {\n if (filters.accountId) {\n folders = folders.filter((f) => f.accountId === filters.accountId);\n }\n if (filters.specialUse) {\n folders = folders.filter((f) => f.specialUse === filters.specialUse);\n }\n if (filters.subscribed !== undefined) {\n folders = folders.filter((f) => f.subscribed === filters.subscribed);\n }\n }\n\n return folders;\n }\n\n /**\n * Refresh counts for all folders in an account\n */\n async refreshAllCounts(accountId: string): Promise<void> {\n const folders = await this.getByAccount(accountId);\n\n for (const folder of folders) {\n await folder.refreshCounts();\n }\n }\n\n /**\n * Get folder statistics for an account\n */\n async getAccountStats(accountId: string): Promise<{\n totalFolders: number;\n totalMessages: number;\n totalUnread: number;\n systemFolders: number;\n userFolders: number;\n }> {\n const folders = await this.getByAccount(accountId);\n\n return {\n totalFolders: folders.length,\n totalMessages: folders.reduce((sum, f) => sum + f.messageCount, 0),\n totalUnread: folders.reduce((sum, f) => sum + f.unreadCount, 0),\n systemFolders: folders.filter((f) => f.isSystemFolder()).length,\n userFolders: folders.filter((f) => !f.isSystemFolder()).length,\n };\n }\n\n /**\n * Create standard system folders for an account\n */\n async createSystemFolders(accountId: string): Promise<void> {\n const standardFolders = [\n { name: 'INBOX', path: 'INBOX', specialUse: '\\\\Inbox' },\n { name: 'Sent', path: 'Sent', specialUse: '\\\\Sent' },\n { name: 'Drafts', path: 'Drafts', specialUse: '\\\\Drafts' },\n { name: 'Trash', path: 'Trash', specialUse: '\\\\Trash' },\n { name: 'Spam', path: 'Spam', specialUse: '\\\\Junk' },\n ];\n\n for (const folderData of standardFolders) {\n const existing = await this.getByPath(accountId, folderData.path);\n if (!existing) {\n // Create through the collection so the DB connection is bound; a bare\n // `new EmailFolder(...)` + save() throws \"Database accessed before\n // initialization\" under per-instance DB injection.\n const folder = await this.create({\n accountId,\n ...folderData,\n });\n await folder.save();\n }\n }\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Tenant Helper Methods\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Find all email folders belonging to a specific tenant\n */\n async findByTenant(tenantId: string): Promise<EmailFolder[]> {\n return this.list({ where: { tenantId } });\n }\n\n /**\n * Find all global email folders (no tenant).\n *\n * EmailFolder is @TenantScoped (CTI, own `email_folders` table). Under an\n * active tenant context list({ tenantId: null }) throws and unflagged raw SQL\n * is blocked (#1596); route through the raw helpers.\n */\n async findGlobal(): Promise<EmailFolder[]> {\n return queryGlobal<EmailFolder>(this);\n }\n\n /**\n * Find email folders for a tenant including global folders.\n */\n async findWithGlobals(tenantId: string): Promise<EmailFolder[]> {\n return queryWithGlobals<EmailFolder>(\n this,\n tenantId,\n 'EmailFolder.findWithGlobals',\n );\n }\n}\n","import { SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport type { BlacklistOptions } from '../types';\n\n/**\n * Blacklist - Block entries for email filtering\n *\n * Supports three pattern types:\n * - email: Exact email address (spam@example.com)\n * - domain: Entire domain (*@spam.com)\n * - regex: Custom regex pattern\n */\n@smrt({\n api: { include: ['list', 'get', 'create', 'update', 'delete'] },\n cli: true,\n tenantScoped: true,\n})\nexport class Blacklist extends SmrtObject {\n pattern: string = '';\n type: 'email' | 'domain' | 'regex' = 'email';\n reason: string = '';\n autoArchive: boolean = true;\n\n constructor(options: BlacklistOptions = {}) {\n super(options);\n\n if (options.pattern !== undefined) {\n this.pattern = options.pattern;\n }\n if (options.type !== undefined) {\n this.type = options.type;\n }\n }\n\n /**\n * Check if an email address matches this blacklist entry\n */\n matches(email: string): boolean {\n const normalizedEmail = email.toLowerCase().trim();\n\n switch (this.type) {\n case 'email':\n return normalizedEmail === this.pattern.toLowerCase().trim();\n\n case 'domain': {\n const domain = normalizedEmail.split('@')[1];\n return domain === this.pattern.toLowerCase().trim();\n }\n\n case 'regex': {\n const pattern = this.pattern.trim();\n if (!pattern) {\n return false;\n }\n try {\n const regex = new RegExp(pattern, 'i');\n return regex.test(normalizedEmail);\n } catch {\n return false;\n }\n }\n\n default:\n return false;\n }\n }\n}\n","import { SmrtCollection } from '@happyvertical/smrt-core';\nimport { Blacklist } from '../models/Blacklist.js';\n\nexport class BlacklistCollection extends SmrtCollection<Blacklist> {\n static readonly _itemClass = Blacklist;\n\n /**\n * Check if an email is blacklisted\n */\n async isBlacklisted(email: string): Promise<boolean> {\n const entries = await this.list({});\n\n for (const entry of entries) {\n if (entry.matches(email)) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Get the matching blacklist entry for an email\n */\n async getMatchingEntry(email: string): Promise<Blacklist | null> {\n const entries = await this.list({});\n\n for (const entry of entries) {\n if (entry.matches(email)) {\n return entry;\n }\n }\n\n return null;\n }\n}\n","import { SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport type { WhitelistOptions } from '../types';\n\n/**\n * Whitelist - Allow-only entries for email filtering\n *\n * Supports three pattern types:\n * - email: Exact email address (user@example.com)\n * - domain: Entire domain (*@example.com)\n * - regex: Custom regex pattern\n */\n@smrt({\n api: { include: ['list', 'get', 'create', 'update', 'delete'] },\n cli: true,\n tenantScoped: true,\n})\nexport class Whitelist extends SmrtObject {\n pattern: string = '';\n type: 'email' | 'domain' | 'regex' = 'email';\n category: string | null = null;\n description: string = '';\n\n constructor(options: WhitelistOptions = {}) {\n super(options);\n\n if (options.pattern !== undefined) {\n this.pattern = options.pattern;\n }\n if (options.type !== undefined) {\n this.type = options.type;\n }\n }\n\n /**\n * Check if an email address matches this whitelist entry\n */\n matches(email: string): boolean {\n const normalizedEmail = email.toLowerCase().trim();\n\n switch (this.type) {\n case 'email':\n return normalizedEmail === this.pattern.toLowerCase().trim();\n\n case 'domain': {\n const domain = normalizedEmail.split('@')[1];\n return domain === this.pattern.toLowerCase().trim();\n }\n\n case 'regex': {\n const pattern = this.pattern.trim();\n if (!pattern) {\n return false;\n }\n try {\n const regex = new RegExp(pattern, 'i');\n return regex.test(normalizedEmail);\n } catch {\n return false;\n }\n }\n\n default:\n return false;\n }\n }\n}\n","import { SmrtCollection } from '@happyvertical/smrt-core';\nimport { Whitelist } from '../models/Whitelist.js';\n\nexport class WhitelistCollection extends SmrtCollection<Whitelist> {\n static readonly _itemClass = Whitelist;\n\n /**\n * Check if an email is whitelisted for a specific category\n */\n async isWhitelisted(email: string, category?: string): Promise<boolean> {\n const entries = await this.list({});\n\n for (const entry of entries) {\n if (!entry.matches(email)) {\n continue;\n }\n\n if (!category) {\n return true;\n }\n\n if (entry.category === category || entry.category === null) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Get the matching whitelist entry for an email\n */\n async getMatchingEntry(email: string): Promise<Whitelist | null> {\n const entries = await this.list({});\n\n for (const entry of entries) {\n if (entry.matches(email)) {\n return entry;\n }\n }\n\n return null;\n }\n\n /**\n * Get whitelist entries by category\n */\n async getByCategory(category: string): Promise<Whitelist[]> {\n return await this.list({\n where: { category },\n });\n }\n}\n","/**\n * SlackAccount model - Slack workspace account extending the Account STI base\n */\n\nimport { smrt } from '@happyvertical/smrt-core';\nimport type { MessageSenderInterface, SlackAccountOptions } from '../types';\nimport { Account } from './Account';\n\n@smrt({\n tableStrategy: 'sti',\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n})\nexport class SlackAccount extends Account {\n workspaceId = '';\n workspaceName = '';\n botUserId = '';\n\n constructor(options: SlackAccountOptions = {}) {\n super(options);\n\n if (options.workspaceId !== undefined)\n this.workspaceId = options.workspaceId;\n if (options.workspaceName !== undefined)\n this.workspaceName = options.workspaceName;\n if (options.botUserId !== undefined) this.botUserId = options.botUserId;\n\n // Default provider type\n if (!this.providerType) this.providerType = 'slack';\n this.channelType = 'slack';\n }\n\n /**\n * Create a sender for this Slack account\n */\n override async createSender(): Promise<MessageSenderInterface> {\n const { SlackSender } = await import('../senders/SlackSender');\n return new SlackSender(this);\n }\n}\n","/**\n * SlackMessage model - Slack message extending the Message STI base\n */\n\nimport { smrt } from '@happyvertical/smrt-core';\nimport type { SlackMessageOptions } from '../types';\nimport { Message } from './Message';\n\n@smrt({\n tableStrategy: 'sti',\n api: { include: ['list', 'get', 'create'] },\n mcp: { include: ['list', 'get'] },\n cli: true,\n})\nexport class SlackMessage extends Message {\n channelId = '';\n channelName = '';\n slackTs = ''; // Slack message timestamp (unique ID)\n slackThreadTs = ''; // Thread parent timestamp\n reactions = ''; // JSON array of {name, count, users[]}\n isEdited = false;\n messageType = ''; // 'message', 'bot_message', etc.\n blocks = ''; // JSON - Slack Block Kit blocks\n\n constructor(options: SlackMessageOptions = {}) {\n super(options);\n\n if (options.channelId !== undefined) this.channelId = options.channelId;\n if (options.channelName !== undefined)\n this.channelName = options.channelName;\n if (options.slackTs !== undefined) this.slackTs = options.slackTs;\n if (options.slackThreadTs !== undefined)\n this.slackThreadTs = options.slackThreadTs;\n if (options.reactions !== undefined) this.reactions = options.reactions;\n if (options.isEdited !== undefined) this.isEdited = options.isEdited;\n if (options.messageType !== undefined)\n this.messageType = options.messageType;\n if (options.blocks !== undefined) this.blocks = options.blocks;\n }\n\n /**\n * Get reactions as parsed array\n */\n getReactions(): Array<{ name: string; count: number; users?: string[] }> {\n if (!this.reactions) return [];\n try {\n return JSON.parse(this.reactions);\n } catch {\n return [];\n }\n }\n\n /**\n * Get blocks as parsed array\n */\n getBlocks(): Record<string, unknown>[] {\n if (!this.blocks) return [];\n try {\n return JSON.parse(this.blocks);\n } catch {\n return [];\n }\n }\n\n /**\n * Check if message is in a thread\n */\n isInThread(): boolean {\n return !!this.slackThreadTs && this.slackThreadTs !== this.slackTs;\n }\n\n /**\n * Get total reaction count\n */\n getTotalReactions(): number {\n return this.getReactions().reduce((sum, r) => sum + r.count, 0);\n }\n}\n","import { smrt } from '@happyvertical/smrt-core';\nimport type { AccountOptions } from '../types.js';\nimport { Account } from './Account.js';\n\n@smrt({\n tableStrategy: 'sti',\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n})\nexport class TelegramAccount extends Account {\n constructor(options: AccountOptions = {}) {\n super(options);\n this.providerType = 'telegram';\n this.channelType = 'telegram';\n }\n}\n","/**\n * Tweet model - Twitter/X message extending the Message STI base\n */\n\nimport { smrt } from '@happyvertical/smrt-core';\nimport type { TweetOptions } from '../types';\nimport { Message } from './Message';\n\n@smrt({\n tableStrategy: 'sti',\n api: { include: ['list', 'get', 'create'] },\n mcp: { include: ['list', 'get'] },\n cli: true,\n})\nexport class Tweet extends Message {\n tweetId = '';\n retweetCount = 0;\n likeCount = 0;\n replyCount = 0;\n isRetweet = false;\n isReply = false;\n mediaUrls = ''; // JSON array\n hashtags = ''; // JSON array\n mentions = ''; // JSON array\n\n constructor(options: TweetOptions = {}) {\n super(options);\n\n if (options.tweetId !== undefined) this.tweetId = options.tweetId;\n if (options.retweetCount !== undefined)\n this.retweetCount = options.retweetCount;\n if (options.likeCount !== undefined) this.likeCount = options.likeCount;\n if (options.replyCount !== undefined) this.replyCount = options.replyCount;\n if (options.isRetweet !== undefined) this.isRetweet = options.isRetweet;\n if (options.isReply !== undefined) this.isReply = options.isReply;\n if (options.mediaUrls !== undefined) this.mediaUrls = options.mediaUrls;\n if (options.hashtags !== undefined) this.hashtags = options.hashtags;\n if (options.mentions !== undefined) this.mentions = options.mentions;\n }\n\n /**\n * Get media URLs as parsed array\n */\n getMediaUrls(): string[] {\n if (!this.mediaUrls) return [];\n try {\n return JSON.parse(this.mediaUrls);\n } catch {\n return [];\n }\n }\n\n /**\n * Get hashtags as parsed array\n */\n getHashtags(): string[] {\n if (!this.hashtags) return [];\n try {\n return JSON.parse(this.hashtags);\n } catch {\n return [];\n }\n }\n\n /**\n * Get mentions as parsed array\n */\n getMentions(): string[] {\n if (!this.mentions) return [];\n try {\n return JSON.parse(this.mentions);\n } catch {\n return [];\n }\n }\n\n /**\n * Get total engagement count\n */\n getEngagement(): number {\n return this.retweetCount + this.likeCount + this.replyCount;\n }\n}\n","/**\n * TwitterAccount model - Twitter/X account extending the Account STI base\n */\n\nimport { smrt } from '@happyvertical/smrt-core';\nimport type { MessageSenderInterface, TwitterAccountOptions } from '../types';\nimport { Account } from './Account';\n\n@smrt({\n tableStrategy: 'sti',\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n})\nexport class TwitterAccount extends Account {\n handle = '';\n twitterUserId = '';\n\n constructor(options: TwitterAccountOptions = {}) {\n super(options);\n\n if (options.handle !== undefined) this.handle = options.handle;\n if (options.twitterUserId !== undefined)\n this.twitterUserId = options.twitterUserId;\n\n // Default provider type\n if (!this.providerType) this.providerType = 'twitter';\n this.channelType = 'twitter';\n }\n\n /**\n * Create a sender for this Twitter account\n */\n override async createSender(): Promise<MessageSenderInterface> {\n const { TweetSender } = await import('../senders/TweetSender');\n return new TweetSender(this);\n }\n}\n","import { smrt } from '@happyvertical/smrt-core';\nimport type { AccountOptions } from '../types.js';\nimport { Account } from './Account.js';\n\n@smrt({\n tableStrategy: 'sti',\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n})\nexport class ZulipAccount extends Account {\n constructor(options: AccountOptions = {}) {\n super(options);\n this.providerType = 'zulip';\n this.channelType = 'zulip';\n }\n}\n","/**\n * EmailSender — sends email messages via the SDK EmailClient\n */\n\nimport type { EmailClient } from '@happyvertical/email';\nimport type { Email } from '../models/Email';\nimport type { EmailAccount } from '../models/EmailAccount';\nimport type {\n MessageSenderInterface,\n MessageSendResult,\n SendMessageOptions,\n} from '../types';\n\nexport class EmailSender implements MessageSenderInterface {\n readonly providerType = 'email';\n private client: EmailClient;\n private account: EmailAccount;\n\n constructor(client: EmailClient, account: EmailAccount) {\n this.client = client;\n this.account = account;\n }\n\n isReady(): boolean {\n return this.client.isConnected();\n }\n\n async send(\n message: Email,\n _options?: SendMessageOptions,\n ): Promise<MessageSendResult> {\n const toAddresses = message.getToAddresses();\n const ccAddresses = message.getCcAddresses();\n const bccAddresses = message.getBccAddresses();\n\n const emailMessage = {\n from: {\n name: message.fromName || this.account.name,\n address: message.fromAddress || this.account.email,\n },\n to: toAddresses.map((r) => ({\n name: r.name,\n address: r.address,\n })),\n cc:\n ccAddresses.length > 0\n ? ccAddresses.map((r) => ({ name: r.name, address: r.address }))\n : undefined,\n bcc:\n bccAddresses.length > 0\n ? bccAddresses.map((r) => ({ name: r.name, address: r.address }))\n : undefined,\n subject: message.subject,\n text: message.textBody || message.body,\n html: message.htmlBody || undefined,\n inReplyTo: message.inReplyTo || undefined,\n };\n\n try {\n const result = await this.client.send(emailMessage);\n\n return {\n success: true,\n providerMessageId: result.messageId,\n accepted: result.accepted,\n rejected: result.rejected,\n providerResponse: { response: result.response },\n sentAt: new Date(),\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n sentAt: new Date(),\n };\n }\n }\n}\n","import type { SmrtClassOptions } from '@happyvertical/smrt-core';\nimport { withTenant } from '@happyvertical/smrt-tenancy';\nimport { AccountCollection } from '../collections/AccountCollection.js';\nimport { MessagingEndpointCollection } from '../collections/MessagingEndpointCollection.js';\nimport { PersonaMessageRouteCollection } from '../collections/PersonaMessageRouteCollection.js';\nimport { Account } from '../models/Account.js';\nimport { EmailAccount } from '../models/EmailAccount.js';\nimport { MessagingEndpoint } from '../models/MessagingEndpoint.js';\nimport { PersonaMessageRoute } from '../models/PersonaMessageRoute.js';\nimport { TelegramAccount } from '../models/TelegramAccount.js';\nimport { ZulipAccount } from '../models/ZulipAccount.js';\nimport {\n assertMessagingPermission,\n MANAGE_MESSAGE_CREDENTIALS_PERMISSION,\n MANAGE_MESSAGE_ROUTES_PERMISSION,\n type MessagingPrincipal,\n} from '../permissions.js';\nimport {\n getMessagingProvider,\n listMessagingProviders,\n type MessagingProviderDefinition,\n type MessagingProviderField,\n type MessagingProviderFunctionKey,\n} from '../providers.js';\nimport type { MessagingChannel } from '../types.js';\n\nexport interface MessagingAccountInput {\n id?: string;\n name: string;\n providerId: string;\n configuration: Record<string, unknown>;\n /** Omit on update to leave the stored secret unchanged. */\n credentials?: Record<string, unknown>;\n active?: boolean;\n}\n\nexport interface MessagingEndpointInput {\n id?: string;\n label: string;\n providerId: string;\n profileId?: string | null;\n address: Record<string, unknown>;\n active?: boolean;\n}\n\nexport interface PersonaMessageRouteInput {\n id?: string;\n personaId: string;\n accountId: string;\n endpointId: string;\n purpose?: string;\n priority?: number;\n enabled?: boolean;\n}\n\nexport interface MessagingAccountView {\n id: string;\n name: string;\n providerId: string;\n channel: MessagingChannel;\n configuration: Record<string, unknown>;\n hasCredentials: boolean;\n active: boolean;\n}\n\nexport interface MessagingEndpointView {\n id: string;\n label: string;\n channel: MessagingChannel;\n profileId: string | null;\n maskedAddress: string;\n active: boolean;\n verified: boolean;\n}\n\n/** Permission-gated server API for a schema-driven messaging settings page. */\nexport class MessagingSettingsService {\n constructor(\n private readonly options: {\n db: SmrtClassOptions['db'];\n tenantId: string;\n principal: MessagingPrincipal;\n /** Cross-package ownership check supplied by the host/personas layer. */\n resolvePersonaTenantId: (personaId: string) => Promise<string | null>;\n },\n ) {}\n\n getProviderDefinitions(options: { includeUnavailable?: boolean } = {}) {\n return listMessagingProviders(options).map(\n ({\n createSender: _createSender,\n createEmailClient: _createEmailClient,\n createMessageClient: _createMessageClient,\n ...provider\n }) => provider,\n );\n }\n\n async list(personaId: string): Promise<{\n providers: Array<\n Omit<MessagingProviderDefinition, MessagingProviderFunctionKey>\n >;\n accounts: MessagingAccountView[];\n endpoints: MessagingEndpointView[];\n routes: PersonaMessageRoute[];\n }> {\n this.assert(MANAGE_MESSAGE_ROUTES_PERMISSION);\n return withTenant({ tenantId: this.options.tenantId }, async () => {\n const accounts = await AccountCollection.create({ db: this.options.db });\n const endpoints = await MessagingEndpointCollection.create({\n db: this.options.db,\n });\n const routes = await PersonaMessageRouteCollection.create({\n db: this.options.db,\n });\n const [accountRows, endpointRows, routeRows] = await Promise.all([\n accounts.list({}),\n endpoints.list({}),\n routes.list({ where: { personaId } }),\n ]);\n return {\n providers: this.getProviderDefinitions({ includeUnavailable: true }),\n accounts: accountRows.map((account) => this.accountView(account)),\n endpoints: endpointRows.map((endpoint) => this.endpointView(endpoint)),\n routes: routeRows,\n };\n });\n }\n\n async saveAccount(\n input: MessagingAccountInput,\n ): Promise<MessagingAccountView> {\n this.assert(MANAGE_MESSAGE_CREDENTIALS_PERMISSION);\n const provider = this.requireProvider(input.providerId);\n if (!provider.available)\n throw new Error(`Provider '${provider.id}' is not available.`);\n this.validateFields(\n input.configuration,\n provider.configurationFields,\n 'configuration',\n );\n if (input.credentials) {\n this.validateFields(\n input.credentials,\n provider.credentialFields,\n 'credentials',\n );\n }\n\n return withTenant({ tenantId: this.options.tenantId }, async () => {\n const collection = await AccountCollection.create({\n db: this.options.db,\n });\n let account = input.id ? await collection.get({ id: input.id }) : null;\n const isNew = !account;\n if (account && account.tenantId !== this.options.tenantId) {\n throw new Error('Messaging account belongs to another tenant.');\n }\n if (account && account.providerType !== provider.id) {\n throw new Error(\n 'A messaging account provider cannot be changed in place.',\n );\n }\n if (\n isNew &&\n !input.credentials &&\n provider.credentialFields.some((field) => field.required)\n ) {\n throw new Error(\n `Credentials are required for new ${provider.label} accounts.`,\n );\n }\n\n if (!account) {\n account = this.newAccount(provider, input);\n await account.initialize();\n }\n\n account.name = input.name.trim();\n account.isActive = input.active ?? account.isActive;\n account.channelType = provider.channel;\n const configuration = this.normalizeConfiguration(\n provider,\n input.configuration,\n );\n account.setConfiguration(configuration);\n if (account instanceof EmailAccount) {\n account.email = String(configuration.email ?? '');\n }\n account.updatedAt = new Date();\n await account.save();\n\n if (input.credentials) {\n await account.setCredentials(\n this.normalizeCredentials(provider, input.credentials),\n );\n }\n\n return this.accountView(account);\n });\n }\n\n async saveEndpoint(\n input: MessagingEndpointInput,\n ): Promise<MessagingEndpointView> {\n this.assert(MANAGE_MESSAGE_ROUTES_PERMISSION);\n const provider = this.requireProvider(input.providerId);\n if (!provider.available)\n throw new Error(`Provider '${provider.id}' is not available.`);\n this.validateFields(input.address, provider.endpointFields, 'endpoint');\n\n return withTenant({ tenantId: this.options.tenantId }, async () => {\n const collection = await MessagingEndpointCollection.create({\n db: this.options.db,\n });\n let endpoint = input.id ? await collection.get({ id: input.id }) : null;\n if (endpoint && endpoint.tenantId !== this.options.tenantId) {\n throw new Error('Messaging endpoint belongs to another tenant.');\n }\n if (!endpoint) {\n endpoint = new MessagingEndpoint({\n db: this.options.db,\n tenantId: this.options.tenantId,\n });\n await endpoint.initialize();\n }\n endpoint.label = input.label.trim();\n if (input.profileId !== undefined) {\n endpoint.profileId = input.profileId;\n }\n endpoint.channel = provider.channel;\n endpoint.isActive = input.active ?? endpoint.isActive;\n endpoint.setAddress(input.address);\n endpoint.updatedAt = new Date();\n await endpoint.save();\n return this.endpointView(endpoint);\n });\n }\n\n async saveRoute(\n input: PersonaMessageRouteInput,\n ): Promise<PersonaMessageRoute> {\n this.assert(MANAGE_MESSAGE_ROUTES_PERMISSION);\n const personaTenantId = await this.options.resolvePersonaTenantId(\n input.personaId,\n );\n if (personaTenantId !== this.options.tenantId) {\n throw new Error('Messaging persona was not found in this tenant.');\n }\n return withTenant({ tenantId: this.options.tenantId }, async () => {\n const accounts = await AccountCollection.create({ db: this.options.db });\n const endpoints = await MessagingEndpointCollection.create({\n db: this.options.db,\n });\n const routes = await PersonaMessageRouteCollection.create({\n db: this.options.db,\n });\n const [account, endpoint] = await Promise.all([\n accounts.get({ id: input.accountId }),\n endpoints.get({ id: input.endpointId }),\n ]);\n if (!account || account.tenantId !== this.options.tenantId) {\n throw new Error('Messaging account was not found in this tenant.');\n }\n if (!endpoint || endpoint.tenantId !== this.options.tenantId) {\n throw new Error('Messaging endpoint was not found in this tenant.');\n }\n const accountProvider = getMessagingProvider(account.providerType);\n if (\n !accountProvider?.available ||\n accountProvider.channel !== account.channelType\n ) {\n throw new Error(\n 'Messaging account provider is not available for outbound delivery.',\n );\n }\n if (account.channelType !== endpoint.channel) {\n throw new Error(\n 'Messaging account and endpoint channels do not match.',\n );\n }\n\n let route = input.id ? await routes.get({ id: input.id }) : null;\n if (route && route.tenantId !== this.options.tenantId) {\n throw new Error('Messaging route belongs to another tenant.');\n }\n if (!route) {\n route = new PersonaMessageRoute({\n db: this.options.db,\n tenantId: this.options.tenantId,\n });\n await route.initialize();\n }\n route.personaId = input.personaId;\n route.accountId = input.accountId;\n route.endpointId = input.endpointId;\n route.purpose = input.purpose?.trim() || 'default';\n route.priority = input.priority ?? 0;\n route.enabled = input.enabled ?? route.enabled;\n route.updatedAt = new Date();\n await route.save();\n return route;\n });\n }\n\n private assert(permission: string): void {\n assertMessagingPermission(\n this.options.principal,\n this.options.tenantId,\n permission,\n );\n }\n\n private requireProvider(providerId: string): MessagingProviderDefinition {\n const provider = getMessagingProvider(providerId);\n if (!provider)\n throw new Error(`Unknown messaging provider '${providerId}'.`);\n return provider;\n }\n\n private validateFields(\n values: Record<string, unknown>,\n fields: MessagingProviderField[],\n kind: string,\n ): void {\n const allowed = new Set(fields.map((field) => field.id));\n for (const key of Object.keys(values)) {\n if (!allowed.has(key)) {\n throw new Error(`Unknown ${kind} field '${key}'.`);\n }\n }\n for (const field of fields) {\n const value = values[field.id];\n const missing = value === undefined || value === '';\n if (field.required && (missing || value === null)) {\n throw new Error(`${field.label} is required in ${kind}.`);\n }\n if (missing) continue;\n\n if (\n field.type === 'number' &&\n (typeof value !== 'number' || !Number.isFinite(value))\n ) {\n throw new Error(`${field.label} must be a finite number in ${kind}.`);\n }\n if (field.type === 'boolean' && typeof value !== 'boolean') {\n throw new Error(`${field.label} must be a boolean in ${kind}.`);\n }\n if (\n field.type !== 'number' &&\n field.type !== 'boolean' &&\n typeof value !== 'string'\n ) {\n throw new Error(`${field.label} must be a string in ${kind}.`);\n }\n if (\n field.type === 'select' &&\n field.options?.length &&\n !field.options.some((option) => option.value === value)\n ) {\n throw new Error(`${field.label} has an invalid option in ${kind}.`);\n }\n }\n }\n\n private newAccount(\n provider: MessagingProviderDefinition,\n input: MessagingAccountInput,\n ): Account {\n const options = {\n db: this.options.db,\n tenantId: this.options.tenantId,\n name: input.name.trim(),\n providerType: provider.id,\n channelType: provider.channel,\n };\n if (provider.id === 'zulip') return new ZulipAccount(options);\n if (provider.id === 'telegram') return new TelegramAccount(options);\n if (provider.channel === 'email') {\n return new EmailAccount({\n ...options,\n providerType: provider.id as 'smtp' | 'imap' | 'pop3' | 'gmail',\n });\n }\n return new Account(options);\n }\n\n private normalizeCredentials(\n provider: MessagingProviderDefinition,\n credentials: Record<string, unknown>,\n ): Record<string, unknown> {\n if (provider.channel !== 'email') return credentials;\n if (provider.id === 'gmail') {\n return { auth: credentials };\n }\n const { username, password, ...rest } = credentials;\n return {\n ...rest,\n auth: { user: username, pass: password },\n };\n }\n\n private normalizeConfiguration(\n provider: MessagingProviderDefinition,\n configuration: Record<string, unknown>,\n ): Record<string, unknown> {\n if (provider.channel !== 'email' || configuration.secure === undefined) {\n return configuration;\n }\n return {\n ...configuration,\n secure: configuration.secure === true || configuration.secure === 'true',\n };\n }\n\n private accountView(account: Account): MessagingAccountView {\n return {\n id: account.id ?? '',\n name: account.name,\n providerId: account.providerType,\n channel: account.channelType,\n configuration: account.getConfiguration(),\n hasCredentials: account.hasCredentials,\n active: account.isActive,\n };\n }\n\n private endpointView(endpoint: MessagingEndpoint): MessagingEndpointView {\n return {\n id: endpoint.id ?? '',\n label: endpoint.label,\n channel: endpoint.channel,\n profileId: endpoint.profileId,\n maskedAddress: endpoint.getMaskedAddress(),\n active: endpoint.isActive,\n verified: endpoint.verifiedAt !== null,\n };\n }\n}\n","import type { SmrtClassOptions } from '@happyvertical/smrt-core';\nimport { withTenant } from '@happyvertical/smrt-tenancy';\nimport { AccountCollection } from '../collections/AccountCollection.js';\nimport { MessagingEndpointCollection } from '../collections/MessagingEndpointCollection.js';\nimport { PersonaMessageRouteCollection } from '../collections/PersonaMessageRouteCollection.js';\nimport { Email } from '../models/Email.js';\nimport { EmailAccount } from '../models/EmailAccount.js';\nimport { Message } from '../models/Message.js';\nimport type { PersonaMessageRoute } from '../models/PersonaMessageRoute.js';\nimport {\n assertMessagingPermission,\n type MessagingPrincipal,\n SEND_MESSAGES_PERMISSION,\n} from '../permissions.js';\nimport type { MessageSendResult, SendPersonaMessageOptions } from '../types.js';\n\nexport interface PersonaMessageSendResult {\n routeId: string;\n messageId: string;\n delivery: MessageSendResult;\n}\n\n/** Resolves a persona-owned route and delivers a persisted outbound message. */\nexport class PersonaMessagingService {\n constructor(\n private readonly options: {\n db: SmrtClassOptions['db'];\n tenantId: string;\n /** Omit only for trusted system code that performs its own authorization. */\n principal?: MessagingPrincipal;\n },\n ) {}\n\n async send(\n input: SendPersonaMessageOptions,\n ): Promise<PersonaMessageSendResult> {\n if (this.options.principal) {\n assertMessagingPermission(\n this.options.principal,\n this.options.tenantId,\n SEND_MESSAGES_PERMISSION,\n );\n }\n if (!input.personaId)\n throw new Error('A persona is required to send a message.');\n if (!input.body.trim()) throw new Error('Message body cannot be empty.');\n\n return withTenant({ tenantId: this.options.tenantId }, async () => {\n const route = await this.resolveRoute(input);\n const accounts = await AccountCollection.create({ db: this.options.db });\n const endpoints = await MessagingEndpointCollection.create({\n db: this.options.db,\n });\n const [account, endpoint] = await Promise.all([\n accounts.get({ id: route.accountId }),\n endpoints.get({ id: route.endpointId }),\n ]);\n if (\n !account ||\n account.tenantId !== this.options.tenantId ||\n !account.isActive\n ) {\n throw new Error('The selected messaging account is unavailable.');\n }\n if (\n !endpoint ||\n endpoint.tenantId !== this.options.tenantId ||\n !endpoint.isActive\n ) {\n throw new Error('The selected messaging endpoint is unavailable.');\n }\n if (account.channelType !== endpoint.channel) {\n throw new Error(\n 'The selected messaging route has mismatched channels.',\n );\n }\n\n let message: Message;\n const base = {\n db: this.options.db,\n tenantId: this.options.tenantId,\n accountId: route.accountId,\n endpointId: route.endpointId,\n personaId: input.personaId,\n correlationId: input.correlationId ?? '',\n subject: input.subject ?? '',\n body: input.body.trim(),\n sendStatus: 'pending' as const,\n };\n if (endpoint.channel === 'email') {\n if (!(account instanceof EmailAccount)) {\n throw new Error('Email routes require an EmailAccount.');\n }\n const address = endpoint.getAddress<{ email?: string }>();\n if (!address.email) throw new Error('Email endpoint has no address.');\n const email = new Email({ ...base, textBody: base.body });\n email.setToAddresses([{ address: address.email }]);\n message = email;\n } else {\n message = new Message(base);\n }\n await message.initialize();\n await message.save();\n const delivery = await message.send();\n return {\n routeId: route.id ?? '',\n messageId: message.id ?? '',\n delivery,\n };\n });\n }\n\n private async resolveRoute(\n input: SendPersonaMessageOptions,\n ): Promise<PersonaMessageRoute> {\n const routes = await PersonaMessageRouteCollection.create({\n db: this.options.db,\n });\n if (input.routeId) {\n const route = await routes.get({ id: input.routeId });\n if (\n !route ||\n route.tenantId !== this.options.tenantId ||\n route.personaId !== input.personaId ||\n !route.enabled\n ) {\n throw new Error(\n 'The requested persona messaging route is unavailable.',\n );\n }\n return route;\n }\n\n let candidates = await routes.forPersona(input.personaId);\n if (input.purpose) {\n candidates = candidates.filter(\n (route) => route.purpose === input.purpose,\n );\n } else {\n const defaults = candidates.filter(\n (route) => route.purpose === 'default',\n );\n if (defaults.length > 0) candidates = defaults;\n }\n candidates.sort((left, right) => right.priority - left.priority);\n\n if (input.channel) {\n const endpoints = await MessagingEndpointCollection.create({\n db: this.options.db,\n });\n for (const route of candidates) {\n const endpoint = await endpoints.get({ id: route.endpointId });\n if (endpoint?.channel === input.channel) return route;\n }\n throw new Error(\n `No ${input.channel} route is configured for this persona.`,\n );\n }\n\n const route = candidates[0];\n if (!route)\n throw new Error('No messaging route is configured for this persona.');\n return route;\n }\n}\n","/**\n * @happyvertical/smrt-messages\n *\n * Unified multi-channel messaging with STI-based hierarchies\n *\n * @packageDocumentation\n */\n\n// Self-register this package's manifest before any @smrt() decorator fires\n// downstream. Must come first so the side effect runs ahead of the class\n// module loads below. See __smrt-register__.ts for issue #1132 context.\nimport './__smrt-register__.js';\n\nimport { ensureMessagingPermissionsRegistered } from './permissions.js';\nimport { ensureBuiltinMessagingProvidersRegistered } from './providers.js';\n\n// ─────────────────────────────────────────────────────────────────────────\n// Base classes (new)\n// ─────────────────────────────────────────────────────────────────────────\n\nexport { AccountCollection } from './collections/AccountCollection';\nexport { AttachmentCollection } from './collections/AttachmentCollection';\n// Base collections\nexport { MessageCollection } from './collections/MessageCollection';\nexport { MessagingEndpointCollection } from './collections/MessagingEndpointCollection.js';\nexport { PersonaMessageRouteCollection } from './collections/PersonaMessageRouteCollection.js';\nexport { Account } from './models/Account';\nexport { Attachment } from './models/Attachment';\n// Base models\nexport { Message } from './models/Message';\nexport { MessagingEndpoint } from './models/MessagingEndpoint.js';\nexport { PersonaMessageRoute } from './models/PersonaMessageRoute.js';\n\n// ─────────────────────────────────────────────────────────────────────────\n// Email (backward-compatible)\n// ─────────────────────────────────────────────────────────────────────────\n\nexport { EmailAccountCollection } from './collections/EmailAccountCollection';\nexport { EmailAttachmentCollection } from './collections/EmailAttachmentCollection';\n// Email collections\nexport { EmailCollection } from './collections/EmailCollection';\nexport { EmailFolderCollection } from './collections/EmailFolderCollection';\n// Email models\nexport { Email } from './models/Email';\nexport { EmailAccount } from './models/EmailAccount';\nexport { EmailAttachment } from './models/EmailAttachment';\nexport { EmailFolder } from './models/EmailFolder';\n\n// ─────────────────────────────────────────────────────────────────────────\n// Email filtering (whitelist/blacklist)\n// ─────────────────────────────────────────────────────────────────────────\n\nexport { BlacklistCollection } from './collections/BlacklistCollection';\nexport { WhitelistCollection } from './collections/WhitelistCollection';\nexport { Blacklist } from './models/Blacklist';\nexport { Whitelist } from './models/Whitelist';\n\n// ─────────────────────────────────────────────────────────────────────────\n// Provider stubs\n// ─────────────────────────────────────────────────────────────────────────\n\n// Account types\nexport { SlackAccount } from './models/SlackAccount';\nexport { SlackMessage } from './models/SlackMessage';\nexport { TelegramAccount } from './models/TelegramAccount.js';\n// Message types\nexport { Tweet } from './models/Tweet';\nexport { TwitterAccount } from './models/TwitterAccount';\nexport { ZulipAccount } from './models/ZulipAccount.js';\n\n// ─────────────────────────────────────────────────────────────────────────\n// Senders\n// ─────────────────────────────────────────────────────────────────────────\n\nexport {\n assertMessagingPermission,\n ensureMessagingPermissionsRegistered,\n MANAGE_MESSAGE_CREDENTIALS_PERMISSION,\n MANAGE_MESSAGE_ROUTES_PERMISSION,\n MESSAGING_PERMISSION_DEFINITIONS,\n type MessagingPrincipal,\n messagingPrincipalFromPermissions,\n SEND_MESSAGES_PERMISSION,\n} from './permissions.js';\nexport {\n ensureBuiltinMessagingProvidersRegistered,\n getMessagingProvider,\n listMessagingProviders,\n type MessagingProviderDefinition,\n type MessagingProviderField,\n type MessagingProviderFieldType,\n registerMessagingProvider,\n} from './providers.js';\nexport { EmailSender } from './senders/EmailSender';\nexport { SlackSender } from './senders/SlackSender';\nexport { TelegramSender } from './senders/TelegramSender.js';\nexport { TweetSender } from './senders/TweetSender';\nexport { ZulipSender } from './senders/ZulipSender.js';\nexport {\n type MessagingAccountInput,\n type MessagingAccountView,\n type MessagingEndpointInput,\n type MessagingEndpointView,\n MessagingSettingsService,\n type PersonaMessageRouteInput,\n} from './services/MessagingSettingsService.js';\nexport {\n type PersonaMessageSendResult,\n PersonaMessagingService,\n} from './services/PersonaMessagingService.js';\n\n// ─────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────\n\nexport type {\n AccountOptions,\n AccountSearchFilters,\n AccountType,\n AttachmentOptions,\n // Email options (backward compat)\n EmailAccountOptions,\n EmailAccountSearchFilters,\n EmailAttachmentOptions,\n EmailFolderOptions,\n EmailFolderSearchFilters,\n EmailOptions,\n EmailSearchFilters,\n KnownMessagingChannel,\n // Base options\n MessageOptions,\n // Search filters\n MessageSearchFilters,\n MessageSenderInterface,\n // Send types\n MessageSendResult,\n // Discriminator types\n MessageType,\n MessagingChannel,\n MessagingEndpointOptions,\n PersonaMessageRouteOptions,\n ProviderType,\n SendEmailOptions,\n SendMessageOptions,\n SendPersonaMessageOptions,\n SendSlackOptions,\n SendStatus,\n SendTweetOptions,\n SlackAccountOptions,\n SlackMessageOptions,\n // Sync types\n SyncOptions,\n SyncProgress,\n SyncResult,\n // Provider options\n TweetOptions,\n TwitterAccountOptions,\n} from './types';\n\nensureBuiltinMessagingProvidersRegistered();\nensureMessagingPermissionsRegistered();\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["route"],"sources":["../src/permissions.ts","../src/models/Attachment.ts","../src/collections/AttachmentCollection.ts","../src/models/MessagingEndpoint.ts","../src/collections/MessagingEndpointCollection.ts","../src/models/PersonaMessageRoute.ts","../src/collections/PersonaMessageRouteCollection.ts","../src/models/EmailAccount.ts","../src/collections/EmailAccountCollection.ts","../src/models/EmailAttachment.ts","../src/collections/EmailAttachmentCollection.ts","../src/collections/EmailCollection.ts","../src/collections/EmailFolderCollection.ts","../src/models/Blacklist.ts","../src/collections/BlacklistCollection.ts","../src/models/Whitelist.ts","../src/collections/WhitelistCollection.ts","../src/models/SlackAccount.ts","../src/models/SlackMessage.ts","../src/models/TelegramAccount.ts","../src/models/Tweet.ts","../src/models/TwitterAccount.ts","../src/models/ZulipAccount.ts","../src/senders/EmailSender.ts","../src/services/MessagingSettingsService.ts","../src/services/PersonaMessagingService.ts","../src/index.ts"],"sourcesContent":["import {\n type PermissionDefinition,\n registerPermissionDefinitions,\n} from '@happyvertical/smrt-users';\n\nexport const SEND_MESSAGES_PERMISSION = 'messages.send';\nexport const MANAGE_MESSAGE_ROUTES_PERMISSION = 'messages.manage-routes';\nexport const MANAGE_MESSAGE_CREDENTIALS_PERMISSION =\n 'messages.manage-credentials';\n\nexport const MESSAGING_PERMISSION_DEFINITIONS: PermissionDefinition[] = [\n {\n slug: SEND_MESSAGES_PERMISSION,\n category: 'messages',\n name: 'Send Messages',\n description: 'Allows send on messages',\n },\n {\n slug: MANAGE_MESSAGE_ROUTES_PERMISSION,\n category: 'messages',\n name: 'Manage Message Routes',\n description: 'Manage persona messaging endpoints and route bindings',\n },\n {\n slug: MANAGE_MESSAGE_CREDENTIALS_PERMISSION,\n category: 'messages',\n name: 'Manage Message Credentials',\n description: 'Create accounts and replace write-only provider credentials',\n },\n];\n\nexport interface MessagingPrincipal {\n readonly id?: string;\n readonly tenantId?: string;\n can(slug: string): boolean;\n}\n\nexport function messagingPrincipalFromPermissions(\n permissions: Iterable<string>,\n options: { id?: string; tenantId?: string } = {},\n): MessagingPrincipal {\n const granted = new Set(permissions);\n return {\n ...options,\n can: (slug) => granted.has(slug),\n };\n}\n\nexport function assertMessagingPermission(\n principal: MessagingPrincipal,\n tenantId: string,\n permission: string,\n): void {\n if (principal.tenantId && principal.tenantId !== tenantId) {\n throw new Error('Messaging principal does not belong to this tenant.');\n }\n if (!principal.can(permission)) {\n throw new Error(`Missing required permission '${permission}'.`);\n }\n}\n\nlet registered = false;\n\nexport function ensureMessagingPermissionsRegistered(): void {\n if (registered) return;\n registered = true;\n registerPermissionDefinitions(MESSAGING_PERMISSION_DEFINITIONS);\n}\n","/**\n * Attachment model - Generalized attachment for any message type\n *\n * Uses messageId instead of emailId for cross-type support.\n */\n\nimport {\n foreignKey,\n importOptionalDependency,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { AttachmentOptions } from '../types';\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n api: { include: ['list', 'get', 'create', 'delete'] },\n mcp: { include: ['list', 'get'] },\n cli: { skipApiCheck: true },\n})\nexport class Attachment extends SmrtObject {\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n @foreignKey('Message')\n messageId = '';\n filename = '';\n contentType = '';\n size = 0;\n contentId = ''; // For inline images (<img src=\"cid:...\">)\n contentDisposition: 'attachment' | 'inline' = 'attachment';\n filePath = ''; // External file storage path\n sourceUrl = ''; // For non-email attachments (media URLs, etc.)\n\n // Timestamps\n createdAt = new Date();\n\n constructor(options: AttachmentOptions = {}) {\n super(options);\n\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.messageId !== undefined) this.messageId = options.messageId;\n if (options.filename !== undefined) this.filename = options.filename;\n if (options.contentType !== undefined)\n this.contentType = options.contentType;\n if (options.size !== undefined) this.size = options.size;\n if (options.contentId !== undefined) this.contentId = options.contentId;\n if (options.contentDisposition !== undefined)\n this.contentDisposition = options.contentDisposition;\n if (options.filePath !== undefined) this.filePath = options.filePath;\n if (options.sourceUrl !== undefined) this.sourceUrl = options.sourceUrl;\n if (options.createdAt) this.createdAt = options.createdAt;\n }\n\n /**\n * Get the message this attachment belongs to\n */\n async getMessage() {\n if (!this.messageId) return null;\n\n const { MessageCollection } = await import(\n '../collections/MessageCollection'\n );\n const collection = await MessageCollection.create(this.options);\n\n return await collection.get({ id: this.messageId });\n }\n\n /**\n * Check if attachment is an image\n */\n isImage(): boolean {\n return this.contentType.startsWith('image/');\n }\n\n /**\n * Check if attachment is a PDF\n */\n isPdf(): boolean {\n return this.contentType === 'application/pdf';\n }\n\n /**\n * Check if attachment is inline (embedded in message body)\n */\n isInline(): boolean {\n return this.contentDisposition === 'inline';\n }\n\n /**\n * Get file extension from filename\n */\n getExtension(): string {\n if (!this.filename) return '';\n const parts = this.filename.split('.');\n return parts.length > 1 ? parts[parts.length - 1].toLowerCase() : '';\n }\n\n /**\n * Get human-readable file size\n */\n getFormattedSize(): string {\n const units = ['B', 'KB', 'MB', 'GB'];\n let size = this.size;\n let unitIndex = 0;\n\n while (size >= 1024 && unitIndex < units.length - 1) {\n size /= 1024;\n unitIndex++;\n }\n\n return `${size.toFixed(1)} ${units[unitIndex]}`;\n }\n\n /**\n * Check if file is stored externally\n */\n hasExternalFile(): boolean {\n return !!this.filePath;\n }\n\n /**\n * Read file content (if stored externally)\n *\n * The files SDK is loaded through core's bundler-invisible optional-import\n * boundary so it never enters provider-neutral consumer bundles (#1979).\n * Absence of the SDK at runtime degrades to the existing null contract.\n */\n async readContent(): Promise<Buffer | null> {\n if (!this.filePath) return null;\n\n try {\n const { getFilesystem } = (await importOptionalDependency(\n '@happyvertical/files',\n \"Import '@happyvertical/smrt-core/filesystem' (or '@happyvertical/smrt-assets/filesystem') during server startup to read externally-stored attachments in bundled builds.\",\n )) as typeof import('@happyvertical/files');\n const files = await getFilesystem({ type: 'local' });\n const data = await files.read(this.filePath);\n return data instanceof Buffer ? data : Buffer.from(data);\n } catch {\n return null;\n }\n }\n}\n","/**\n * AttachmentCollection - Generalized attachment collection using messageId\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { queryGlobal, queryWithGlobals } from '@happyvertical/smrt-tenancy';\nimport { Attachment } from '../models/Attachment';\n\nexport class AttachmentCollection extends SmrtCollection<Attachment> {\n static readonly _itemClass = Attachment;\n\n /**\n * Get attachments for a message\n */\n async getByMessage(messageId: string): Promise<Attachment[]> {\n return await this.list({ where: { messageId } });\n }\n\n /**\n * Get attachments by content type\n */\n async getByContentType(contentType: string): Promise<Attachment[]> {\n return await this.list({ where: { contentType } });\n }\n\n /**\n * Get image attachments\n */\n async getImages(messageId?: string): Promise<Attachment[]> {\n const attachments = messageId\n ? await this.getByMessage(messageId)\n : await this.list({});\n\n return attachments.filter((a) => a.isImage());\n }\n\n /**\n * Get PDF attachments\n */\n async getPdfs(messageId?: string): Promise<Attachment[]> {\n const attachments = messageId\n ? await this.getByMessage(messageId)\n : await this.list({});\n\n return attachments.filter((a) => a.isPdf());\n }\n\n /**\n * Get inline attachments (embedded in message body)\n */\n async getInline(messageId: string): Promise<Attachment[]> {\n const attachments = await this.getByMessage(messageId);\n return attachments.filter((a) => a.isInline());\n }\n\n /**\n * Get regular attachments (not inline)\n */\n async getRegular(messageId: string): Promise<Attachment[]> {\n const attachments = await this.getByMessage(messageId);\n return attachments.filter((a) => !a.isInline());\n }\n\n /**\n * Get attachments with external files\n */\n async getWithExternalFiles(): Promise<Attachment[]> {\n const attachments = await this.list({});\n return attachments.filter((a) => a.hasExternalFile());\n }\n\n /**\n * Get total size of attachments for a message\n */\n async getTotalSize(messageId: string): Promise<number> {\n const attachments = await this.getByMessage(messageId);\n return attachments.reduce((sum, a) => sum + a.size, 0);\n }\n\n /**\n * Get largest attachments\n */\n async getLargest(limit = 10): Promise<Attachment[]> {\n const attachments = await this.list({});\n return attachments.sort((a, b) => b.size - a.size).slice(0, limit);\n }\n\n /**\n * Search attachments by filename\n */\n async searchByFilename(query: string): Promise<Attachment[]> {\n const attachments = await this.list({});\n const lowerQuery = query.toLowerCase();\n\n return attachments.filter((a) =>\n a.filename?.toLowerCase().includes(lowerQuery),\n );\n }\n\n /**\n * Get attachments by extension\n */\n async getByExtension(extension: string): Promise<Attachment[]> {\n const attachments = await this.list({});\n const lowerExt = extension.toLowerCase().replace(/^\\./, '');\n\n return attachments.filter((a) => a.getExtension() === lowerExt);\n }\n\n /**\n * Get attachment statistics\n */\n async getStats(): Promise<{\n total: number;\n totalSize: number;\n byType: Record<string, number>;\n inline: number;\n regular: number;\n }> {\n const attachments = await this.list({});\n\n const byType: Record<string, number> = {};\n for (const attachment of attachments) {\n const type = attachment.contentType.split('/')[0] || 'other';\n byType[type] = (byType[type] || 0) + 1;\n }\n\n return {\n total: attachments.length,\n totalSize: attachments.reduce((sum, a) => sum + a.size, 0),\n byType,\n inline: attachments.filter((a) => a.isInline()).length,\n regular: attachments.filter((a) => !a.isInline()).length,\n };\n }\n\n /**\n * Delete all attachments for a message\n */\n async deleteByMessage(messageId: string): Promise<number> {\n const attachments = await this.getByMessage(messageId);\n let count = 0;\n\n for (const attachment of attachments) {\n await attachment.delete();\n count++;\n }\n\n return count;\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Tenant Helper Methods\n // ─────────────────────────────────────────────────────────────────────────\n\n async findByTenant(tenantId: string): Promise<Attachment[]> {\n return this.list({ where: { tenantId } });\n }\n\n // Attachment is @TenantScoped (CTI, own `attachments` table). Under an active\n // tenant context list({ tenantId: null }) throws and unflagged raw SQL is\n // blocked (#1596); route through the raw helpers.\n async findGlobal(): Promise<Attachment[]> {\n return queryGlobal<Attachment>(this);\n }\n\n async findWithGlobals(tenantId: string): Promise<Attachment[]> {\n return queryWithGlobals<Attachment>(\n this,\n tenantId,\n 'Attachment.findWithGlobals',\n );\n }\n}\n","import type { SmrtObjectOptions } from '@happyvertical/smrt-core';\nimport {\n crossPackageRef,\n field,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { MessagingChannel, MessagingEndpointOptions } from '../types.js';\n\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'messaging_endpoints',\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n conflictColumns: ['tenant_id', 'channel', 'label'],\n})\nexport class MessagingEndpoint extends SmrtObject {\n @tenantId()\n tenantId = '';\n\n @crossPackageRef('@happyvertical/smrt-profiles:Profile', { nullable: true })\n profileId: string | null = null;\n\n @field({ required: true })\n label = '';\n\n @field({ required: true })\n channel: MessagingChannel = 'email';\n\n /** Provider-specific destination JSON. Hidden from generated read surfaces. */\n @field({ required: true, sensitive: true })\n address = '{}';\n\n isActive = true;\n verifiedAt: Date | null = null;\n createdAt = new Date();\n updatedAt = new Date();\n\n constructor(options: MessagingEndpointOptions = {}) {\n super(options as SmrtObjectOptions);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.profileId !== undefined) this.profileId = options.profileId;\n if (options.label !== undefined) this.label = options.label;\n if (options.channel !== undefined) this.channel = options.channel;\n if (options.address !== undefined) this.address = options.address;\n if (options.isActive !== undefined) this.isActive = options.isActive;\n if (options.verifiedAt !== undefined) this.verifiedAt = options.verifiedAt;\n if (options.createdAt !== undefined) this.createdAt = options.createdAt;\n if (options.updatedAt !== undefined) this.updatedAt = options.updatedAt;\n }\n\n getAddress<T extends Record<string, unknown> = Record<string, unknown>>(): T {\n try {\n return JSON.parse(this.address) as T;\n } catch {\n return {} as T;\n }\n }\n\n setAddress(address: Record<string, unknown>): void {\n this.address = JSON.stringify(address);\n }\n\n getMaskedAddress(): string {\n const address = this.getAddress();\n const visible =\n address.email ??\n address.chatId ??\n address.to ??\n address.stream ??\n address.phoneNumber;\n if (typeof visible !== 'string' && typeof visible !== 'number')\n return '••••';\n const value = String(visible);\n if (value.includes('@')) {\n const [name, domain] = value.split('@');\n return `${name.slice(0, 2)}•••@${domain}`;\n }\n return value.length <= 4 ? '••••' : `••••${value.slice(-4)}`;\n }\n}\n","import { SmrtCollection } from '@happyvertical/smrt-core';\nimport { MessagingEndpoint } from '../models/MessagingEndpoint.js';\n\nexport class MessagingEndpointCollection extends SmrtCollection<MessagingEndpoint> {\n static readonly _itemClass = MessagingEndpoint;\n}\n","import {\n crossPackageRef,\n field,\n foreignKey,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { PersonaMessageRouteOptions } from '../types.js';\n\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'persona_message_routes',\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n conflictColumns: [\n 'tenant_id',\n 'persona_id',\n 'account_id',\n 'endpoint_id',\n 'purpose',\n ],\n})\nexport class PersonaMessageRoute extends SmrtObject {\n @tenantId()\n tenantId = '';\n\n @crossPackageRef('@happyvertical/smrt-personas:AgentPersona', {\n required: true,\n })\n personaId = '';\n\n @foreignKey('Account', { required: true })\n accountId = '';\n\n @foreignKey('MessagingEndpoint', { required: true })\n endpointId = '';\n\n @field({ required: true })\n purpose = 'default';\n\n priority = 0;\n enabled = true;\n createdAt = new Date();\n updatedAt = new Date();\n\n constructor(options: PersonaMessageRouteOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.personaId !== undefined) this.personaId = options.personaId;\n if (options.accountId !== undefined) this.accountId = options.accountId;\n if (options.endpointId !== undefined) this.endpointId = options.endpointId;\n if (options.purpose !== undefined) this.purpose = options.purpose;\n if (options.priority !== undefined) this.priority = options.priority;\n if (options.enabled !== undefined) this.enabled = options.enabled;\n if (options.createdAt !== undefined) this.createdAt = options.createdAt;\n if (options.updatedAt !== undefined) this.updatedAt = options.updatedAt;\n }\n}\n","import { SmrtCollection } from '@happyvertical/smrt-core';\nimport { PersonaMessageRoute } from '../models/PersonaMessageRoute.js';\n\nexport class PersonaMessageRouteCollection extends SmrtCollection<PersonaMessageRoute> {\n static readonly _itemClass = PersonaMessageRoute;\n\n async forPersona(personaId: string): Promise<PersonaMessageRoute[]> {\n return this.list({ where: { personaId, enabled: true } });\n }\n}\n","/**\n * EmailAccount model - Email account extending the Account STI base\n *\n * Retains email-specific fields and sync capability.\n */\n\nimport type { FetchOptions, GetEmailClientOptions } from '@happyvertical/email';\nimport { smrt } from '@happyvertical/smrt-core';\nimport type {\n EmailAccountOptions,\n MessageSenderInterface,\n ProviderType,\n SyncOptions,\n SyncResult,\n} from '../types';\nimport { Account } from './Account';\n\n@smrt({\n tableStrategy: 'sti',\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n})\nexport class EmailAccount extends Account {\n email = '';\n syncIntervalMinutes = 60;\n\n constructor(options: EmailAccountOptions = {}) {\n super(options);\n\n if (options.email !== undefined) this.email = options.email;\n if (options.providerType !== undefined)\n this.providerType = options.providerType;\n if (options.syncIntervalMinutes !== undefined)\n this.syncIntervalMinutes = options.syncIntervalMinutes;\n this.channelType = 'email';\n }\n\n /**\n * Options for child rows (folders/emails) created during sync: carries the DB\n * connection + tenant context from this account, but strips this account's own\n * identity fields. When this account was hydrated from the DB, `this.options`\n * holds the account row's `id`/`slug`/`_skipLoad`; spreading those into a new\n * child would make every synced row inherit the account's primary key and\n * upsert over each other.\n */\n private childOptions(): Record<string, unknown> {\n const rest = { ...(this.options as Record<string, unknown>) };\n delete rest.id;\n delete rest.slug;\n delete rest._skipLoad;\n return rest;\n }\n\n /**\n * Create a sender for this email account\n */\n override async createSender(): Promise<MessageSenderInterface> {\n const client = await this.createClient();\n await client.connect();\n const { EmailSender } = await import('../senders/EmailSender');\n return new EmailSender(client, this);\n }\n\n /**\n * Create an EmailClient from stored settings\n * Retrieves credentials from smrt-secrets if credentialSecretId is set\n *\n * The client factory comes from the messaging provider registry rather than\n * a direct `@happyvertical/email` import so the email SDK\n * (googleapis/nodemailer) never becomes reachable from provider-neutral\n * consumer bundles (#1979). Server code that uses email accounts must\n * import '@happyvertical/smrt-messages/providers/email' (or\n * '/providers/all') once during startup.\n */\n async createClient() {\n const { getMessagingProvider } = await import('../providers.js');\n const createEmailClient = getMessagingProvider(\n this.providerType,\n )?.createEmailClient;\n if (!createEmailClient) {\n throw new Error(\n `Email provider '${this.providerType}' has no client implementation registered. ` +\n \"Import '@happyvertical/smrt-messages/providers/email' (or '/providers/all') \" +\n 'during server startup to enable outbound email and mailbox sync.',\n );\n }\n const settings: Record<string, unknown> = {\n ...this.getConfiguration(),\n ...((await this.getCredentials()) ?? {}),\n };\n delete settings.email;\n\n return await createEmailClient({\n type: this.providerType as ProviderType,\n ...settings,\n } as GetEmailClientOptions);\n }\n\n /**\n * Sync emails from the email server to the database\n */\n async syncFrom(options: SyncOptions = {}): Promise<SyncResult> {\n const startTime = Date.now();\n const result: SyncResult = {\n folders: [],\n messagesProcessed: 0,\n messagesDownloaded: 0,\n messagesSkipped: 0,\n errors: [],\n duration: 0,\n };\n\n try {\n // Create email client\n const client = await this.createClient();\n await client.connect();\n\n // Get folders to sync\n const foldersToSync = options.folders || ['INBOX'];\n result.folders = foldersToSync;\n\n // Import collections\n const { EmailCollection } = await import(\n '../collections/EmailCollection'\n );\n const { EmailFolderCollection } = await import(\n '../collections/EmailFolderCollection'\n );\n\n const emailCollection = await EmailCollection.create(this.options);\n const folderCollection = await EmailFolderCollection.create(this.options);\n\n if (!this.id) {\n throw new Error(\n 'EmailAccount.syncFrom requires a persisted account (missing id)',\n );\n }\n const accountId = this.id;\n for (const folderName of foldersToSync) {\n try {\n // Ensure folder exists in database\n let folder = await folderCollection.getByPath(accountId, folderName);\n\n if (!folder) {\n // Create folder record\n const { EmailFolder } = await import('./EmailFolder');\n folder = new EmailFolder({\n ...this.childOptions(),\n accountId,\n name: folderName,\n path: folderName,\n });\n // initialize() binds the DB connection; without it save() throws\n // \"Database accessed before initialization\" and sync persists nothing.\n await folder.initialize();\n await folder.save();\n }\n\n // Fetch messages from server\n const fetchOptions: FetchOptions = {\n folder: folderName,\n limit: options.batchSize || 100,\n };\n\n if (options.since) {\n fetchOptions.since = options.since;\n }\n if (options.before) {\n fetchOptions.before = options.before;\n }\n\n const messages = await client.fetch(fetchOptions);\n\n for (const msg of messages) {\n result.messagesProcessed++;\n\n try {\n // Check if message already exists\n const existingEmail = await emailCollection.getByMessageId(\n accountId,\n msg.messageId || '',\n );\n\n if (existingEmail && !options.fullSync) {\n result.messagesSkipped++;\n continue;\n }\n\n // Create or update email record\n const { Email } = await import('./Email');\n let email = existingEmail;\n if (!email) {\n email = new Email({\n ...this.childOptions(),\n accountId,\n });\n // Bind the DB connection before save() (existingEmail is already\n // initialized via the query that loaded it).\n await email.initialize();\n }\n\n // Update fields\n email.messageId = msg.messageId || '';\n email.threadId = msg.threadId || '';\n email.inReplyTo = msg.inReplyTo || '';\n email.fromAddress = msg.from?.address || '';\n email.fromName = msg.from?.name || '';\n email.toAddresses = JSON.stringify(msg.to || []);\n email.ccAddresses = JSON.stringify(msg.cc || []);\n email.bccAddresses = JSON.stringify(msg.bcc || []);\n email.replyToAddress = msg.replyTo?.address || '';\n email.replyToName = msg.replyTo?.name || '';\n email.subject = msg.subject || '';\n email.date = msg.date || null;\n email.textBody = msg.text || '';\n email.htmlBody = msg.html || '';\n email.body = msg.text || '';\n email.folderId = folder.id ?? '';\n email.folderPath = folderName;\n email.labels = JSON.stringify(msg.labels || []);\n email.flags = JSON.stringify(msg.flags || []);\n email.hasAttachments =\n (msg.attachments && msg.attachments.length > 0) || false;\n email.size = msg.size || 0;\n email.headers = JSON.stringify(msg.headers || {});\n email.updatedAt = new Date();\n\n await email.save();\n result.messagesDownloaded++;\n\n // Report progress\n if (options.onProgress) {\n options.onProgress({\n folder: folderName,\n processed: result.messagesProcessed,\n total: messages.length,\n downloaded: result.messagesDownloaded,\n skipped: result.messagesSkipped,\n errors: result.errors.length,\n });\n }\n } catch (error) {\n const err =\n error instanceof Error ? error : new Error(String(error));\n result.errors.push(err);\n if (options.onError) {\n options.onError(err, msg);\n }\n }\n }\n\n // Update folder counts\n const folderId = folder.id ?? '';\n folder.messageCount = await emailCollection.countByFolder(folderId);\n folder.unreadCount =\n await emailCollection.countUnreadByFolder(folderId);\n await folder.save();\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n result.errors.push(err);\n if (options.onError) {\n options.onError(err);\n }\n }\n }\n\n // Update last sync time\n this.lastSyncAt = new Date();\n this.updatedAt = new Date();\n await this.save();\n\n await client.disconnect();\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n result.errors.push(err);\n if (options.onError) {\n options.onError(err);\n }\n }\n\n result.duration = Date.now() - startTime;\n return result;\n }\n\n /**\n * Get all folders for this account\n */\n async getFolders() {\n const { EmailFolderCollection } = await import(\n '../collections/EmailFolderCollection'\n );\n const collection = await EmailFolderCollection.create(this.options);\n\n return await collection.list({ where: { accountId: this.id } });\n }\n\n /**\n * Get all emails for this account\n */\n async getEmails(limit?: number) {\n const { EmailCollection } = await import('../collections/EmailCollection');\n const collection = await EmailCollection.create(this.options);\n\n const options: { where: Record<string, unknown>; limit?: number } = {\n where: { accountId: this.id },\n };\n if (limit) {\n options.limit = limit;\n }\n\n return await collection.list(options);\n }\n\n /**\n * Get unread email count\n */\n async getUnreadCount(): Promise<number> {\n const { EmailCollection } = await import('../collections/EmailCollection');\n const collection = await EmailCollection.create(this.options);\n\n return await collection.countUnreadByAccount(this.id ?? '');\n }\n\n /**\n * Store credentials securely using smrt-secrets (email-specific)\n */\n override async setCredentials(\n credentials: Record<string, unknown>,\n options: {\n description?: string;\n category?: string;\n } = {},\n ): Promise<void> {\n await super.setCredentials(credentials, {\n description: options.description || `Email credentials for ${this.name}`,\n category: options.category || 'email',\n });\n }\n\n /**\n * Sync all active email accounts (for job runner)\n *\n * NOTE: This is a class-wide operation, not per-instance. It syncs ALL active\n * accounts, ignoring `this` instance. It exists as an instance method because\n * the TaskRunner dispatches via `objectType: 'EmailAccount', method: 'syncAll'`\n * which requires an instance method signature.\n */\n async syncAll(\n args?: Record<string, unknown>,\n ): Promise<Map<string, { success: boolean; error?: Error }>> {\n const { EmailAccountCollection } = await import(\n '../collections/EmailAccountCollection'\n );\n const collection = await EmailAccountCollection.create({\n db: this.db,\n });\n return collection.syncAll(args as SyncOptions | undefined);\n }\n\n /**\n * Migrate from plain-text settings to secrets\n */\n async migrateToSecrets(): Promise<void> {\n if (this.credentialSecretId) {\n return;\n }\n\n const settings = this.getSettings();\n if (Object.keys(settings).length === 0) {\n return;\n }\n\n await this.setCredentials(settings, {\n description: `Migrated IMAP credentials for ${this.name}`,\n });\n }\n}\n","/**\n * EmailAccountCollection - Collection manager for EmailAccount objects\n *\n * Extends AccountCollection with email-specific query methods.\n */\n\nimport { queryGlobal, queryWithGlobals } from '@happyvertical/smrt-tenancy';\nimport { EmailAccount } from '../models/EmailAccount';\nimport type {\n EmailAccountSearchFilters,\n ProviderType,\n SyncOptions,\n} from '../types';\nimport { AccountCollection } from './AccountCollection';\n\nexport class EmailAccountCollection extends AccountCollection {\n static override readonly _itemClass = EmailAccount;\n\n /**\n * Get account by email address\n */\n async getByEmail(email: string): Promise<EmailAccount | null> {\n const accounts = await this.list({ where: { email } });\n return (accounts[0] as EmailAccount) || null;\n }\n\n /**\n * Get accounts by email provider type\n */\n async getByEmailProviderType(\n providerType: ProviderType,\n ): Promise<EmailAccount[]> {\n return (await this.list({ where: { providerType } })) as EmailAccount[];\n }\n\n /**\n * Get active email accounts\n */\n override async getActive(): Promise<EmailAccount[]> {\n return (await this.list({ where: { isActive: true } })) as EmailAccount[];\n }\n\n /**\n * Get inactive email accounts\n */\n override async getInactive(): Promise<EmailAccount[]> {\n return (await this.list({ where: { isActive: false } })) as EmailAccount[];\n }\n\n /**\n * Get accounts that need syncing\n */\n async getNeedingSync(maxAgeMinutes = 60): Promise<EmailAccount[]> {\n const allAccounts = await this.getActive();\n const cutoffTime = new Date(Date.now() - maxAgeMinutes * 60 * 1000);\n\n return allAccounts.filter(\n (account) => !account.lastSyncAt || account.lastSyncAt < cutoffTime,\n ) as EmailAccount[];\n }\n\n /**\n * Search email accounts with filters.\n * Alias: `search()` for backward compatibility.\n */\n override async search(\n query: string,\n filters?: EmailAccountSearchFilters,\n ): Promise<EmailAccount[]> {\n return this.searchEmailAccounts(query, filters);\n }\n\n /**\n * Get accounts by email provider type.\n * Alias: `getByProviderType()` for backward compatibility.\n */\n override async getByProviderType(\n providerType: string,\n ): Promise<EmailAccount[]> {\n return this.getByEmailProviderType(providerType as ProviderType);\n }\n\n /**\n * Get email account statistics.\n * Alias: `getStats()` for backward compatibility.\n */\n override async getStats(): Promise<{\n total: number;\n active: number;\n inactive: number;\n byType: Record<string, number>;\n }> {\n const stats = await this.getEmailStats();\n return {\n total: stats.total,\n active: stats.active,\n inactive: stats.inactive,\n byType: stats.byProvider as unknown as Record<string, number>,\n };\n }\n\n /**\n * Search email accounts with filters\n */\n async searchEmailAccounts(\n query: string,\n filters?: EmailAccountSearchFilters,\n ): Promise<EmailAccount[]> {\n let accounts = (await this.list({})) as EmailAccount[];\n\n // Filter by query\n if (query) {\n const lowerQuery = query.toLowerCase();\n accounts = accounts.filter(\n (a) =>\n a.name?.toLowerCase().includes(lowerQuery) ||\n a.email?.toLowerCase().includes(lowerQuery),\n );\n }\n\n // Apply filters\n if (filters) {\n if (filters.providerType) {\n accounts = accounts.filter(\n (a) => a.providerType === filters.providerType,\n );\n }\n if (filters.email) {\n const emailLower = filters.email.toLowerCase();\n accounts = accounts.filter((a) =>\n a.email?.toLowerCase().includes(emailLower),\n );\n }\n if (filters.isActive !== undefined) {\n accounts = accounts.filter((a) => a.isActive === filters.isActive);\n }\n }\n\n return accounts;\n }\n\n /**\n * Sync all active email accounts\n */\n async syncAll(\n options?: SyncOptions,\n ): Promise<Map<string, { success: boolean; error?: Error }>> {\n const results = new Map<string, { success: boolean; error?: Error }>();\n const accounts = await this.getActive();\n\n for (const account of accounts) {\n const ea = account as EmailAccount;\n const accountId = ea.id ?? ea.email ?? 'unknown';\n try {\n await ea.syncFrom(options);\n results.set(accountId, { success: true });\n } catch (error) {\n results.set(accountId, {\n success: false,\n error: error instanceof Error ? error : new Error(String(error)),\n });\n }\n }\n\n return results;\n }\n\n /**\n * Get total unread count across all email accounts\n */\n async getTotalUnreadCount(): Promise<number> {\n const accounts = await this.getActive();\n let total = 0;\n\n for (const account of accounts) {\n total += await (account as EmailAccount).getUnreadCount();\n }\n\n return total;\n }\n\n /**\n * Get email account statistics\n */\n async getEmailStats(): Promise<{\n total: number;\n active: number;\n inactive: number;\n byProvider: Record<ProviderType, number>;\n }> {\n const accounts = (await this.list({})) as EmailAccount[];\n\n const byProvider: Record<ProviderType, number> = {\n smtp: 0,\n imap: 0,\n pop3: 0,\n gmail: 0,\n };\n\n for (const account of accounts) {\n const pt = account.providerType as ProviderType;\n if (pt in byProvider) {\n byProvider[pt]++;\n }\n }\n\n return {\n total: accounts.length,\n active: accounts.filter((a) => a.isActive).length,\n inactive: accounts.filter((a) => !a.isActive).length,\n byProvider,\n };\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Tenant Helper Methods\n // ─────────────────────────────────────────────────────────────────────────\n\n override async findByTenant(tenantId: string): Promise<EmailAccount[]> {\n return this.list({ where: { tenantId } }) as Promise<EmailAccount[]>;\n }\n\n // EmailAccount inherits Account's @TenantScoped recognition (#1596); see\n // EmailCollection for why these route through the raw helpers. They auto-scope\n // to the EmailAccount `_meta_type` (via getStiChildMetaType) so the shared\n // `accounts` table never returns sibling Account subtypes. (#1600)\n override async findGlobal(): Promise<EmailAccount[]> {\n return queryGlobal<EmailAccount>(this);\n }\n\n override async findWithGlobals(tenantId: string): Promise<EmailAccount[]> {\n return queryWithGlobals<EmailAccount>(\n this,\n tenantId,\n 'EmailAccount.findWithGlobals',\n );\n }\n}\n","/**\n * EmailAttachment - Backward-compatible alias for Attachment\n *\n * @deprecated Use Attachment instead. EmailAttachment is preserved for backward compatibility.\n */\n\nimport type { EmailAttachmentOptions } from '../types';\nimport { Attachment } from './Attachment';\n\n/**\n * @deprecated Use Attachment instead\n */\nexport class EmailAttachment extends Attachment {\n /**\n * Legacy emailId field — maps to messageId\n */\n get emailId(): string {\n return this.messageId;\n }\n\n set emailId(value: string) {\n this.messageId = value;\n }\n\n constructor(options: EmailAttachmentOptions = {}) {\n // Map emailId to messageId for backward compat\n const mappedOptions = {\n ...options,\n messageId: options.emailId || options.messageId || '',\n };\n super(mappedOptions);\n }\n\n /**\n * Get the email this attachment belongs to\n * @deprecated Use getMessage() instead\n */\n async getEmail() {\n if (!this.messageId) return null;\n\n const { EmailCollection } = await import('../collections/EmailCollection');\n const collection = await EmailCollection.create(this.options);\n\n return await collection.get({ id: this.messageId });\n }\n}\n","/**\n * EmailAttachmentCollection - Backward-compatible collection for EmailAttachment\n *\n * @deprecated Use AttachmentCollection instead\n */\n\nimport { queryGlobal, queryWithGlobals } from '@happyvertical/smrt-tenancy';\nimport { EmailAttachment } from '../models/EmailAttachment';\nimport { AttachmentCollection } from './AttachmentCollection';\n\n/**\n * @deprecated Use AttachmentCollection instead\n */\nexport class EmailAttachmentCollection extends AttachmentCollection {\n static override readonly _itemClass = EmailAttachment;\n\n /**\n * Get attachments for an email\n * @deprecated Use getByMessage() instead\n */\n async getByEmail(emailId: string): Promise<EmailAttachment[]> {\n return (await this.getByMessage(emailId)) as EmailAttachment[];\n }\n\n /**\n * Get image attachments\n */\n override async getImages(emailId?: string): Promise<EmailAttachment[]> {\n return (await super.getImages(emailId)) as EmailAttachment[];\n }\n\n /**\n * Get PDF attachments\n */\n override async getPdfs(emailId?: string): Promise<EmailAttachment[]> {\n return (await super.getPdfs(emailId)) as EmailAttachment[];\n }\n\n /**\n * Get inline attachments\n */\n override async getInline(emailId: string): Promise<EmailAttachment[]> {\n return (await super.getInline(emailId)) as EmailAttachment[];\n }\n\n /**\n * Get regular attachments\n */\n override async getRegular(emailId: string): Promise<EmailAttachment[]> {\n return (await super.getRegular(emailId)) as EmailAttachment[];\n }\n\n /**\n * Delete all attachments for an email\n * @deprecated Use deleteByMessage() instead\n */\n async deleteByEmail(emailId: string): Promise<number> {\n return await this.deleteByMessage(emailId);\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Tenant Helper Methods\n // ─────────────────────────────────────────────────────────────────────────\n\n override async findByTenant(tenantId: string): Promise<EmailAttachment[]> {\n return this.list({ where: { tenantId } }) as Promise<EmailAttachment[]>;\n }\n\n // EmailAttachment is a CTI subclass of the @TenantScoped Attachment (own\n // `email_attachments` table, no `_meta_type`) and inherits its recognition\n // (#1596); route global / cross-global lookups through the raw helpers.\n override async findGlobal(): Promise<EmailAttachment[]> {\n return queryGlobal<EmailAttachment>(this);\n }\n\n override async findWithGlobals(tenantId: string): Promise<EmailAttachment[]> {\n return queryWithGlobals<EmailAttachment>(\n this,\n tenantId,\n 'EmailAttachment.findWithGlobals',\n );\n }\n}\n","/**\n * EmailCollection - Collection manager for Email objects\n *\n * Extends MessageCollection with email-specific query methods.\n * STI framework auto-filters to Email instances.\n */\n\nimport { queryGlobal, queryWithGlobals } from '@happyvertical/smrt-tenancy';\nimport { Email } from '../models/Email';\nimport type { EmailSearchFilters } from '../types';\nimport { MessageCollection } from './MessageCollection';\n\nexport class EmailCollection extends MessageCollection {\n static override readonly _itemClass = Email;\n\n /**\n * Get email by RFC 822 Message-ID\n */\n async getByMessageId(\n accountId: string,\n messageId: string,\n ): Promise<Email | null> {\n const emails = await this.list({\n where: { accountId, messageId },\n limit: 1,\n });\n return (emails[0] as Email) || null;\n }\n\n /**\n * Get emails by account\n */\n async getByAccount(accountId: string): Promise<Email[]> {\n return (await this.list({ where: { accountId } })) as Email[];\n }\n\n /**\n * Get emails by folder\n */\n async getByFolder(folderId: string): Promise<Email[]> {\n return (await this.list({ where: { folderId } })) as Email[];\n }\n\n /**\n * Get emails by thread\n */\n override async getByThread(threadId: string): Promise<Email[]> {\n return (await this.list({ where: { threadId } })) as Email[];\n }\n\n /**\n * Get unread emails\n */\n override async getUnread(accountId?: string): Promise<Email[]> {\n const where: Record<string, unknown> = { isRead: false };\n if (accountId) {\n where.accountId = accountId;\n }\n return (await this.list({ where })) as Email[];\n }\n\n /**\n * Get flagged emails\n */\n override async getFlagged(accountId?: string): Promise<Email[]> {\n const where: Record<string, unknown> = { isFlagged: true };\n if (accountId) {\n where.accountId = accountId;\n }\n return (await this.list({ where })) as Email[];\n }\n\n /**\n * Get emails with attachments\n */\n async getWithAttachments(accountId?: string): Promise<Email[]> {\n const where: Record<string, unknown> = { hasAttachments: true };\n if (accountId) {\n where.accountId = accountId;\n }\n return (await this.list({ where })) as Email[];\n }\n\n /**\n * Get recent emails\n */\n override async getRecent(limit = 20, accountId?: string): Promise<Email[]> {\n const allEmails = (await this.list({\n where: accountId ? { accountId } : undefined,\n })) as Email[];\n\n return allEmails\n .sort((a, b) => {\n const dateA = a.date?.getTime() || 0;\n const dateB = b.date?.getTime() || 0;\n return dateB - dateA;\n })\n .slice(0, limit);\n }\n\n /**\n * Count emails in a folder\n */\n async countByFolder(folderId: string): Promise<number> {\n const emails = await this.list({ where: { folderId } });\n return emails.length;\n }\n\n /**\n * Count unread emails in a folder\n */\n async countUnreadByFolder(folderId: string): Promise<number> {\n const emails = await this.list({ where: { folderId, isRead: false } });\n return emails.length;\n }\n\n /**\n * Count unread emails for an account\n */\n async countUnreadByAccount(accountId: string): Promise<number> {\n const emails = await this.list({ where: { accountId, isRead: false } });\n return emails.length;\n }\n\n /**\n * Search emails with email-specific filters.\n * Alias: `search()` for backward compatibility.\n */\n override async search(\n query: string,\n filters?: EmailSearchFilters,\n ): Promise<Email[]> {\n return this.searchEmails(query, filters);\n }\n\n /**\n * Search emails with email-specific filters\n */\n async searchEmails(\n query: string,\n filters?: EmailSearchFilters,\n ): Promise<Email[]> {\n let emails = (await this.list({})) as Email[];\n\n // Filter by query\n if (query) {\n const lowerQuery = query.toLowerCase();\n emails = emails.filter(\n (e) =>\n e.subject?.toLowerCase().includes(lowerQuery) ||\n e.textBody?.toLowerCase().includes(lowerQuery) ||\n e.fromAddress?.toLowerCase().includes(lowerQuery) ||\n e.fromName?.toLowerCase().includes(lowerQuery),\n );\n }\n\n // Apply filters\n if (filters) {\n if (filters.accountId) {\n emails = emails.filter((e) => e.accountId === filters.accountId);\n }\n if (filters.folderId) {\n emails = emails.filter((e) => e.folderId === filters.folderId);\n }\n if (filters.threadId) {\n emails = emails.filter((e) => e.threadId === filters.threadId);\n }\n if (filters.from) {\n const fromLower = filters.from.toLowerCase();\n emails = emails.filter(\n (e) =>\n e.fromAddress?.toLowerCase().includes(fromLower) ||\n e.fromName?.toLowerCase().includes(fromLower),\n );\n }\n if (filters.to) {\n const toLower = filters.to.toLowerCase();\n emails = emails.filter((e) =>\n e.toAddresses?.toLowerCase().includes(toLower),\n );\n }\n if (filters.subject) {\n const subjectLower = filters.subject.toLowerCase();\n emails = emails.filter((e) =>\n e.subject?.toLowerCase().includes(subjectLower),\n );\n }\n if (filters.isRead !== undefined) {\n emails = emails.filter((e) => e.isRead === filters.isRead);\n }\n if (filters.isFlagged !== undefined) {\n emails = emails.filter((e) => e.isFlagged === filters.isFlagged);\n }\n if (filters.hasAttachments !== undefined) {\n emails = emails.filter(\n (e) => e.hasAttachments === filters.hasAttachments,\n );\n }\n if (filters.sincDate) {\n emails = emails.filter(\n (e) => e.date && e.date >= (filters.sincDate as Date),\n );\n }\n if (filters.beforeDate) {\n emails = emails.filter(\n (e) => e.date && e.date < (filters.beforeDate as Date),\n );\n }\n }\n\n return emails;\n }\n\n /**\n * Mark all emails in a folder as read\n */\n async markFolderRead(folderId: string): Promise<void> {\n const emails = (await this.getUnread()) as Email[];\n const folderEmails = emails.filter((e) => e.folderId === folderId);\n\n for (const email of folderEmails) {\n await email.markRead();\n }\n }\n\n /**\n * Delete emails by folder\n */\n async deleteByFolder(folderId: string): Promise<number> {\n const emails = await this.getByFolder(folderId);\n let count = 0;\n\n for (const email of emails) {\n await email.delete();\n count++;\n }\n\n return count;\n }\n\n /**\n * Get email statistics for an account\n */\n override async getAccountStats(accountId: string): Promise<{\n total: number;\n unread: number;\n flagged: number;\n withAttachments: number;\n byType: Record<string, number>;\n }> {\n const emails = await this.getByAccount(accountId);\n\n return {\n total: emails.length,\n unread: emails.filter((e) => !e.isRead).length,\n flagged: emails.filter((e) => e.isFlagged).length,\n withAttachments: emails.filter((e) => e.hasAttachments).length,\n byType: { Email: emails.length },\n };\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Tenant Helper Methods\n // ─────────────────────────────────────────────────────────────────────────\n\n override async findByTenant(tenantId: string): Promise<Email[]> {\n return this.list({ where: { tenantId } }) as Promise<Email[]>;\n }\n\n // Now that Email inherits Message's @TenantScoped recognition (#1596), an\n // explicit `tenant_id IS NULL` filter via list() throws and unflagged raw SQL\n // is blocked under an active tenant context — so route global / cross-global\n // lookups through the shared raw helpers. They auto-scope to the Email\n // `_meta_type` (via getStiChildMetaType) so the shared `messages` table never\n // returns sibling Message subtypes. (#1600)\n override async findGlobal(): Promise<Email[]> {\n return queryGlobal<Email>(this);\n }\n\n override async findWithGlobals(tenantId: string): Promise<Email[]> {\n return queryWithGlobals<Email>(this, tenantId, 'Email.findWithGlobals');\n }\n}\n","/**\n * EmailFolderCollection - Collection manager for EmailFolder objects\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { queryGlobal, queryWithGlobals } from '@happyvertical/smrt-tenancy';\nimport { EmailFolder } from '../models/EmailFolder';\nimport type { EmailFolderSearchFilters } from '../types';\n\nexport class EmailFolderCollection extends SmrtCollection<EmailFolder> {\n static readonly _itemClass = EmailFolder;\n\n /**\n * Get folder by path for an account\n */\n async getByPath(\n accountId: string,\n path: string,\n ): Promise<EmailFolder | null> {\n const folders = await this.list({ where: { accountId, path } });\n return folders[0] || null;\n }\n\n /**\n * Get folders by account\n */\n async getByAccount(accountId: string): Promise<EmailFolder[]> {\n return await this.list({ where: { accountId } });\n }\n\n /**\n * Get inbox folder for an account\n */\n async getInbox(accountId: string): Promise<EmailFolder | null> {\n const folders = await this.getByAccount(accountId);\n return folders.find((f) => f.isInbox()) || null;\n }\n\n /**\n * Get sent folder for an account\n */\n async getSent(accountId: string): Promise<EmailFolder | null> {\n const folders = await this.getByAccount(accountId);\n return folders.find((f) => f.isSent()) || null;\n }\n\n /**\n * Get drafts folder for an account\n */\n async getDrafts(accountId: string): Promise<EmailFolder | null> {\n const folders = await this.getByAccount(accountId);\n return folders.find((f) => f.isDrafts()) || null;\n }\n\n /**\n * Get trash folder for an account\n */\n async getTrash(accountId: string): Promise<EmailFolder | null> {\n const folders = await this.getByAccount(accountId);\n return folders.find((f) => f.isTrash()) || null;\n }\n\n /**\n * Get spam folder for an account\n */\n async getSpam(accountId: string): Promise<EmailFolder | null> {\n const folders = await this.getByAccount(accountId);\n return folders.find((f) => f.isSpam()) || null;\n }\n\n /**\n * Get system folders for an account\n */\n async getSystemFolders(accountId: string): Promise<EmailFolder[]> {\n const folders = await this.getByAccount(accountId);\n return folders.filter((f) => f.isSystemFolder());\n }\n\n /**\n * Get user-created folders for an account\n */\n async getUserFolders(accountId: string): Promise<EmailFolder[]> {\n const folders = await this.getByAccount(accountId);\n return folders.filter((f) => !f.isSystemFolder());\n }\n\n /**\n * Get subscribed folders\n */\n async getSubscribed(accountId?: string): Promise<EmailFolder[]> {\n const where: Record<string, unknown> = { subscribed: true };\n if (accountId) {\n where.accountId = accountId;\n }\n return await this.list({ where });\n }\n\n /**\n * Get folders with unread messages\n */\n async getWithUnread(accountId?: string): Promise<EmailFolder[]> {\n const folders = accountId\n ? await this.getByAccount(accountId)\n : await this.list({});\n\n return folders.filter((f) => f.unreadCount > 0);\n }\n\n /**\n * Search folders with filters\n */\n async search(\n query: string,\n filters?: EmailFolderSearchFilters,\n ): Promise<EmailFolder[]> {\n let folders = await this.list({});\n\n // Filter by query\n if (query) {\n const lowerQuery = query.toLowerCase();\n folders = folders.filter(\n (f) =>\n f.name?.toLowerCase().includes(lowerQuery) ||\n f.path?.toLowerCase().includes(lowerQuery),\n );\n }\n\n // Apply filters\n if (filters) {\n if (filters.accountId) {\n folders = folders.filter((f) => f.accountId === filters.accountId);\n }\n if (filters.specialUse) {\n folders = folders.filter((f) => f.specialUse === filters.specialUse);\n }\n if (filters.subscribed !== undefined) {\n folders = folders.filter((f) => f.subscribed === filters.subscribed);\n }\n }\n\n return folders;\n }\n\n /**\n * Refresh counts for all folders in an account\n */\n async refreshAllCounts(accountId: string): Promise<void> {\n const folders = await this.getByAccount(accountId);\n\n for (const folder of folders) {\n await folder.refreshCounts();\n }\n }\n\n /**\n * Get folder statistics for an account\n */\n async getAccountStats(accountId: string): Promise<{\n totalFolders: number;\n totalMessages: number;\n totalUnread: number;\n systemFolders: number;\n userFolders: number;\n }> {\n const folders = await this.getByAccount(accountId);\n\n return {\n totalFolders: folders.length,\n totalMessages: folders.reduce((sum, f) => sum + f.messageCount, 0),\n totalUnread: folders.reduce((sum, f) => sum + f.unreadCount, 0),\n systemFolders: folders.filter((f) => f.isSystemFolder()).length,\n userFolders: folders.filter((f) => !f.isSystemFolder()).length,\n };\n }\n\n /**\n * Create standard system folders for an account\n */\n async createSystemFolders(accountId: string): Promise<void> {\n const standardFolders = [\n { name: 'INBOX', path: 'INBOX', specialUse: '\\\\Inbox' },\n { name: 'Sent', path: 'Sent', specialUse: '\\\\Sent' },\n { name: 'Drafts', path: 'Drafts', specialUse: '\\\\Drafts' },\n { name: 'Trash', path: 'Trash', specialUse: '\\\\Trash' },\n { name: 'Spam', path: 'Spam', specialUse: '\\\\Junk' },\n ];\n\n for (const folderData of standardFolders) {\n const existing = await this.getByPath(accountId, folderData.path);\n if (!existing) {\n // Create through the collection so the DB connection is bound; a bare\n // `new EmailFolder(...)` + save() throws \"Database accessed before\n // initialization\" under per-instance DB injection.\n const folder = await this.create({\n accountId,\n ...folderData,\n });\n await folder.save();\n }\n }\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Tenant Helper Methods\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Find all email folders belonging to a specific tenant\n */\n async findByTenant(tenantId: string): Promise<EmailFolder[]> {\n return this.list({ where: { tenantId } });\n }\n\n /**\n * Find all global email folders (no tenant).\n *\n * EmailFolder is @TenantScoped (CTI, own `email_folders` table). Under an\n * active tenant context list({ tenantId: null }) throws and unflagged raw SQL\n * is blocked (#1596); route through the raw helpers.\n */\n async findGlobal(): Promise<EmailFolder[]> {\n return queryGlobal<EmailFolder>(this);\n }\n\n /**\n * Find email folders for a tenant including global folders.\n */\n async findWithGlobals(tenantId: string): Promise<EmailFolder[]> {\n return queryWithGlobals<EmailFolder>(\n this,\n tenantId,\n 'EmailFolder.findWithGlobals',\n );\n }\n}\n","import { SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport type { BlacklistOptions } from '../types';\n\n/**\n * Blacklist - Block entries for email filtering\n *\n * Supports three pattern types:\n * - email: Exact email address (spam@example.com)\n * - domain: Entire domain (*@spam.com)\n * - regex: Custom regex pattern\n */\n@smrt({\n api: { include: ['list', 'get', 'create', 'update', 'delete'] },\n cli: { skipApiCheck: true },\n tenantScoped: true,\n})\nexport class Blacklist extends SmrtObject {\n pattern: string = '';\n type: 'email' | 'domain' | 'regex' = 'email';\n reason: string = '';\n autoArchive: boolean = true;\n\n constructor(options: BlacklistOptions = {}) {\n super(options);\n\n if (options.pattern !== undefined) {\n this.pattern = options.pattern;\n }\n if (options.type !== undefined) {\n this.type = options.type;\n }\n }\n\n /**\n * Check if an email address matches this blacklist entry\n */\n matches(email: string): boolean {\n const normalizedEmail = email.toLowerCase().trim();\n\n switch (this.type) {\n case 'email':\n return normalizedEmail === this.pattern.toLowerCase().trim();\n\n case 'domain': {\n const domain = normalizedEmail.split('@')[1];\n return domain === this.pattern.toLowerCase().trim();\n }\n\n case 'regex': {\n const pattern = this.pattern.trim();\n if (!pattern) {\n return false;\n }\n try {\n const regex = new RegExp(pattern, 'i');\n return regex.test(normalizedEmail);\n } catch {\n return false;\n }\n }\n\n default:\n return false;\n }\n }\n}\n","import { SmrtCollection } from '@happyvertical/smrt-core';\nimport { Blacklist } from '../models/Blacklist.js';\n\nexport class BlacklistCollection extends SmrtCollection<Blacklist> {\n static readonly _itemClass = Blacklist;\n\n /**\n * Check if an email is blacklisted\n */\n async isBlacklisted(email: string): Promise<boolean> {\n const entries = await this.list({});\n\n for (const entry of entries) {\n if (entry.matches(email)) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Get the matching blacklist entry for an email\n */\n async getMatchingEntry(email: string): Promise<Blacklist | null> {\n const entries = await this.list({});\n\n for (const entry of entries) {\n if (entry.matches(email)) {\n return entry;\n }\n }\n\n return null;\n }\n}\n","import { SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport type { WhitelistOptions } from '../types';\n\n/**\n * Whitelist - Allow-only entries for email filtering\n *\n * Supports three pattern types:\n * - email: Exact email address (user@example.com)\n * - domain: Entire domain (*@example.com)\n * - regex: Custom regex pattern\n */\n@smrt({\n api: { include: ['list', 'get', 'create', 'update', 'delete'] },\n cli: { skipApiCheck: true },\n tenantScoped: true,\n})\nexport class Whitelist extends SmrtObject {\n pattern: string = '';\n type: 'email' | 'domain' | 'regex' = 'email';\n category: string | null = null;\n description: string = '';\n\n constructor(options: WhitelistOptions = {}) {\n super(options);\n\n if (options.pattern !== undefined) {\n this.pattern = options.pattern;\n }\n if (options.type !== undefined) {\n this.type = options.type;\n }\n }\n\n /**\n * Check if an email address matches this whitelist entry\n */\n matches(email: string): boolean {\n const normalizedEmail = email.toLowerCase().trim();\n\n switch (this.type) {\n case 'email':\n return normalizedEmail === this.pattern.toLowerCase().trim();\n\n case 'domain': {\n const domain = normalizedEmail.split('@')[1];\n return domain === this.pattern.toLowerCase().trim();\n }\n\n case 'regex': {\n const pattern = this.pattern.trim();\n if (!pattern) {\n return false;\n }\n try {\n const regex = new RegExp(pattern, 'i');\n return regex.test(normalizedEmail);\n } catch {\n return false;\n }\n }\n\n default:\n return false;\n }\n }\n}\n","import { SmrtCollection } from '@happyvertical/smrt-core';\nimport { Whitelist } from '../models/Whitelist.js';\n\nexport class WhitelistCollection extends SmrtCollection<Whitelist> {\n static readonly _itemClass = Whitelist;\n\n /**\n * Check if an email is whitelisted for a specific category\n */\n async isWhitelisted(email: string, category?: string): Promise<boolean> {\n const entries = await this.list({});\n\n for (const entry of entries) {\n if (!entry.matches(email)) {\n continue;\n }\n\n if (!category) {\n return true;\n }\n\n if (entry.category === category || entry.category === null) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Get the matching whitelist entry for an email\n */\n async getMatchingEntry(email: string): Promise<Whitelist | null> {\n const entries = await this.list({});\n\n for (const entry of entries) {\n if (entry.matches(email)) {\n return entry;\n }\n }\n\n return null;\n }\n\n /**\n * Get whitelist entries by category\n */\n async getByCategory(category: string): Promise<Whitelist[]> {\n return await this.list({\n where: { category },\n });\n }\n}\n","/**\n * SlackAccount model - Slack workspace account extending the Account STI base\n */\n\nimport { smrt } from '@happyvertical/smrt-core';\nimport type { MessageSenderInterface, SlackAccountOptions } from '../types';\nimport { Account } from './Account';\n\n@smrt({\n tableStrategy: 'sti',\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n})\nexport class SlackAccount extends Account {\n workspaceId = '';\n workspaceName = '';\n botUserId = '';\n\n constructor(options: SlackAccountOptions = {}) {\n super(options);\n\n if (options.workspaceId !== undefined)\n this.workspaceId = options.workspaceId;\n if (options.workspaceName !== undefined)\n this.workspaceName = options.workspaceName;\n if (options.botUserId !== undefined) this.botUserId = options.botUserId;\n\n // Default provider type\n if (!this.providerType) this.providerType = 'slack';\n this.channelType = 'slack';\n }\n\n /**\n * Create a sender for this Slack account\n */\n override async createSender(): Promise<MessageSenderInterface> {\n const { SlackSender } = await import('../senders/SlackSender');\n return new SlackSender(this);\n }\n}\n","/**\n * SlackMessage model - Slack message extending the Message STI base\n */\n\nimport { smrt } from '@happyvertical/smrt-core';\nimport type { SlackMessageOptions } from '../types';\nimport { Message } from './Message';\n\n@smrt({\n tableStrategy: 'sti',\n api: { include: ['list', 'get', 'create'] },\n mcp: { include: ['list', 'get'] },\n cli: { skipApiCheck: true },\n})\nexport class SlackMessage extends Message {\n channelId = '';\n channelName = '';\n slackTs = ''; // Slack message timestamp (unique ID)\n slackThreadTs = ''; // Thread parent timestamp\n reactions = ''; // JSON array of {name, count, users[]}\n isEdited = false;\n messageType = ''; // 'message', 'bot_message', etc.\n blocks = ''; // JSON - Slack Block Kit blocks\n\n constructor(options: SlackMessageOptions = {}) {\n super(options);\n\n if (options.channelId !== undefined) this.channelId = options.channelId;\n if (options.channelName !== undefined)\n this.channelName = options.channelName;\n if (options.slackTs !== undefined) this.slackTs = options.slackTs;\n if (options.slackThreadTs !== undefined)\n this.slackThreadTs = options.slackThreadTs;\n if (options.reactions !== undefined) this.reactions = options.reactions;\n if (options.isEdited !== undefined) this.isEdited = options.isEdited;\n if (options.messageType !== undefined)\n this.messageType = options.messageType;\n if (options.blocks !== undefined) this.blocks = options.blocks;\n }\n\n /**\n * Get reactions as parsed array\n */\n getReactions(): Array<{ name: string; count: number; users?: string[] }> {\n if (!this.reactions) return [];\n try {\n return JSON.parse(this.reactions);\n } catch {\n return [];\n }\n }\n\n /**\n * Get blocks as parsed array\n */\n getBlocks(): Record<string, unknown>[] {\n if (!this.blocks) return [];\n try {\n return JSON.parse(this.blocks);\n } catch {\n return [];\n }\n }\n\n /**\n * Check if message is in a thread\n */\n isInThread(): boolean {\n return !!this.slackThreadTs && this.slackThreadTs !== this.slackTs;\n }\n\n /**\n * Get total reaction count\n */\n getTotalReactions(): number {\n return this.getReactions().reduce((sum, r) => sum + r.count, 0);\n }\n}\n","import { smrt } from '@happyvertical/smrt-core';\nimport type { AccountOptions } from '../types.js';\nimport { Account } from './Account.js';\n\n@smrt({\n tableStrategy: 'sti',\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n})\nexport class TelegramAccount extends Account {\n constructor(options: AccountOptions = {}) {\n super(options);\n this.providerType = 'telegram';\n this.channelType = 'telegram';\n }\n}\n","/**\n * Tweet model - Twitter/X message extending the Message STI base\n */\n\nimport { smrt } from '@happyvertical/smrt-core';\nimport type { TweetOptions } from '../types';\nimport { Message } from './Message';\n\n@smrt({\n tableStrategy: 'sti',\n api: { include: ['list', 'get', 'create'] },\n mcp: { include: ['list', 'get'] },\n cli: { skipApiCheck: true },\n})\nexport class Tweet extends Message {\n tweetId = '';\n retweetCount = 0;\n likeCount = 0;\n replyCount = 0;\n isRetweet = false;\n isReply = false;\n mediaUrls = ''; // JSON array\n hashtags = ''; // JSON array\n mentions = ''; // JSON array\n\n constructor(options: TweetOptions = {}) {\n super(options);\n\n if (options.tweetId !== undefined) this.tweetId = options.tweetId;\n if (options.retweetCount !== undefined)\n this.retweetCount = options.retweetCount;\n if (options.likeCount !== undefined) this.likeCount = options.likeCount;\n if (options.replyCount !== undefined) this.replyCount = options.replyCount;\n if (options.isRetweet !== undefined) this.isRetweet = options.isRetweet;\n if (options.isReply !== undefined) this.isReply = options.isReply;\n if (options.mediaUrls !== undefined) this.mediaUrls = options.mediaUrls;\n if (options.hashtags !== undefined) this.hashtags = options.hashtags;\n if (options.mentions !== undefined) this.mentions = options.mentions;\n }\n\n /**\n * Get media URLs as parsed array\n */\n getMediaUrls(): string[] {\n if (!this.mediaUrls) return [];\n try {\n return JSON.parse(this.mediaUrls);\n } catch {\n return [];\n }\n }\n\n /**\n * Get hashtags as parsed array\n */\n getHashtags(): string[] {\n if (!this.hashtags) return [];\n try {\n return JSON.parse(this.hashtags);\n } catch {\n return [];\n }\n }\n\n /**\n * Get mentions as parsed array\n */\n getMentions(): string[] {\n if (!this.mentions) return [];\n try {\n return JSON.parse(this.mentions);\n } catch {\n return [];\n }\n }\n\n /**\n * Get total engagement count\n */\n getEngagement(): number {\n return this.retweetCount + this.likeCount + this.replyCount;\n }\n}\n","/**\n * TwitterAccount model - Twitter/X account extending the Account STI base\n */\n\nimport { smrt } from '@happyvertical/smrt-core';\nimport type { MessageSenderInterface, TwitterAccountOptions } from '../types';\nimport { Account } from './Account';\n\n@smrt({\n tableStrategy: 'sti',\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n})\nexport class TwitterAccount extends Account {\n handle = '';\n twitterUserId = '';\n\n constructor(options: TwitterAccountOptions = {}) {\n super(options);\n\n if (options.handle !== undefined) this.handle = options.handle;\n if (options.twitterUserId !== undefined)\n this.twitterUserId = options.twitterUserId;\n\n // Default provider type\n if (!this.providerType) this.providerType = 'twitter';\n this.channelType = 'twitter';\n }\n\n /**\n * Create a sender for this Twitter account\n */\n override async createSender(): Promise<MessageSenderInterface> {\n const { TweetSender } = await import('../senders/TweetSender');\n return new TweetSender(this);\n }\n}\n","import { smrt } from '@happyvertical/smrt-core';\nimport type { AccountOptions } from '../types.js';\nimport { Account } from './Account.js';\n\n@smrt({\n tableStrategy: 'sti',\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n})\nexport class ZulipAccount extends Account {\n constructor(options: AccountOptions = {}) {\n super(options);\n this.providerType = 'zulip';\n this.channelType = 'zulip';\n }\n}\n","/**\n * EmailSender — sends email messages via the SDK EmailClient\n */\n\nimport type { EmailClient } from '@happyvertical/email';\nimport type { Email } from '../models/Email';\nimport type { EmailAccount } from '../models/EmailAccount';\nimport type {\n MessageSenderInterface,\n MessageSendResult,\n SendMessageOptions,\n} from '../types';\n\nexport class EmailSender implements MessageSenderInterface {\n readonly providerType = 'email';\n private client: EmailClient;\n private account: EmailAccount;\n\n constructor(client: EmailClient, account: EmailAccount) {\n this.client = client;\n this.account = account;\n }\n\n isReady(): boolean {\n return this.client.isConnected();\n }\n\n async send(\n message: Email,\n _options?: SendMessageOptions,\n ): Promise<MessageSendResult> {\n const toAddresses = message.getToAddresses();\n const ccAddresses = message.getCcAddresses();\n const bccAddresses = message.getBccAddresses();\n\n const emailMessage = {\n from: {\n name: message.fromName || this.account.name,\n address: message.fromAddress || this.account.email,\n },\n to: toAddresses.map((r) => ({\n name: r.name,\n address: r.address,\n })),\n cc:\n ccAddresses.length > 0\n ? ccAddresses.map((r) => ({ name: r.name, address: r.address }))\n : undefined,\n bcc:\n bccAddresses.length > 0\n ? bccAddresses.map((r) => ({ name: r.name, address: r.address }))\n : undefined,\n subject: message.subject,\n text: message.textBody || message.body,\n html: message.htmlBody || undefined,\n inReplyTo: message.inReplyTo || undefined,\n };\n\n try {\n const result = await this.client.send(emailMessage);\n\n return {\n success: true,\n providerMessageId: result.messageId,\n accepted: result.accepted,\n rejected: result.rejected,\n providerResponse: { response: result.response },\n sentAt: new Date(),\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n sentAt: new Date(),\n };\n }\n }\n}\n","import type { SmrtClassOptions } from '@happyvertical/smrt-core';\nimport { withTenant } from '@happyvertical/smrt-tenancy';\nimport { AccountCollection } from '../collections/AccountCollection.js';\nimport { MessagingEndpointCollection } from '../collections/MessagingEndpointCollection.js';\nimport { PersonaMessageRouteCollection } from '../collections/PersonaMessageRouteCollection.js';\nimport { Account } from '../models/Account.js';\nimport { EmailAccount } from '../models/EmailAccount.js';\nimport { MessagingEndpoint } from '../models/MessagingEndpoint.js';\nimport { PersonaMessageRoute } from '../models/PersonaMessageRoute.js';\nimport { TelegramAccount } from '../models/TelegramAccount.js';\nimport { ZulipAccount } from '../models/ZulipAccount.js';\nimport {\n assertMessagingPermission,\n MANAGE_MESSAGE_CREDENTIALS_PERMISSION,\n MANAGE_MESSAGE_ROUTES_PERMISSION,\n type MessagingPrincipal,\n} from '../permissions.js';\nimport {\n getMessagingProvider,\n listMessagingProviders,\n type MessagingProviderDefinition,\n type MessagingProviderField,\n type MessagingProviderFunctionKey,\n} from '../providers.js';\nimport type { MessagingChannel } from '../types.js';\n\nexport interface MessagingAccountInput {\n id?: string;\n name: string;\n providerId: string;\n configuration: Record<string, unknown>;\n /** Omit on update to leave the stored secret unchanged. */\n credentials?: Record<string, unknown>;\n active?: boolean;\n}\n\nexport interface MessagingEndpointInput {\n id?: string;\n label: string;\n providerId: string;\n profileId?: string | null;\n address: Record<string, unknown>;\n active?: boolean;\n}\n\nexport interface PersonaMessageRouteInput {\n id?: string;\n personaId: string;\n accountId: string;\n endpointId: string;\n purpose?: string;\n priority?: number;\n enabled?: boolean;\n}\n\nexport interface MessagingAccountView {\n id: string;\n name: string;\n providerId: string;\n channel: MessagingChannel;\n configuration: Record<string, unknown>;\n hasCredentials: boolean;\n active: boolean;\n}\n\nexport interface MessagingEndpointView {\n id: string;\n label: string;\n channel: MessagingChannel;\n profileId: string | null;\n maskedAddress: string;\n active: boolean;\n verified: boolean;\n}\n\n/** Permission-gated server API for a schema-driven messaging settings page. */\nexport class MessagingSettingsService {\n constructor(\n private readonly options: {\n db: SmrtClassOptions['db'];\n tenantId: string;\n principal: MessagingPrincipal;\n /** Cross-package ownership check supplied by the host/personas layer. */\n resolvePersonaTenantId: (personaId: string) => Promise<string | null>;\n },\n ) {}\n\n getProviderDefinitions(options: { includeUnavailable?: boolean } = {}) {\n return listMessagingProviders(options).map(\n ({\n createSender: _createSender,\n createEmailClient: _createEmailClient,\n createMessageClient: _createMessageClient,\n ...provider\n }) => provider,\n );\n }\n\n async list(personaId: string): Promise<{\n providers: Array<\n Omit<MessagingProviderDefinition, MessagingProviderFunctionKey>\n >;\n accounts: MessagingAccountView[];\n endpoints: MessagingEndpointView[];\n routes: PersonaMessageRoute[];\n }> {\n this.assert(MANAGE_MESSAGE_ROUTES_PERMISSION);\n return withTenant({ tenantId: this.options.tenantId }, async () => {\n const accounts = await AccountCollection.create({ db: this.options.db });\n const endpoints = await MessagingEndpointCollection.create({\n db: this.options.db,\n });\n const routes = await PersonaMessageRouteCollection.create({\n db: this.options.db,\n });\n const [accountRows, endpointRows, routeRows] = await Promise.all([\n accounts.list({}),\n endpoints.list({}),\n routes.list({ where: { personaId } }),\n ]);\n return {\n providers: this.getProviderDefinitions({ includeUnavailable: true }),\n accounts: accountRows.map((account) => this.accountView(account)),\n endpoints: endpointRows.map((endpoint) => this.endpointView(endpoint)),\n routes: routeRows,\n };\n });\n }\n\n async saveAccount(\n input: MessagingAccountInput,\n ): Promise<MessagingAccountView> {\n this.assert(MANAGE_MESSAGE_CREDENTIALS_PERMISSION);\n const provider = this.requireProvider(input.providerId);\n if (!provider.available)\n throw new Error(`Provider '${provider.id}' is not available.`);\n this.validateFields(\n input.configuration,\n provider.configurationFields,\n 'configuration',\n );\n if (input.credentials) {\n this.validateFields(\n input.credentials,\n provider.credentialFields,\n 'credentials',\n );\n }\n\n return withTenant({ tenantId: this.options.tenantId }, async () => {\n const collection = await AccountCollection.create({\n db: this.options.db,\n });\n let account = input.id ? await collection.get({ id: input.id }) : null;\n const isNew = !account;\n if (account && account.tenantId !== this.options.tenantId) {\n throw new Error('Messaging account belongs to another tenant.');\n }\n if (account && account.providerType !== provider.id) {\n throw new Error(\n 'A messaging account provider cannot be changed in place.',\n );\n }\n if (\n isNew &&\n !input.credentials &&\n provider.credentialFields.some((field) => field.required)\n ) {\n throw new Error(\n `Credentials are required for new ${provider.label} accounts.`,\n );\n }\n\n if (!account) {\n account = this.newAccount(provider, input);\n await account.initialize();\n }\n\n account.name = input.name.trim();\n account.isActive = input.active ?? account.isActive;\n account.channelType = provider.channel;\n const configuration = this.normalizeConfiguration(\n provider,\n input.configuration,\n );\n account.setConfiguration(configuration);\n if (account instanceof EmailAccount) {\n account.email = String(configuration.email ?? '');\n }\n account.updatedAt = new Date();\n await account.save();\n\n if (input.credentials) {\n await account.setCredentials(\n this.normalizeCredentials(provider, input.credentials),\n );\n }\n\n return this.accountView(account);\n });\n }\n\n async saveEndpoint(\n input: MessagingEndpointInput,\n ): Promise<MessagingEndpointView> {\n this.assert(MANAGE_MESSAGE_ROUTES_PERMISSION);\n const provider = this.requireProvider(input.providerId);\n if (!provider.available)\n throw new Error(`Provider '${provider.id}' is not available.`);\n this.validateFields(input.address, provider.endpointFields, 'endpoint');\n\n return withTenant({ tenantId: this.options.tenantId }, async () => {\n const collection = await MessagingEndpointCollection.create({\n db: this.options.db,\n });\n let endpoint = input.id ? await collection.get({ id: input.id }) : null;\n if (endpoint && endpoint.tenantId !== this.options.tenantId) {\n throw new Error('Messaging endpoint belongs to another tenant.');\n }\n if (!endpoint) {\n endpoint = new MessagingEndpoint({\n db: this.options.db,\n tenantId: this.options.tenantId,\n });\n await endpoint.initialize();\n }\n endpoint.label = input.label.trim();\n if (input.profileId !== undefined) {\n endpoint.profileId = input.profileId;\n }\n endpoint.channel = provider.channel;\n endpoint.isActive = input.active ?? endpoint.isActive;\n endpoint.setAddress(input.address);\n endpoint.updatedAt = new Date();\n await endpoint.save();\n return this.endpointView(endpoint);\n });\n }\n\n async saveRoute(\n input: PersonaMessageRouteInput,\n ): Promise<PersonaMessageRoute> {\n this.assert(MANAGE_MESSAGE_ROUTES_PERMISSION);\n const personaTenantId = await this.options.resolvePersonaTenantId(\n input.personaId,\n );\n if (personaTenantId !== this.options.tenantId) {\n throw new Error('Messaging persona was not found in this tenant.');\n }\n return withTenant({ tenantId: this.options.tenantId }, async () => {\n const accounts = await AccountCollection.create({ db: this.options.db });\n const endpoints = await MessagingEndpointCollection.create({\n db: this.options.db,\n });\n const routes = await PersonaMessageRouteCollection.create({\n db: this.options.db,\n });\n const [account, endpoint] = await Promise.all([\n accounts.get({ id: input.accountId }),\n endpoints.get({ id: input.endpointId }),\n ]);\n if (!account || account.tenantId !== this.options.tenantId) {\n throw new Error('Messaging account was not found in this tenant.');\n }\n if (!endpoint || endpoint.tenantId !== this.options.tenantId) {\n throw new Error('Messaging endpoint was not found in this tenant.');\n }\n const accountProvider = getMessagingProvider(account.providerType);\n if (\n !accountProvider?.available ||\n accountProvider.channel !== account.channelType\n ) {\n throw new Error(\n 'Messaging account provider is not available for outbound delivery.',\n );\n }\n if (account.channelType !== endpoint.channel) {\n throw new Error(\n 'Messaging account and endpoint channels do not match.',\n );\n }\n\n let route = input.id ? await routes.get({ id: input.id }) : null;\n if (route && route.tenantId !== this.options.tenantId) {\n throw new Error('Messaging route belongs to another tenant.');\n }\n if (!route) {\n route = new PersonaMessageRoute({\n db: this.options.db,\n tenantId: this.options.tenantId,\n });\n await route.initialize();\n }\n route.personaId = input.personaId;\n route.accountId = input.accountId;\n route.endpointId = input.endpointId;\n route.purpose = input.purpose?.trim() || 'default';\n route.priority = input.priority ?? 0;\n route.enabled = input.enabled ?? route.enabled;\n route.updatedAt = new Date();\n await route.save();\n return route;\n });\n }\n\n private assert(permission: string): void {\n assertMessagingPermission(\n this.options.principal,\n this.options.tenantId,\n permission,\n );\n }\n\n private requireProvider(providerId: string): MessagingProviderDefinition {\n const provider = getMessagingProvider(providerId);\n if (!provider)\n throw new Error(`Unknown messaging provider '${providerId}'.`);\n return provider;\n }\n\n private validateFields(\n values: Record<string, unknown>,\n fields: MessagingProviderField[],\n kind: string,\n ): void {\n const allowed = new Set(fields.map((field) => field.id));\n for (const key of Object.keys(values)) {\n if (!allowed.has(key)) {\n throw new Error(`Unknown ${kind} field '${key}'.`);\n }\n }\n for (const field of fields) {\n const value = values[field.id];\n const missing = value === undefined || value === '';\n if (field.required && (missing || value === null)) {\n throw new Error(`${field.label} is required in ${kind}.`);\n }\n if (missing) continue;\n\n if (\n field.type === 'number' &&\n (typeof value !== 'number' || !Number.isFinite(value))\n ) {\n throw new Error(`${field.label} must be a finite number in ${kind}.`);\n }\n if (field.type === 'boolean' && typeof value !== 'boolean') {\n throw new Error(`${field.label} must be a boolean in ${kind}.`);\n }\n if (\n field.type !== 'number' &&\n field.type !== 'boolean' &&\n typeof value !== 'string'\n ) {\n throw new Error(`${field.label} must be a string in ${kind}.`);\n }\n if (\n field.type === 'select' &&\n field.options?.length &&\n !field.options.some((option) => option.value === value)\n ) {\n throw new Error(`${field.label} has an invalid option in ${kind}.`);\n }\n }\n }\n\n private newAccount(\n provider: MessagingProviderDefinition,\n input: MessagingAccountInput,\n ): Account {\n const options = {\n db: this.options.db,\n tenantId: this.options.tenantId,\n name: input.name.trim(),\n providerType: provider.id,\n channelType: provider.channel,\n };\n if (provider.id === 'zulip') return new ZulipAccount(options);\n if (provider.id === 'telegram') return new TelegramAccount(options);\n if (provider.channel === 'email') {\n return new EmailAccount({\n ...options,\n providerType: provider.id as 'smtp' | 'imap' | 'pop3' | 'gmail',\n });\n }\n return new Account(options);\n }\n\n private normalizeCredentials(\n provider: MessagingProviderDefinition,\n credentials: Record<string, unknown>,\n ): Record<string, unknown> {\n if (provider.channel !== 'email') return credentials;\n if (provider.id === 'gmail') {\n return { auth: credentials };\n }\n const { username, password, ...rest } = credentials;\n return {\n ...rest,\n auth: { user: username, pass: password },\n };\n }\n\n private normalizeConfiguration(\n provider: MessagingProviderDefinition,\n configuration: Record<string, unknown>,\n ): Record<string, unknown> {\n if (provider.channel !== 'email' || configuration.secure === undefined) {\n return configuration;\n }\n return {\n ...configuration,\n secure: configuration.secure === true || configuration.secure === 'true',\n };\n }\n\n private accountView(account: Account): MessagingAccountView {\n return {\n id: account.id ?? '',\n name: account.name,\n providerId: account.providerType,\n channel: account.channelType,\n configuration: account.getConfiguration(),\n hasCredentials: account.hasCredentials,\n active: account.isActive,\n };\n }\n\n private endpointView(endpoint: MessagingEndpoint): MessagingEndpointView {\n return {\n id: endpoint.id ?? '',\n label: endpoint.label,\n channel: endpoint.channel,\n profileId: endpoint.profileId,\n maskedAddress: endpoint.getMaskedAddress(),\n active: endpoint.isActive,\n verified: endpoint.verifiedAt !== null,\n };\n }\n}\n","import type { SmrtClassOptions } from '@happyvertical/smrt-core';\nimport { withTenant } from '@happyvertical/smrt-tenancy';\nimport { AccountCollection } from '../collections/AccountCollection.js';\nimport { MessagingEndpointCollection } from '../collections/MessagingEndpointCollection.js';\nimport { PersonaMessageRouteCollection } from '../collections/PersonaMessageRouteCollection.js';\nimport { Email } from '../models/Email.js';\nimport { EmailAccount } from '../models/EmailAccount.js';\nimport { Message } from '../models/Message.js';\nimport type { PersonaMessageRoute } from '../models/PersonaMessageRoute.js';\nimport {\n assertMessagingPermission,\n type MessagingPrincipal,\n SEND_MESSAGES_PERMISSION,\n} from '../permissions.js';\nimport type { MessageSendResult, SendPersonaMessageOptions } from '../types.js';\n\nexport interface PersonaMessageSendResult {\n routeId: string;\n messageId: string;\n delivery: MessageSendResult;\n}\n\n/** Resolves a persona-owned route and delivers a persisted outbound message. */\nexport class PersonaMessagingService {\n constructor(\n private readonly options: {\n db: SmrtClassOptions['db'];\n tenantId: string;\n /** Omit only for trusted system code that performs its own authorization. */\n principal?: MessagingPrincipal;\n },\n ) {}\n\n async send(\n input: SendPersonaMessageOptions,\n ): Promise<PersonaMessageSendResult> {\n if (this.options.principal) {\n assertMessagingPermission(\n this.options.principal,\n this.options.tenantId,\n SEND_MESSAGES_PERMISSION,\n );\n }\n if (!input.personaId)\n throw new Error('A persona is required to send a message.');\n if (!input.body.trim()) throw new Error('Message body cannot be empty.');\n\n return withTenant({ tenantId: this.options.tenantId }, async () => {\n const route = await this.resolveRoute(input);\n const accounts = await AccountCollection.create({ db: this.options.db });\n const endpoints = await MessagingEndpointCollection.create({\n db: this.options.db,\n });\n const [account, endpoint] = await Promise.all([\n accounts.get({ id: route.accountId }),\n endpoints.get({ id: route.endpointId }),\n ]);\n if (\n !account ||\n account.tenantId !== this.options.tenantId ||\n !account.isActive\n ) {\n throw new Error('The selected messaging account is unavailable.');\n }\n if (\n !endpoint ||\n endpoint.tenantId !== this.options.tenantId ||\n !endpoint.isActive\n ) {\n throw new Error('The selected messaging endpoint is unavailable.');\n }\n if (account.channelType !== endpoint.channel) {\n throw new Error(\n 'The selected messaging route has mismatched channels.',\n );\n }\n\n let message: Message;\n const base = {\n db: this.options.db,\n tenantId: this.options.tenantId,\n accountId: route.accountId,\n endpointId: route.endpointId,\n personaId: input.personaId,\n correlationId: input.correlationId ?? '',\n subject: input.subject ?? '',\n body: input.body.trim(),\n sendStatus: 'pending' as const,\n };\n if (endpoint.channel === 'email') {\n if (!(account instanceof EmailAccount)) {\n throw new Error('Email routes require an EmailAccount.');\n }\n const address = endpoint.getAddress<{ email?: string }>();\n if (!address.email) throw new Error('Email endpoint has no address.');\n const email = new Email({ ...base, textBody: base.body });\n email.setToAddresses([{ address: address.email }]);\n message = email;\n } else {\n message = new Message(base);\n }\n await message.initialize();\n await message.save();\n const delivery = await message.send();\n return {\n routeId: route.id ?? '',\n messageId: message.id ?? '',\n delivery,\n };\n });\n }\n\n private async resolveRoute(\n input: SendPersonaMessageOptions,\n ): Promise<PersonaMessageRoute> {\n const routes = await PersonaMessageRouteCollection.create({\n db: this.options.db,\n });\n if (input.routeId) {\n const route = await routes.get({ id: input.routeId });\n if (\n !route ||\n route.tenantId !== this.options.tenantId ||\n route.personaId !== input.personaId ||\n !route.enabled\n ) {\n throw new Error(\n 'The requested persona messaging route is unavailable.',\n );\n }\n return route;\n }\n\n let candidates = await routes.forPersona(input.personaId);\n if (input.purpose) {\n candidates = candidates.filter(\n (route) => route.purpose === input.purpose,\n );\n } else {\n const defaults = candidates.filter(\n (route) => route.purpose === 'default',\n );\n if (defaults.length > 0) candidates = defaults;\n }\n candidates.sort((left, right) => right.priority - left.priority);\n\n if (input.channel) {\n const endpoints = await MessagingEndpointCollection.create({\n db: this.options.db,\n });\n for (const route of candidates) {\n const endpoint = await endpoints.get({ id: route.endpointId });\n if (endpoint?.channel === input.channel) return route;\n }\n throw new Error(\n `No ${input.channel} route is configured for this persona.`,\n );\n }\n\n const route = candidates[0];\n if (!route)\n throw new Error('No messaging route is configured for this persona.');\n return route;\n }\n}\n","/**\n * @happyvertical/smrt-messages\n *\n * Unified multi-channel messaging with STI-based hierarchies\n *\n * @packageDocumentation\n */\n\n// Self-register this package's manifest before any @smrt() decorator fires\n// downstream. Must come first so the side effect runs ahead of the class\n// module loads below. See __smrt-register__.ts for issue #1132 context.\nimport './__smrt-register__.js';\n\nimport { ensureMessagingPermissionsRegistered } from './permissions.js';\nimport { ensureBuiltinMessagingProvidersRegistered } from './providers.js';\n\n// ─────────────────────────────────────────────────────────────────────────\n// Base classes (new)\n// ─────────────────────────────────────────────────────────────────────────\n\nexport { AccountCollection } from './collections/AccountCollection';\nexport { AttachmentCollection } from './collections/AttachmentCollection';\n// Base collections\nexport { MessageCollection } from './collections/MessageCollection';\nexport { MessagingEndpointCollection } from './collections/MessagingEndpointCollection.js';\nexport { PersonaMessageRouteCollection } from './collections/PersonaMessageRouteCollection.js';\nexport { Account } from './models/Account';\nexport { Attachment } from './models/Attachment';\n// Base models\nexport { Message } from './models/Message';\nexport { MessagingEndpoint } from './models/MessagingEndpoint.js';\nexport { PersonaMessageRoute } from './models/PersonaMessageRoute.js';\n\n// ─────────────────────────────────────────────────────────────────────────\n// Email (backward-compatible)\n// ─────────────────────────────────────────────────────────────────────────\n\nexport { EmailAccountCollection } from './collections/EmailAccountCollection';\nexport { EmailAttachmentCollection } from './collections/EmailAttachmentCollection';\n// Email collections\nexport { EmailCollection } from './collections/EmailCollection';\nexport { EmailFolderCollection } from './collections/EmailFolderCollection';\n// Email models\nexport { Email } from './models/Email';\nexport { EmailAccount } from './models/EmailAccount';\nexport { EmailAttachment } from './models/EmailAttachment';\nexport { EmailFolder } from './models/EmailFolder';\n\n// ─────────────────────────────────────────────────────────────────────────\n// Email filtering (whitelist/blacklist)\n// ─────────────────────────────────────────────────────────────────────────\n\nexport { BlacklistCollection } from './collections/BlacklistCollection';\nexport { WhitelistCollection } from './collections/WhitelistCollection';\nexport { Blacklist } from './models/Blacklist';\nexport { Whitelist } from './models/Whitelist';\n\n// ─────────────────────────────────────────────────────────────────────────\n// Provider stubs\n// ─────────────────────────────────────────────────────────────────────────\n\n// Account types\nexport { SlackAccount } from './models/SlackAccount';\nexport { SlackMessage } from './models/SlackMessage';\nexport { TelegramAccount } from './models/TelegramAccount.js';\n// Message types\nexport { Tweet } from './models/Tweet';\nexport { TwitterAccount } from './models/TwitterAccount';\nexport { ZulipAccount } from './models/ZulipAccount.js';\n\n// ─────────────────────────────────────────────────────────────────────────\n// Senders\n// ─────────────────────────────────────────────────────────────────────────\n\nexport {\n assertMessagingPermission,\n ensureMessagingPermissionsRegistered,\n MANAGE_MESSAGE_CREDENTIALS_PERMISSION,\n MANAGE_MESSAGE_ROUTES_PERMISSION,\n MESSAGING_PERMISSION_DEFINITIONS,\n type MessagingPrincipal,\n messagingPrincipalFromPermissions,\n SEND_MESSAGES_PERMISSION,\n} from './permissions.js';\nexport {\n ensureBuiltinMessagingProvidersRegistered,\n getMessagingProvider,\n listMessagingProviders,\n type MessagingProviderDefinition,\n type MessagingProviderField,\n type MessagingProviderFieldType,\n registerMessagingProvider,\n} from './providers.js';\nexport { EmailSender } from './senders/EmailSender';\nexport { SlackSender } from './senders/SlackSender';\nexport { TelegramSender } from './senders/TelegramSender.js';\nexport { TweetSender } from './senders/TweetSender';\nexport { ZulipSender } from './senders/ZulipSender.js';\nexport {\n type MessagingAccountInput,\n type MessagingAccountView,\n type MessagingEndpointInput,\n type MessagingEndpointView,\n MessagingSettingsService,\n type PersonaMessageRouteInput,\n} from './services/MessagingSettingsService.js';\nexport {\n type PersonaMessageSendResult,\n PersonaMessagingService,\n} from './services/PersonaMessagingService.js';\n\n// ─────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────\n\nexport type {\n AccountOptions,\n AccountSearchFilters,\n AccountType,\n AttachmentOptions,\n // Email options (backward compat)\n EmailAccountOptions,\n EmailAccountSearchFilters,\n EmailAttachmentOptions,\n EmailFolderOptions,\n EmailFolderSearchFilters,\n EmailOptions,\n EmailSearchFilters,\n KnownMessagingChannel,\n // Base options\n MessageOptions,\n // Search filters\n MessageSearchFilters,\n MessageSenderInterface,\n // Send types\n MessageSendResult,\n // Discriminator types\n MessageType,\n MessagingChannel,\n MessagingEndpointOptions,\n PersonaMessageRouteOptions,\n ProviderType,\n SendEmailOptions,\n SendMessageOptions,\n SendPersonaMessageOptions,\n SendSlackOptions,\n SendStatus,\n SendTweetOptions,\n SlackAccountOptions,\n SlackMessageOptions,\n // Sync types\n SyncOptions,\n SyncProgress,\n SyncResult,\n // Provider options\n TweetOptions,\n TwitterAccountOptions,\n} from './types';\n\nensureBuiltinMessagingProvidersRegistered();\nensureMessagingPermissionsRegistered();\n"],"mappings":"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"}
|