@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.
Files changed (38) hide show
  1. package/AGENTS.md +17 -0
  2. package/README.md +40 -0
  3. package/agents/notification-outbox.md +116 -0
  4. package/dist/chunks/{AccountCollection-O-zbituV.js → AccountCollection-By48bdwt.js} +2 -2
  5. package/dist/chunks/{AccountCollection-O-zbituV.js.map → AccountCollection-By48bdwt.js.map} +1 -1
  6. package/dist/chunks/{Email-MRtj6D2s.js → Email-CMUK3aWU.js} +3 -3
  7. package/dist/chunks/{Email-MRtj6D2s.js.map → Email-CMUK3aWU.js.map} +1 -1
  8. package/dist/chunks/{EmailFolder-qpOwfo_O.js → EmailFolder-DLJvqNqI.js} +2 -2
  9. package/dist/chunks/{EmailFolder-qpOwfo_O.js.map → EmailFolder-DLJvqNqI.js.map} +1 -1
  10. package/dist/chunks/{Message-5Xz9tauF.js → Message-DXpqot5f.js} +52 -5
  11. package/dist/chunks/Message-DXpqot5f.js.map +1 -0
  12. package/dist/chunks/{MessageCollection-m1C6fDwS.js → MessageCollection-CMGaSGBc.js} +2 -2
  13. package/dist/chunks/{MessageCollection-m1C6fDwS.js.map → MessageCollection-CMGaSGBc.js.map} +1 -1
  14. package/dist/chunks/__smrt-register__-CaGLtiEU.js +6 -0
  15. package/dist/chunks/__smrt-register__-CaGLtiEU.js.map +1 -0
  16. package/dist/collections/NotificationDeliveryCollection.d.ts +6 -0
  17. package/dist/collections/NotificationDeliveryCollection.d.ts.map +1 -0
  18. package/dist/index.d.ts +3 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +780 -38
  21. package/dist/index.js.map +1 -1
  22. package/dist/manifest.json +1135 -89
  23. package/dist/models/Message.d.ts +15 -0
  24. package/dist/models/Message.d.ts.map +1 -1
  25. package/dist/models/NotificationDelivery.d.ts +128 -0
  26. package/dist/models/NotificationDelivery.d.ts.map +1 -0
  27. package/dist/senders/EmailSender.d.ts +9 -0
  28. package/dist/senders/EmailSender.d.ts.map +1 -1
  29. package/dist/services/NotificationOutboxService.d.ts +226 -0
  30. package/dist/services/NotificationOutboxService.d.ts.map +1 -0
  31. package/dist/smrt-knowledge.json +470 -9
  32. package/dist/smrt-knowledge.okf.md +155 -0
  33. package/dist/types.d.ts +6 -0
  34. package/dist/types.d.ts.map +1 -1
  35. package/package.json +17 -16
  36. package/dist/chunks/Message-5Xz9tauF.js.map +0 -1
  37. package/dist/chunks/__smrt-register__-DwNoP4GB.js +0 -6
  38. package/dist/chunks/__smrt-register__-DwNoP4GB.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Message-DXpqot5f.js","names":["result"],"sources":["../../src/models/Message.ts"],"sourcesContent":["/**\n * Message model - Base class for all message types (STI)\n *\n * Common fields shared across email, tweets, slack messages, etc.\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 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';\nimport type {\n MessageOptions,\n MessageSendResult,\n SendMessageOptions,\n SendStatus,\n} from '../types';\n\n/** `metadata` key recording that the last failed send may have been accepted. */\nexport const SEND_OUTCOME_UNKNOWN_METADATA_KEY = 'sendOutcomeUnknown';\n\n/**\n * The stored metadata JSON with the outcome-unknown marker set or cleared, or\n * undefined when it needs no change (or is not a JSON object to edit).\n */\nfunction withSendOutcomeMarker(\n stored: unknown,\n outcomeUnknown: boolean,\n): string | undefined {\n let bag: Record<string, unknown> = {};\n if (typeof stored === 'string' && stored.trim()) {\n try {\n const parsed: unknown = JSON.parse(stored);\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n return undefined;\n }\n bag = parsed as Record<string, unknown>;\n } catch {\n return undefined;\n }\n }\n if (Boolean(bag[SEND_OUTCOME_UNKNOWN_METADATA_KEY]) === outcomeUnknown) {\n return undefined;\n }\n if (outcomeUnknown) bag[SEND_OUTCOME_UNKNOWN_METADATA_KEY] = true;\n else delete bag[SEND_OUTCOME_UNKNOWN_METADATA_KEY];\n return JSON.stringify(bag);\n}\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableStrategy: 'sti',\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: { skipApiCheck: true },\n})\nexport class Message extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-messages\";\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n @foreignKey('Account')\n @field({\n description: 'The connected account used to receive or send this message.',\n })\n accountId = '';\n @crossPackageRef('@happyvertical/smrt-personas:AgentPersona', {\n nullable: true,\n })\n @field({\n description:\n 'The assistant identity associated with this message, when one was used.',\n })\n personaId: string | null = null;\n @foreignKey('MessagingEndpoint')\n @field({ description: 'The saved destination used to deliver this message.' })\n endpointId: string | null = null;\n @field({\n description:\n 'A tracking reference that connects this message to related activity.',\n })\n correlationId = '';\n @field({ description: 'The conversation this message belongs to.' })\n threadId = '';\n @field({ description: 'The subject shown in the message list.' })\n subject = '';\n @field({ description: 'The message content in plain text.' })\n body = ''; // Normalized plain text\n @field({ description: 'The address the message was sent from.' })\n fromAddress = '';\n @field({ description: 'The sender name shown beside their address.' })\n fromName = '';\n @field({ description: 'The people or addresses receiving this message.' })\n toAddresses = ''; // JSON array of {address, name}\n @field({ description: 'When the message was sent or received.' })\n date: Date | null = null;\n @field({ description: 'Whether this message has been marked as read.' })\n isRead = false;\n @field({ description: 'Whether this message is flagged for follow-up.' })\n isFlagged = false;\n @field({ description: 'Whether files are attached to this message.' })\n hasAttachments = false;\n @field({ description: 'The size of the message in bytes.' })\n size = 0;\n @field({\n description: 'Additional details supplied by the messaging connection.',\n })\n metadata = ''; // JSON extension bag\n\n // Send lifecycle fields\n @field({\n description:\n 'The latest sending state: draft, sending, sent, or failed. Received mail may also show draft here.',\n })\n sendStatus: SendStatus = 'draft';\n @field({ description: 'When the message was successfully sent.' })\n sentAt: Date | null = null;\n @field({ description: 'The reason the latest send attempt failed.' })\n sendError = '';\n @field({ description: 'How many times delivery has been retried.' })\n retryCount = 0;\n @field({ description: 'The maximum number of delivery retries allowed.' })\n maxRetries = 3;\n @field({ description: 'When this message is scheduled to be sent.' })\n scheduledSendAt: Date | null = null;\n @foreignKey('Message')\n @field({ description: 'The earlier message this one replies to.' })\n inReplyToMessageId = '';\n\n // Timestamps\n @field({ description: 'When this message was recorded.' })\n createdAt = new Date();\n @field({ description: 'When this message was last changed.' })\n updatedAt = new Date();\n\n constructor(options: MessageOptions = {}) {\n super(options);\n\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.accountId !== undefined) this.accountId = options.accountId;\n if (options.personaId !== undefined) this.personaId = options.personaId;\n if (options.endpointId !== undefined) this.endpointId = options.endpointId;\n if (options.correlationId !== undefined)\n this.correlationId = options.correlationId;\n if (options.threadId !== undefined) this.threadId = options.threadId;\n if (options.subject !== undefined) this.subject = options.subject;\n if (options.body !== undefined) this.body = options.body;\n if (options.fromAddress !== undefined)\n this.fromAddress = options.fromAddress;\n if (options.fromName !== undefined) this.fromName = options.fromName;\n if (options.toAddresses !== undefined)\n this.toAddresses = options.toAddresses;\n if (options.date !== undefined) this.date = options.date || null;\n if (options.isRead !== undefined) this.isRead = options.isRead;\n if (options.isFlagged !== undefined) this.isFlagged = options.isFlagged;\n if (options.hasAttachments !== undefined)\n this.hasAttachments = options.hasAttachments;\n if (options.size !== undefined) this.size = options.size;\n if (options.metadata !== undefined) this.metadata = options.metadata;\n if (options.sendStatus !== undefined) this.sendStatus = options.sendStatus;\n if (options.sentAt !== undefined) this.sentAt = options.sentAt || null;\n if (options.sendError !== undefined) this.sendError = options.sendError;\n if (options.retryCount !== undefined) this.retryCount = options.retryCount;\n if (options.maxRetries !== undefined) this.maxRetries = options.maxRetries;\n if (options.scheduledSendAt !== undefined)\n this.scheduledSendAt = options.scheduledSendAt || null;\n if (options.inReplyToMessageId !== undefined)\n this.inReplyToMessageId = options.inReplyToMessageId;\n if (options.createdAt) this.createdAt = options.createdAt;\n if (options.updatedAt) this.updatedAt = options.updatedAt;\n }\n\n private async finalizeSendLifecycle(\n result: MessageSendResult,\n ): Promise<void> {\n if (!this.id) throw new Error('Cannot finalize an unsaved message send');\n\n const sendStatus: SendStatus = result.success ? 'sent' : 'failed';\n const sendError = result.success ? '' : (result.error ?? 'Send failed');\n const useEmbeddedFallback = usesEmbeddedRevisionFallback(this.db);\n for (let attempt = 0; attempt < 8; attempt += 1) {\n let nextRevision: Date | undefined;\n await withEmbeddedWriteQueue(this.db, useEmbeddedFallback, async () => {\n const current = await this.getCanonicalPersistedRow({ id: this.id });\n if (current?.send_status !== 'sending') return;\n const currentRevision = current.updated_at;\n const currentRevisionMs = new Date(String(currentRevision)).getTime();\n if (!Number.isFinite(currentRevisionMs)) return;\n nextRevision = new Date(Math.max(Date.now(), currentRevisionMs + 1));\n // Record durably whether a failure may still have been accepted, so a\n // later reconciliation can tell it from a definite rejection.\n const metadata = withSendOutcomeMarker(\n current.metadata,\n !result.success && result.outcomeUnknown === true,\n );\n const values = {\n send_status: sendStatus,\n sent_at: result.success ? result.sentAt : null,\n send_error: sendError,\n updated_at: nextRevision,\n ...(metadata === undefined ? {} : { metadata }),\n };\n if (useEmbeddedFallback) {\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 send_status: 'sending',\n updated_at:\n currentRevision instanceof Date\n ? currentRevision.toISOString()\n : currentRevision,\n },\n values,\n );\n });\n // DuckDB's generic update result reports one affected row even when the\n // predicate matched none. Verify the durable lifecycle value instead of\n // trusting adapter row-count metadata before declaring finalization.\n const verified = await this.getCanonicalPersistedRow({ id: this.id });\n if (verified?.send_status === sendStatus) {\n await this.completePersistedUpdate(verified);\n return;\n }\n }\n throw new Error('Cannot finalize: message revision kept changing');\n }\n\n /**\n * Get to addresses as parsed array\n */\n getToAddresses(): Array<{ address: string; name?: string }> {\n if (!this.toAddresses) return [];\n try {\n return JSON.parse(this.toAddresses);\n } catch {\n return [];\n }\n }\n\n /**\n * Set to addresses from array\n */\n setToAddresses(addresses: Array<{ address: string; name?: string }>): void {\n this.toAddresses = JSON.stringify(addresses);\n }\n\n /**\n * Get metadata as parsed object\n */\n getMetadata(): Record<string, unknown> {\n if (!this.metadata) return {};\n try {\n return JSON.parse(this.metadata);\n } catch {\n return {};\n }\n }\n\n /**\n * Set metadata from object\n */\n setMetadata(data: Record<string, unknown>): void {\n this.metadata = JSON.stringify(data);\n }\n\n /**\n * Mark message as read\n */\n async markRead(): Promise<void> {\n this.isRead = true;\n this.updatedAt = new Date();\n await this.save();\n }\n\n /**\n * Mark message as unread\n */\n async markUnread(): Promise<void> {\n this.isRead = false;\n this.updatedAt = new Date();\n await this.save();\n }\n\n /**\n * Toggle flagged status\n */\n async toggleFlagged(): Promise<void> {\n this.isFlagged = !this.isFlagged;\n this.updatedAt = new Date();\n await this.save();\n }\n\n /**\n * Check if message is unread\n */\n isUnread(): boolean {\n return !this.isRead;\n }\n\n /**\n * Get a short preview of the message body\n */\n getPreview(maxLength = 200): string {\n const text = this.body || '';\n if (text.length <= maxLength) return text;\n return `${text.slice(0, maxLength)}...`;\n }\n\n /**\n * Get the account for this message\n */\n async getAccount() {\n if (!this.accountId) return null;\n\n const { AccountCollection } = await import(\n '../collections/AccountCollection'\n );\n const collection = await AccountCollection.create(this.options);\n\n return await collection.get({ id: this.accountId });\n }\n\n async getEndpoint() {\n if (!this.endpointId) return null;\n const { MessagingEndpointCollection } = await import(\n '../collections/MessagingEndpointCollection.js'\n );\n const collection = await MessagingEndpointCollection.create(this.options);\n return collection.get({ id: this.endpointId });\n }\n\n /**\n * Get messages in the same thread\n */\n async getThreadMessages(): Promise<Message[]> {\n if (!this.threadId) return [this];\n\n const { MessageCollection } = await import(\n '../collections/MessageCollection'\n );\n const collection = await MessageCollection.create(this.options);\n\n return await collection.list({ where: { threadId: this.threadId } });\n }\n\n /**\n * Get attachments for this message\n */\n async getAttachments() {\n const { AttachmentCollection } = await import(\n '../collections/AttachmentCollection'\n );\n const collection = await AttachmentCollection.create(this.options);\n\n return await collection.list({ where: { messageId: this.id } });\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Send Lifecycle\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Send this message via its account's sender\n */\n async send(options?: SendMessageOptions): Promise<MessageSendResult> {\n // Entry guard: a message that is already in flight or delivered must not be\n // sent again. Catches same-instance double-clicks before any work happens.\n if (this.sendStatus === 'sending' || this.sendStatus === 'sent') {\n return {\n success: false,\n error: `Cannot send: message is already '${this.sendStatus}'`,\n sentAt: new Date(),\n };\n }\n\n // Resolve account\n const account = await this.getAccount();\n if (!account) {\n const result: MessageSendResult = {\n success: false,\n error: 'No account associated with this message',\n sentAt: new Date(),\n };\n this.sendStatus = 'failed';\n this.sendError = result.error ?? '';\n this.updatedAt = new Date();\n await this.save();\n return result;\n }\n\n if (!account.isActive) {\n const result: MessageSendResult = {\n success: false,\n error: 'Messaging account is inactive',\n sentAt: new Date(),\n };\n this.sendStatus = 'failed';\n this.sendError = result.error ?? '';\n this.updatedAt = new Date();\n await this.save();\n return result;\n }\n\n // Get sender from account\n let sender: Awaited<ReturnType<typeof account.createSender>>;\n try {\n sender = await account.createSender();\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n this.sendStatus = 'failed';\n this.sendError = errorMessage;\n this.updatedAt = new Date();\n await this.save();\n return {\n success: false,\n error: errorMessage,\n sentAt: new Date(),\n };\n }\n\n // Claim the send. For a persisted row, do a compare-and-set so only one\n // concurrent sender wins: flip send_status to 'sending' atomically, gated on\n // the status we observed. If no row matched, another sender already claimed\n // it — abort without delivering (prevents duplicate sends). For an unsaved\n // draft there is no row yet, so the in-memory transition + save() (INSERT)\n // serves as the claim.\n const claimFromStatus = this.sendStatus;\n if (this.isPersisted && this.id) {\n const loadedRevision = this.updated_at;\n if (!loadedRevision) {\n return {\n success: false,\n error: 'Cannot send: persisted message has no loaded revision',\n sentAt: new Date(),\n };\n }\n const claimedRevision = new Date(\n Math.max(Date.now(), loadedRevision.getTime() + 1),\n );\n const useEmbeddedFallback = usesEmbeddedRevisionFallback(this.db);\n let claimed = false;\n await withEmbeddedWriteQueue(this.db, useEmbeddedFallback, async () => {\n if (useEmbeddedFallback) {\n const current = await this.getCanonicalPersistedRow({ id: this.id });\n const storedRevision = current?.updated_at;\n const currentRevision =\n storedRevision instanceof Date\n ? storedRevision.getTime()\n : typeof storedRevision === 'string'\n ? Date.parse(storedRevision)\n : Number.NaN;\n if (\n !current ||\n current.send_status !== claimFromStatus ||\n !Number.isFinite(currentRevision) ||\n currentRevision !== loadedRevision.getTime()\n )\n return;\n await this.db.upsert(this.tableName, ['id'], {\n ...current,\n send_status: 'sending',\n updated_at: claimedRevision,\n });\n claimed = true;\n return;\n }\n const claim = await this.db.update(\n this.tableName,\n {\n id: this.id,\n send_status: claimFromStatus,\n updated_at: loadedRevision.toISOString(),\n },\n { send_status: 'sending', updated_at: claimedRevision },\n );\n claimed = claim?.affected === 1;\n });\n if (!claimed) {\n return {\n success: false,\n error: 'Cannot send: message is already being sent',\n sentAt: new Date(),\n };\n }\n this.sendStatus = 'sending';\n this.updated_at = claimedRevision;\n this.updatedAt = new Date();\n } else {\n this.sendStatus = 'sending';\n this.updatedAt = new Date();\n await this.save();\n }\n\n let result: MessageSendResult;\n try {\n result = await sender.send(this, options);\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n // A sender that throws mid-send says nothing about provider acceptance.\n result = {\n success: false,\n error: errorMessage,\n outcomeUnknown: true,\n sentAt: new Date(),\n };\n }\n await this.finalizeSendLifecycle(result);\n return result;\n }\n\n /**\n * Whether the latest failed send may still have been accepted by the\n * provider (see `MessageSendResult.outcomeUnknown`).\n */\n isSendOutcomeUnknown(): boolean {\n return (\n this.sendStatus === 'failed' &&\n this.getMetadata()[SEND_OUTCOME_UNKNOWN_METADATA_KEY] === true\n );\n }\n\n /**\n * Release a send claim whose sender is gone (a crash or lost lease left the\n * row in `sending`): move it to `failed` with an unknown outcome so the\n * owner of the delivery decision can send it again. Returns false, changing\n * nothing, unless the stored row is still `sending`. Only for callers that\n * have established that no live sender holds the claim.\n */\n async abandonSendAttempt(reason: string): Promise<boolean> {\n if (!this.id) return false;\n const current = await this.getCanonicalPersistedRow({ id: this.id });\n if (current?.send_status !== 'sending') return false;\n try {\n await this.finalizeSendLifecycle({\n success: false,\n error: reason,\n outcomeUnknown: true,\n sentAt: new Date(),\n });\n } catch {\n return false;\n }\n return this.sendStatus === 'failed';\n }\n\n /**\n * Retry sending a failed message\n */\n async retrySend(options?: SendMessageOptions): Promise<MessageSendResult> {\n if (this.sendStatus !== 'failed') {\n return {\n success: false,\n error: `Cannot retry: message status is '${this.sendStatus}', expected 'failed'`,\n sentAt: new Date(),\n };\n }\n\n if (this.retryCount >= this.maxRetries) {\n return {\n success: false,\n error: `Retry budget exhausted (${this.retryCount}/${this.maxRetries})`,\n sentAt: new Date(),\n };\n }\n\n this.retryCount++;\n this.updatedAt = new Date();\n await this.save();\n\n return this.send(options);\n }\n\n /**\n * Options for a derived draft (reply/forward) built from this message. Carries\n * the DB connection + tenant context from `this.options`, but strips this\n * message's own identity fields. When this message was hydrated from the DB,\n * `this.options` holds the row's `id`/`slug`/`context`/`_skipLoad`; spreading\n * those into a new draft would make `draft.save()` upsert onto the natural-key\n * conflict columns (`slug`/`context`/`_meta_type`) and overwrite the ORIGINAL\n * message instead of inserting a new row. See EmailAccount.childOptions().\n */\n protected draftOptions(): Record<string, unknown> {\n const rest = { ...(this.options as Record<string, unknown>) };\n delete rest.id;\n delete rest.slug;\n delete rest.context;\n delete rest._skipLoad;\n return rest;\n }\n\n /**\n * Create a reply to this message (returns unsaved draft)\n */\n createReply(_options?: { replyAll?: boolean }): Message {\n const reply = new (this.constructor as typeof Message)({\n ...this.draftOptions(),\n id: undefined,\n accountId: this.accountId,\n threadId: this.threadId || this.id || '',\n subject: this.subject.startsWith('Re:')\n ? this.subject\n : `Re: ${this.subject}`,\n toAddresses: JSON.stringify([\n { address: this.fromAddress, name: this.fromName },\n ]),\n fromAddress: '',\n fromName: '',\n body: this.buildQuotedBody(),\n inReplyToMessageId: this.id || '',\n sendStatus: 'draft',\n isRead: true,\n date: null,\n createdAt: undefined,\n updatedAt: undefined,\n });\n\n return reply;\n }\n\n /**\n * Create a forward of this message (returns unsaved draft)\n */\n createForward(): Message {\n const forward = new (this.constructor as typeof Message)({\n ...this.draftOptions(),\n id: undefined,\n accountId: this.accountId,\n threadId: '',\n subject: this.subject.startsWith('Fwd:')\n ? this.subject\n : `Fwd: ${this.subject}`,\n toAddresses: '[]',\n fromAddress: '',\n fromName: '',\n body: this.buildQuotedBody(),\n hasAttachments: this.hasAttachments,\n inReplyToMessageId: '',\n sendStatus: 'draft',\n isRead: true,\n date: null,\n createdAt: undefined,\n updatedAt: undefined,\n });\n\n return forward;\n }\n\n /**\n * Build quoted body for reply/forward\n */\n protected buildQuotedBody(): string {\n const dateStr = this.date ? this.date.toLocaleString() : 'unknown date';\n const from = this.fromName\n ? `${this.fromName} <${this.fromAddress}>`\n : this.fromAddress;\n\n const quotedLines = (this.body || '')\n .split('\\n')\n .map((line) => `> ${line}`)\n .join('\\n');\n\n return `\\n\\nOn ${dateStr}, ${from} wrote:\\n${quotedLines}`;\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { t as Message } from "./Message-5Xz9tauF.js";
2
+ import { t as Message } from "./Message-DXpqot5f.js";
3
3
  import { SmrtCollection } from "@happyvertical/smrt-core";
4
4
  import { queryGlobal, queryWithGlobals } from "@happyvertical/smrt-tenancy";
5
5
  //#region src/collections/MessageCollection.ts
@@ -166,4 +166,4 @@ var MessageCollection = class extends SmrtCollection {
166
166
  //#endregion
167
167
  export { MessageCollection_exports as n, MessageCollection as t };
168
168
 
169
- //# sourceMappingURL=MessageCollection-m1C6fDwS.js.map
169
+ //# sourceMappingURL=MessageCollection-CMGaSGBc.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MessageCollection-m1C6fDwS.js","names":[],"sources":["../../src/collections/MessageCollection.ts"],"sourcesContent":["/**\n * MessageCollection - Unified collection for polymorphic message queries\n *\n * Queries the messages table with STI, returning correct subclass instances.\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { queryGlobal, queryWithGlobals } from '@happyvertical/smrt-tenancy';\nimport { Message } from '../models/Message';\nimport type { MessageSearchFilters } from '../types';\n\nexport class MessageCollection extends SmrtCollection<Message> {\n static readonly _itemClass = Message;\n\n /**\n * Search messages with filters\n */\n async search(\n query: string,\n filters?: MessageSearchFilters,\n ): Promise<Message[]> {\n let messages = await this.list({});\n\n // Filter by query\n if (query) {\n const lowerQuery = query.toLowerCase();\n messages = messages.filter(\n (m) =>\n m.subject?.toLowerCase().includes(lowerQuery) ||\n m.body?.toLowerCase().includes(lowerQuery) ||\n m.fromAddress?.toLowerCase().includes(lowerQuery) ||\n m.fromName?.toLowerCase().includes(lowerQuery),\n );\n }\n\n // Apply filters\n if (filters) {\n if (filters.accountIds && filters.accountIds.length > 0) {\n messages = messages.filter((m) =>\n filters.accountIds?.includes(m.accountId),\n );\n }\n if (filters.messageType) {\n messages = messages.filter((m) => {\n const metaType = (m as { _meta_type?: string })._meta_type || '';\n return metaType.includes(filters.messageType as string);\n });\n }\n if (filters.from) {\n const fromLower = filters.from.toLowerCase();\n messages = messages.filter(\n (m) =>\n m.fromAddress?.toLowerCase().includes(fromLower) ||\n m.fromName?.toLowerCase().includes(fromLower),\n );\n }\n if (filters.to) {\n const toLower = filters.to.toLowerCase();\n messages = messages.filter((m) =>\n m.toAddresses?.toLowerCase().includes(toLower),\n );\n }\n if (filters.isRead !== undefined) {\n messages = messages.filter((m) => m.isRead === filters.isRead);\n }\n if (filters.isFlagged !== undefined) {\n messages = messages.filter((m) => m.isFlagged === filters.isFlagged);\n }\n if (filters.sinceDate) {\n messages = messages.filter(\n (m) => m.date && m.date >= (filters.sinceDate as Date),\n );\n }\n if (filters.beforeDate) {\n messages = messages.filter(\n (m) => m.date && m.date < (filters.beforeDate as Date),\n );\n }\n if (filters.query) {\n const q = filters.query.toLowerCase();\n messages = messages.filter(\n (m) =>\n m.subject?.toLowerCase().includes(q) ||\n m.body?.toLowerCase().includes(q),\n );\n }\n }\n\n return messages;\n }\n\n /**\n * Get messages by multiple accounts\n */\n async getByAccounts(accountIds: string[]): Promise<Message[]> {\n const allMessages = await this.list({});\n return allMessages.filter((m) => accountIds.includes(m.accountId));\n }\n\n /**\n * Get messages by STI type.\n *\n * Accepts either the full discriminator (e.g. \"@happyvertical/smrt-messages:Email\")\n * or the short type name (e.g. \"Email\").\n */\n async getByType(messageType: string): Promise<Message[]> {\n if (messageType.includes(':') || messageType.startsWith('@')) {\n return await this.list({ where: { _meta_type: messageType } });\n }\n const allMessages = await this.list({});\n return allMessages.filter((m) => {\n const metaType = (m as { _meta_type?: string })._meta_type || '';\n return metaType.endsWith(`:${messageType}`);\n });\n }\n\n /**\n * Get unread messages\n */\n async getUnread(accountId?: string): Promise<Message[]> {\n const where: Record<string, unknown> = { isRead: false };\n if (accountId) {\n where.accountId = accountId;\n }\n return await this.list({ where });\n }\n\n /**\n * Get flagged messages\n */\n async getFlagged(accountId?: string): Promise<Message[]> {\n const where: Record<string, unknown> = { isFlagged: true };\n if (accountId) {\n where.accountId = accountId;\n }\n return await this.list({ where });\n }\n\n /**\n * Get recent messages\n */\n async getRecent(limit = 20, accountId?: string): Promise<Message[]> {\n const allMessages = await this.list({\n where: accountId ? { accountId } : undefined,\n });\n\n return allMessages\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 * Get messages by thread\n */\n async getByThread(threadId: string): Promise<Message[]> {\n return await this.list({ where: { threadId } });\n }\n\n /**\n * Mark multiple messages as read\n */\n async markAllRead(messageIds: string[]): Promise<void> {\n for (const id of messageIds) {\n const message = await this.get({ id });\n if (message) {\n await message.markRead();\n }\n }\n }\n\n /**\n * Get message statistics for an account\n */\n async getAccountStats(accountId: string): Promise<{\n total: number;\n unread: number;\n flagged: number;\n byType: Record<string, number>;\n }> {\n const messages = await this.list({ where: { accountId } });\n const byType: Record<string, number> = {};\n\n for (const msg of messages) {\n const metaType = (msg as { _meta_type?: string })._meta_type || 'Unknown';\n const shortType = metaType.split(':').pop() || metaType;\n byType[shortType] = (byType[shortType] || 0) + 1;\n }\n\n return {\n total: messages.length,\n unread: messages.filter((m) => !m.isRead).length,\n flagged: messages.filter((m) => m.isFlagged).length,\n byType,\n };\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Send / Draft Queries\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Get draft messages\n */\n async getDrafts(accountId?: string): Promise<Message[]> {\n const where: Record<string, unknown> = { sendStatus: 'draft' };\n if (accountId) where.accountId = accountId;\n return await this.list({ where });\n }\n\n /**\n * Get sent messages\n */\n async getSent(accountId?: string): Promise<Message[]> {\n const where: Record<string, unknown> = { sendStatus: 'sent' };\n if (accountId) where.accountId = accountId;\n return await this.list({ where });\n }\n\n /**\n * Get scheduled messages\n */\n async getScheduled(accountId?: string): Promise<Message[]> {\n const where: Record<string, unknown> = { sendStatus: 'scheduled' };\n if (accountId) where.accountId = accountId;\n return await this.list({ where });\n }\n\n /**\n * Get messages that failed to send\n */\n async getFailedSends(accountId?: string): Promise<Message[]> {\n const where: Record<string, unknown> = { sendStatus: 'failed' };\n if (accountId) where.accountId = accountId;\n return await this.list({ where });\n }\n\n /**\n * Get outbox (pending + sending + scheduled)\n */\n async getOutbox(accountId?: string): Promise<Message[]> {\n const allMessages = await this.list({\n where: accountId ? { accountId } : undefined,\n });\n return allMessages.filter(\n (m) =>\n m.sendStatus === 'pending' ||\n m.sendStatus === 'sending' ||\n m.sendStatus === 'scheduled',\n );\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Tenant Helper Methods\n // ─────────────────────────────────────────────────────────────────────────\n\n async findByTenant(tenantId: string): Promise<Message[]> {\n return this.list({ where: { tenantId } });\n }\n\n // Message is the @TenantScoped STI base, so an explicit `tenant_id IS NULL`\n // filter via list() throws and unflagged raw SQL is blocked under an active\n // tenant context (#1596). Route through the raw helpers — no `_meta_type`\n // scope so the base collection still returns ALL message subtypes.\n async findGlobal(): Promise<Message[]> {\n return queryGlobal<Message>(this);\n }\n\n async findWithGlobals(tenantId: string): Promise<Message[]> {\n return queryWithGlobals<Message>(this, tenantId, 'Message.findWithGlobals');\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"MessageCollection-CMGaSGBc.js","names":[],"sources":["../../src/collections/MessageCollection.ts"],"sourcesContent":["/**\n * MessageCollection - Unified collection for polymorphic message queries\n *\n * Queries the messages table with STI, returning correct subclass instances.\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { queryGlobal, queryWithGlobals } from '@happyvertical/smrt-tenancy';\nimport { Message } from '../models/Message';\nimport type { MessageSearchFilters } from '../types';\n\nexport class MessageCollection extends SmrtCollection<Message> {\n static readonly _itemClass = Message;\n\n /**\n * Search messages with filters\n */\n async search(\n query: string,\n filters?: MessageSearchFilters,\n ): Promise<Message[]> {\n let messages = await this.list({});\n\n // Filter by query\n if (query) {\n const lowerQuery = query.toLowerCase();\n messages = messages.filter(\n (m) =>\n m.subject?.toLowerCase().includes(lowerQuery) ||\n m.body?.toLowerCase().includes(lowerQuery) ||\n m.fromAddress?.toLowerCase().includes(lowerQuery) ||\n m.fromName?.toLowerCase().includes(lowerQuery),\n );\n }\n\n // Apply filters\n if (filters) {\n if (filters.accountIds && filters.accountIds.length > 0) {\n messages = messages.filter((m) =>\n filters.accountIds?.includes(m.accountId),\n );\n }\n if (filters.messageType) {\n messages = messages.filter((m) => {\n const metaType = (m as { _meta_type?: string })._meta_type || '';\n return metaType.includes(filters.messageType as string);\n });\n }\n if (filters.from) {\n const fromLower = filters.from.toLowerCase();\n messages = messages.filter(\n (m) =>\n m.fromAddress?.toLowerCase().includes(fromLower) ||\n m.fromName?.toLowerCase().includes(fromLower),\n );\n }\n if (filters.to) {\n const toLower = filters.to.toLowerCase();\n messages = messages.filter((m) =>\n m.toAddresses?.toLowerCase().includes(toLower),\n );\n }\n if (filters.isRead !== undefined) {\n messages = messages.filter((m) => m.isRead === filters.isRead);\n }\n if (filters.isFlagged !== undefined) {\n messages = messages.filter((m) => m.isFlagged === filters.isFlagged);\n }\n if (filters.sinceDate) {\n messages = messages.filter(\n (m) => m.date && m.date >= (filters.sinceDate as Date),\n );\n }\n if (filters.beforeDate) {\n messages = messages.filter(\n (m) => m.date && m.date < (filters.beforeDate as Date),\n );\n }\n if (filters.query) {\n const q = filters.query.toLowerCase();\n messages = messages.filter(\n (m) =>\n m.subject?.toLowerCase().includes(q) ||\n m.body?.toLowerCase().includes(q),\n );\n }\n }\n\n return messages;\n }\n\n /**\n * Get messages by multiple accounts\n */\n async getByAccounts(accountIds: string[]): Promise<Message[]> {\n const allMessages = await this.list({});\n return allMessages.filter((m) => accountIds.includes(m.accountId));\n }\n\n /**\n * Get messages by STI type.\n *\n * Accepts either the full discriminator (e.g. \"@happyvertical/smrt-messages:Email\")\n * or the short type name (e.g. \"Email\").\n */\n async getByType(messageType: string): Promise<Message[]> {\n if (messageType.includes(':') || messageType.startsWith('@')) {\n return await this.list({ where: { _meta_type: messageType } });\n }\n const allMessages = await this.list({});\n return allMessages.filter((m) => {\n const metaType = (m as { _meta_type?: string })._meta_type || '';\n return metaType.endsWith(`:${messageType}`);\n });\n }\n\n /**\n * Get unread messages\n */\n async getUnread(accountId?: string): Promise<Message[]> {\n const where: Record<string, unknown> = { isRead: false };\n if (accountId) {\n where.accountId = accountId;\n }\n return await this.list({ where });\n }\n\n /**\n * Get flagged messages\n */\n async getFlagged(accountId?: string): Promise<Message[]> {\n const where: Record<string, unknown> = { isFlagged: true };\n if (accountId) {\n where.accountId = accountId;\n }\n return await this.list({ where });\n }\n\n /**\n * Get recent messages\n */\n async getRecent(limit = 20, accountId?: string): Promise<Message[]> {\n const allMessages = await this.list({\n where: accountId ? { accountId } : undefined,\n });\n\n return allMessages\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 * Get messages by thread\n */\n async getByThread(threadId: string): Promise<Message[]> {\n return await this.list({ where: { threadId } });\n }\n\n /**\n * Mark multiple messages as read\n */\n async markAllRead(messageIds: string[]): Promise<void> {\n for (const id of messageIds) {\n const message = await this.get({ id });\n if (message) {\n await message.markRead();\n }\n }\n }\n\n /**\n * Get message statistics for an account\n */\n async getAccountStats(accountId: string): Promise<{\n total: number;\n unread: number;\n flagged: number;\n byType: Record<string, number>;\n }> {\n const messages = await this.list({ where: { accountId } });\n const byType: Record<string, number> = {};\n\n for (const msg of messages) {\n const metaType = (msg as { _meta_type?: string })._meta_type || 'Unknown';\n const shortType = metaType.split(':').pop() || metaType;\n byType[shortType] = (byType[shortType] || 0) + 1;\n }\n\n return {\n total: messages.length,\n unread: messages.filter((m) => !m.isRead).length,\n flagged: messages.filter((m) => m.isFlagged).length,\n byType,\n };\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Send / Draft Queries\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Get draft messages\n */\n async getDrafts(accountId?: string): Promise<Message[]> {\n const where: Record<string, unknown> = { sendStatus: 'draft' };\n if (accountId) where.accountId = accountId;\n return await this.list({ where });\n }\n\n /**\n * Get sent messages\n */\n async getSent(accountId?: string): Promise<Message[]> {\n const where: Record<string, unknown> = { sendStatus: 'sent' };\n if (accountId) where.accountId = accountId;\n return await this.list({ where });\n }\n\n /**\n * Get scheduled messages\n */\n async getScheduled(accountId?: string): Promise<Message[]> {\n const where: Record<string, unknown> = { sendStatus: 'scheduled' };\n if (accountId) where.accountId = accountId;\n return await this.list({ where });\n }\n\n /**\n * Get messages that failed to send\n */\n async getFailedSends(accountId?: string): Promise<Message[]> {\n const where: Record<string, unknown> = { sendStatus: 'failed' };\n if (accountId) where.accountId = accountId;\n return await this.list({ where });\n }\n\n /**\n * Get outbox (pending + sending + scheduled)\n */\n async getOutbox(accountId?: string): Promise<Message[]> {\n const allMessages = await this.list({\n where: accountId ? { accountId } : undefined,\n });\n return allMessages.filter(\n (m) =>\n m.sendStatus === 'pending' ||\n m.sendStatus === 'sending' ||\n m.sendStatus === 'scheduled',\n );\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Tenant Helper Methods\n // ─────────────────────────────────────────────────────────────────────────\n\n async findByTenant(tenantId: string): Promise<Message[]> {\n return this.list({ where: { tenantId } });\n }\n\n // Message is the @TenantScoped STI base, so an explicit `tenant_id IS NULL`\n // filter via list() throws and unflagged raw SQL is blocked under an active\n // tenant context (#1596). Route through the raw helpers — no `_meta_type`\n // scope so the base collection still returns ALL message subtypes.\n async findGlobal(): Promise<Message[]> {\n return queryGlobal<Message>(this);\n }\n\n async findWithGlobals(tenantId: string): Promise<Message[]> {\n return queryWithGlobals<Message>(this, tenantId, 'Message.findWithGlobals');\n }\n}\n"],"mappings":"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"}