@happyvertical/smrt-messages 0.43.8 → 0.43.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.
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { t as Message } from "./Message-CORy3jwy.js";
2
+ import { t as Message } from "./Message-68WwnJi0.js";
3
3
  import { smrt } from "@happyvertical/smrt-core";
4
4
  //#region src/models/Email.ts
5
5
  var Email_exports = /* @__PURE__ */ __exportAll({ Email: () => Email });
@@ -279,4 +279,4 @@ Email = __decorateClass([smrt({
279
279
  //#endregion
280
280
  export { Email_exports as n, Email as t };
281
281
 
282
- //# sourceMappingURL=Email-BwMhh-Dr.js.map
282
+ //# sourceMappingURL=Email-BR0NkbZc.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Email-BwMhh-Dr.js","names":[],"sources":["../../src/models/Email.ts"],"sourcesContent":["/**\n * Email model - Email message extending the Message STI base\n *\n * Retains all email-specific fields (RFC 822 compliance, folders, etc.)\n * while inheriting common message fields from Message.\n */\n\nimport { smrt } from '@happyvertical/smrt-core';\nimport type { EmailOptions } from '../types';\nimport { Message } from './Message';\n\n@smrt({\n tableStrategy: 'sti',\n api: { include: ['list', 'get', 'create', 'update', 'delete'] },\n mcp: { include: ['list', 'get'] },\n cli: true,\n})\nexport class Email extends Message {\n // RFC 822 fields\n messageId = ''; // RFC 822 Message-ID header\n inReplyTo = '';\n\n // Additional recipients\n ccAddresses = '';\n bccAddresses = '';\n replyToAddress = '';\n replyToName = '';\n\n // Email-specific content\n textBody = '';\n htmlBody = '';\n\n // Location\n folderId = '';\n folderPath = '';\n labels = ''; // JSON array (Gmail)\n flags = ''; // JSON array (IMAP)\n\n // Email-specific status flags\n isAnswered = false;\n isDraft = false;\n\n // Raw data\n rawMessage = '';\n headers = ''; // JSON object\n\n constructor(options: EmailOptions = {}) {\n super(options);\n\n if (options.messageId !== undefined) this.messageId = options.messageId;\n if (options.inReplyTo !== undefined) this.inReplyTo = options.inReplyTo;\n if (options.ccAddresses !== undefined)\n this.ccAddresses = options.ccAddresses;\n if (options.bccAddresses !== undefined)\n this.bccAddresses = options.bccAddresses;\n if (options.replyToAddress !== undefined)\n this.replyToAddress = options.replyToAddress;\n if (options.replyToName !== undefined)\n this.replyToName = options.replyToName;\n if (options.textBody !== undefined) this.textBody = options.textBody;\n if (options.htmlBody !== undefined) this.htmlBody = options.htmlBody;\n if (options.folderId !== undefined) this.folderId = options.folderId;\n if (options.folderPath !== undefined) this.folderPath = options.folderPath;\n if (options.labels !== undefined) this.labels = options.labels;\n if (options.flags !== undefined) this.flags = options.flags;\n if (options.isAnswered !== undefined) this.isAnswered = options.isAnswered;\n if (options.isDraft !== undefined) this.isDraft = options.isDraft;\n if (options.rawMessage !== undefined) this.rawMessage = options.rawMessage;\n if (options.headers !== undefined) this.headers = options.headers;\n\n // Populate base body from textBody for unified access\n if (options.textBody && !options.body) {\n this.body = options.textBody;\n }\n }\n\n /**\n * Get CC addresses as parsed array\n */\n getCcAddresses(): Array<{ address: string; name?: string }> {\n if (!this.ccAddresses) return [];\n try {\n return JSON.parse(this.ccAddresses);\n } catch {\n return [];\n }\n }\n\n /**\n * Get BCC addresses as parsed array\n */\n getBccAddresses(): Array<{ address: string; name?: string }> {\n if (!this.bccAddresses) return [];\n try {\n return JSON.parse(this.bccAddresses);\n } catch {\n return [];\n }\n }\n\n /**\n * Get labels as parsed array\n */\n getLabels(): string[] {\n if (!this.labels) return [];\n try {\n return JSON.parse(this.labels);\n } catch {\n return [];\n }\n }\n\n /**\n * Set labels from array\n */\n setLabels(labels: string[]): void {\n this.labels = JSON.stringify(labels);\n }\n\n /**\n * Get flags as parsed array\n */\n getFlags(): string[] {\n if (!this.flags) return [];\n try {\n return JSON.parse(this.flags);\n } catch {\n return [];\n }\n }\n\n /**\n * Set flags from array\n */\n setFlags(flags: string[]): void {\n this.flags = JSON.stringify(flags);\n }\n\n /**\n * Get headers as parsed object\n */\n getHeaders(): Record<string, string | string[]> {\n if (!this.headers) return {};\n try {\n return JSON.parse(this.headers);\n } catch {\n return {};\n }\n }\n\n /**\n * Set headers from object\n */\n setHeaders(headers: Record<string, string | string[]>): void {\n this.headers = JSON.stringify(headers);\n }\n\n /**\n * Get the email account (typed as EmailAccount)\n */\n override async getAccount() {\n if (!this.accountId) return null;\n\n const { EmailAccountCollection } = await import(\n '../collections/EmailAccountCollection'\n );\n const collection = await EmailAccountCollection.create(this.options);\n\n return await collection.get({ id: this.accountId });\n }\n\n /**\n * Get the folder\n */\n async getFolder() {\n if (!this.folderId) return null;\n\n const { EmailFolderCollection } = await import(\n '../collections/EmailFolderCollection'\n );\n const collection = await EmailFolderCollection.create(this.options);\n\n return await collection.get({ id: this.folderId });\n }\n\n /**\n * Get emails in the same thread\n */\n async getThreadEmails(): Promise<Email[]> {\n if (!this.threadId) return [this];\n\n const { EmailCollection } = await import('../collections/EmailCollection');\n const collection = await EmailCollection.create(this.options);\n\n return await collection.getByThread(this.threadId);\n }\n\n /**\n * Get a short preview of the email body\n */\n override getPreview(maxLength = 200): string {\n const body = this.textBody || this.htmlBody?.replace(/<[^>]*>/g, '') || '';\n if (body.length <= maxLength) return body;\n return `${body.slice(0, maxLength)}...`;\n }\n\n /**\n * Get References header values as array\n */\n getReferences(): string[] {\n const headers = this.getHeaders();\n const refs = headers.references;\n if (!refs) return [];\n if (Array.isArray(refs)) return refs;\n return refs.split(/\\s+/).filter(Boolean);\n }\n\n /**\n * Create a reply to this email with RFC 822 threading\n */\n override createReply(options?: { replyAll?: boolean }): Email {\n const reply = new Email({\n ...this.draftOptions(),\n id: undefined,\n accountId: this.accountId,\n threadId: this.threadId || this.id || undefined,\n subject: this.subject.startsWith('Re:')\n ? this.subject\n : `Re: ${this.subject}`,\n fromAddress: '',\n fromName: '',\n inReplyToMessageId: this.id || undefined,\n sendStatus: 'draft',\n isRead: true,\n isDraft: true,\n date: null,\n createdAt: undefined,\n updatedAt: undefined,\n\n // RFC 822 threading\n inReplyTo: this.messageId,\n\n // To: original sender\n toAddresses: JSON.stringify([\n { address: this.fromAddress, name: this.fromName },\n ]),\n });\n\n // RFC 822 References: original references + original Message-ID\n const refs = [...this.getReferences()];\n if (this.messageId && !refs.includes(this.messageId)) {\n refs.push(this.messageId);\n }\n reply.setHeaders({ references: refs.join(' ') });\n\n // Reply-All: add original To/CC as CC (excluding self)\n if (options?.replyAll) {\n const allRecipients = [\n ...this.getToAddresses(),\n ...this.getCcAddresses(),\n ];\n // Remove original sender (already in To:) and any duplicates\n const seen = new Set([this.fromAddress.toLowerCase()]);\n const ccAddresses = allRecipients.filter((r) => {\n const addr = r.address.toLowerCase();\n if (seen.has(addr)) return false;\n seen.add(addr);\n return true;\n });\n reply.ccAddresses = JSON.stringify(ccAddresses);\n }\n\n reply.body = this.buildQuotedBody();\n reply.textBody = reply.body;\n\n return reply;\n }\n\n /**\n * Create a forward of this email\n */\n override createForward(): Email {\n const forwardBody = this.buildForwardBody();\n\n const forward = new Email({\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 ccAddresses: '[]',\n bccAddresses: '[]',\n fromAddress: '',\n fromName: '',\n body: forwardBody,\n textBody: forwardBody,\n hasAttachments: this.hasAttachments,\n inReplyToMessageId: '',\n inReplyTo: '',\n sendStatus: 'draft',\n isDraft: true,\n isRead: true,\n date: null,\n createdAt: undefined,\n updatedAt: undefined,\n });\n\n return forward;\n }\n\n /**\n * Build email-specific quoted body for replies\n */\n protected override 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 bodyText = this.textBody || this.body || '';\n const quotedLines = bodyText\n .split('\\n')\n .map((line) => `> ${line}`)\n .join('\\n');\n\n return `\\n\\nOn ${dateStr}, ${from} wrote:\\n${quotedLines}`;\n }\n\n /**\n * Build forwarded message body\n */\n private buildForwardBody(): 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 toStr = this.getToAddresses()\n .map((r) => (r.name ? `${r.name} <${r.address}>` : r.address))\n .join(', ');\n\n const bodyText = this.textBody || this.body || '';\n\n return [\n '',\n '',\n '---------- Forwarded message ----------',\n `From: ${from}`,\n `Date: ${dateStr}`,\n `Subject: ${this.subject}`,\n `To: ${toStr}`,\n '',\n bodyText,\n ].join('\\n');\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Email-BR0NkbZc.js","names":[],"sources":["../../src/models/Email.ts"],"sourcesContent":["/**\n * Email model - Email message extending the Message STI base\n *\n * Retains all email-specific fields (RFC 822 compliance, folders, etc.)\n * while inheriting common message fields from Message.\n */\n\nimport { smrt } from '@happyvertical/smrt-core';\nimport type { EmailOptions } from '../types';\nimport { Message } from './Message';\n\n@smrt({\n tableStrategy: 'sti',\n api: { include: ['list', 'get', 'create', 'update', 'delete'] },\n mcp: { include: ['list', 'get'] },\n cli: true,\n})\nexport class Email extends Message {\n // RFC 822 fields\n messageId = ''; // RFC 822 Message-ID header\n inReplyTo = '';\n\n // Additional recipients\n ccAddresses = '';\n bccAddresses = '';\n replyToAddress = '';\n replyToName = '';\n\n // Email-specific content\n textBody = '';\n htmlBody = '';\n\n // Location\n folderId = '';\n folderPath = '';\n labels = ''; // JSON array (Gmail)\n flags = ''; // JSON array (IMAP)\n\n // Email-specific status flags\n isAnswered = false;\n isDraft = false;\n\n // Raw data\n rawMessage = '';\n headers = ''; // JSON object\n\n constructor(options: EmailOptions = {}) {\n super(options);\n\n if (options.messageId !== undefined) this.messageId = options.messageId;\n if (options.inReplyTo !== undefined) this.inReplyTo = options.inReplyTo;\n if (options.ccAddresses !== undefined)\n this.ccAddresses = options.ccAddresses;\n if (options.bccAddresses !== undefined)\n this.bccAddresses = options.bccAddresses;\n if (options.replyToAddress !== undefined)\n this.replyToAddress = options.replyToAddress;\n if (options.replyToName !== undefined)\n this.replyToName = options.replyToName;\n if (options.textBody !== undefined) this.textBody = options.textBody;\n if (options.htmlBody !== undefined) this.htmlBody = options.htmlBody;\n if (options.folderId !== undefined) this.folderId = options.folderId;\n if (options.folderPath !== undefined) this.folderPath = options.folderPath;\n if (options.labels !== undefined) this.labels = options.labels;\n if (options.flags !== undefined) this.flags = options.flags;\n if (options.isAnswered !== undefined) this.isAnswered = options.isAnswered;\n if (options.isDraft !== undefined) this.isDraft = options.isDraft;\n if (options.rawMessage !== undefined) this.rawMessage = options.rawMessage;\n if (options.headers !== undefined) this.headers = options.headers;\n\n // Populate base body from textBody for unified access\n if (options.textBody && !options.body) {\n this.body = options.textBody;\n }\n }\n\n /**\n * Get CC addresses as parsed array\n */\n getCcAddresses(): Array<{ address: string; name?: string }> {\n if (!this.ccAddresses) return [];\n try {\n return JSON.parse(this.ccAddresses);\n } catch {\n return [];\n }\n }\n\n /**\n * Get BCC addresses as parsed array\n */\n getBccAddresses(): Array<{ address: string; name?: string }> {\n if (!this.bccAddresses) return [];\n try {\n return JSON.parse(this.bccAddresses);\n } catch {\n return [];\n }\n }\n\n /**\n * Get labels as parsed array\n */\n getLabels(): string[] {\n if (!this.labels) return [];\n try {\n return JSON.parse(this.labels);\n } catch {\n return [];\n }\n }\n\n /**\n * Set labels from array\n */\n setLabels(labels: string[]): void {\n this.labels = JSON.stringify(labels);\n }\n\n /**\n * Get flags as parsed array\n */\n getFlags(): string[] {\n if (!this.flags) return [];\n try {\n return JSON.parse(this.flags);\n } catch {\n return [];\n }\n }\n\n /**\n * Set flags from array\n */\n setFlags(flags: string[]): void {\n this.flags = JSON.stringify(flags);\n }\n\n /**\n * Get headers as parsed object\n */\n getHeaders(): Record<string, string | string[]> {\n if (!this.headers) return {};\n try {\n return JSON.parse(this.headers);\n } catch {\n return {};\n }\n }\n\n /**\n * Set headers from object\n */\n setHeaders(headers: Record<string, string | string[]>): void {\n this.headers = JSON.stringify(headers);\n }\n\n /**\n * Get the email account (typed as EmailAccount)\n */\n override async getAccount() {\n if (!this.accountId) return null;\n\n const { EmailAccountCollection } = await import(\n '../collections/EmailAccountCollection'\n );\n const collection = await EmailAccountCollection.create(this.options);\n\n return await collection.get({ id: this.accountId });\n }\n\n /**\n * Get the folder\n */\n async getFolder() {\n if (!this.folderId) return null;\n\n const { EmailFolderCollection } = await import(\n '../collections/EmailFolderCollection'\n );\n const collection = await EmailFolderCollection.create(this.options);\n\n return await collection.get({ id: this.folderId });\n }\n\n /**\n * Get emails in the same thread\n */\n async getThreadEmails(): Promise<Email[]> {\n if (!this.threadId) return [this];\n\n const { EmailCollection } = await import('../collections/EmailCollection');\n const collection = await EmailCollection.create(this.options);\n\n return await collection.getByThread(this.threadId);\n }\n\n /**\n * Get a short preview of the email body\n */\n override getPreview(maxLength = 200): string {\n const body = this.textBody || this.htmlBody?.replace(/<[^>]*>/g, '') || '';\n if (body.length <= maxLength) return body;\n return `${body.slice(0, maxLength)}...`;\n }\n\n /**\n * Get References header values as array\n */\n getReferences(): string[] {\n const headers = this.getHeaders();\n const refs = headers.references;\n if (!refs) return [];\n if (Array.isArray(refs)) return refs;\n return refs.split(/\\s+/).filter(Boolean);\n }\n\n /**\n * Create a reply to this email with RFC 822 threading\n */\n override createReply(options?: { replyAll?: boolean }): Email {\n const reply = new Email({\n ...this.draftOptions(),\n id: undefined,\n accountId: this.accountId,\n threadId: this.threadId || this.id || undefined,\n subject: this.subject.startsWith('Re:')\n ? this.subject\n : `Re: ${this.subject}`,\n fromAddress: '',\n fromName: '',\n inReplyToMessageId: this.id || undefined,\n sendStatus: 'draft',\n isRead: true,\n isDraft: true,\n date: null,\n createdAt: undefined,\n updatedAt: undefined,\n\n // RFC 822 threading\n inReplyTo: this.messageId,\n\n // To: original sender\n toAddresses: JSON.stringify([\n { address: this.fromAddress, name: this.fromName },\n ]),\n });\n\n // RFC 822 References: original references + original Message-ID\n const refs = [...this.getReferences()];\n if (this.messageId && !refs.includes(this.messageId)) {\n refs.push(this.messageId);\n }\n reply.setHeaders({ references: refs.join(' ') });\n\n // Reply-All: add original To/CC as CC (excluding self)\n if (options?.replyAll) {\n const allRecipients = [\n ...this.getToAddresses(),\n ...this.getCcAddresses(),\n ];\n // Remove original sender (already in To:) and any duplicates\n const seen = new Set([this.fromAddress.toLowerCase()]);\n const ccAddresses = allRecipients.filter((r) => {\n const addr = r.address.toLowerCase();\n if (seen.has(addr)) return false;\n seen.add(addr);\n return true;\n });\n reply.ccAddresses = JSON.stringify(ccAddresses);\n }\n\n reply.body = this.buildQuotedBody();\n reply.textBody = reply.body;\n\n return reply;\n }\n\n /**\n * Create a forward of this email\n */\n override createForward(): Email {\n const forwardBody = this.buildForwardBody();\n\n const forward = new Email({\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 ccAddresses: '[]',\n bccAddresses: '[]',\n fromAddress: '',\n fromName: '',\n body: forwardBody,\n textBody: forwardBody,\n hasAttachments: this.hasAttachments,\n inReplyToMessageId: '',\n inReplyTo: '',\n sendStatus: 'draft',\n isDraft: true,\n isRead: true,\n date: null,\n createdAt: undefined,\n updatedAt: undefined,\n });\n\n return forward;\n }\n\n /**\n * Build email-specific quoted body for replies\n */\n protected override 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 bodyText = this.textBody || this.body || '';\n const quotedLines = bodyText\n .split('\\n')\n .map((line) => `> ${line}`)\n .join('\\n');\n\n return `\\n\\nOn ${dateStr}, ${from} wrote:\\n${quotedLines}`;\n }\n\n /**\n * Build forwarded message body\n */\n private buildForwardBody(): 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 toStr = this.getToAddresses()\n .map((r) => (r.name ? `${r.name} <${r.address}>` : r.address))\n .join(', ');\n\n const bodyText = this.textBody || this.body || '';\n\n return [\n '',\n '',\n '---------- Forwarded message ----------',\n `From: ${from}`,\n `Date: ${dateStr}`,\n `Subject: ${this.subject}`,\n `To: ${toStr}`,\n '',\n bodyText,\n ].join('\\n');\n }\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { SmrtObject, crossPackageRef, foreignKey, smrt } from "@happyvertical/smrt-core";
1
+ import { SmrtObject, crossPackageRef, foreignKey, smrt, usesEmbeddedRevisionFallback, withEmbeddedWriteQueue } from "@happyvertical/smrt-core";
2
2
  import { TenantScoped, tenantId } from "@happyvertical/smrt-tenancy";
3
3
  //#region src/models/Message.ts
4
4
  var __defProp = Object.defineProperty;
@@ -65,6 +65,47 @@ var Message = class extends SmrtObject {
65
65
  if (options.createdAt) this.createdAt = options.createdAt;
66
66
  if (options.updatedAt) this.updatedAt = options.updatedAt;
67
67
  }
68
+ async finalizeSendLifecycle(result) {
69
+ if (!this.id) throw new Error("Cannot finalize an unsaved message send");
70
+ const sendStatus = result.success ? "sent" : "failed";
71
+ const sendError = result.success ? "" : result.error ?? "Send failed";
72
+ const useEmbeddedFallback = usesEmbeddedRevisionFallback(this.db);
73
+ for (let attempt = 0; attempt < 8; attempt += 1) {
74
+ let nextRevision;
75
+ await withEmbeddedWriteQueue(this.db, useEmbeddedFallback, async () => {
76
+ const current = await this.getCanonicalPersistedRow({ id: this.id });
77
+ if (current?.send_status !== "sending") return;
78
+ const currentRevision = current.updated_at;
79
+ const currentRevisionMs = new Date(String(currentRevision)).getTime();
80
+ if (!Number.isFinite(currentRevisionMs)) return;
81
+ nextRevision = new Date(Math.max(Date.now(), currentRevisionMs + 1));
82
+ const values = {
83
+ send_status: sendStatus,
84
+ sent_at: result.success ? result.sentAt : null,
85
+ send_error: sendError,
86
+ updated_at: nextRevision
87
+ };
88
+ if (useEmbeddedFallback) {
89
+ await this.db.upsert(this.tableName, ["id"], {
90
+ ...current,
91
+ ...values
92
+ });
93
+ return;
94
+ }
95
+ await this.db.update(this.tableName, {
96
+ id: this.id,
97
+ send_status: "sending",
98
+ updated_at: currentRevision instanceof Date ? currentRevision.toISOString() : currentRevision
99
+ }, values);
100
+ });
101
+ const verified = await this.getCanonicalPersistedRow({ id: this.id });
102
+ if (verified?.send_status === sendStatus) {
103
+ await this.completePersistedUpdate(verified);
104
+ return;
105
+ }
106
+ }
107
+ throw new Error("Cannot finalize: message revision kept changing");
108
+ }
68
109
  /**
69
110
  * Get to addresses as parsed array
70
111
  */
@@ -155,7 +196,7 @@ var Message = class extends SmrtObject {
155
196
  */
156
197
  async getThreadMessages() {
157
198
  if (!this.threadId) return [this];
158
- const { MessageCollection } = await import("./MessageCollection-D6zqQoJV.js").then((n) => n.n);
199
+ const { MessageCollection } = await import("./MessageCollection-Db1A7xHc.js").then((n) => n.n);
159
200
  return await (await MessageCollection.create(this.options)).list({ where: { threadId: this.threadId } });
160
201
  }
161
202
  /**
@@ -176,28 +217,28 @@ var Message = class extends SmrtObject {
176
217
  };
177
218
  const account = await this.getAccount();
178
219
  if (!account) {
179
- const result = {
220
+ const result2 = {
180
221
  success: false,
181
222
  error: "No account associated with this message",
182
223
  sentAt: /* @__PURE__ */ new Date()
183
224
  };
184
225
  this.sendStatus = "failed";
185
- this.sendError = result.error ?? "";
226
+ this.sendError = result2.error ?? "";
186
227
  this.updatedAt = /* @__PURE__ */ new Date();
187
228
  await this.save();
188
- return result;
229
+ return result2;
189
230
  }
190
231
  if (!account.isActive) {
191
- const result = {
232
+ const result2 = {
192
233
  success: false,
193
234
  error: "Messaging account is inactive",
194
235
  sentAt: /* @__PURE__ */ new Date()
195
236
  };
196
237
  this.sendStatus = "failed";
197
- this.sendError = result.error ?? "";
238
+ this.sendError = result2.error ?? "";
198
239
  this.updatedAt = /* @__PURE__ */ new Date();
199
240
  await this.save();
200
- return result;
241
+ return result2;
201
242
  }
202
243
  let sender;
203
244
  try {
@@ -216,50 +257,63 @@ var Message = class extends SmrtObject {
216
257
  }
217
258
  const claimFromStatus = this.sendStatus;
218
259
  if (this.isPersisted && this.id) {
219
- const claim = await this.db.update(this.tableName, {
220
- id: this.id,
221
- send_status: claimFromStatus
222
- }, {
223
- send_status: "sending",
224
- updated_at: /* @__PURE__ */ new Date()
260
+ const loadedRevision = this.updated_at;
261
+ if (!loadedRevision) return {
262
+ success: false,
263
+ error: "Cannot send: persisted message has no loaded revision",
264
+ sentAt: /* @__PURE__ */ new Date()
265
+ };
266
+ const claimedRevision = new Date(Math.max(Date.now(), loadedRevision.getTime() + 1));
267
+ const useEmbeddedFallback = usesEmbeddedRevisionFallback(this.db);
268
+ let claimed = false;
269
+ await withEmbeddedWriteQueue(this.db, useEmbeddedFallback, async () => {
270
+ if (useEmbeddedFallback) {
271
+ const current = await this.getCanonicalPersistedRow({ id: this.id });
272
+ const storedRevision = current?.updated_at;
273
+ const currentRevision = storedRevision instanceof Date ? storedRevision.getTime() : typeof storedRevision === "string" ? Date.parse(storedRevision) : NaN;
274
+ if (!current || current.send_status !== claimFromStatus || !Number.isFinite(currentRevision) || currentRevision !== loadedRevision.getTime()) return;
275
+ await this.db.upsert(this.tableName, ["id"], {
276
+ ...current,
277
+ send_status: "sending",
278
+ updated_at: claimedRevision
279
+ });
280
+ claimed = true;
281
+ return;
282
+ }
283
+ claimed = (await this.db.update(this.tableName, {
284
+ id: this.id,
285
+ send_status: claimFromStatus,
286
+ updated_at: loadedRevision.toISOString()
287
+ }, {
288
+ send_status: "sending",
289
+ updated_at: claimedRevision
290
+ }))?.affected === 1;
225
291
  });
226
- if (!claim || claim.affected < 1) return {
292
+ if (!claimed) return {
227
293
  success: false,
228
294
  error: "Cannot send: message is already being sent",
229
295
  sentAt: /* @__PURE__ */ new Date()
230
296
  };
231
297
  this.sendStatus = "sending";
298
+ this.updated_at = claimedRevision;
232
299
  this.updatedAt = /* @__PURE__ */ new Date();
233
300
  } else {
234
301
  this.sendStatus = "sending";
235
302
  this.updatedAt = /* @__PURE__ */ new Date();
236
303
  await this.save();
237
304
  }
305
+ let result;
238
306
  try {
239
- const result = await sender.send(this, options);
240
- if (result.success) {
241
- this.sendStatus = "sent";
242
- this.sentAt = result.sentAt;
243
- this.sendError = "";
244
- } else {
245
- this.sendStatus = "failed";
246
- this.sendError = result.error ?? "Send failed";
247
- }
248
- this.updatedAt = /* @__PURE__ */ new Date();
249
- await this.save();
250
- return result;
307
+ result = await sender.send(this, options);
251
308
  } catch (error) {
252
- const errorMessage = error instanceof Error ? error.message : String(error);
253
- this.sendStatus = "failed";
254
- this.sendError = errorMessage;
255
- this.updatedAt = /* @__PURE__ */ new Date();
256
- await this.save();
257
- return {
309
+ result = {
258
310
  success: false,
259
- error: errorMessage,
311
+ error: error instanceof Error ? error.message : String(error),
260
312
  sentAt: /* @__PURE__ */ new Date()
261
313
  };
262
314
  }
315
+ await this.finalizeSendLifecycle(result);
316
+ return result;
263
317
  }
264
318
  /**
265
319
  * Retry sending a failed message
@@ -369,4 +423,4 @@ Message = __decorateClass([TenantScoped({ mode: "optional" }), smrt({
369
423
  //#endregion
370
424
  export { Message as t };
371
425
 
372
- //# sourceMappingURL=Message-CORy3jwy.js.map
426
+ //# sourceMappingURL=Message-68WwnJi0.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Message-68WwnJi0.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\nimport {\n crossPackageRef,\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@TenantScoped({ mode: 'optional' })\n@smrt({\n tableStrategy: 'sti',\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: true,\n})\nexport class Message extends SmrtObject {\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n @foreignKey('Account')\n accountId = '';\n @crossPackageRef('@happyvertical/smrt-personas:AgentPersona', {\n nullable: true,\n })\n personaId: string | null = null;\n @foreignKey('MessagingEndpoint')\n endpointId: string | null = null;\n correlationId = '';\n threadId = '';\n subject = '';\n body = ''; // Normalized plain text\n fromAddress = '';\n fromName = '';\n toAddresses = ''; // JSON array of {address, name}\n date: Date | null = null;\n isRead = false;\n isFlagged = false;\n hasAttachments = false;\n size = 0;\n metadata = ''; // JSON extension bag\n\n // Send lifecycle fields\n sendStatus: SendStatus = 'draft';\n sentAt: Date | null = null;\n sendError = '';\n retryCount = 0;\n maxRetries = 3;\n scheduledSendAt: Date | null = null;\n @foreignKey('Message')\n inReplyToMessageId = '';\n\n // Timestamps\n createdAt = new Date();\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 const values = {\n send_status: sendStatus,\n sent_at: result.success ? result.sentAt : null,\n send_error: sendError,\n updated_at: nextRevision,\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 result = {\n success: false,\n error: errorMessage,\n sentAt: new Date(),\n };\n }\n await this.finalizeSendLifecycle(result);\n return result;\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-CORy3jwy.js";
2
+ import { t as Message } from "./Message-68WwnJi0.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-D6zqQoJV.js.map
169
+ //# sourceMappingURL=MessageCollection-Db1A7xHc.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MessageCollection-D6zqQoJV.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-Db1A7xHc.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":";;;;;;AAWO,IAAM,oBAAN,cAAgC,eAAwB;CAC7D,OAAgB,aAAa;;;;CAK7B,MAAM,OACJ,OACA,SACoB;EACpB,IAAI,WAAW,MAAM,KAAK,KAAK,CAAC,CAAC;EAGjC,IAAI,OAAO;GACT,MAAM,aAAa,MAAM,YAAY;GACrC,WAAW,SAAS,QACjB,MACC,EAAE,SAAS,YAAY,CAAA,CAAE,SAAS,UAAU,KAC5C,EAAE,MAAM,YAAY,CAAA,CAAE,SAAS,UAAU,KACzC,EAAE,aAAa,YAAY,CAAA,CAAE,SAAS,UAAU,KAChD,EAAE,UAAU,YAAY,CAAA,CAAE,SAAS,UAAU,CACjD;EACF;EAGA,IAAI,SAAS;GACX,IAAI,QAAQ,cAAc,QAAQ,WAAW,SAAS,GACpD,WAAW,SAAS,QAAQ,MAC1B,QAAQ,YAAY,SAAS,EAAE,SAAS,CAC1C;GAEF,IAAI,QAAQ,aACV,WAAW,SAAS,QAAQ,MAAM;IAEhC,QADkB,EAA8B,cAAc,GAAA,CAC9C,SAAS,QAAQ,WAAqB;GACxD,CAAC;GAEH,IAAI,QAAQ,MAAM;IAChB,MAAM,YAAY,QAAQ,KAAK,YAAY;IAC3C,WAAW,SAAS,QACjB,MACC,EAAE,aAAa,YAAY,CAAA,CAAE,SAAS,SAAS,KAC/C,EAAE,UAAU,YAAY,CAAA,CAAE,SAAS,SAAS,CAChD;GACF;GACA,IAAI,QAAQ,IAAI;IACd,MAAM,UAAU,QAAQ,GAAG,YAAY;IACvC,WAAW,SAAS,QAAQ,MAC1B,EAAE,aAAa,YAAY,CAAA,CAAE,SAAS,OAAO,CAC/C;GACF;GACA,IAAI,QAAQ,WAAW,KAAA,GACrB,WAAW,SAAS,QAAQ,MAAM,EAAE,WAAW,QAAQ,MAAM;GAE/D,IAAI,QAAQ,cAAc,KAAA,GACxB,WAAW,SAAS,QAAQ,MAAM,EAAE,cAAc,QAAQ,SAAS;GAErE,IAAI,QAAQ,WACV,WAAW,SAAS,QACjB,MAAM,EAAE,QAAQ,EAAE,QAAS,QAAQ,SACtC;GAEF,IAAI,QAAQ,YACV,WAAW,SAAS,QACjB,MAAM,EAAE,QAAQ,EAAE,OAAQ,QAAQ,UACrC;GAEF,IAAI,QAAQ,OAAO;IACjB,MAAM,IAAI,QAAQ,MAAM,YAAY;IACpC,WAAW,SAAS,QACjB,MACC,EAAE,SAAS,YAAY,CAAA,CAAE,SAAS,CAAC,KACnC,EAAE,MAAM,YAAY,CAAA,CAAE,SAAS,CAAC,CACpC;GACF;EACF;EAEA,OAAO;CACT;;;;CAKA,MAAM,cAAc,YAA0C;EAE5D,QAAO,MADmB,KAAK,KAAK,CAAC,CAAC,EAAA,CACnB,QAAQ,MAAM,WAAW,SAAS,EAAE,SAAS,CAAC;CACnE;;;;;;;CAQA,MAAM,UAAU,aAAyC;EACvD,IAAI,YAAY,SAAS,GAAG,KAAK,YAAY,WAAW,GAAG,GACzD,OAAO,MAAM,KAAK,KAAK,EAAE,OAAO,EAAE,YAAY,YAAY,EAAE,CAAC;EAG/D,QAAO,MADmB,KAAK,KAAK,CAAC,CAAC,EAAA,CACnB,QAAQ,MAAM;GAE/B,QADkB,EAA8B,cAAc,GAAA,CAC9C,SAAS,IAAI,aAAa;EAC5C,CAAC;CACH;;;;CAKA,MAAM,UAAU,WAAwC;EACtD,MAAM,QAAiC,EAAE,QAAQ,MAAM;EACvD,IAAI,WACF,MAAM,YAAY;EAEpB,OAAO,MAAM,KAAK,KAAK,EAAE,MAAM,CAAC;CAClC;;;;CAKA,MAAM,WAAW,WAAwC;EACvD,MAAM,QAAiC,EAAE,WAAW,KAAK;EACzD,IAAI,WACF,MAAM,YAAY;EAEpB,OAAO,MAAM,KAAK,KAAK,EAAE,MAAM,CAAC;CAClC;;;;CAKA,MAAM,UAAU,QAAQ,IAAI,WAAwC;EAKlE,QAAO,MAJmB,KAAK,KAAK,EAClC,OAAO,YAAY,EAAE,UAAU,IAAI,KAAA,EACrC,CAAC,EAAA,CAGE,MAAM,GAAG,MAAM;GACd,MAAM,QAAQ,EAAE,MAAM,QAAQ,KAAK;GAEnC,QADc,EAAE,MAAM,QAAQ,KAAK,KACpB;EACjB,CAAC,CAAA,CACA,MAAM,GAAG,KAAK;CACnB;;;;CAKA,MAAM,YAAY,UAAsC;EACtD,OAAO,MAAM,KAAK,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;CAChD;;;;CAKA,MAAM,YAAY,YAAqC;EACrD,KAAA,MAAW,MAAM,YAAY;GAC3B,MAAM,UAAU,MAAM,KAAK,IAAI,EAAE,GAAG,CAAC;GACrC,IAAI,SACF,MAAM,QAAQ,SAAS;EAE3B;CACF;;;;CAKA,MAAM,gBAAgB,WAKnB;EACD,MAAM,WAAW,MAAM,KAAK,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;EACzD,MAAM,SAAiC,CAAC;EAExC,KAAA,MAAW,OAAO,UAAU;GAC1B,MAAM,WAAY,IAAgC,cAAc;GAChE,MAAM,YAAY,SAAS,MAAM,GAAG,CAAA,CAAE,IAAI,KAAK;GAC/C,OAAO,cAAc,OAAO,cAAc,KAAK;EACjD;EAEA,OAAO;GACL,OAAO,SAAS;GAChB,QAAQ,SAAS,QAAQ,MAAM,CAAC,EAAE,MAAM,CAAA,CAAE;GAC1C,SAAS,SAAS,QAAQ,MAAM,EAAE,SAAS,CAAA,CAAE;GAC7C;EACF;CACF;;;;CASA,MAAM,UAAU,WAAwC;EACtD,MAAM,QAAiC,EAAE,YAAY,QAAQ;EAC7D,IAAI,WAAW,MAAM,YAAY;EACjC,OAAO,MAAM,KAAK,KAAK,EAAE,MAAM,CAAC;CAClC;;;;CAKA,MAAM,QAAQ,WAAwC;EACpD,MAAM,QAAiC,EAAE,YAAY,OAAO;EAC5D,IAAI,WAAW,MAAM,YAAY;EACjC,OAAO,MAAM,KAAK,KAAK,EAAE,MAAM,CAAC;CAClC;;;;CAKA,MAAM,aAAa,WAAwC;EACzD,MAAM,QAAiC,EAAE,YAAY,YAAY;EACjE,IAAI,WAAW,MAAM,YAAY;EACjC,OAAO,MAAM,KAAK,KAAK,EAAE,MAAM,CAAC;CAClC;;;;CAKA,MAAM,eAAe,WAAwC;EAC3D,MAAM,QAAiC,EAAE,YAAY,SAAS;EAC9D,IAAI,WAAW,MAAM,YAAY;EACjC,OAAO,MAAM,KAAK,KAAK,EAAE,MAAM,CAAC;CAClC;;;;CAKA,MAAM,UAAU,WAAwC;EAItD,QAAO,MAHmB,KAAK,KAAK,EAClC,OAAO,YAAY,EAAE,UAAU,IAAI,KAAA,EACrC,CAAC,EAAA,CACkB,QAChB,MACC,EAAE,eAAe,aACjB,EAAE,eAAe,aACjB,EAAE,eAAe,WACrB;CACF;CAMA,MAAM,aAAa,UAAsC;EACvD,OAAO,KAAK,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;CAC1C;CAMA,MAAM,aAAiC;EACrC,OAAO,YAAqB,IAAI;CAClC;CAEA,MAAM,gBAAgB,UAAsC;EAC1D,OAAO,iBAA0B,MAAM,UAAU,yBAAyB;CAC5E;AACF"}
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { t as __exportAll } from "./chunks/rolldown-runtime-D7D4PA-g.js";
2
2
  import { a as registerMessagingProvider, n as getMessagingProvider, o as ZulipSender, r as listMessagingProviders, s as TelegramSender, t as ensureBuiltinMessagingProvidersRegistered } from "./chunks/providers-4iLula-V.js";
3
3
  import { r as Account, t as AccountCollection } from "./chunks/AccountCollection-5IchK-_S.js";
4
- import { t as Message } from "./chunks/Message-CORy3jwy.js";
5
- import { t as MessageCollection } from "./chunks/MessageCollection-D6zqQoJV.js";
6
- import { t as Email } from "./chunks/Email-BwMhh-Dr.js";
4
+ import { t as Message } from "./chunks/Message-68WwnJi0.js";
5
+ import { t as MessageCollection } from "./chunks/MessageCollection-Db1A7xHc.js";
6
+ import { t as Email } from "./chunks/Email-BR0NkbZc.js";
7
7
  import { t as EmailFolder } from "./chunks/EmailFolder-DvZODbnW.js";
8
8
  import { t as SlackSender } from "./chunks/SlackSender-CjSvwY1K.js";
9
9
  import { t as TweetSender } from "./chunks/TweetSender-CcLPNNi1.js";
@@ -90,7 +90,7 @@ var Attachment = class extends SmrtObject {
90
90
  */
91
91
  async getMessage() {
92
92
  if (!this.messageId) return null;
93
- const { MessageCollection } = await import("./chunks/MessageCollection-D6zqQoJV.js").then((n) => n.n);
93
+ const { MessageCollection } = await import("./chunks/MessageCollection-Db1A7xHc.js").then((n) => n.n);
94
94
  return await (await MessageCollection.create(this.options)).get({ id: this.messageId });
95
95
  }
96
96
  /**
@@ -550,7 +550,7 @@ var EmailAccount = class extends Account {
550
550
  result.messagesSkipped++;
551
551
  continue;
552
552
  }
553
- const { Email } = await import("./chunks/Email-BwMhh-Dr.js").then((n) => n.n);
553
+ const { Email } = await import("./chunks/Email-BR0NkbZc.js").then((n) => n.n);
554
554
  let email = existingEmail;
555
555
  if (!email) {
556
556
  email = new Email({