@happyvertical/smrt-messages 0.60.8 → 0.60.10
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/AGENTS.md +17 -0
- package/README.md +40 -0
- package/agents/notification-outbox.md +116 -0
- package/dist/chunks/{AccountCollection-O-zbituV.js → AccountCollection-By48bdwt.js} +2 -2
- package/dist/chunks/{AccountCollection-O-zbituV.js.map → AccountCollection-By48bdwt.js.map} +1 -1
- package/dist/chunks/{Email-MRtj6D2s.js → Email-CMUK3aWU.js} +3 -3
- package/dist/chunks/{Email-MRtj6D2s.js.map → Email-CMUK3aWU.js.map} +1 -1
- package/dist/chunks/{EmailFolder-qpOwfo_O.js → EmailFolder-DLJvqNqI.js} +2 -2
- package/dist/chunks/{EmailFolder-qpOwfo_O.js.map → EmailFolder-DLJvqNqI.js.map} +1 -1
- package/dist/chunks/{Message-5Xz9tauF.js → Message-DXpqot5f.js} +52 -5
- package/dist/chunks/Message-DXpqot5f.js.map +1 -0
- package/dist/chunks/{MessageCollection-m1C6fDwS.js → MessageCollection-CMGaSGBc.js} +2 -2
- package/dist/chunks/{MessageCollection-m1C6fDwS.js.map → MessageCollection-CMGaSGBc.js.map} +1 -1
- package/dist/chunks/__smrt-register__-CaGLtiEU.js +6 -0
- package/dist/chunks/__smrt-register__-CaGLtiEU.js.map +1 -0
- package/dist/collections/NotificationDeliveryCollection.d.ts +6 -0
- package/dist/collections/NotificationDeliveryCollection.d.ts.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +780 -38
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +1135 -89
- package/dist/models/Message.d.ts +15 -0
- package/dist/models/Message.d.ts.map +1 -1
- package/dist/models/NotificationDelivery.d.ts +128 -0
- package/dist/models/NotificationDelivery.d.ts.map +1 -0
- package/dist/senders/EmailSender.d.ts +9 -0
- package/dist/senders/EmailSender.d.ts.map +1 -1
- package/dist/services/NotificationOutboxService.d.ts +226 -0
- package/dist/services/NotificationOutboxService.d.ts.map +1 -0
- package/dist/smrt-knowledge.json +470 -9
- package/dist/smrt-knowledge.okf.md +155 -0
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +17 -16
- package/dist/chunks/Message-5Xz9tauF.js.map +0 -1
- package/dist/chunks/__smrt-register__-DwNoP4GB.js +0 -6
- package/dist/chunks/__smrt-register__-DwNoP4GB.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/UserNotification.ts","../src/collections/UserNotificationCollection.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/services/UserNotificationService.ts","../src/recipes.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\n// Register the package manifest before this module's @smrt() decorator\n// runs, whichever chunk the library build places it in (#3098).\nimport '../__smrt-register__.js';\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/**\n * Split an absolute path into its directory and file name, or return null for\n * a relative path. Plain string handling rather than `node:path`: the package\n * root must stay browser-reachable (the bundle-gate forbids `node:*` there).\n */\nfunction splitAbsolutePath(\n filePath: string,\n): { dir: string; base: string } | null {\n // A backslash separates segments only in a Windows path; in a POSIX path it\n // is an ordinary filename character.\n const windows = /^[A-Za-z]:[\\\\/]/.test(filePath);\n if (!windows && !filePath.startsWith('/')) return null;\n const cut = windows\n ? Math.max(filePath.lastIndexOf('/'), filePath.lastIndexOf('\\\\'))\n : filePath.lastIndexOf('/');\n const dir = filePath.slice(0, cut) || filePath.slice(0, cut + 1);\n return { dir, base: filePath.slice(cut + 1) };\n}\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 { static __smrtPackage__ = \"@happyvertical/smrt-messages\";\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 * The local provider joins every path onto its base path (the process cwd\n * by default), so an absolute `filePath` is rooted at its own directory, and\n * the bytes are read raw: decoding a PDF as UTF-8 corrupts it (#3808).\n */\n async readContent(): Promise<Buffer | null> {\n if (!this.filePath) return null;\n\n try {\n const { getFilesystem, initializeProviders } =\n (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 // The SDK registers its providers asynchronously on import; make the\n // local one available before asking for it.\n await initializeProviders?.();\n const split = splitAbsolutePath(this.filePath);\n const files = await getFilesystem(\n split ? { type: 'local', basePath: split.dir } : { type: 'local' },\n );\n const data = await files.read(split ? split.base : this.filePath, {\n raw: true,\n });\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';\n// Register the package manifest before this module's @smrt() decorator\n// runs, whichever chunk the library build places it in (#3098).\nimport '../__smrt-register__.js';\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 { static __smrtPackage__ = \"@happyvertical/smrt-messages\";\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';\n// Register the package manifest before this module's @smrt() decorator\n// runs, whichever chunk the library build places it in (#3098).\nimport '../__smrt-register__.js';\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 { static __smrtPackage__ = \"@happyvertical/smrt-messages\";\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","import type { SmrtObjectOptions } from '@happyvertical/smrt-core';\n// Register the package manifest before this module's @smrt() decorator\n// runs, whichever chunk the library build places it in (#3098).\nimport '../__smrt-register__.js';\nimport {\n crossPackageRef,\n field,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\n\n/** How much a notification matters to its recipient. */\nexport type UserNotificationSeverity = 'info' | 'success' | 'warning' | 'error';\n\nexport const USER_NOTIFICATION_SEVERITIES: readonly UserNotificationSeverity[] =\n ['info', 'success', 'warning', 'error'];\n\nexport interface UserNotificationOptions extends SmrtObjectOptions {\n tenantId?: string;\n recipientUserId?: string;\n kind?: string;\n title?: string;\n body?: string;\n href?: string | null;\n severity?: UserNotificationSeverity;\n sourceRef?: string;\n occurredAt?: Date;\n readAt?: Date | null;\n dismissedAt?: Date | null;\n}\n\n/**\n * One in-app notification for one person, with its own read state.\n *\n * The in-app channel of smrt-messages: where `Message` is delivered through\n * an external provider, a `UserNotification` is stored for a user and shown\n * by the host (a bell, a notifications page). Create, list, and change read\n * state through `UserNotificationService`, which checks the recipient on\n * every write; the generated REST/MCP/CLI surfaces are off because a plain\n * tenant-scoped list would show every member's notifications.\n *\n * `sourceRef` is the dedupe key: one row per `(tenant, recipient, sourceRef)`\n * (the conflict identity), so re-deriving the same event (a failed social\n * post, a failed render) never notifies twice. The service generates a unique\n * ref when the caller has none.\n */\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'user_notifications',\n api: false,\n mcp: false,\n cli: false,\n conflictColumns: ['tenant_id', 'recipient_user_id', 'source_ref'],\n // The bell reads a recipient's newest rows in one tenant.\n indexes: [\n {\n name: 'user_notifications_recipient_occurred_idx',\n columns: ['tenantId', 'recipientUserId', 'occurredAt'],\n },\n ],\n})\nexport class UserNotification extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-messages\";\n @tenantId()\n tenantId = '';\n\n /** The person this notification is for (`smrt-users:User`, uuid). */\n @crossPackageRef('@happyvertical/smrt-users:User', { required: true })\n recipientUserId = '';\n\n /** Host-defined type, e.g. `social-post.failed` (used for icons/filters). */\n @field({ required: true })\n kind = '';\n\n /** One short plain sentence. */\n @field({ required: true })\n title = '';\n\n /** Optional detail line. */\n body = '';\n\n /** Where the notification leads (host-relative path or URL). */\n href: string | null = null;\n\n severity: UserNotificationSeverity = 'info';\n\n /** Dedupe key, unique per tenant and recipient (see class docs). */\n @field({ required: true })\n sourceRef = '';\n\n /** When the underlying event happened (sort key). */\n occurredAt = new Date();\n\n /** Set when the recipient has seen it. */\n readAt: Date | null = null;\n\n /** Set when the recipient has cleared it; dismissed rows are hidden. */\n dismissedAt: Date | null = null;\n\n constructor(options: UserNotificationOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.recipientUserId !== undefined)\n this.recipientUserId = options.recipientUserId;\n if (options.kind !== undefined) this.kind = options.kind;\n if (options.title !== undefined) this.title = options.title;\n if (options.body !== undefined) this.body = options.body;\n if (options.href !== undefined) this.href = options.href;\n if (options.severity !== undefined) this.severity = options.severity;\n if (options.sourceRef !== undefined) this.sourceRef = options.sourceRef;\n if (options.occurredAt !== undefined) this.occurredAt = options.occurredAt;\n if (options.readAt !== undefined) this.readAt = options.readAt;\n if (options.dismissedAt !== undefined)\n this.dismissedAt = options.dismissedAt;\n }\n\n get isRead(): boolean {\n return this.readAt !== null;\n }\n\n get isDismissed(): boolean {\n return this.dismissedAt !== null;\n }\n}\n","import { SmrtCollection } from '@happyvertical/smrt-core';\nimport { UserNotification } from '../models/UserNotification.js';\n\nexport class UserNotificationCollection extends SmrtCollection<UserNotification> {\n static readonly _itemClass = UserNotification;\n}\n","/**\n * EmailAccount model - Email account extending the Account STI base\n *\n * Retains email-specific fields and sync capability.\n */\n\n// Register the package manifest before this module's @smrt() decorator\n// runs, whichever chunk the library build places it in (#3098).\nimport '../__smrt-register__.js';\nimport type { FetchOptions, GetEmailClientOptions } from '@happyvertical/email';\nimport { field, 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 { static __smrtPackage__ = \"@happyvertical/smrt-messages\";\n @field({ description: 'The email address associated with this mailbox.' })\n email = '';\n @field({\n description: 'The time in minutes between scheduled mailbox checks.',\n })\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 * Read an immutable body/attachment-byte snapshot for an authorized intake host.\n * Does not sync, acknowledge, mark read or advance mailbox checkpoints.\n * Metadata-only providers fail explicitly; provider paths are never dereferenced.\n */\n async readIntakeMessage(\n locator: string,\n maxBytes: number,\n imapIdentity?: { folder: string; uidValidity: number; uid: string },\n ) {\n if (!this.id || !this.isActive || !locator) {\n throw new Error('Email intake account unavailable');\n }\n const client = await this.createClient();\n try {\n await client.connect();\n if (this.providerType === 'imap') {\n if (\n !imapIdentity?.folder ||\n !imapIdentity.uid ||\n !Number.isSafeInteger(imapIdentity.uidValidity)\n ) {\n throw new Error(\n 'IMAP intake requires folder and immutable UID identity',\n );\n }\n const folder = await client.selectFolder(imapIdentity.folder);\n if (folder.uidValidity !== imapIdentity.uidValidity) {\n throw new Error('IMAP intake identity changed');\n }\n }\n const message = await client.getMessage(locator);\n if (this.providerType === 'imap' && message.id !== imapIdentity?.uid) {\n throw new Error('IMAP intake identity changed');\n }\n const { snapshotEmailForIntake } = await import('../intake-snapshot.js');\n return snapshotEmailForIntake(this.id, message, maxBytes);\n } finally {\n await client.disconnect();\n }\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';\n// Register the package manifest before this module's @smrt() decorator\n// runs, whichever chunk the library build places it in (#3098).\nimport '../__smrt-register__.js';\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 { static __smrtPackage__ = \"@happyvertical/smrt-messages\";\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';\n// Register the package manifest before this module's @smrt() decorator\n// runs, whichever chunk the library build places it in (#3098).\nimport '../__smrt-register__.js';\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 { static __smrtPackage__ = \"@happyvertical/smrt-messages\";\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\n// Register the package manifest before this module's @smrt() decorator\n// runs, whichever chunk the library build places it in (#3098).\nimport '../__smrt-register__.js';\nimport { field, 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 { static __smrtPackage__ = \"@happyvertical/smrt-messages\";\n @field({ description: 'The identifier of the connected workspace.' })\n workspaceId = '';\n @field({ description: 'The name of the connected workspace.' })\n workspaceName = '';\n @field({\n description: 'The bot user your application posts as in this workspace.',\n })\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\n// Register the package manifest before this module's @smrt() decorator\n// runs, whichever chunk the library build places it in (#3098).\nimport '../__smrt-register__.js';\nimport { field, 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 // Message is read-only over REST; this provider type is writable there.\n widenParentExposure: { api: ['create'] },\n})\nexport class SlackMessage extends Message { static __smrtPackage__ = \"@happyvertical/smrt-messages\";\n @field({ description: 'The identifier of the channel this message is in.' })\n channelId = '';\n @field({ description: 'The name of the channel this message was posted in.' })\n channelName = '';\n @field({ description: \"The workspace's own reference for this message.\" })\n slackTs = ''; // Slack message timestamp (unique ID)\n @field({\n description:\n \"The workspace's own reference for the thread this message belongs to.\",\n })\n slackThreadTs = ''; // Thread parent timestamp\n @field({ description: 'The reactions people added to this message.' })\n reactions = ''; // JSON array of {name, count, users[]}\n @field({ description: 'Whether this message was edited after posting.' })\n isEdited = false;\n @field({\n description: 'The kind of message, such as one from a person or a bot.',\n })\n messageType = ''; // 'message', 'bot_message', etc.\n @field({\n description: 'The rich layout of the message as the workspace stores it.',\n })\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';\n// Register the package manifest before this module's @smrt() decorator\n// runs, whichever chunk the library build places it in (#3098).\nimport '../__smrt-register__.js';\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 { static __smrtPackage__ = \"@happyvertical/smrt-messages\";\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\n// Register the package manifest before this module's @smrt() decorator\n// runs, whichever chunk the library build places it in (#3098).\nimport '../__smrt-register__.js';\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 // Message is read-only over REST; this provider type is writable there.\n widenParentExposure: { api: ['create'] },\n})\nexport class Tweet extends Message { static __smrtPackage__ = \"@happyvertical/smrt-messages\";\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\n// Register the package manifest before this module's @smrt() decorator\n// runs, whichever chunk the library build places it in (#3098).\nimport '../__smrt-register__.js';\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 { static __smrtPackage__ = \"@happyvertical/smrt-messages\";\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';\n// Register the package manifest before this module's @smrt() decorator\n// runs, whichever chunk the library build places it in (#3098).\nimport '../__smrt-register__.js';\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 { static __smrtPackage__ = \"@happyvertical/smrt-messages\";\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 { Attachment, EmailClient } from '@happyvertical/email';\nimport type { Email } from '../models/Email';\nimport type { EmailAccount } from '../models/EmailAccount';\nimport type {\n MessageSenderInterface,\n MessageSendResult,\n SendEmailOptions,\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?: SendEmailOptions,\n ): Promise<MessageSendResult> {\n const toAddresses = message.getToAddresses();\n const ccAddresses = message.getCcAddresses();\n const bccAddresses = message.getBccAddresses();\n\n // Resolve every attachment before anything reaches the transport: a file\n // that cannot be read fails the send instead of leaving silently (#3808).\n let attachments: Attachment[];\n try {\n attachments = await this.collectAttachments(message, options);\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 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 attachments: attachments.length > 0 ? attachments : 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 /**\n * The message's stored `Attachment` rows followed by the send-time bytes.\n *\n * Stored rows are listed through the message's own options, so the lookup\n * runs under the same tenant context as the message. A row's file is read\n * through `Attachment.readContent()`, the package's one attachment-reading\n * seam, so the bytes are handed to the transport rather than a path it\n * would have to resolve itself.\n */\n private async collectAttachments(\n message: Email,\n options?: SendEmailOptions,\n ): Promise<Attachment[]> {\n const resolved: Attachment[] = [];\n\n // Only a message backed by a row can own attachment rows; an unsaved\n // draft sent directly through the sender has none to look up.\n const stored = message.isPersisted ? await message.getAttachments() : [];\n for (const attachment of stored) {\n if (\n message.tenantId &&\n attachment.tenantId &&\n attachment.tenantId !== message.tenantId\n ) {\n throw new Error(\n `Attachment \"${attachment.filename}\" belongs to another tenant than its message.`,\n );\n }\n if (!attachment.filePath) {\n throw new Error(\n `Attachment \"${attachment.filename}\" has no stored file to send` +\n (attachment.sourceUrl\n ? ' (a sourceUrl is not fetched at send time).'\n : '.'),\n );\n }\n const content = await attachment.readContent();\n if (!content) {\n throw new Error(\n `Attachment \"${attachment.filename}\" could not be read from \"${attachment.filePath}\": ` +\n 'the file is missing or unreadable, or the files SDK is not loaded ' +\n '(see Attachment.readContent()).',\n );\n }\n resolved.push({\n filename: attachment.filename,\n contentType: attachment.contentType || 'application/octet-stream',\n size: content.length,\n content,\n contentId: attachment.contentId || undefined,\n contentDisposition: attachment.contentDisposition,\n });\n }\n\n for (const attachment of options?.attachments ?? []) {\n if (!attachment.filename) {\n throw new Error('A send-time attachment needs a filename.');\n }\n if (!attachment.content) {\n throw new Error(\n `Send-time attachment \"${attachment.filename}\" has no content.`,\n );\n }\n const content = Buffer.isBuffer(attachment.content)\n ? attachment.content\n : Buffer.from(\n attachment.content.buffer,\n attachment.content.byteOffset,\n attachment.content.byteLength,\n );\n resolved.push({\n filename: attachment.filename,\n contentType: attachment.contentType || 'application/octet-stream',\n size: content.length,\n content,\n contentId: attachment.contentId,\n contentDisposition: attachment.contentDisposition ?? 'attachment',\n });\n }\n\n return resolved;\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 {\n MessageSendResult,\n SendEmailOptions,\n SendPersonaMessageOptions,\n} 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 if (input.attachments?.length && endpoint.channel !== 'email') {\n throw new Error('Attachments are only supported on email routes.');\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({\n ...base,\n textBody: base.body,\n hasAttachments: Boolean(input.attachments?.length),\n });\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 sendOptions: SendEmailOptions | undefined = input.attachments\n ?.length\n ? { attachments: input.attachments }\n : undefined;\n const delivery = await message.send(sendOptions);\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","import {\n isUniqueViolationError,\n type SmrtClassOptions,\n} from '@happyvertical/smrt-core';\nimport { withTenant } from '@happyvertical/smrt-tenancy';\nimport { UserNotificationCollection } from '../collections/UserNotificationCollection.js';\nimport {\n USER_NOTIFICATION_SEVERITIES,\n type UserNotification,\n type UserNotificationSeverity,\n} from '../models/UserNotification.js';\n\n/** What to tell one person. */\nexport interface UserNotificationInput {\n tenantId: string;\n recipientUserId: string;\n /** Host-defined type, e.g. `social-post.failed`. */\n kind: string;\n title: string;\n body?: string;\n href?: string | null;\n severity?: UserNotificationSeverity;\n /**\n * Dedupe key for the underlying event (e.g. `social-post:<id>:failed`). A\n * second `notify()` with the same `(tenantId, recipientUserId, sourceRef)`\n * returns the existing row untouched, read state included. Omit for\n * one-off notifications; a unique ref is generated.\n */\n sourceRef?: string;\n /** When the event happened (default: now). */\n occurredAt?: Date;\n}\n\nexport interface UserNotificationNotifyResult {\n notification: UserNotification;\n /** False when `sourceRef` matched an existing notification. */\n created: boolean;\n}\n\nexport interface UserNotificationListOptions {\n /** Tenants to read (at least one). Each is read under its own tenant scope. */\n tenantIds: readonly string[];\n /** Only rows not yet read. */\n unreadOnly?: boolean;\n /** Include dismissed rows (default false). */\n includeDismissed?: boolean;\n /** Only rows that happened at or after this time. */\n since?: Date;\n /** Newest-first cap across all tenants (default 50, max 200). */\n limit?: number;\n}\n\nexport interface UserNotificationScope {\n tenantId: string;\n}\n\n/** Notification ids are uuids; anything else can match no row. */\nconst UUID_PATTERN =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\nconst DEFAULT_LIMIT = 50;\nconst MAX_LIMIT = 200;\n\nfunction requireText(value: string | undefined, name: string): string {\n const text = value?.trim();\n if (!text) throw new Error(`A notification ${name} is required.`);\n return text;\n}\n\nfunction clampLimit(limit: number | undefined): number {\n if (limit === undefined) return DEFAULT_LIMIT;\n if (!Number.isInteger(limit) || limit < 1) {\n throw new Error('Notification list limit must be a positive integer.');\n }\n return Math.min(limit, MAX_LIMIT);\n}\n\n/**\n * Creates, lists, and updates per-user notifications (`UserNotification`).\n *\n * The service is the authorization boundary for the model: every read and\n * write is filtered to one recipient and runs under an explicit tenant\n * scope. The host decides who may be notified (e.g. the poster of a failed\n * social post) and passes the signed-in user's id for reads; it never lets\n * a request choose another user's id.\n */\nexport class UserNotificationService {\n constructor(private readonly options: { db: SmrtClassOptions['db'] }) {}\n\n private collection(): Promise<UserNotificationCollection> {\n return UserNotificationCollection.create({ db: this.options.db });\n }\n\n /** Store a notification unless its `sourceRef` already exists. */\n async notify(\n input: UserNotificationInput,\n ): Promise<UserNotificationNotifyResult> {\n const tenantId = requireText(input.tenantId, 'tenant');\n const recipientUserId = requireText(input.recipientUserId, 'recipient');\n const kind = requireText(input.kind, 'kind');\n const title = requireText(input.title, 'title');\n const severity = input.severity ?? 'info';\n if (!USER_NOTIFICATION_SEVERITIES.includes(severity)) {\n throw new Error(`Unknown notification severity '${severity}'.`);\n }\n const sourceRef =\n input.sourceRef?.trim() || `notification:${crypto.randomUUID()}`;\n\n return withTenant({ tenantId }, async () => {\n const notifications = await this.collection();\n const findExisting = async () =>\n (\n await notifications.list({\n where: { tenantId, recipientUserId, sourceRef },\n limit: 1,\n })\n )[0];\n const existing = await findExisting();\n if (existing) return { notification: existing, created: false };\n\n // Insert-only: a concurrent notify() for the same event may have stored\n // the row since the lookup above. An upsert would then overwrite it —\n // title, and read/dismissed state reset to null — so a collision is\n // resolved by returning the stored row untouched instead.\n let notification: UserNotification;\n try {\n notification = await notifications.create({\n _insertOnly: true,\n tenantId,\n recipientUserId,\n kind,\n title,\n body: input.body?.trim() ?? '',\n href: input.href ?? null,\n severity,\n sourceRef,\n occurredAt: input.occurredAt ?? new Date(),\n readAt: null,\n dismissedAt: null,\n });\n } catch (error) {\n if (!isUniqueViolationError(error)) throw error;\n const winner = await findExisting();\n if (!winner) throw error;\n return { notification: winner, created: false };\n }\n return { notification, created: true };\n });\n }\n\n /** `notify()` for each recipient (duplicates in the list are ignored). */\n async notifyMany(\n recipientUserIds: readonly string[],\n input: Omit<UserNotificationInput, 'recipientUserId'>,\n ): Promise<UserNotificationNotifyResult[]> {\n const results: UserNotificationNotifyResult[] = [];\n for (const recipientUserId of new Set(recipientUserIds)) {\n results.push(await this.notify({ ...input, recipientUserId }));\n }\n return results;\n }\n\n /** A user's notifications across the given tenants, newest first. */\n async listForUser(\n userId: string,\n options: UserNotificationListOptions,\n ): Promise<UserNotification[]> {\n const recipientUserId = requireText(userId, 'recipient');\n const limit = clampLimit(options.limit);\n const tenantIds = [...new Set(options.tenantIds.filter(Boolean))];\n const notifications = await this.collection();\n\n const perTenant = await Promise.all(\n tenantIds.map((tenantId) =>\n withTenant({ tenantId }, () =>\n notifications.list({\n where: {\n tenantId,\n recipientUserId,\n ...(options.includeDismissed ? {} : { dismissedAt: null }),\n ...(options.unreadOnly ? { readAt: null } : {}),\n ...(options.since ? { 'occurredAt >=': options.since } : {}),\n },\n orderBy: 'occurredAt DESC',\n limit,\n }),\n ),\n ),\n );\n\n return perTenant\n .flat()\n .sort((a, b) => b.occurredAt.getTime() - a.occurredAt.getTime())\n .slice(0, limit);\n }\n\n /** Unread, undismissed count across the given tenants. */\n async countUnread(\n userId: string,\n options: Pick<UserNotificationListOptions, 'tenantIds' | 'since'>,\n ): Promise<number> {\n const recipientUserId = requireText(userId, 'recipient');\n const notifications = await this.collection();\n const counts = await Promise.all(\n [...new Set(options.tenantIds.filter(Boolean))].map((tenantId) =>\n withTenant({ tenantId }, () =>\n notifications.count({\n where: {\n tenantId,\n recipientUserId,\n readAt: null,\n dismissedAt: null,\n ...(options.since ? { 'occurredAt >=': options.since } : {}),\n },\n }),\n ),\n ),\n );\n return counts.reduce((sum, count) => sum + Number(count), 0);\n }\n\n /** Mark the user's own notifications read; returns how many changed. */\n async markRead(\n userId: string,\n ids: readonly string[],\n scope: UserNotificationScope,\n ): Promise<number> {\n return this.stamp(userId, ids, scope, 'readAt');\n }\n\n /** Dismiss (and mark read) the user's own notifications. */\n async dismiss(\n userId: string,\n ids: readonly string[],\n scope: UserNotificationScope,\n ): Promise<number> {\n return this.stamp(userId, ids, scope, 'dismissedAt');\n }\n\n /** Mark every unread notification of the user in these tenants read. */\n async markAllRead(\n userId: string,\n options: Pick<UserNotificationListOptions, 'tenantIds'>,\n ): Promise<number> {\n const recipientUserId = requireText(userId, 'recipient');\n const notifications = await this.collection();\n const now = new Date();\n let changed = 0;\n for (const tenantId of new Set(options.tenantIds.filter(Boolean))) {\n changed += await withTenant({ tenantId }, async () => {\n const unread = await notifications.list({\n where: { tenantId, recipientUserId, readAt: null },\n });\n for (const notification of unread) {\n notification.readAt = now;\n await notification.save();\n }\n return unread.length;\n });\n }\n return changed;\n }\n\n private async stamp(\n userId: string,\n ids: readonly string[],\n scope: UserNotificationScope,\n column: 'readAt' | 'dismissedAt',\n ): Promise<number> {\n const recipientUserId = requireText(userId, 'recipient');\n const tenantId = requireText(scope.tenantId, 'tenant');\n // Ids come from requests. A malformed one can match no row, and on a\n // native uuid column (PostgreSQL) it would fail the whole query (22P02)\n // instead, so drop it before querying.\n const wanted = [\n ...new Set(\n ids.filter(\n (id): id is string => typeof id === 'string' && UUID_PATTERN.test(id),\n ),\n ),\n ];\n if (wanted.length === 0) return 0;\n\n return withTenant({ tenantId }, async () => {\n const notifications = await this.collection();\n // The recipient filter is the authorization check: another user's id\n // simply matches nothing.\n const rows = await notifications.list({\n where: { tenantId, recipientUserId, 'id in': wanted },\n });\n const now = new Date();\n let changed = 0;\n for (const notification of rows) {\n if (notification[column] !== null) continue;\n notification[column] = now;\n if (column === 'dismissedAt' && notification.readAt === null) {\n notification.readAt = now;\n }\n await notification.save();\n changed += 1;\n }\n return changed;\n });\n }\n}\n","import { SmrtRecipe } from '@happyvertical/smrt-core';\nimport { Email } from './models/Email.js';\nimport { EmailAccount } from './models/EmailAccount.js';\nimport { SlackAccount } from './models/SlackAccount.js';\nimport { SlackMessage } from './models/SlackMessage.js';\nimport { UserNotification } from './models/UserNotification.js';\n\n/** Email reading and composing with application-owned transport. */\nexport class MailboxRecipe extends SmrtRecipe {\n static id = 'messages.mailbox';\n static label = 'Mailbox';\n static summary = 'Read and compose email from your connected accounts.';\n static synonyms = ['email', 'inbox', 'mail'];\n static group = {\n id: 'messages',\n label: 'Messaging',\n summary: 'Choose email and personal updates independently.',\n };\n static section = {\n id: 'messages',\n label: 'Messaging',\n icon: 'folder',\n description: 'Read email and keep up with updates addressed to you.',\n };\n static models = [Email, EmailAccount];\n static runtime = 'both' as const;\n static surfaces = [\n {\n kind: 'route',\n path: '/messages/mailbox',\n export: '@happyvertical/smrt-messages/svelte#MessageList',\n label: 'Mailbox',\n },\n {\n kind: 'playground',\n export: '@happyvertical/smrt-messages/svelte#MailboxDemo',\n label: 'Mailbox with mocked sending',\n },\n ] as const;\n static providers = [\n {\n id: 'email-inbox',\n kind: 'email',\n options: ['imap', 'pop3', 'gmail'],\n required: true,\n },\n {\n id: 'email-send',\n kind: 'email',\n options: ['smtp', 'gmail'],\n required: false,\n },\n ];\n static demoSeed = {\n data: {\n accounts: [\n {\n id: 'demo-account',\n name: 'Demo Inbox',\n providerType: 'email',\n email: 'you@example.com',\n isActive: true,\n },\n ],\n messages: [\n {\n id: 'demo-welcome',\n type: 'email',\n accountId: 'demo-account',\n subject: 'Welcome to your mailbox',\n body: 'Fictional mail. Sending is mocked; nothing leaves this browser.',\n senderName: 'Demo colleague',\n senderAddress: 'colleague@example.com',\n recipientAddresses: [{ address: 'you@example.com' }],\n date: '2026-01-01T12:00:00Z',\n isRead: false,\n isFlagged: false,\n hasAttachments: false,\n },\n ],\n },\n };\n static nav = [\n {\n label: 'Mailbox',\n model: Email,\n key: 'mailbox',\n icon: 'folder',\n noun: 'email',\n description: 'Read email from your connected accounts.',\n },\n {\n label: 'Failed sends',\n model: Email,\n key: 'failed-sends',\n icon: 'fileText',\n noun: 'email',\n description: 'Review email whose last send attempt failed.',\n filter: { field: 'sendStatus', value: 'failed' },\n },\n ];\n static help = './help/mailbox.md';\n static options = {\n Email: {\n fields: {\n created_at: { help: 'When this email was first recorded.' },\n updated_at: { help: 'When this email record was last changed.' },\n },\n },\n EmailAccount: {\n fields: {\n created_at: {\n help: 'When this mailbox connection was first recorded.',\n },\n updated_at: { help: 'When this mailbox connection was last changed.' },\n },\n },\n } as const;\n}\n\n/** Recipient-scoped in-app notification bell. */\nexport class NotificationsRecipe extends SmrtRecipe {\n static id = 'messages.notifications';\n static label = 'Notifications';\n static summary = 'See updates addressed to you and mark them read.';\n static synonyms = ['alerts', 'notification bell'];\n static group = {\n id: 'messages',\n label: 'Messaging',\n summary: 'Choose email and personal updates independently.',\n };\n static section = {\n id: 'messages',\n label: 'Messaging',\n icon: 'folder',\n description: 'Read email and keep up with updates addressed to you.',\n };\n static models = [UserNotification];\n static runtime = 'both' as const;\n static surfaces = [\n {\n kind: 'shell-widget',\n slot: 'header.end',\n export: '@happyvertical/smrt-svelte/notifications#NotificationBell',\n label: 'Notifications',\n },\n ] as const;\n static providers = [\n {\n id: 'notifications',\n kind: 'notifications',\n options: ['user-notification-service'],\n required: true,\n },\n ];\n static demoSeed = {\n data: {\n items: [\n {\n id: 'demo-notification',\n title: 'You were mentioned',\n body: 'A fictional update for the demo user.',\n occurredAt: '2026-01-01T12:00:00Z',\n severity: 'info',\n readAt: null,\n },\n ],\n },\n };\n // Recipient-scoped reads use the bell provider, never generated model routes.\n static nav = [];\n static help = './help/notifications.md';\n}\n\n/** Slack messages from connected workspaces, read by channel and thread. */\nexport class SlackRecipe extends SmrtRecipe {\n static id = 'messages.slack';\n static label = 'Slack';\n static summary = 'Read Slack messages from your connected workspaces.';\n static synonyms = [\n 'slack',\n 'slack messages',\n 'slack channels',\n 'workspace chat',\n 'team chat',\n ];\n static group = {\n id: 'messages',\n label: 'Messaging',\n summary: 'Choose email and personal updates independently.',\n };\n static section = {\n id: 'messages',\n label: 'Messaging',\n icon: 'folder',\n description: 'Read email and keep up with updates addressed to you.',\n };\n static models = [SlackMessage, SlackAccount];\n static nav = [\n {\n label: 'Slack messages',\n model: SlackMessage,\n key: 'slack-messages',\n icon: 'folder',\n noun: 'message',\n description: 'Read messages from your connected workspaces by channel.',\n },\n {\n label: 'Slack workspaces',\n model: SlackAccount,\n icon: 'users',\n noun: 'workspace',\n description: 'The workspaces your application is connected to.',\n },\n ];\n static help = './help/slack.md';\n static options = {\n SlackMessage: {\n fields: {\n channelName: { label: 'Channel', order: 1 },\n body: { label: 'Message', order: 2 },\n threadId: { label: 'Thread', order: 3 },\n sendStatus: { label: 'Sent status', order: 4 },\n accountId: { label: 'Workspace', order: 5 },\n fromName: { label: 'From', visibility: 'advanced' },\n fromAddress: { visibility: 'advanced' },\n toAddresses: { visibility: 'advanced' },\n subject: { visibility: 'advanced' },\n date: { visibility: 'advanced' },\n isRead: { visibility: 'advanced' },\n isFlagged: { visibility: 'advanced' },\n isEdited: { label: 'Edited', visibility: 'advanced' },\n messageType: { label: 'Message kind', visibility: 'advanced' },\n reactions: { visibility: 'advanced' },\n hasAttachments: { visibility: 'advanced' },\n channelId: { visibility: 'advanced' },\n sentAt: { visibility: 'advanced' },\n sendError: { visibility: 'advanced' },\n scheduledSendAt: { visibility: 'advanced' },\n inReplyToMessageId: { label: 'Replying to', visibility: 'advanced' },\n personaId: { visibility: 'advanced' },\n endpointId: { visibility: 'advanced' },\n retryCount: { visibility: 'hidden' },\n maxRetries: { visibility: 'hidden' },\n size: { visibility: 'hidden' },\n correlationId: { visibility: 'hidden' },\n slackTs: { visibility: 'hidden' },\n slackThreadTs: { visibility: 'hidden' },\n blocks: { visibility: 'hidden' },\n metadata: { visibility: 'hidden' },\n tenantId: { visibility: 'hidden' },\n created_at: { help: 'When this message was first recorded.' },\n updated_at: { help: 'When this message record was last changed.' },\n },\n },\n SlackAccount: {\n fields: {\n name: { order: 1 },\n workspaceName: { label: 'Workspace', order: 2 },\n isActive: { label: 'Enabled', order: 3 },\n lastSyncAt: { label: 'Last checked', order: 4 },\n workspaceId: { visibility: 'advanced' },\n credentialSecretId: { visibility: 'hidden' },\n settings: { visibility: 'hidden' },\n botUserId: { label: 'Bot user', visibility: 'advanced' },\n providerType: { visibility: 'advanced' },\n channelType: { visibility: 'advanced' },\n configuration: { visibility: 'advanced' },\n tenantId: { visibility: 'hidden' },\n created_at: {\n help: 'When this workspace connection was first recorded.',\n },\n updated_at: {\n help: 'When this workspace connection was last changed.',\n },\n },\n },\n } as const;\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 { UserNotificationCollection } from './collections/UserNotificationCollection.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';\nexport {\n USER_NOTIFICATION_SEVERITIES,\n UserNotification,\n type UserNotificationOptions,\n type UserNotificationSeverity,\n} from './models/UserNotification.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';\nexport {\n type UserNotificationInput,\n type UserNotificationListOptions,\n type UserNotificationNotifyResult,\n type UserNotificationScope,\n UserNotificationService,\n} from './services/UserNotificationService.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 SendEmailAttachment,\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\nexport { MailboxRecipe, NotificationsRecipe, SlackRecipe } from './recipes.js';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["message","route"],"sources":["../src/permissions.ts","../src/models/Attachment.ts","../src/collections/AttachmentCollection.ts","../src/models/MessagingEndpoint.ts","../src/collections/MessagingEndpointCollection.ts","../src/models/NotificationDelivery.ts","../src/collections/NotificationDeliveryCollection.ts","../src/models/PersonaMessageRoute.ts","../src/collections/PersonaMessageRouteCollection.ts","../src/models/UserNotification.ts","../src/collections/UserNotificationCollection.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/NotificationOutboxService.ts","../src/services/PersonaMessagingService.ts","../src/services/UserNotificationService.ts","../src/recipes.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\n// Register the package manifest before this module's @smrt() decorator\n// runs, whichever chunk the library build places it in (#3098).\nimport '../__smrt-register__.js';\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/**\n * Split an absolute path into its directory and file name, or return null for\n * a relative path. Plain string handling rather than `node:path`: the package\n * root must stay browser-reachable (the bundle-gate forbids `node:*` there).\n */\nfunction splitAbsolutePath(\n filePath: string,\n): { dir: string; base: string } | null {\n // A backslash separates segments only in a Windows path; in a POSIX path it\n // is an ordinary filename character.\n const windows = /^[A-Za-z]:[\\\\/]/.test(filePath);\n if (!windows && !filePath.startsWith('/')) return null;\n const cut = windows\n ? Math.max(filePath.lastIndexOf('/'), filePath.lastIndexOf('\\\\'))\n : filePath.lastIndexOf('/');\n const dir = filePath.slice(0, cut) || filePath.slice(0, cut + 1);\n return { dir, base: filePath.slice(cut + 1) };\n}\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 { static __smrtPackage__ = \"@happyvertical/smrt-messages\";\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 * The local provider joins every path onto its base path (the process cwd\n * by default), so an absolute `filePath` is rooted at its own directory, and\n * the bytes are read raw: decoding a PDF as UTF-8 corrupts it (#3808).\n */\n async readContent(): Promise<Buffer | null> {\n if (!this.filePath) return null;\n\n try {\n const { getFilesystem, initializeProviders } =\n (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 // The SDK registers its providers asynchronously on import; make the\n // local one available before asking for it.\n await initializeProviders?.();\n const split = splitAbsolutePath(this.filePath);\n const files = await getFilesystem(\n split ? { type: 'local', basePath: split.dir } : { type: 'local' },\n );\n const data = await files.read(split ? split.base : this.filePath, {\n raw: true,\n });\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';\n// Register the package manifest before this module's @smrt() decorator\n// runs, whichever chunk the library build places it in (#3098).\nimport '../__smrt-register__.js';\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 { static __smrtPackage__ = \"@happyvertical/smrt-messages\";\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 type { SmrtObjectOptions } from '@happyvertical/smrt-core';\n// Register the package manifest before this module's @smrt() decorator\n// runs, whichever chunk the library build places it in (#3098).\nimport '../__smrt-register__.js';\nimport {\n crossPackageRef,\n field,\n foreignKey,\n SmrtObject,\n smrt,\n usesEmbeddedRevisionFallback,\n withEmbeddedWriteQueue,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\n\n/** Channels the notification outbox can deliver through. */\nexport type NotificationDeliveryChannel = 'email';\n\nexport const NOTIFICATION_DELIVERY_CHANNELS: readonly NotificationDeliveryChannel[] =\n ['email'];\n\n/**\n * Where a delivery is in its lifecycle.\n *\n * - `pending`: waiting for `nextAttemptAt`.\n * - `sending`: leased by one dispatcher until `leaseExpiresAt`.\n * - `sent`: the provider accepted it (terminal).\n * - `failed`: rejected for good or out of attempts (terminal).\n * - `uncertain`: handed to a provider whose outcome is unknown; waits for\n * reconciliation and is never resent automatically.\n * - `cancelled`: suppressed by the host before handoff (terminal).\n */\nexport type NotificationDeliveryStatus =\n | 'pending'\n | 'sending'\n | 'sent'\n | 'failed'\n | 'uncertain'\n | 'cancelled';\n\nexport interface NotificationDeliveryOptions extends SmrtObjectOptions {\n tenantId?: string;\n recipientUserId?: string;\n channel?: NotificationDeliveryChannel;\n sourceRef?: string;\n kind?: string;\n subject?: string;\n textBody?: string;\n href?: string;\n recipientAddress?: string;\n recipientName?: string;\n accountId?: string;\n messageId?: string | null;\n status?: NotificationDeliveryStatus;\n stateVersion?: number;\n transitionId?: string;\n attempts?: number;\n maxAttempts?: number;\n nextAttemptAt?: Date;\n leaseToken?: string | null;\n leaseExpiresAt?: Date | null;\n handedOffAt?: Date | null;\n deliveredAt?: Date | null;\n providerMessageId?: string;\n lastError?: string;\n}\n\n/** Column values a lease transition may change (camelCase field names). */\nexport type NotificationDeliveryTransition = Partial<\n Pick<\n NotificationDelivery,\n | 'messageId'\n | 'status'\n | 'attempts'\n | 'nextAttemptAt'\n | 'leaseToken'\n | 'leaseExpiresAt'\n | 'handedOffAt'\n | 'deliveredAt'\n | 'providerMessageId'\n | 'lastError'\n >\n>;\n\nconst TRANSITION_COLUMNS: Record<keyof NotificationDeliveryTransition, string> =\n {\n messageId: 'message_id',\n status: 'status',\n attempts: 'attempts',\n nextAttemptAt: 'next_attempt_at',\n leaseToken: 'lease_token',\n leaseExpiresAt: 'lease_expires_at',\n handedOffAt: 'handed_off_at',\n deliveredAt: 'delivered_at',\n providerMessageId: 'provider_message_id',\n lastError: 'last_error',\n };\n\n/**\n * One durable, source-keyed notification delivery to one person over one\n * external channel (the outbox row behind `NotificationOutboxService`).\n *\n * `sourceRef` is the idempotency key: one row per\n * `(tenant, recipient, channel, sourceRef)` (the conflict identity), and that\n * row produces at most one outbound `Message`. The recipient address is a\n * snapshot taken from the host's recipient resolver at enqueue time, never a\n * caller-chosen address.\n *\n * Every state change after creation goes through {@link transition}, a\n * compare-and-set on `stateVersion`, so concurrent dispatchers cannot both\n * hold the lease or overwrite each other's outcome. Generated REST/MCP/CLI\n * are off: rows carry recipient addresses and are reached only through the\n * service.\n */\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'notification_deliveries',\n api: false,\n mcp: false,\n cli: false,\n conflictColumns: ['tenant_id', 'recipient_user_id', 'channel', 'source_ref'],\n indexes: [\n {\n name: 'notification_deliveries_due_idx',\n columns: ['status', 'nextAttemptAt'],\n },\n {\n name: 'notification_deliveries_lease_idx',\n columns: ['status', 'leaseExpiresAt'],\n },\n ],\n})\nexport class NotificationDelivery extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-messages\";\n @tenantId()\n tenantId = '';\n\n /** The person being told (`smrt-users:User`, uuid). */\n @crossPackageRef('@happyvertical/smrt-users:User', { required: true })\n recipientUserId = '';\n\n /** Delivery channel; only `email` today. */\n @field({ required: true })\n channel: NotificationDeliveryChannel = 'email';\n\n /** Idempotency key for the underlying event (see class docs). */\n @field({ required: true })\n sourceRef = '';\n\n /** Host-defined type, e.g. `project-question.asked`. */\n @field({ required: true })\n kind = '';\n\n /** Email subject line. */\n @field({ required: true })\n subject = '';\n\n /** Plain-text body; the deep link is appended on its own line. */\n @field({ required: true })\n textBody = '';\n\n /** Absolute deep link on the host's configured origin (no credentials). */\n @field({ required: true })\n href = '';\n\n /** Address snapshot from the host recipient resolver. */\n @field({ required: true })\n recipientAddress = '';\n\n /** Display name snapshot from the host recipient resolver. */\n recipientName = '';\n\n /** Sender `EmailAccount` in the same tenant. */\n @foreignKey('Account')\n accountId = '';\n\n /** The single outbound `Message` (created under the first lease). */\n @foreignKey('Message')\n messageId: string | null = null;\n\n status: NotificationDeliveryStatus = 'pending';\n\n /** Compare-and-set counter; bumped by every transition. */\n stateVersion = 0;\n\n /** Unique id of the transition that wrote the current state. */\n transitionId = '';\n\n /** Leases acquired so far (provider handoffs are a subset). */\n attempts = 0;\n\n /** Lease budget before the delivery fails for good. */\n maxAttempts = 5;\n\n /** Earliest time a dispatcher may lease a `pending` row. */\n nextAttemptAt = new Date();\n\n /** Proof of the current lease holder; cleared when the lease ends. */\n leaseToken: string | null = null;\n\n /** When the current lease lapses and the row becomes recoverable. */\n leaseExpiresAt: Date | null = null;\n\n /** Set just before the current attempt reaches the provider. */\n handedOffAt: Date | null = null;\n\n /** When the provider accepted the message. */\n deliveredAt: Date | null = null;\n\n /** Provider message id, when the provider returns one. */\n providerMessageId = '';\n\n /** The latest failure or uncertainty reason. */\n lastError = '';\n\n constructor(options: NotificationDeliveryOptions = {}) {\n super(options);\n const assign = <K extends keyof NotificationDeliveryOptions>(key: K) => {\n if (options[key] !== undefined) {\n (this as unknown as Record<string, unknown>)[key as string] =\n options[key];\n }\n };\n for (const key of [\n 'tenantId',\n 'recipientUserId',\n 'channel',\n 'sourceRef',\n 'kind',\n 'subject',\n 'textBody',\n 'href',\n 'recipientAddress',\n 'recipientName',\n 'accountId',\n 'messageId',\n 'status',\n 'stateVersion',\n 'transitionId',\n 'attempts',\n 'maxAttempts',\n 'nextAttemptAt',\n 'leaseToken',\n 'leaseExpiresAt',\n 'handedOffAt',\n 'deliveredAt',\n 'providerMessageId',\n 'lastError',\n ] as const) {\n assign(key);\n }\n }\n\n /** Whether no further automatic work will happen on this row. */\n get isSettled(): boolean {\n return (\n this.status === 'sent' ||\n this.status === 'failed' ||\n this.status === 'cancelled' ||\n this.status === 'uncertain'\n );\n }\n\n /**\n * Apply `changes` only if the stored row is still at `stateVersion` (and,\n * when `leaseToken` is given, still held by that lease). Returns whether\n * this caller won; on success the instance reflects the stored row.\n *\n * PostgreSQL and remote LibSQL evaluate the guard in one conditional\n * UPDATE; local embedded engines use the process write queue, matching\n * `Message.send()`'s claim. The durable row is re-read either way, and the\n * write is recognised by its unique `transitionId`, because DuckDB's update\n * result over-reports affected rows.\n */\n async transition(\n changes: NotificationDeliveryTransition,\n expected: { leaseToken?: string } = {},\n ): Promise<boolean> {\n if (!this.id) throw new Error('Cannot transition an unsaved delivery.');\n const fromVersion = this.stateVersion;\n const nextVersion = fromVersion + 1;\n const transitionId = crypto.randomUUID();\n const values: Record<string, unknown> = {\n state_version: nextVersion,\n transition_id: transitionId,\n updated_at: new Date(),\n };\n for (const [key, value] of Object.entries(changes)) {\n const column =\n TRANSITION_COLUMNS[key as keyof NotificationDeliveryTransition];\n if (!column) throw new Error(`'${key}' is not a transition field.`);\n values[column] = value;\n }\n\n const matches = (row: Record<string, unknown> | null) =>\n row !== null &&\n Number(row.state_version) === fromVersion &&\n (expected.leaseToken === undefined ||\n row.lease_token === expected.leaseToken);\n\n const useEmbeddedFallback = usesEmbeddedRevisionFallback(this.db);\n await withEmbeddedWriteQueue(this.db, useEmbeddedFallback, async () => {\n if (useEmbeddedFallback) {\n const current = await this.getCanonicalPersistedRow({ id: this.id });\n if (!matches(current)) return;\n await this.db.upsert(this.tableName, ['id'], {\n ...current,\n ...values,\n });\n return;\n }\n await this.db.update(\n this.tableName,\n {\n id: this.id,\n tenant_id: this.tenantId,\n state_version: fromVersion,\n ...(expected.leaseToken === undefined\n ? {}\n : { lease_token: expected.leaseToken }),\n },\n values,\n );\n });\n\n const verified = await this.getCanonicalPersistedRow({ id: this.id });\n // The transition id, not the version, proves this caller's write won:\n // a losing caller would see the winner's identical next version.\n if (!verified || verified.transition_id !== transitionId) return false;\n await this.completePersistedUpdate(verified);\n return true;\n }\n}\n","import { SmrtCollection } from '@happyvertical/smrt-core';\nimport { NotificationDelivery } from '../models/NotificationDelivery.js';\n\nexport class NotificationDeliveryCollection extends SmrtCollection<NotificationDelivery> {\n static readonly _itemClass = NotificationDelivery;\n}\n","import {\n crossPackageRef,\n field,\n foreignKey,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\n// Register the package manifest before this module's @smrt() decorator\n// runs, whichever chunk the library build places it in (#3098).\nimport '../__smrt-register__.js';\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 { static __smrtPackage__ = \"@happyvertical/smrt-messages\";\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","import type { SmrtObjectOptions } from '@happyvertical/smrt-core';\n// Register the package manifest before this module's @smrt() decorator\n// runs, whichever chunk the library build places it in (#3098).\nimport '../__smrt-register__.js';\nimport {\n crossPackageRef,\n field,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\n\n/** How much a notification matters to its recipient. */\nexport type UserNotificationSeverity = 'info' | 'success' | 'warning' | 'error';\n\nexport const USER_NOTIFICATION_SEVERITIES: readonly UserNotificationSeverity[] =\n ['info', 'success', 'warning', 'error'];\n\nexport interface UserNotificationOptions extends SmrtObjectOptions {\n tenantId?: string;\n recipientUserId?: string;\n kind?: string;\n title?: string;\n body?: string;\n href?: string | null;\n severity?: UserNotificationSeverity;\n sourceRef?: string;\n occurredAt?: Date;\n readAt?: Date | null;\n dismissedAt?: Date | null;\n}\n\n/**\n * One in-app notification for one person, with its own read state.\n *\n * The in-app channel of smrt-messages: where `Message` is delivered through\n * an external provider, a `UserNotification` is stored for a user and shown\n * by the host (a bell, a notifications page). Create, list, and change read\n * state through `UserNotificationService`, which checks the recipient on\n * every write; the generated REST/MCP/CLI surfaces are off because a plain\n * tenant-scoped list would show every member's notifications.\n *\n * `sourceRef` is the dedupe key: one row per `(tenant, recipient, sourceRef)`\n * (the conflict identity), so re-deriving the same event (a failed social\n * post, a failed render) never notifies twice. The service generates a unique\n * ref when the caller has none.\n */\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'user_notifications',\n api: false,\n mcp: false,\n cli: false,\n conflictColumns: ['tenant_id', 'recipient_user_id', 'source_ref'],\n // The bell reads a recipient's newest rows in one tenant.\n indexes: [\n {\n name: 'user_notifications_recipient_occurred_idx',\n columns: ['tenantId', 'recipientUserId', 'occurredAt'],\n },\n ],\n})\nexport class UserNotification extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-messages\";\n @tenantId()\n tenantId = '';\n\n /** The person this notification is for (`smrt-users:User`, uuid). */\n @crossPackageRef('@happyvertical/smrt-users:User', { required: true })\n recipientUserId = '';\n\n /** Host-defined type, e.g. `social-post.failed` (used for icons/filters). */\n @field({ required: true })\n kind = '';\n\n /** One short plain sentence. */\n @field({ required: true })\n title = '';\n\n /** Optional detail line. */\n body = '';\n\n /** Where the notification leads (host-relative path or URL). */\n href: string | null = null;\n\n severity: UserNotificationSeverity = 'info';\n\n /** Dedupe key, unique per tenant and recipient (see class docs). */\n @field({ required: true })\n sourceRef = '';\n\n /** When the underlying event happened (sort key). */\n occurredAt = new Date();\n\n /** Set when the recipient has seen it. */\n readAt: Date | null = null;\n\n /** Set when the recipient has cleared it; dismissed rows are hidden. */\n dismissedAt: Date | null = null;\n\n constructor(options: UserNotificationOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.recipientUserId !== undefined)\n this.recipientUserId = options.recipientUserId;\n if (options.kind !== undefined) this.kind = options.kind;\n if (options.title !== undefined) this.title = options.title;\n if (options.body !== undefined) this.body = options.body;\n if (options.href !== undefined) this.href = options.href;\n if (options.severity !== undefined) this.severity = options.severity;\n if (options.sourceRef !== undefined) this.sourceRef = options.sourceRef;\n if (options.occurredAt !== undefined) this.occurredAt = options.occurredAt;\n if (options.readAt !== undefined) this.readAt = options.readAt;\n if (options.dismissedAt !== undefined)\n this.dismissedAt = options.dismissedAt;\n }\n\n get isRead(): boolean {\n return this.readAt !== null;\n }\n\n get isDismissed(): boolean {\n return this.dismissedAt !== null;\n }\n}\n","import { SmrtCollection } from '@happyvertical/smrt-core';\nimport { UserNotification } from '../models/UserNotification.js';\n\nexport class UserNotificationCollection extends SmrtCollection<UserNotification> {\n static readonly _itemClass = UserNotification;\n}\n","/**\n * EmailAccount model - Email account extending the Account STI base\n *\n * Retains email-specific fields and sync capability.\n */\n\n// Register the package manifest before this module's @smrt() decorator\n// runs, whichever chunk the library build places it in (#3098).\nimport '../__smrt-register__.js';\nimport type { FetchOptions, GetEmailClientOptions } from '@happyvertical/email';\nimport { field, 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 { static __smrtPackage__ = \"@happyvertical/smrt-messages\";\n @field({ description: 'The email address associated with this mailbox.' })\n email = '';\n @field({\n description: 'The time in minutes between scheduled mailbox checks.',\n })\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 * Read an immutable body/attachment-byte snapshot for an authorized intake host.\n * Does not sync, acknowledge, mark read or advance mailbox checkpoints.\n * Metadata-only providers fail explicitly; provider paths are never dereferenced.\n */\n async readIntakeMessage(\n locator: string,\n maxBytes: number,\n imapIdentity?: { folder: string; uidValidity: number; uid: string },\n ) {\n if (!this.id || !this.isActive || !locator) {\n throw new Error('Email intake account unavailable');\n }\n const client = await this.createClient();\n try {\n await client.connect();\n if (this.providerType === 'imap') {\n if (\n !imapIdentity?.folder ||\n !imapIdentity.uid ||\n !Number.isSafeInteger(imapIdentity.uidValidity)\n ) {\n throw new Error(\n 'IMAP intake requires folder and immutable UID identity',\n );\n }\n const folder = await client.selectFolder(imapIdentity.folder);\n if (folder.uidValidity !== imapIdentity.uidValidity) {\n throw new Error('IMAP intake identity changed');\n }\n }\n const message = await client.getMessage(locator);\n if (this.providerType === 'imap' && message.id !== imapIdentity?.uid) {\n throw new Error('IMAP intake identity changed');\n }\n const { snapshotEmailForIntake } = await import('../intake-snapshot.js');\n return snapshotEmailForIntake(this.id, message, maxBytes);\n } finally {\n await client.disconnect();\n }\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';\n// Register the package manifest before this module's @smrt() decorator\n// runs, whichever chunk the library build places it in (#3098).\nimport '../__smrt-register__.js';\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 { static __smrtPackage__ = \"@happyvertical/smrt-messages\";\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';\n// Register the package manifest before this module's @smrt() decorator\n// runs, whichever chunk the library build places it in (#3098).\nimport '../__smrt-register__.js';\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 { static __smrtPackage__ = \"@happyvertical/smrt-messages\";\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\n// Register the package manifest before this module's @smrt() decorator\n// runs, whichever chunk the library build places it in (#3098).\nimport '../__smrt-register__.js';\nimport { field, 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 { static __smrtPackage__ = \"@happyvertical/smrt-messages\";\n @field({ description: 'The identifier of the connected workspace.' })\n workspaceId = '';\n @field({ description: 'The name of the connected workspace.' })\n workspaceName = '';\n @field({\n description: 'The bot user your application posts as in this workspace.',\n })\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\n// Register the package manifest before this module's @smrt() decorator\n// runs, whichever chunk the library build places it in (#3098).\nimport '../__smrt-register__.js';\nimport { field, 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 // Message is read-only over REST; this provider type is writable there.\n widenParentExposure: { api: ['create'] },\n})\nexport class SlackMessage extends Message { static __smrtPackage__ = \"@happyvertical/smrt-messages\";\n @field({ description: 'The identifier of the channel this message is in.' })\n channelId = '';\n @field({ description: 'The name of the channel this message was posted in.' })\n channelName = '';\n @field({ description: \"The workspace's own reference for this message.\" })\n slackTs = ''; // Slack message timestamp (unique ID)\n @field({\n description:\n \"The workspace's own reference for the thread this message belongs to.\",\n })\n slackThreadTs = ''; // Thread parent timestamp\n @field({ description: 'The reactions people added to this message.' })\n reactions = ''; // JSON array of {name, count, users[]}\n @field({ description: 'Whether this message was edited after posting.' })\n isEdited = false;\n @field({\n description: 'The kind of message, such as one from a person or a bot.',\n })\n messageType = ''; // 'message', 'bot_message', etc.\n @field({\n description: 'The rich layout of the message as the workspace stores it.',\n })\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';\n// Register the package manifest before this module's @smrt() decorator\n// runs, whichever chunk the library build places it in (#3098).\nimport '../__smrt-register__.js';\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 { static __smrtPackage__ = \"@happyvertical/smrt-messages\";\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\n// Register the package manifest before this module's @smrt() decorator\n// runs, whichever chunk the library build places it in (#3098).\nimport '../__smrt-register__.js';\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 // Message is read-only over REST; this provider type is writable there.\n widenParentExposure: { api: ['create'] },\n})\nexport class Tweet extends Message { static __smrtPackage__ = \"@happyvertical/smrt-messages\";\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\n// Register the package manifest before this module's @smrt() decorator\n// runs, whichever chunk the library build places it in (#3098).\nimport '../__smrt-register__.js';\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 { static __smrtPackage__ = \"@happyvertical/smrt-messages\";\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';\n// Register the package manifest before this module's @smrt() decorator\n// runs, whichever chunk the library build places it in (#3098).\nimport '../__smrt-register__.js';\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 { static __smrtPackage__ = \"@happyvertical/smrt-messages\";\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 { Attachment, EmailClient } from '@happyvertical/email';\nimport type { Email } from '../models/Email';\nimport type { EmailAccount } from '../models/EmailAccount';\nimport type {\n MessageSenderInterface,\n MessageSendResult,\n SendEmailOptions,\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?: SendEmailOptions,\n ): Promise<MessageSendResult> {\n const toAddresses = message.getToAddresses();\n const ccAddresses = message.getCcAddresses();\n const bccAddresses = message.getBccAddresses();\n\n // Resolve every attachment before anything reaches the transport: a file\n // that cannot be read fails the send instead of leaving silently (#3808).\n let attachments: Attachment[];\n try {\n attachments = await this.collectAttachments(message, options);\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 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 attachments: attachments.length > 0 ? attachments : 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 ...(isDefiniteSendRejection(error) ? {} : { outcomeUnknown: true }),\n sentAt: new Date(),\n };\n }\n }\n\n /**\n * The message's stored `Attachment` rows followed by the send-time bytes.\n *\n * Stored rows are listed through the message's own options, so the lookup\n * runs under the same tenant context as the message. A row's file is read\n * through `Attachment.readContent()`, the package's one attachment-reading\n * seam, so the bytes are handed to the transport rather than a path it\n * would have to resolve itself.\n */\n private async collectAttachments(\n message: Email,\n options?: SendEmailOptions,\n ): Promise<Attachment[]> {\n const resolved: Attachment[] = [];\n\n // Only a message backed by a row can own attachment rows; an unsaved\n // draft sent directly through the sender has none to look up.\n const stored = message.isPersisted ? await message.getAttachments() : [];\n for (const attachment of stored) {\n if (\n message.tenantId &&\n attachment.tenantId &&\n attachment.tenantId !== message.tenantId\n ) {\n throw new Error(\n `Attachment \"${attachment.filename}\" belongs to another tenant than its message.`,\n );\n }\n if (!attachment.filePath) {\n throw new Error(\n `Attachment \"${attachment.filename}\" has no stored file to send` +\n (attachment.sourceUrl\n ? ' (a sourceUrl is not fetched at send time).'\n : '.'),\n );\n }\n const content = await attachment.readContent();\n if (!content) {\n throw new Error(\n `Attachment \"${attachment.filename}\" could not be read from \"${attachment.filePath}\": ` +\n 'the file is missing or unreadable, or the files SDK is not loaded ' +\n '(see Attachment.readContent()).',\n );\n }\n resolved.push({\n filename: attachment.filename,\n contentType: attachment.contentType || 'application/octet-stream',\n size: content.length,\n content,\n contentId: attachment.contentId || undefined,\n contentDisposition: attachment.contentDisposition,\n });\n }\n\n for (const attachment of options?.attachments ?? []) {\n if (!attachment.filename) {\n throw new Error('A send-time attachment needs a filename.');\n }\n if (!attachment.content) {\n throw new Error(\n `Send-time attachment \"${attachment.filename}\" has no content.`,\n );\n }\n const content = Buffer.isBuffer(attachment.content)\n ? attachment.content\n : Buffer.from(\n attachment.content.buffer,\n attachment.content.byteOffset,\n attachment.content.byteLength,\n );\n resolved.push({\n filename: attachment.filename,\n contentType: attachment.contentType || 'application/octet-stream',\n size: content.length,\n content,\n contentId: attachment.contentId,\n contentDisposition: attachment.contentDisposition ?? 'attachment',\n });\n }\n\n return resolved;\n }\n}\n\n/** Error codes the SDK email clients use for a send that was refused. */\nconst DEFINITE_EMAIL_ERROR_CODES = new Set([\n 'AUTHENTICATION_ERROR',\n 'AUTHORIZATION_ERROR',\n 'INVALID_MESSAGE',\n 'ATTACHMENT_ERROR',\n]);\n\n/** Socket errors raised before any connection to the server existed. */\nconst NEVER_CONNECTED_CODES = new Set([\n 'ECONNREFUSED',\n 'ENOTFOUND',\n 'EHOSTUNREACH',\n 'EAI_AGAIN',\n]);\n\n/**\n * Whether a provider send error proves the message was not accepted: the\n * server answered with an SMTP reply code, the SDK classified it as an\n * authentication/validation failure, a send error accepted no recipient, or\n * the connection was never made. Anything else (a timeout, a reset\n * connection, an unclassified error) may have happened after the server took\n * the message, so its outcome is unknown.\n */\nexport function isDefiniteSendRejection(error: unknown): boolean {\n if (!error || typeof error !== 'object') return false;\n const candidates = [error, (error as { cause?: unknown }).cause].filter(\n (value): value is Record<string, unknown> =>\n !!value && typeof value === 'object',\n );\n for (const candidate of candidates) {\n if (typeof candidate.responseCode === 'number') return true;\n if (typeof candidate.code === 'string') {\n if (DEFINITE_EMAIL_ERROR_CODES.has(candidate.code)) return true;\n if (NEVER_CONNECTED_CODES.has(candidate.code)) return true;\n }\n }\n const sendError = error as { code?: unknown; accepted?: unknown };\n return (\n sendError.code === 'SEND_ERROR' &&\n Array.isArray(sendError.accepted) &&\n sendError.accepted.length === 0\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 {\n isUniqueViolationError,\n type SmrtClassOptions,\n} from '@happyvertical/smrt-core';\nimport { withSystemContext, withTenant } from '@happyvertical/smrt-tenancy';\nimport { AccountCollection } from '../collections/AccountCollection.js';\nimport { EmailCollection } from '../collections/EmailCollection.js';\nimport { MessageCollection } from '../collections/MessageCollection.js';\nimport { NotificationDeliveryCollection } from '../collections/NotificationDeliveryCollection.js';\nimport { EmailAccount } from '../models/EmailAccount.js';\nimport type { Message } from '../models/Message.js';\nimport type {\n NotificationDelivery,\n NotificationDeliveryChannel,\n NotificationDeliveryTransition,\n} from '../models/NotificationDelivery.js';\nimport {\n assertMessagingPermission,\n type MessagingPrincipal,\n SEND_MESSAGES_PERMISSION,\n} from '../permissions.js';\n\n// ─────────────────────────────────────────────────────────────────────────\n// Transport seam\n// ─────────────────────────────────────────────────────────────────────────\n\n/** What a transport knows about one provider handoff. */\nexport type NotificationTransportOutcome =\n | { status: 'accepted'; providerMessageId?: string }\n | { status: 'rejected'; error: string; retryable: boolean }\n | { status: 'unknown'; error: string };\n\n/** What a transport can say about an earlier handoff during recovery. */\nexport type NotificationTransportReconciliation =\n | NotificationTransportOutcome\n | { status: 'not-sent' };\n\nexport interface NotificationTransportRequest {\n delivery: NotificationDelivery;\n /** The delivery's single outbound message (an `Email` for `email`). */\n message: Message;\n /** Stable per delivery; pass it to providers that dedupe on a key. */\n idempotencyKey: string;\n}\n\n/**\n * Hands one outbound message to a provider. The default\n * ({@link messageSendTransport}) delivers through `Message.send()` and the\n * message's account sender; tests and hosts with their own provider inject\n * another.\n */\nexport interface NotificationTransport {\n readonly name: string;\n /**\n * True only when the provider deduplicates on `idempotencyKey`, so sending\n * again after an unknown outcome cannot deliver twice. Then an unknown\n * outcome is retried; otherwise it becomes `uncertain`.\n */\n readonly idempotent?: boolean;\n send(\n request: NotificationTransportRequest,\n ): Promise<NotificationTransportOutcome>;\n /**\n * After a crash or lease loss following a handoff, report what is known\n * from durable state. Omit when nothing can be known (outcome: uncertain).\n */\n reconcile?(\n request: NotificationTransportRequest,\n ): Promise<NotificationTransportReconciliation>;\n}\n\n/**\n * Delivers through the canonical `Message.send()` (account → provider sender)\n * and reconciles from the message's own `sendStatus`.\n *\n * SMTP and the SDK email providers take no idempotency key, so this\n * transport is not idempotent: a handoff whose outcome is lost stays\n * `uncertain` instead of risking a second email.\n */\nexport const messageSendTransport: NotificationTransport = {\n name: 'message-send',\n idempotent: false,\n async send({ message }) {\n const result = await message.send();\n if (result.success) {\n return {\n status: 'accepted',\n ...(result.providerMessageId\n ? { providerMessageId: result.providerMessageId }\n : {}),\n };\n }\n // The provider may have taken it (a dropped connection or a thrown\n // sender), or send() refused because its own claim on the message\n // failed and another sender may be mid-flight: never retry blindly.\n if (\n result.outcomeUnknown ||\n message.sendStatus === 'sending' ||\n message.sendStatus === 'sent'\n ) {\n return {\n status: 'unknown',\n error: result.error ?? 'The provider did not confirm the outcome.',\n };\n }\n return {\n status: 'rejected',\n error: result.error ?? 'Send failed',\n retryable: true,\n };\n },\n async reconcile({ message }) {\n const messages = await MessageCollection.create({ db: message.db });\n const stored = message.id ? await messages.get({ id: message.id }) : null;\n switch (stored?.sendStatus) {\n case 'sent':\n return { status: 'accepted' };\n case 'failed':\n if (stored.isSendOutcomeUnknown()) {\n return {\n status: 'unknown',\n error:\n stored.sendError || 'The provider did not confirm the outcome.',\n };\n }\n return {\n status: 'rejected',\n error: stored.sendError || 'Send failed',\n retryable: true,\n };\n case 'draft':\n case 'pending':\n case 'scheduled':\n return { status: 'not-sent' };\n default:\n return {\n status: 'unknown',\n error: 'The provider handoff did not record an outcome.',\n };\n }\n },\n};\n\n// ─────────────────────────────────────────────────────────────────────────\n// Service contract\n// ─────────────────────────────────────────────────────────────────────────\n\nexport type NotificationOutboxDenialReason =\n | 'permission'\n | 'recipient'\n | 'sender'\n | 'link';\n\n/** Thrown when the host's policy refuses an enqueue; nothing is stored. */\nexport class NotificationOutboxDeniedError extends Error {\n constructor(\n readonly reason: NotificationOutboxDenialReason,\n message: string,\n ) {\n super(message);\n this.name = 'NotificationOutboxDeniedError';\n }\n}\n\nexport interface NotificationRecipientRequest {\n tenantId: string;\n recipientUserId: string;\n channel: NotificationDeliveryChannel;\n}\n\nexport interface NotificationRecipient {\n address: string;\n name?: string;\n}\n\nexport interface NotificationSuppressionRequest\n extends NotificationRecipientRequest {\n kind: string;\n sourceRef: string;\n}\n\nexport interface NotificationOutboxOptions {\n db: SmrtClassOptions['db'];\n /**\n * Host authorization for recipients: the address of `recipientUserId` when\n * the host allows notifying them in `tenantId` (e.g. a member of that\n * tenant), otherwise null, which denies the enqueue. Callers never supply\n * an address.\n */\n resolveRecipient(\n request: NotificationRecipientRequest,\n ): Promise<NotificationRecipient | null> | NotificationRecipient | null;\n /** The sending `EmailAccount` id for a tenant (deployment setup). */\n resolveSenderAccountId(request: {\n tenantId: string;\n }): Promise<string | null> | string | null;\n /** Absolute http(s) URL deep links are built on, e.g. `https://app.example.com`. */\n linkBaseUrl: string;\n /** Optional opt-out hook, checked at enqueue and again before handoff. */\n isSuppressed?(\n request: NotificationSuppressionRequest,\n ): Promise<boolean> | boolean;\n /** Provider seam; defaults to {@link messageSendTransport}. */\n transport?: NotificationTransport;\n /**\n * When set, enqueue and reconcile require `messages.send` in the tenant.\n * Omit only for trusted system code that performs its own authorization.\n */\n principal?: MessagingPrincipal;\n /** Lease length; must exceed the slowest provider handoff (default 5 min). */\n leaseMs?: number;\n /** Lease budget per delivery (default 5). */\n maxAttempts?: number;\n /** Delay before attempt `n + 1` after `n` failed (default 1 min · 2ⁿ⁻¹, ≤ 1 h). */\n retryDelayMs?(attempts: number): number;\n /** Clock (tests). */\n now?(): Date;\n}\n\nexport interface NotificationEmailInput {\n tenantId: string;\n recipientUserId: string;\n /** Idempotency key for the event, e.g. `project-question:<id>:asked`. */\n sourceRef: string;\n /** Host-defined type, e.g. `project-question.asked`. */\n kind: string;\n /** One line; CR/LF are rejected. */\n subject: string;\n /** Plain-text body; the deep link is appended on its own line. */\n text: string;\n /** Host-relative path of the deep link (`/portal/...`). */\n path: string;\n /** Do not send before this time (default: now). */\n notBefore?: Date;\n}\n\nexport interface NotificationEnqueueResult {\n delivery: NotificationDelivery;\n /** False when `sourceRef` matched an existing delivery (returned untouched). */\n created: boolean;\n}\n\nexport type NotificationDispatchOutcome =\n | 'sent'\n | 'retry-scheduled'\n | 'failed'\n | 'uncertain'\n | 'cancelled'\n | 'lease-lost';\n\nexport interface NotificationDispatchReport {\n /** Rows this call won a lease on. */\n leased: number;\n outcomes: Array<{\n deliveryId: string;\n tenantId: string;\n outcome: NotificationDispatchOutcome;\n }>;\n}\n\nexport interface NotificationDispatchOptions {\n /** Tenants to dispatch; omit to discover due rows across all tenants. */\n tenantIds?: readonly string[];\n /** Maximum rows to lease in this call (default 25, max 200). */\n limit?: number;\n}\n\nexport type NotificationReconcileOutcome = 'sent' | 'retry' | 'failed';\n\n/** Delivery ids are uuids; anything else can match no row. */\nconst UUID_PATTERN =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\nconst DEFAULT_LEASE_MS = 5 * 60_000;\nconst DEFAULT_MAX_ATTEMPTS = 5;\nconst DEFAULT_LIMIT = 25;\nconst MAX_LIMIT = 200;\n\nfunction defaultRetryDelayMs(attempts: number): number {\n return Math.min(60_000 * 2 ** Math.max(0, attempts - 1), 60 * 60_000);\n}\n\nfunction requireText(value: string | undefined, name: string): string {\n const text = value?.trim();\n if (!text) throw new Error(`A notification ${name} is required.`);\n return text;\n}\n\nfunction errorText(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/**\n * The id of a delivery's one outbound message: a name-based uuid derived from\n * the delivery id, so every dispatcher computes the same identity.\n */\nexport async function notificationDeliveryMessageId(\n deliveryId: string,\n): Promise<string> {\n const digest = await crypto.subtle.digest(\n 'SHA-256',\n new TextEncoder().encode(\n `smrt-messages:notification-delivery:${deliveryId}`,\n ),\n );\n const bytes = new Uint8Array(digest).slice(0, 16);\n bytes[6] = ((bytes[6] ?? 0) & 0x0f) | 0x50; // version 5 (name-based)\n bytes[8] = ((bytes[8] ?? 0) & 0x3f) | 0x80; // RFC 4122 variant\n const hex = [...bytes].map((byte) => byte.toString(16).padStart(2, '0'));\n return [\n hex.slice(0, 4),\n hex.slice(4, 6),\n hex.slice(6, 8),\n hex.slice(8, 10),\n hex.slice(10, 16),\n ]\n .map((group) => group.join(''))\n .join('-');\n}\n\n/** The correlation id that ties a delivery to its one outbound message. */\nexport function notificationDeliveryCorrelationId(deliveryId: string): string {\n return `notification-delivery:${deliveryId}`;\n}\n\n/**\n * Build an absolute deep link from a host-relative `path` on `baseUrl`.\n *\n * The link always stays on the configured origin (no `//host`, backslash, or\n * scheme tricks) and never carries credentials: the destination is an\n * ordinary authenticated route, so the recipient signs in as themselves.\n */\nexport function buildNotificationLink(baseUrl: string, path: string): string {\n let base: URL;\n try {\n base = new URL(baseUrl);\n } catch {\n throw new Error('Notification link base URL must be an absolute URL.');\n }\n if (base.protocol !== 'https:' && base.protocol !== 'http:') {\n throw new Error('Notification link base URL must use http or https.');\n }\n if (base.username || base.password || base.search || base.hash) {\n throw new Error(\n 'Notification link base URL must not carry credentials, a query, or a fragment.',\n );\n }\n if (\n typeof path !== 'string' ||\n !path.startsWith('/') ||\n path.startsWith('//') ||\n /[\\\\\\s]/u.test(path) ||\n // biome-ignore lint/suspicious/noControlCharactersInRegex: rejecting them is the point\n /[\\u0000-\\u001f\\u007f]/u.test(path)\n ) {\n throw new NotificationOutboxDeniedError(\n 'link',\n 'Notification links must be a host-relative path such as /inbox/123.',\n );\n }\n const prefix = base.pathname.replace(/\\/+$/u, '');\n const link = new URL(`${prefix}${path}`, base.origin);\n if (link.origin !== base.origin) {\n throw new NotificationOutboxDeniedError(\n 'link',\n 'Notification links must stay on the configured origin.',\n );\n }\n return link.toString();\n}\n\n/**\n * Source-keyed, durable notification email outbox.\n *\n * `enqueueEmail()` stores one `NotificationDelivery` per\n * `(tenant, recipient, email, sourceRef)` — a repeated event returns the\n * existing row — after the host has authorized the recipient and sender.\n * `dispatchDue()` leases due rows with a compare-and-set, creates the single\n * outbound `Email` under the lease, hands it to the transport, and records\n * the outcome; it is safe to run from several workers at once and to crash\n * at any point. See `packages/messages/agents/notification-outbox.md`.\n */\nexport class NotificationOutboxService {\n private readonly transport: NotificationTransport;\n private readonly leaseMs: number;\n private readonly maxAttempts: number;\n private readonly retryDelayMs: (attempts: number) => number;\n private readonly now: () => Date;\n\n constructor(private readonly options: NotificationOutboxOptions) {\n // Validate the configured origin eagerly so a bad deployment fails at boot.\n buildNotificationLink(options.linkBaseUrl, '/');\n this.transport = options.transport ?? messageSendTransport;\n this.leaseMs = options.leaseMs ?? DEFAULT_LEASE_MS;\n this.maxAttempts = options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;\n this.retryDelayMs = options.retryDelayMs ?? defaultRetryDelayMs;\n this.now = options.now ?? (() => new Date());\n if (!Number.isInteger(this.leaseMs) || this.leaseMs < 1_000) {\n throw new Error('Notification lease must be at least 1000 ms.');\n }\n if (!Number.isInteger(this.maxAttempts) || this.maxAttempts < 1) {\n throw new Error('Notification maxAttempts must be a positive integer.');\n }\n }\n\n private collection(): Promise<NotificationDeliveryCollection> {\n return NotificationDeliveryCollection.create({ db: this.options.db });\n }\n\n private authorize(tenantId: string): void {\n if (!this.options.principal) return;\n try {\n assertMessagingPermission(\n this.options.principal,\n tenantId,\n SEND_MESSAGES_PERMISSION,\n );\n } catch (error) {\n throw new NotificationOutboxDeniedError('permission', errorText(error));\n }\n }\n\n /** Store one email delivery for the event unless `sourceRef` already has one. */\n async enqueueEmail(\n input: NotificationEmailInput,\n ): Promise<NotificationEnqueueResult> {\n const tenantId = requireText(input.tenantId, 'tenant');\n const recipientUserId = requireText(input.recipientUserId, 'recipient');\n const sourceRef = requireText(input.sourceRef, 'sourceRef');\n const kind = requireText(input.kind, 'kind');\n const subject = requireText(input.subject, 'subject');\n const text = requireText(input.text, 'text');\n if (/[\\r\\n]/u.test(subject)) {\n throw new Error('A notification subject must be a single line.');\n }\n const channel: NotificationDeliveryChannel = 'email';\n this.authorize(tenantId);\n const href = buildNotificationLink(this.options.linkBaseUrl, input.path);\n\n return withTenant({ tenantId }, async () => {\n const deliveries = await this.collection();\n const findExisting = async () =>\n (\n await deliveries.list({\n where: { tenantId, recipientUserId, channel, sourceRef },\n limit: 1,\n })\n )[0];\n const existing = await findExisting();\n if (existing) return { delivery: existing, created: false };\n\n const recipient = await this.options.resolveRecipient({\n tenantId,\n recipientUserId,\n channel,\n });\n const address = recipient?.address?.trim();\n if (!address || /[\\s,;<>]/u.test(address) || !address.includes('@')) {\n throw new NotificationOutboxDeniedError(\n 'recipient',\n 'The host did not authorize an email recipient for this user.',\n );\n }\n const accountId = await this.requireSenderAccount(tenantId);\n const suppressed = await this.isSuppressed({\n tenantId,\n recipientUserId,\n channel,\n kind,\n sourceRef,\n });\n\n try {\n const delivery = await deliveries.create({\n _insertOnly: true,\n tenantId,\n recipientUserId,\n channel,\n sourceRef,\n kind,\n subject,\n textBody: text,\n href,\n recipientAddress: address,\n recipientName: recipient?.name?.trim() ?? '',\n accountId,\n messageId: null,\n status: suppressed ? 'cancelled' : 'pending',\n stateVersion: 0,\n transitionId: '',\n attempts: 0,\n maxAttempts: this.maxAttempts,\n nextAttemptAt: input.notBefore ?? this.now(),\n leaseToken: null,\n leaseExpiresAt: null,\n handedOffAt: null,\n deliveredAt: null,\n providerMessageId: '',\n lastError: suppressed ? 'Suppressed by recipient preference.' : '',\n });\n return { delivery, created: true };\n } catch (error) {\n if (!isUniqueViolationError(error)) throw error;\n const winner = await findExisting();\n if (!winner) throw error;\n return { delivery: winner, created: false };\n }\n });\n }\n\n /** Lease and deliver due rows; returns what happened to each leased row. */\n async dispatchDue(\n options: NotificationDispatchOptions = {},\n ): Promise<NotificationDispatchReport> {\n const limit = Math.min(options.limit ?? DEFAULT_LIMIT, MAX_LIMIT);\n if (!Number.isInteger(limit) || limit < 1) {\n throw new Error(\n 'Notification dispatch limit must be a positive integer.',\n );\n }\n const candidates = await this.findDue(options.tenantIds, limit);\n const report: NotificationDispatchReport = { leased: 0, outcomes: [] };\n for (const candidate of candidates) {\n if (report.leased >= limit) break;\n const outcome = await withTenant({ tenantId: candidate.tenantId }, () =>\n this.dispatchOne(candidate),\n );\n if (!outcome) continue;\n report.leased += 1;\n report.outcomes.push({\n deliveryId: candidate.id as string,\n tenantId: candidate.tenantId,\n outcome,\n });\n }\n return report;\n }\n\n /** Deliveries waiting for a reconciliation decision, oldest first. */\n async listUncertain(options: {\n tenantId: string;\n limit?: number;\n }): Promise<NotificationDelivery[]> {\n const tenantId = requireText(options.tenantId, 'tenant');\n this.authorize(tenantId);\n return withTenant({ tenantId }, async () =>\n (await this.collection()).list({\n where: { tenantId, status: 'uncertain' },\n orderBy: 'handedOffAt ASC',\n limit: Math.min(options.limit ?? DEFAULT_LIMIT, MAX_LIMIT),\n }),\n );\n }\n\n /**\n * Settle an `uncertain` delivery after checking the provider out of band:\n * `sent` (it arrived), `failed` (give up), or `retry` (send again,\n * accepting the risk of a duplicate; a message left claimed by a dead\n * sender is released first). Returns false when the row is not uncertain\n * any more, or for `retry` when the message is recorded as sent.\n */\n async reconcile(input: {\n tenantId: string;\n deliveryId: string;\n outcome: NotificationReconcileOutcome;\n note?: string;\n }): Promise<boolean> {\n const tenantId = requireText(input.tenantId, 'tenant');\n this.authorize(tenantId);\n // Ids may come from requests; on a native uuid column (PostgreSQL) a\n // malformed one would fail the query (22P02) instead of matching nothing.\n if (!UUID_PATTERN.test(input.deliveryId ?? '')) return false;\n return withTenant({ tenantId }, async () => {\n const delivery = (\n await (\n await this.collection()\n ).list({\n where: { tenantId, id: input.deliveryId },\n limit: 1,\n })\n )[0];\n if (delivery?.status !== 'uncertain') return false;\n const note = input.note?.trim();\n const now = this.now();\n switch (input.outcome) {\n case 'sent':\n return delivery.transition({\n status: 'sent',\n deliveredAt: now,\n ...(note ? { lastError: note } : {}),\n });\n case 'failed':\n return delivery.transition({\n status: 'failed',\n lastError: note || delivery.lastError,\n });\n case 'retry': {\n // The canonical message must be sendable again: a crash can leave\n // it claimed ('sending') by a sender that no longer exists. The\n // delivery is uncertain, so no dispatcher holds it.\n const message = delivery.messageId\n ? await this.loadMessage(delivery.messageId)\n : null;\n if (message?.sendStatus === 'sent') return false;\n if (\n message?.sendStatus === 'sending' &&\n !(await message.abandonSendAttempt(\n note || 'Released for an operator-approved retry.',\n ))\n ) {\n return false;\n }\n return delivery.transition({\n status: 'pending',\n nextAttemptAt: now,\n handedOffAt: null,\n // One more lease, so a delivery already at its budget can retry.\n attempts: Math.min(delivery.attempts, delivery.maxAttempts - 1),\n ...(note ? { lastError: note } : {}),\n });\n }\n default:\n throw new Error(`Unknown reconcile outcome '${input.outcome}'.`);\n }\n });\n }\n\n // ───────────────────────────────────────────────────────────────────────\n\n private async requireSenderAccount(tenantId: string): Promise<string> {\n const accountId = (\n await this.options.resolveSenderAccountId({ tenantId })\n )?.trim();\n const account = accountId\n ? await (await AccountCollection.create({ db: this.options.db })).get({\n id: accountId,\n })\n : null;\n if (\n !account ||\n !(account instanceof EmailAccount) ||\n account.tenantId !== tenantId ||\n !account.isActive\n ) {\n throw new NotificationOutboxDeniedError(\n 'sender',\n 'No active email sender account is configured for this tenant.',\n );\n }\n return account.id as string;\n }\n\n private async isSuppressed(\n request: NotificationSuppressionRequest,\n ): Promise<boolean> {\n return Boolean(await this.options.isSuppressed?.(request));\n }\n\n private async findDue(\n tenantIds: readonly string[] | undefined,\n limit: number,\n ): Promise<NotificationDelivery[]> {\n const now = this.now();\n const read = async (tenantFilter: { tenantId?: string }) => {\n const deliveries = await this.collection();\n const [due, expired] = await Promise.all([\n deliveries.list({\n where: {\n ...tenantFilter,\n status: 'pending',\n 'nextAttemptAt <=': now,\n },\n orderBy: 'nextAttemptAt ASC',\n limit,\n }),\n deliveries.list({\n where: {\n ...tenantFilter,\n status: 'sending',\n 'leaseExpiresAt <=': now,\n },\n orderBy: 'leaseExpiresAt ASC',\n limit,\n }),\n ]);\n return [...expired, ...due];\n };\n\n const rows =\n tenantIds === undefined\n ? await withSystemContext(() => read({}))\n : (\n await Promise.all(\n [...new Set(tenantIds.filter(Boolean))].map((tenantId) =>\n withTenant({ tenantId }, () => read({ tenantId })),\n ),\n )\n ).flat();\n // Recover lapsed leases first, then oldest due.\n return rows.slice(0, limit * 2);\n }\n\n /** Lease one candidate and carry it to an outcome; null when not leased. */\n private async dispatchOne(\n candidate: NotificationDelivery,\n ): Promise<NotificationDispatchOutcome | null> {\n // Re-read under the tenant scope; the candidate may be stale.\n const delivery = (\n await (\n await this.collection()\n ).list({\n where: { tenantId: candidate.tenantId, id: candidate.id },\n limit: 1,\n })\n )[0];\n if (!delivery) return null;\n const now = this.now();\n\n const recovering =\n delivery.status === 'sending' &&\n delivery.leaseExpiresAt !== null &&\n delivery.leaseExpiresAt.getTime() <= now.getTime();\n const due =\n delivery.status === 'pending' &&\n delivery.nextAttemptAt.getTime() <= now.getTime();\n if (!recovering && !due) return null;\n\n const leaseToken = crypto.randomUUID();\n const leaseExpiresAt = new Date(now.getTime() + this.leaseMs);\n // A lapsed lease whose attempt already reached the provider is a crash or\n // lease loss mid-handoff: learn what we can before anything is resent.\n const priorHandoff = recovering && delivery.handedOffAt !== null;\n const won = await delivery.transition({\n status: 'sending',\n leaseToken,\n leaseExpiresAt,\n attempts: priorHandoff ? delivery.attempts : delivery.attempts + 1,\n ...(priorHandoff ? {} : { handedOffAt: null }),\n });\n if (!won) return null;\n\n try {\n if (priorHandoff) {\n const resolved = await this.recoverHandoff(delivery, leaseToken);\n if (resolved) return resolved;\n }\n\n if (\n await this.isSuppressed({\n tenantId: delivery.tenantId,\n recipientUserId: delivery.recipientUserId,\n channel: delivery.channel,\n kind: delivery.kind,\n sourceRef: delivery.sourceRef,\n })\n ) {\n return this.settle(delivery, leaseToken, {\n status: 'cancelled',\n lastError: 'Suppressed by recipient preference.',\n });\n }\n\n const message = await this.ensureMessage(delivery, leaseToken);\n if (!message) return 'lease-lost';\n if (\n !(await delivery.transition(\n { handedOffAt: this.now() },\n { leaseToken },\n ))\n ) {\n return 'lease-lost';\n }\n\n let outcome: NotificationTransportOutcome;\n try {\n outcome = await this.transport.send({\n delivery,\n message,\n idempotencyKey: notificationDeliveryCorrelationId(\n delivery.id as string,\n ),\n });\n } catch (error) {\n // A throw after handoff says nothing about whether the provider\n // accepted the message.\n outcome = { status: 'unknown', error: errorText(error) };\n }\n return this.applyOutcome(delivery, leaseToken, outcome);\n } catch (error) {\n // A failure before handoff (message creation, suppression hook) is safe\n // to retry; one after handoff has already been mapped to an outcome.\n if (delivery.handedOffAt !== null) throw error;\n return this.applyOutcome(delivery, leaseToken, {\n status: 'rejected',\n error: errorText(error),\n retryable: true,\n });\n }\n }\n\n private async recoverHandoff(\n delivery: NotificationDelivery,\n leaseToken: string,\n ): Promise<NotificationDispatchOutcome | null> {\n const message = delivery.messageId\n ? await this.loadMessage(delivery.messageId)\n : null;\n let known: NotificationTransportReconciliation = {\n status: 'unknown',\n error: 'Lease lapsed after the provider handoff; outcome unknown.',\n };\n if (message && this.transport.reconcile) {\n try {\n known = await this.transport.reconcile({\n delivery,\n message,\n idempotencyKey: notificationDeliveryCorrelationId(\n delivery.id as string,\n ),\n });\n } catch (error) {\n known = { status: 'unknown', error: errorText(error) };\n }\n }\n if (known.status === 'not-sent') {\n // Nothing reached the provider; this lease becomes a fresh attempt.\n if (\n !(await delivery.transition(\n { handedOffAt: null, attempts: delivery.attempts + 1 },\n { leaseToken },\n ))\n ) {\n return 'lease-lost';\n }\n return null;\n }\n if (known.status === 'unknown' && this.transport.idempotent) {\n // The provider dedupes on the key: resending is the reconciliation.\n if (\n !(await delivery.transition(\n { handedOffAt: null, attempts: delivery.attempts + 1 },\n { leaseToken },\n ))\n ) {\n return 'lease-lost';\n }\n return null;\n }\n return this.applyOutcome(delivery, leaseToken, known);\n }\n\n private async applyOutcome(\n delivery: NotificationDelivery,\n leaseToken: string,\n outcome: NotificationTransportOutcome,\n ): Promise<NotificationDispatchOutcome> {\n if (outcome.status === 'accepted') {\n return this.settle(delivery, leaseToken, {\n status: 'sent',\n deliveredAt: this.now(),\n providerMessageId: outcome.providerMessageId ?? '',\n lastError: '',\n });\n }\n if (outcome.status === 'unknown') {\n if (\n this.transport.idempotent &&\n delivery.attempts < delivery.maxAttempts\n ) {\n return this.scheduleRetry(delivery, leaseToken, outcome.error);\n }\n return this.settle(delivery, leaseToken, {\n status: 'uncertain',\n lastError: outcome.error,\n });\n }\n if (outcome.retryable && delivery.attempts < delivery.maxAttempts) {\n return this.scheduleRetry(delivery, leaseToken, outcome.error);\n }\n return this.settle(delivery, leaseToken, {\n status: 'failed',\n lastError: outcome.error,\n });\n }\n\n private async scheduleRetry(\n delivery: NotificationDelivery,\n leaseToken: string,\n error: string,\n ): Promise<NotificationDispatchOutcome> {\n const delay = this.retryDelayMs(delivery.attempts);\n const won = await this.endLease(delivery, leaseToken, {\n status: 'pending',\n nextAttemptAt: new Date(this.now().getTime() + Math.max(0, delay)),\n handedOffAt: null,\n lastError: error,\n });\n return won ? 'retry-scheduled' : 'lease-lost';\n }\n\n /** End the lease in a terminal status; reports lease loss instead of overwriting. */\n private async settle(\n delivery: NotificationDelivery,\n leaseToken: string,\n changes: NotificationDeliveryTransition & {\n status: 'sent' | 'failed' | 'uncertain' | 'cancelled';\n },\n ): Promise<NotificationDispatchOutcome> {\n const won = await this.endLease(delivery, leaseToken, changes);\n return won ? changes.status : 'lease-lost';\n }\n\n private endLease(\n delivery: NotificationDelivery,\n leaseToken: string,\n changes: NotificationDeliveryTransition,\n ): Promise<boolean> {\n return delivery.transition(\n { ...changes, leaseToken: null, leaseExpiresAt: null },\n { leaseToken },\n );\n }\n\n private async loadMessage(messageId: string): Promise<Message | null> {\n const messages = await MessageCollection.create({ db: this.options.db });\n return (await messages.get({ id: messageId })) ?? null;\n }\n\n /**\n * The delivery's single outbound `Email`, created under the lease. Its id\n * is derived from the delivery id and inserted insert-only, so a stale\n * dispatcher that resumes after its lease was taken over hits the stored\n * row (a unique violation) instead of creating a second email.\n */\n private async ensureMessage(\n delivery: NotificationDelivery,\n leaseToken: string,\n ): Promise<Message | null> {\n if (delivery.messageId) {\n const message = await this.loadMessage(delivery.messageId);\n if (message) return message;\n }\n const messageId = await notificationDeliveryMessageId(\n delivery.id as string,\n );\n let message = await this.loadMessage(messageId);\n if (!message) {\n const body = `${delivery.textBody}\\n\\n${delivery.href}\\n`;\n const emails = await EmailCollection.create({ db: this.options.db });\n try {\n await emails.create({\n _insertOnly: true,\n id: messageId,\n tenantId: delivery.tenantId,\n accountId: delivery.accountId,\n correlationId: notificationDeliveryCorrelationId(\n delivery.id as string,\n ),\n subject: delivery.subject,\n body,\n textBody: body,\n toAddresses: JSON.stringify([\n {\n address: delivery.recipientAddress,\n ...(delivery.recipientName\n ? { name: delivery.recipientName }\n : {}),\n },\n ]),\n sendStatus: 'pending',\n // Delivery is owned by the outbox's attempt budget, not the message's.\n maxRetries: 0,\n });\n } catch (error) {\n if (!isUniqueViolationError(error)) throw error;\n }\n // Reload so send()'s compare-and-set sees the stored revision.\n message = await this.loadMessage(messageId);\n if (!message) throw new Error('The outbound email could not be stored.');\n }\n if (delivery.messageId !== message.id) {\n if (\n !(await delivery.transition(\n { messageId: message.id as string },\n { leaseToken },\n ))\n ) {\n return null;\n }\n }\n return message;\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 {\n MessageSendResult,\n SendEmailOptions,\n SendPersonaMessageOptions,\n} 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 if (input.attachments?.length && endpoint.channel !== 'email') {\n throw new Error('Attachments are only supported on email routes.');\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({\n ...base,\n textBody: base.body,\n hasAttachments: Boolean(input.attachments?.length),\n });\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 sendOptions: SendEmailOptions | undefined = input.attachments\n ?.length\n ? { attachments: input.attachments }\n : undefined;\n const delivery = await message.send(sendOptions);\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","import {\n isUniqueViolationError,\n type SmrtClassOptions,\n} from '@happyvertical/smrt-core';\nimport { withTenant } from '@happyvertical/smrt-tenancy';\nimport { UserNotificationCollection } from '../collections/UserNotificationCollection.js';\nimport {\n USER_NOTIFICATION_SEVERITIES,\n type UserNotification,\n type UserNotificationSeverity,\n} from '../models/UserNotification.js';\n\n/** What to tell one person. */\nexport interface UserNotificationInput {\n tenantId: string;\n recipientUserId: string;\n /** Host-defined type, e.g. `social-post.failed`. */\n kind: string;\n title: string;\n body?: string;\n href?: string | null;\n severity?: UserNotificationSeverity;\n /**\n * Dedupe key for the underlying event (e.g. `social-post:<id>:failed`). A\n * second `notify()` with the same `(tenantId, recipientUserId, sourceRef)`\n * returns the existing row untouched, read state included. Omit for\n * one-off notifications; a unique ref is generated.\n */\n sourceRef?: string;\n /** When the event happened (default: now). */\n occurredAt?: Date;\n}\n\nexport interface UserNotificationNotifyResult {\n notification: UserNotification;\n /** False when `sourceRef` matched an existing notification. */\n created: boolean;\n}\n\nexport interface UserNotificationListOptions {\n /** Tenants to read (at least one). Each is read under its own tenant scope. */\n tenantIds: readonly string[];\n /** Only rows not yet read. */\n unreadOnly?: boolean;\n /** Include dismissed rows (default false). */\n includeDismissed?: boolean;\n /** Only rows that happened at or after this time. */\n since?: Date;\n /** Newest-first cap across all tenants (default 50, max 200). */\n limit?: number;\n}\n\nexport interface UserNotificationScope {\n tenantId: string;\n}\n\n/** Notification ids are uuids; anything else can match no row. */\nconst UUID_PATTERN =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\nconst DEFAULT_LIMIT = 50;\nconst MAX_LIMIT = 200;\n\nfunction requireText(value: string | undefined, name: string): string {\n const text = value?.trim();\n if (!text) throw new Error(`A notification ${name} is required.`);\n return text;\n}\n\nfunction clampLimit(limit: number | undefined): number {\n if (limit === undefined) return DEFAULT_LIMIT;\n if (!Number.isInteger(limit) || limit < 1) {\n throw new Error('Notification list limit must be a positive integer.');\n }\n return Math.min(limit, MAX_LIMIT);\n}\n\n/**\n * Creates, lists, and updates per-user notifications (`UserNotification`).\n *\n * The service is the authorization boundary for the model: every read and\n * write is filtered to one recipient and runs under an explicit tenant\n * scope. The host decides who may be notified (e.g. the poster of a failed\n * social post) and passes the signed-in user's id for reads; it never lets\n * a request choose another user's id.\n */\nexport class UserNotificationService {\n constructor(private readonly options: { db: SmrtClassOptions['db'] }) {}\n\n private collection(): Promise<UserNotificationCollection> {\n return UserNotificationCollection.create({ db: this.options.db });\n }\n\n /** Store a notification unless its `sourceRef` already exists. */\n async notify(\n input: UserNotificationInput,\n ): Promise<UserNotificationNotifyResult> {\n const tenantId = requireText(input.tenantId, 'tenant');\n const recipientUserId = requireText(input.recipientUserId, 'recipient');\n const kind = requireText(input.kind, 'kind');\n const title = requireText(input.title, 'title');\n const severity = input.severity ?? 'info';\n if (!USER_NOTIFICATION_SEVERITIES.includes(severity)) {\n throw new Error(`Unknown notification severity '${severity}'.`);\n }\n const sourceRef =\n input.sourceRef?.trim() || `notification:${crypto.randomUUID()}`;\n\n return withTenant({ tenantId }, async () => {\n const notifications = await this.collection();\n const findExisting = async () =>\n (\n await notifications.list({\n where: { tenantId, recipientUserId, sourceRef },\n limit: 1,\n })\n )[0];\n const existing = await findExisting();\n if (existing) return { notification: existing, created: false };\n\n // Insert-only: a concurrent notify() for the same event may have stored\n // the row since the lookup above. An upsert would then overwrite it —\n // title, and read/dismissed state reset to null — so a collision is\n // resolved by returning the stored row untouched instead.\n let notification: UserNotification;\n try {\n notification = await notifications.create({\n _insertOnly: true,\n tenantId,\n recipientUserId,\n kind,\n title,\n body: input.body?.trim() ?? '',\n href: input.href ?? null,\n severity,\n sourceRef,\n occurredAt: input.occurredAt ?? new Date(),\n readAt: null,\n dismissedAt: null,\n });\n } catch (error) {\n if (!isUniqueViolationError(error)) throw error;\n const winner = await findExisting();\n if (!winner) throw error;\n return { notification: winner, created: false };\n }\n return { notification, created: true };\n });\n }\n\n /** `notify()` for each recipient (duplicates in the list are ignored). */\n async notifyMany(\n recipientUserIds: readonly string[],\n input: Omit<UserNotificationInput, 'recipientUserId'>,\n ): Promise<UserNotificationNotifyResult[]> {\n const results: UserNotificationNotifyResult[] = [];\n for (const recipientUserId of new Set(recipientUserIds)) {\n results.push(await this.notify({ ...input, recipientUserId }));\n }\n return results;\n }\n\n /** A user's notifications across the given tenants, newest first. */\n async listForUser(\n userId: string,\n options: UserNotificationListOptions,\n ): Promise<UserNotification[]> {\n const recipientUserId = requireText(userId, 'recipient');\n const limit = clampLimit(options.limit);\n const tenantIds = [...new Set(options.tenantIds.filter(Boolean))];\n const notifications = await this.collection();\n\n const perTenant = await Promise.all(\n tenantIds.map((tenantId) =>\n withTenant({ tenantId }, () =>\n notifications.list({\n where: {\n tenantId,\n recipientUserId,\n ...(options.includeDismissed ? {} : { dismissedAt: null }),\n ...(options.unreadOnly ? { readAt: null } : {}),\n ...(options.since ? { 'occurredAt >=': options.since } : {}),\n },\n orderBy: 'occurredAt DESC',\n limit,\n }),\n ),\n ),\n );\n\n return perTenant\n .flat()\n .sort((a, b) => b.occurredAt.getTime() - a.occurredAt.getTime())\n .slice(0, limit);\n }\n\n /** Unread, undismissed count across the given tenants. */\n async countUnread(\n userId: string,\n options: Pick<UserNotificationListOptions, 'tenantIds' | 'since'>,\n ): Promise<number> {\n const recipientUserId = requireText(userId, 'recipient');\n const notifications = await this.collection();\n const counts = await Promise.all(\n [...new Set(options.tenantIds.filter(Boolean))].map((tenantId) =>\n withTenant({ tenantId }, () =>\n notifications.count({\n where: {\n tenantId,\n recipientUserId,\n readAt: null,\n dismissedAt: null,\n ...(options.since ? { 'occurredAt >=': options.since } : {}),\n },\n }),\n ),\n ),\n );\n return counts.reduce((sum, count) => sum + Number(count), 0);\n }\n\n /** Mark the user's own notifications read; returns how many changed. */\n async markRead(\n userId: string,\n ids: readonly string[],\n scope: UserNotificationScope,\n ): Promise<number> {\n return this.stamp(userId, ids, scope, 'readAt');\n }\n\n /** Dismiss (and mark read) the user's own notifications. */\n async dismiss(\n userId: string,\n ids: readonly string[],\n scope: UserNotificationScope,\n ): Promise<number> {\n return this.stamp(userId, ids, scope, 'dismissedAt');\n }\n\n /** Mark every unread notification of the user in these tenants read. */\n async markAllRead(\n userId: string,\n options: Pick<UserNotificationListOptions, 'tenantIds'>,\n ): Promise<number> {\n const recipientUserId = requireText(userId, 'recipient');\n const notifications = await this.collection();\n const now = new Date();\n let changed = 0;\n for (const tenantId of new Set(options.tenantIds.filter(Boolean))) {\n changed += await withTenant({ tenantId }, async () => {\n const unread = await notifications.list({\n where: { tenantId, recipientUserId, readAt: null },\n });\n for (const notification of unread) {\n notification.readAt = now;\n await notification.save();\n }\n return unread.length;\n });\n }\n return changed;\n }\n\n private async stamp(\n userId: string,\n ids: readonly string[],\n scope: UserNotificationScope,\n column: 'readAt' | 'dismissedAt',\n ): Promise<number> {\n const recipientUserId = requireText(userId, 'recipient');\n const tenantId = requireText(scope.tenantId, 'tenant');\n // Ids come from requests. A malformed one can match no row, and on a\n // native uuid column (PostgreSQL) it would fail the whole query (22P02)\n // instead, so drop it before querying.\n const wanted = [\n ...new Set(\n ids.filter(\n (id): id is string => typeof id === 'string' && UUID_PATTERN.test(id),\n ),\n ),\n ];\n if (wanted.length === 0) return 0;\n\n return withTenant({ tenantId }, async () => {\n const notifications = await this.collection();\n // The recipient filter is the authorization check: another user's id\n // simply matches nothing.\n const rows = await notifications.list({\n where: { tenantId, recipientUserId, 'id in': wanted },\n });\n const now = new Date();\n let changed = 0;\n for (const notification of rows) {\n if (notification[column] !== null) continue;\n notification[column] = now;\n if (column === 'dismissedAt' && notification.readAt === null) {\n notification.readAt = now;\n }\n await notification.save();\n changed += 1;\n }\n return changed;\n });\n }\n}\n","import { SmrtRecipe } from '@happyvertical/smrt-core';\nimport { Email } from './models/Email.js';\nimport { EmailAccount } from './models/EmailAccount.js';\nimport { SlackAccount } from './models/SlackAccount.js';\nimport { SlackMessage } from './models/SlackMessage.js';\nimport { UserNotification } from './models/UserNotification.js';\n\n/** Email reading and composing with application-owned transport. */\nexport class MailboxRecipe extends SmrtRecipe {\n static id = 'messages.mailbox';\n static label = 'Mailbox';\n static summary = 'Read and compose email from your connected accounts.';\n static synonyms = ['email', 'inbox', 'mail'];\n static group = {\n id: 'messages',\n label: 'Messaging',\n summary: 'Choose email and personal updates independently.',\n };\n static section = {\n id: 'messages',\n label: 'Messaging',\n icon: 'folder',\n description: 'Read email and keep up with updates addressed to you.',\n };\n static models = [Email, EmailAccount];\n static runtime = 'both' as const;\n static surfaces = [\n {\n kind: 'route',\n path: '/messages/mailbox',\n export: '@happyvertical/smrt-messages/svelte#MessageList',\n label: 'Mailbox',\n },\n {\n kind: 'playground',\n export: '@happyvertical/smrt-messages/svelte#MailboxDemo',\n label: 'Mailbox with mocked sending',\n },\n ] as const;\n static providers = [\n {\n id: 'email-inbox',\n kind: 'email',\n options: ['imap', 'pop3', 'gmail'],\n required: true,\n },\n {\n id: 'email-send',\n kind: 'email',\n options: ['smtp', 'gmail'],\n required: false,\n },\n ];\n static demoSeed = {\n data: {\n accounts: [\n {\n id: 'demo-account',\n name: 'Demo Inbox',\n providerType: 'email',\n email: 'you@example.com',\n isActive: true,\n },\n ],\n messages: [\n {\n id: 'demo-welcome',\n type: 'email',\n accountId: 'demo-account',\n subject: 'Welcome to your mailbox',\n body: 'Fictional mail. Sending is mocked; nothing leaves this browser.',\n senderName: 'Demo colleague',\n senderAddress: 'colleague@example.com',\n recipientAddresses: [{ address: 'you@example.com' }],\n date: '2026-01-01T12:00:00Z',\n isRead: false,\n isFlagged: false,\n hasAttachments: false,\n },\n ],\n },\n };\n static nav = [\n {\n label: 'Mailbox',\n model: Email,\n key: 'mailbox',\n icon: 'folder',\n noun: 'email',\n description: 'Read email from your connected accounts.',\n },\n {\n label: 'Failed sends',\n model: Email,\n key: 'failed-sends',\n icon: 'fileText',\n noun: 'email',\n description: 'Review email whose last send attempt failed.',\n filter: { field: 'sendStatus', value: 'failed' },\n },\n ];\n static help = './help/mailbox.md';\n static options = {\n Email: {\n fields: {\n created_at: { help: 'When this email was first recorded.' },\n updated_at: { help: 'When this email record was last changed.' },\n },\n },\n EmailAccount: {\n fields: {\n created_at: {\n help: 'When this mailbox connection was first recorded.',\n },\n updated_at: { help: 'When this mailbox connection was last changed.' },\n },\n },\n } as const;\n}\n\n/** Recipient-scoped in-app notification bell. */\nexport class NotificationsRecipe extends SmrtRecipe {\n static id = 'messages.notifications';\n static label = 'Notifications';\n static summary = 'See updates addressed to you and mark them read.';\n static synonyms = ['alerts', 'notification bell'];\n static group = {\n id: 'messages',\n label: 'Messaging',\n summary: 'Choose email and personal updates independently.',\n };\n static section = {\n id: 'messages',\n label: 'Messaging',\n icon: 'folder',\n description: 'Read email and keep up with updates addressed to you.',\n };\n static models = [UserNotification];\n static runtime = 'both' as const;\n static surfaces = [\n {\n kind: 'shell-widget',\n slot: 'header.end',\n export: '@happyvertical/smrt-svelte/notifications#NotificationBell',\n label: 'Notifications',\n },\n ] as const;\n static providers = [\n {\n id: 'notifications',\n kind: 'notifications',\n options: ['user-notification-service'],\n required: true,\n },\n ];\n static demoSeed = {\n data: {\n items: [\n {\n id: 'demo-notification',\n title: 'You were mentioned',\n body: 'A fictional update for the demo user.',\n occurredAt: '2026-01-01T12:00:00Z',\n severity: 'info',\n readAt: null,\n },\n ],\n },\n };\n // Recipient-scoped reads use the bell provider, never generated model routes.\n static nav = [];\n static help = './help/notifications.md';\n}\n\n/** Slack messages from connected workspaces, read by channel and thread. */\nexport class SlackRecipe extends SmrtRecipe {\n static id = 'messages.slack';\n static label = 'Slack';\n static summary = 'Read Slack messages from your connected workspaces.';\n static synonyms = [\n 'slack',\n 'slack messages',\n 'slack channels',\n 'workspace chat',\n 'team chat',\n ];\n static group = {\n id: 'messages',\n label: 'Messaging',\n summary: 'Choose email and personal updates independently.',\n };\n static section = {\n id: 'messages',\n label: 'Messaging',\n icon: 'folder',\n description: 'Read email and keep up with updates addressed to you.',\n };\n static models = [SlackMessage, SlackAccount];\n static nav = [\n {\n label: 'Slack messages',\n model: SlackMessage,\n key: 'slack-messages',\n icon: 'folder',\n noun: 'message',\n description: 'Read messages from your connected workspaces by channel.',\n },\n {\n label: 'Slack workspaces',\n model: SlackAccount,\n icon: 'users',\n noun: 'workspace',\n description: 'The workspaces your application is connected to.',\n },\n ];\n static help = './help/slack.md';\n static options = {\n SlackMessage: {\n fields: {\n channelName: { label: 'Channel', order: 1 },\n body: { label: 'Message', order: 2 },\n threadId: { label: 'Thread', order: 3 },\n sendStatus: { label: 'Sent status', order: 4 },\n accountId: { label: 'Workspace', order: 5 },\n fromName: { label: 'From', visibility: 'advanced' },\n fromAddress: { visibility: 'advanced' },\n toAddresses: { visibility: 'advanced' },\n subject: { visibility: 'advanced' },\n date: { visibility: 'advanced' },\n isRead: { visibility: 'advanced' },\n isFlagged: { visibility: 'advanced' },\n isEdited: { label: 'Edited', visibility: 'advanced' },\n messageType: { label: 'Message kind', visibility: 'advanced' },\n reactions: { visibility: 'advanced' },\n hasAttachments: { visibility: 'advanced' },\n channelId: { visibility: 'advanced' },\n sentAt: { visibility: 'advanced' },\n sendError: { visibility: 'advanced' },\n scheduledSendAt: { visibility: 'advanced' },\n inReplyToMessageId: { label: 'Replying to', visibility: 'advanced' },\n personaId: { visibility: 'advanced' },\n endpointId: { visibility: 'advanced' },\n retryCount: { visibility: 'hidden' },\n maxRetries: { visibility: 'hidden' },\n size: { visibility: 'hidden' },\n correlationId: { visibility: 'hidden' },\n slackTs: { visibility: 'hidden' },\n slackThreadTs: { visibility: 'hidden' },\n blocks: { visibility: 'hidden' },\n metadata: { visibility: 'hidden' },\n tenantId: { visibility: 'hidden' },\n created_at: { help: 'When this message was first recorded.' },\n updated_at: { help: 'When this message record was last changed.' },\n },\n },\n SlackAccount: {\n fields: {\n name: { order: 1 },\n workspaceName: { label: 'Workspace', order: 2 },\n isActive: { label: 'Enabled', order: 3 },\n lastSyncAt: { label: 'Last checked', order: 4 },\n workspaceId: { visibility: 'advanced' },\n credentialSecretId: { visibility: 'hidden' },\n settings: { visibility: 'hidden' },\n botUserId: { label: 'Bot user', visibility: 'advanced' },\n providerType: { visibility: 'advanced' },\n channelType: { visibility: 'advanced' },\n configuration: { visibility: 'advanced' },\n tenantId: { visibility: 'hidden' },\n created_at: {\n help: 'When this workspace connection was first recorded.',\n },\n updated_at: {\n help: 'When this workspace connection was last changed.',\n },\n },\n },\n } as const;\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 { NotificationDeliveryCollection } from './collections/NotificationDeliveryCollection.js';\nexport { PersonaMessageRouteCollection } from './collections/PersonaMessageRouteCollection.js';\nexport { UserNotificationCollection } from './collections/UserNotificationCollection.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 {\n NOTIFICATION_DELIVERY_CHANNELS,\n NotificationDelivery,\n type NotificationDeliveryChannel,\n type NotificationDeliveryOptions,\n type NotificationDeliveryStatus,\n type NotificationDeliveryTransition,\n} from './models/NotificationDelivery.js';\nexport { PersonaMessageRoute } from './models/PersonaMessageRoute.js';\nexport {\n USER_NOTIFICATION_SEVERITIES,\n UserNotification,\n type UserNotificationOptions,\n type UserNotificationSeverity,\n} from './models/UserNotification.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 buildNotificationLink,\n messageSendTransport,\n type NotificationDispatchOptions,\n type NotificationDispatchOutcome,\n type NotificationDispatchReport,\n type NotificationEmailInput,\n type NotificationEnqueueResult,\n type NotificationOutboxDenialReason,\n NotificationOutboxDeniedError,\n type NotificationOutboxOptions,\n NotificationOutboxService,\n type NotificationRecipient,\n type NotificationRecipientRequest,\n type NotificationReconcileOutcome,\n type NotificationSuppressionRequest,\n type NotificationTransport,\n type NotificationTransportOutcome,\n type NotificationTransportReconciliation,\n type NotificationTransportRequest,\n notificationDeliveryCorrelationId,\n notificationDeliveryMessageId,\n} from './services/NotificationOutboxService.js';\nexport {\n type PersonaMessageSendResult,\n PersonaMessagingService,\n} from './services/PersonaMessagingService.js';\nexport {\n type UserNotificationInput,\n type UserNotificationListOptions,\n type UserNotificationNotifyResult,\n type UserNotificationScope,\n UserNotificationService,\n} from './services/UserNotificationService.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 SendEmailAttachment,\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\nexport { MailboxRecipe, NotificationsRecipe, SlackRecipe } from './recipes.js';\n"],"mappings":"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"}
|