@soulbatical/tetra-core 0.1.39 → 0.1.40

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.

Potentially problematic release.


This version of @soulbatical/tetra-core might be problematic. Click here for more details.

Files changed (48) hide show
  1. package/dist/core/dualWriteProxy.d.ts +11 -0
  2. package/dist/core/dualWriteProxy.d.ts.map +1 -1
  3. package/dist/core/dualWriteProxy.js +142 -198
  4. package/dist/core/dualWriteProxy.js.map +1 -1
  5. package/dist/index.d.ts +2 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +2 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/shared/email/EmailService.d.ts +9 -1
  10. package/dist/shared/email/EmailService.d.ts.map +1 -1
  11. package/dist/shared/email/EmailService.js +83 -7
  12. package/dist/shared/email/EmailService.js.map +1 -1
  13. package/dist/shared/email/mailgun.d.ts +4 -1
  14. package/dist/shared/email/mailgun.d.ts.map +1 -1
  15. package/dist/shared/email/mailgun.js +41 -10
  16. package/dist/shared/email/mailgun.js.map +1 -1
  17. package/dist/shared/email/smtp.d.ts +4 -1
  18. package/dist/shared/email/smtp.d.ts.map +1 -1
  19. package/dist/shared/email/smtp.js +14 -2
  20. package/dist/shared/email/smtp.js.map +1 -1
  21. package/dist/shared/email/types.d.ts +23 -1
  22. package/dist/shared/email/types.d.ts.map +1 -1
  23. package/dist/shared/email/webhookRoutes.d.ts +29 -0
  24. package/dist/shared/email/webhookRoutes.d.ts.map +1 -0
  25. package/dist/shared/email/webhookRoutes.js +125 -0
  26. package/dist/shared/email/webhookRoutes.js.map +1 -0
  27. package/dist/shared/planner/GoogleCalendarService.d.ts +103 -0
  28. package/dist/shared/planner/GoogleCalendarService.d.ts.map +1 -0
  29. package/dist/shared/planner/GoogleCalendarService.js +365 -0
  30. package/dist/shared/planner/GoogleCalendarService.js.map +1 -0
  31. package/dist/shared/planner/PlannerService.d.ts +170 -0
  32. package/dist/shared/planner/PlannerService.d.ts.map +1 -0
  33. package/dist/shared/planner/PlannerService.js +860 -0
  34. package/dist/shared/planner/PlannerService.js.map +1 -0
  35. package/dist/shared/planner/index.d.ts +35 -0
  36. package/dist/shared/planner/index.d.ts.map +1 -0
  37. package/dist/shared/planner/index.js +34 -0
  38. package/dist/shared/planner/index.js.map +1 -0
  39. package/dist/shared/planner/routes.d.ts +67 -0
  40. package/dist/shared/planner/routes.d.ts.map +1 -0
  41. package/dist/shared/planner/routes.js +524 -0
  42. package/dist/shared/planner/routes.js.map +1 -0
  43. package/dist/shared/planner/types.d.ts +262 -0
  44. package/dist/shared/planner/types.d.ts.map +1 -0
  45. package/dist/shared/planner/types.js +9 -0
  46. package/dist/shared/planner/types.js.map +1 -0
  47. package/package.json +1 -1
  48. package/src/shared/email/migrations/004_add_email_logs_tracking_columns.sql +15 -0
@@ -2,7 +2,7 @@
2
2
  * EmailService — Core service for sending templated emails.
3
3
  *
4
4
  * Template lookup with language + org fallback, Handlebars rendering,
5
- * DB logging, and Mailgun delivery.
5
+ * DB logging, and multi-transport delivery (Gmail, SMTP, Mailgun).
6
6
  *
7
7
  * @module @soulbatical/tetra-core/email
8
8
  */
@@ -10,9 +10,11 @@ import Handlebars from 'handlebars';
10
10
  import { sendMailgunEmail } from './mailgun.js';
11
11
  import { sendSmtpEmail } from './smtp.js';
12
12
  import { getGmailClient } from './gmail.js';
13
+ const CACHE_TTL = 5 * 60 * 1000; // 5 minutes
13
14
  export class EmailService {
14
15
  supabase;
15
16
  config;
17
+ templateCache = new Map();
16
18
  constructor(supabase, config) {
17
19
  this.supabase = supabase;
18
20
  this.config = config;
@@ -36,6 +38,9 @@ export class EmailService {
36
38
  const html = template
37
39
  ? this.render(template.body_html, opts.variables)
38
40
  : opts.fallbackHtml || `<p>${subject}</p>`;
41
+ const text = template?.body_text
42
+ ? this.render(template.body_text, opts.variables)
43
+ : opts.fallbackText || undefined;
39
44
  // 2. Create log entry (pending)
40
45
  const logId = await this.createLog({
41
46
  organizationId: opts.organizationId,
@@ -44,10 +49,20 @@ export class EmailService {
44
49
  subject,
45
50
  templateSlug: opts.templateSlug,
46
51
  variables: opts.variables,
52
+ emailType: opts.emailType,
53
+ metadata: opts.metadata,
47
54
  feedbackId: opts.feedbackId,
48
55
  });
49
56
  // 3. Send via configured transport
50
- const result = await this.deliver({ from: this.config.fromAddress, to: opts.to, subject, html });
57
+ const result = await this.deliver({
58
+ from: this.config.fromAddress,
59
+ to: opts.to,
60
+ subject,
61
+ html,
62
+ text,
63
+ replyTo: opts.replyTo,
64
+ attachments: opts.attachments,
65
+ });
51
66
  // 4. Update log
52
67
  if (logId) {
53
68
  await this.updateLog(logId, {
@@ -58,6 +73,22 @@ export class EmailService {
58
73
  }
59
74
  return { success: result.success, logId: logId || undefined };
60
75
  }
76
+ /**
77
+ * Clear template cache. Call after template is updated via admin UI.
78
+ */
79
+ clearCache(slug) {
80
+ if (slug) {
81
+ // Clear all cache keys that start with this slug (all language/org variants)
82
+ for (const key of this.templateCache.keys()) {
83
+ if (key.startsWith(`${slug}:`)) {
84
+ this.templateCache.delete(key);
85
+ }
86
+ }
87
+ }
88
+ else {
89
+ this.templateCache.clear();
90
+ }
91
+ }
61
92
  /**
62
93
  * Resolve transport and send email.
63
94
  * Priority: explicit config.transport > auto-detect (gmail > smtp > mailgun).
@@ -69,7 +100,13 @@ export class EmailService {
69
100
  }
70
101
  if (transport === 'smtp') {
71
102
  return sendSmtpEmail({
72
- ...params,
103
+ from: params.from,
104
+ to: params.to,
105
+ subject: params.subject,
106
+ html: params.html,
107
+ text: params.text,
108
+ replyTo: params.replyTo,
109
+ attachments: params.attachments,
73
110
  smtpHost: this.config.smtpHost,
74
111
  smtpPort: this.config.smtpPort ?? 587,
75
112
  smtpUser: this.config.smtpUser,
@@ -78,7 +115,12 @@ export class EmailService {
78
115
  });
79
116
  }
80
117
  return sendMailgunEmail({
81
- ...params,
118
+ from: params.from,
119
+ to: params.to,
120
+ subject: params.subject,
121
+ html: params.html,
122
+ text: params.text,
123
+ replyTo: params.replyTo,
82
124
  apiKey: this.config.mailgunApiKey,
83
125
  domain: this.config.mailgunDomain,
84
126
  endpoint: this.config.mailgunEndpoint,
@@ -122,10 +164,15 @@ export class EmailService {
122
164
  }
123
165
  /**
124
166
  * Template lookup with language + org fallback chain.
167
+ * Results are cached for 5 minutes.
125
168
  */
126
169
  async loadTemplate(slug, language, organizationId) {
127
170
  // Try: slug + language + org (if org provided)
128
171
  if (organizationId) {
172
+ const cacheKey = `${slug}:${language}:${organizationId}`;
173
+ const cached = this.getCached(cacheKey);
174
+ if (cached !== undefined)
175
+ return cached;
129
176
  const { data } = await this.supabase
130
177
  .from('email_templates')
131
178
  .select('*')
@@ -135,10 +182,16 @@ export class EmailService {
135
182
  .eq('is_active', true)
136
183
  .limit(1)
137
184
  .single();
138
- if (data)
185
+ if (data) {
186
+ this.setCache(cacheKey, data);
139
187
  return data;
188
+ }
140
189
  }
141
190
  // Try: slug + language + system default (org IS NULL)
191
+ const langKey = `${slug}:${language}:system`;
192
+ const cachedLang = this.getCached(langKey);
193
+ if (cachedLang !== undefined)
194
+ return cachedLang;
142
195
  const { data: langDefault } = await this.supabase
143
196
  .from('email_templates')
144
197
  .select('*')
@@ -148,10 +201,16 @@ export class EmailService {
148
201
  .eq('is_active', true)
149
202
  .limit(1)
150
203
  .single();
151
- if (langDefault)
204
+ if (langDefault) {
205
+ this.setCache(langKey, langDefault);
152
206
  return langDefault;
207
+ }
153
208
  // Try: slug + English fallback + system default
154
209
  if (language !== 'en') {
210
+ const enKey = `${slug}:en:system`;
211
+ const cachedEn = this.getCached(enKey);
212
+ if (cachedEn !== undefined)
213
+ return cachedEn;
155
214
  const { data: enDefault } = await this.supabase
156
215
  .from('email_templates')
157
216
  .select('*')
@@ -161,11 +220,26 @@ export class EmailService {
161
220
  .eq('is_active', true)
162
221
  .limit(1)
163
222
  .single();
164
- if (enDefault)
223
+ if (enDefault) {
224
+ this.setCache(enKey, enDefault);
165
225
  return enDefault;
226
+ }
166
227
  }
167
228
  return null;
168
229
  }
230
+ getCached(key) {
231
+ const entry = this.templateCache.get(key);
232
+ if (!entry)
233
+ return undefined;
234
+ if (Date.now() - entry.cachedAt > CACHE_TTL) {
235
+ this.templateCache.delete(key);
236
+ return undefined;
237
+ }
238
+ return entry.template;
239
+ }
240
+ setCache(key, template) {
241
+ this.templateCache.set(key, { template, cachedAt: Date.now() });
242
+ }
169
243
  /**
170
244
  * Render a Handlebars template string with variables.
171
245
  * Rejects templates with triple-brace {{{…}}} syntax to prevent escaping bypass.
@@ -188,6 +262,8 @@ export class EmailService {
188
262
  subject: opts.subject,
189
263
  template_slug: opts.templateSlug || null,
190
264
  variables_used: opts.variables || {},
265
+ email_type: opts.emailType || null,
266
+ metadata: opts.metadata || null,
191
267
  status: 'pending',
192
268
  };
193
269
  // feedbackId is app-specific — only include if the column exists
@@ -1 +1 @@
1
- {"version":3,"file":"EmailService.js","sourceRoot":"","sources":["../../../src/shared/email/EmailService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"EmailService.js","sourceRoot":"","sources":["../../../src/shared/email/EmailService.ts"],"names":[],"mappings":"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"}
@@ -2,12 +2,15 @@
2
2
  * Mailgun email helper — native fetch, no axios.
3
3
  * Graceful no-op when credentials are missing.
4
4
  */
5
- import type { MailgunResponse } from './types.js';
5
+ import type { MailgunResponse, EmailAttachment } from './types.js';
6
6
  export declare function sendMailgunEmail(params: {
7
7
  from: string;
8
8
  to: string;
9
9
  subject: string;
10
10
  html: string;
11
+ text?: string;
12
+ replyTo?: string;
13
+ attachments?: EmailAttachment[];
11
14
  apiKey?: string;
12
15
  domain?: string;
13
16
  endpoint?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"mailgun.d.ts","sourceRoot":"","sources":["../../../src/shared/email/mailgun.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAIlD,wBAAsB,gBAAgB,CAAC,MAAM,EAAE;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,eAAe,CAAC,CA2C3B"}
1
+ {"version":3,"file":"mailgun.d.ts","sourceRoot":"","sources":["../../../src/shared/email/mailgun.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAInE,wBAAsB,gBAAgB,CAAC,MAAM,EAAE;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,eAAe,EAAE,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,eAAe,CAAC,CAyE3B"}
@@ -10,19 +10,50 @@ export async function sendMailgunEmail(params) {
10
10
  return { success: false, message: 'Mailgun not configured' };
11
11
  }
12
12
  const baseUrl = params.endpoint || DEFAULT_EU_ENDPOINT;
13
- const formData = new URLSearchParams();
14
- formData.append('from', params.from);
15
- formData.append('to', params.to);
16
- formData.append('subject', params.subject);
17
- formData.append('html', params.html);
18
13
  try {
14
+ let body;
15
+ let contentType;
16
+ if (params.attachments?.length) {
17
+ // Use FormData for multipart (attachments)
18
+ const formData = new FormData();
19
+ formData.append('from', params.from);
20
+ formData.append('to', params.to);
21
+ formData.append('subject', params.subject);
22
+ formData.append('html', params.html);
23
+ if (params.text)
24
+ formData.append('text', params.text);
25
+ if (params.replyTo)
26
+ formData.append('h:Reply-To', params.replyTo);
27
+ for (const att of params.attachments) {
28
+ const blob = new Blob([att.data], { type: att.contentType || 'application/octet-stream' });
29
+ formData.append('attachment', blob, att.filename);
30
+ }
31
+ body = formData;
32
+ // Let fetch set the Content-Type with boundary
33
+ }
34
+ else {
35
+ // Simple URL-encoded form (no attachments)
36
+ const formData = new URLSearchParams();
37
+ formData.append('from', params.from);
38
+ formData.append('to', params.to);
39
+ formData.append('subject', params.subject);
40
+ formData.append('html', params.html);
41
+ if (params.text)
42
+ formData.append('text', params.text);
43
+ if (params.replyTo)
44
+ formData.append('h:Reply-To', params.replyTo);
45
+ body = formData.toString();
46
+ contentType = 'application/x-www-form-urlencoded';
47
+ }
48
+ const headers = {
49
+ Authorization: 'Basic ' + Buffer.from(`api:${apiKey}`).toString('base64'),
50
+ };
51
+ if (contentType)
52
+ headers['Content-Type'] = contentType;
19
53
  const resp = await fetch(`${baseUrl}/${domain}/messages`, {
20
54
  method: 'POST',
21
- headers: {
22
- Authorization: 'Basic ' + Buffer.from(`api:${apiKey}`).toString('base64'),
23
- 'Content-Type': 'application/x-www-form-urlencoded',
24
- },
25
- body: formData.toString(),
55
+ headers,
56
+ body,
26
57
  });
27
58
  if (!resp.ok) {
28
59
  const text = (await resp.text()).slice(0, 500);
@@ -1 +1 @@
1
- {"version":3,"file":"mailgun.js","sourceRoot":"","sources":["../../../src/shared/email/mailgun.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,mBAAmB,GAAG,+BAA+B,CAAC;AAE5D,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,MAQtC;IACC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IAElC,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;QACvB,OAAO,CAAC,IAAI,CAAC,sDAAsD,CAAC,CAAC;QACrE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,wBAAwB,EAAE,CAAC;IAC/D,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,IAAI,mBAAmB,CAAC;IAEvD,MAAM,QAAQ,GAAG,IAAI,eAAe,EAAE,CAAC;IACvC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;IACrC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IACjC,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAC3C,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;IAErC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,IAAI,MAAM,WAAW,EAAE;YACxD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,aAAa,EAAE,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;gBACzE,cAAc,EAAE,mCAAmC;aACpD;YACD,IAAI,EAAE,QAAQ,CAAC,QAAQ,EAAE;SAC1B,CAAC,CAAC;QAEH,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;YACb,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YAC/C,OAAO,CAAC,KAAK,CAAC,6BAA6B,IAAI,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC,CAAC;YACnE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,kBAAkB,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;QACtE,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAsC,CAAC;QACtE,OAAO;YACL,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,YAAY;YACrC,SAAS,EAAE,IAAI,CAAC,EAAE;SACnB,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,GAAG,CAAC,CAAC;QACnD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,gBAAgB,GAAG,EAAE,EAAE,CAAC;IAC5D,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"mailgun.js","sourceRoot":"","sources":["../../../src/shared/email/mailgun.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,mBAAmB,GAAG,+BAA+B,CAAC;AAE5D,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,MAWtC;IACC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IAElC,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;QACvB,OAAO,CAAC,IAAI,CAAC,sDAAsD,CAAC,CAAC;QACrE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,wBAAwB,EAAE,CAAC;IAC/D,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,IAAI,mBAAmB,CAAC;IAEvD,IAAI,CAAC;QACH,IAAI,IAAS,CAAC;QACd,IAAI,WAA+B,CAAC;QAEpC,IAAI,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,CAAC;YAC/B,2CAA2C;YAC3C,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC;YAChC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;YACrC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;YACjC,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;YAC3C,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;YACrC,IAAI,MAAM,CAAC,IAAI;gBAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;YACtD,IAAI,MAAM,CAAC,OAAO;gBAAE,QAAQ,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;YAElE,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;gBACrC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,WAAW,IAAI,0BAA0B,EAAE,CAAC,CAAC;gBAC3F,QAAQ,CAAC,MAAM,CAAC,YAAY,EAAE,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;YACpD,CAAC;YAED,IAAI,GAAG,QAAQ,CAAC;YAChB,+CAA+C;QACjD,CAAC;aAAM,CAAC;YACN,2CAA2C;YAC3C,MAAM,QAAQ,GAAG,IAAI,eAAe,EAAE,CAAC;YACvC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;YACrC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;YACjC,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;YAC3C,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;YACrC,IAAI,MAAM,CAAC,IAAI;gBAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;YACtD,IAAI,MAAM,CAAC,OAAO;gBAAE,QAAQ,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;YAElE,IAAI,GAAG,QAAQ,CAAC,QAAQ,EAAE,CAAC;YAC3B,WAAW,GAAG,mCAAmC,CAAC;QACpD,CAAC;QAED,MAAM,OAAO,GAA2B;YACtC,aAAa,EAAE,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;SAC1E,CAAC;QACF,IAAI,WAAW;YAAE,OAAO,CAAC,cAAc,CAAC,GAAG,WAAW,CAAC;QAEvD,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,IAAI,MAAM,WAAW,EAAE;YACxD,MAAM,EAAE,MAAM;YACd,OAAO;YACP,IAAI;SACL,CAAC,CAAC;QAEH,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;YACb,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YAC/C,OAAO,CAAC,KAAK,CAAC,6BAA6B,IAAI,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC,CAAC;YACnE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,kBAAkB,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;QACtE,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAsC,CAAC;QACtE,OAAO;YACL,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,YAAY;YACrC,SAAS,EAAE,IAAI,CAAC,EAAE;SACnB,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,GAAG,CAAC,CAAC;QACnD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,gBAAgB,GAAG,EAAE,EAAE,CAAC;IAC5D,CAAC;AACH,CAAC"}
@@ -2,12 +2,15 @@
2
2
  * SMTP email helper — uses nodemailer for sending via SMTP (Gmail, Outlook, etc.).
3
3
  * Graceful no-op when credentials are missing.
4
4
  */
5
- import type { SmtpResponse } from './types.js';
5
+ import type { SmtpResponse, EmailAttachment } from './types.js';
6
6
  export declare function sendSmtpEmail(params: {
7
7
  from: string;
8
8
  to: string;
9
9
  subject: string;
10
10
  html: string;
11
+ text?: string;
12
+ replyTo?: string;
13
+ attachments?: EmailAttachment[];
11
14
  smtpHost: string;
12
15
  smtpPort: number;
13
16
  smtpUser: string;
@@ -1 +1 @@
1
- {"version":3,"file":"smtp.d.ts","sourceRoot":"","sources":["../../../src/shared/email/smtp.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,wBAAsB,aAAa,CAAC,MAAM,EAAE;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,GAAG,OAAO,CAAC,YAAY,CAAC,CAuCxB"}
1
+ {"version":3,"file":"smtp.d.ts","sourceRoot":"","sources":["../../../src/shared/email/smtp.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAEhE,wBAAsB,aAAa,CAAC,MAAM,EAAE;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,eAAe,EAAE,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,GAAG,OAAO,CAAC,YAAY,CAAC,CAoDxB"}
@@ -20,12 +20,24 @@ export async function sendSmtpEmail(params) {
20
20
  pass: params.smtpPass,
21
21
  },
22
22
  });
23
- const info = await transporter.sendMail({
23
+ const mailOpts = {
24
24
  from: params.from,
25
25
  to: params.to,
26
26
  subject: params.subject,
27
27
  html: params.html,
28
- });
28
+ };
29
+ if (params.text)
30
+ mailOpts.text = params.text;
31
+ if (params.replyTo)
32
+ mailOpts.replyTo = params.replyTo;
33
+ if (params.attachments?.length) {
34
+ mailOpts.attachments = params.attachments.map(att => ({
35
+ filename: att.filename,
36
+ content: att.data,
37
+ contentType: att.contentType || 'application/octet-stream',
38
+ }));
39
+ }
40
+ const info = await transporter.sendMail(mailOpts);
29
41
  return {
30
42
  success: true,
31
43
  message: 'Email sent via SMTP',
@@ -1 +1 @@
1
- {"version":3,"file":"smtp.js","sourceRoot":"","sources":["../../../src/shared/email/smtp.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAUnC;IACC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;IAEhD,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,EAAE,CAAC;QACxC,OAAO,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC;QAClE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,qBAAqB,EAAE,CAAC;IAC5D,CAAC;IAED,IAAI,CAAC;QACH,wDAAwD;QACxD,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;QAE9C,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,CAAC,eAAe,CAAC;YACrD,IAAI,EAAE,MAAM,CAAC,QAAQ;YACrB,IAAI,EAAE,MAAM,CAAC,QAAQ;YACrB,MAAM,EAAE,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,QAAQ,KAAK,GAAG;YACpD,IAAI,EAAE;gBACJ,IAAI,EAAE,MAAM,CAAC,QAAQ;gBACrB,IAAI,EAAE,MAAM,CAAC,QAAQ;aACtB;SACF,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC;YACtC,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,EAAE,EAAE,MAAM,CAAC,EAAE;YACb,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,IAAI,EAAE,MAAM,CAAC,IAAI;SAClB,CAAC,CAAC;QAEH,OAAO;YACL,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,qBAAqB;YAC9B,SAAS,EAAE,IAAI,CAAC,SAAS;SAC1B,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,GAAG,CAAC,CAAC;QAChD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,qBAAqB,GAAG,EAAE,EAAE,CAAC;IACjE,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"smtp.js","sourceRoot":"","sources":["../../../src/shared/email/smtp.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAanC;IACC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;IAEhD,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,EAAE,CAAC;QACxC,OAAO,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC;QAClE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,qBAAqB,EAAE,CAAC;IAC5D,CAAC;IAED,IAAI,CAAC;QACH,wDAAwD;QACxD,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;QAE9C,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,CAAC,eAAe,CAAC;YACrD,IAAI,EAAE,MAAM,CAAC,QAAQ;YACrB,IAAI,EAAE,MAAM,CAAC,QAAQ;YACrB,MAAM,EAAE,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,QAAQ,KAAK,GAAG;YACpD,IAAI,EAAE;gBACJ,IAAI,EAAE,MAAM,CAAC,QAAQ;gBACrB,IAAI,EAAE,MAAM,CAAC,QAAQ;aACtB;SACF,CAAC,CAAC;QAEH,MAAM,QAAQ,GAA4B;YACxC,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,EAAE,EAAE,MAAM,CAAC,EAAE;YACb,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,IAAI,EAAE,MAAM,CAAC,IAAI;SAClB,CAAC;QAEF,IAAI,MAAM,CAAC,IAAI;YAAE,QAAQ,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;QAC7C,IAAI,MAAM,CAAC,OAAO;YAAE,QAAQ,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;QAEtD,IAAI,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,CAAC;YAC/B,QAAQ,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACpD,QAAQ,EAAE,GAAG,CAAC,QAAQ;gBACtB,OAAO,EAAE,GAAG,CAAC,IAAI;gBACjB,WAAW,EAAE,GAAG,CAAC,WAAW,IAAI,0BAA0B;aAC3D,CAAC,CAAC,CAAC;QACN,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAElD,OAAO;YACL,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,qBAAqB;YAC9B,SAAS,EAAE,IAAI,CAAC,SAAS;SAC1B,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,GAAG,CAAC,CAAC;QAChD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,qBAAqB,GAAG,EAAE,EAAE,CAAC;IACjE,CAAC;AACH,CAAC"}
@@ -3,6 +3,11 @@
3
3
  *
4
4
  * @module @soulbatical/tetra-core/email
5
5
  */
6
+ export interface EmailAttachment {
7
+ filename: string;
8
+ data: Buffer;
9
+ contentType?: string;
10
+ }
6
11
  export interface EmailConfig {
7
12
  /** From address, e.g. "VinciFox <noreply@vincifox.com>" */
8
13
  fromAddress: string;
@@ -18,6 +23,8 @@ export interface EmailConfig {
18
23
  mailgunDomain?: string;
19
24
  /** Mailgun API endpoint — defaults to EU endpoint */
20
25
  mailgunEndpoint?: string;
26
+ /** Mailgun webhook signing key — required for webhook signature verification */
27
+ mailgunWebhookSigningKey?: string;
21
28
  /** SMTP host, e.g. smtp.gmail.com */
22
29
  smtpHost?: string;
23
30
  /** SMTP port — defaults to 587 */
@@ -40,12 +47,22 @@ export interface SendEmailOpts {
40
47
  /** Language for template lookup, falls back to config.defaultLanguage */
41
48
  language?: string;
42
49
  organizationId?: string;
50
+ /** Reply-To address (e.g. for contact forms) */
51
+ replyTo?: string;
52
+ /** File attachments */
53
+ attachments?: EmailAttachment[];
54
+ /** Email type for logging/categorization (e.g. 'transactional', 'contact_admin') */
55
+ emailType?: string;
56
+ /** Arbitrary metadata stored in email_logs for tracking/debugging */
57
+ metadata?: Record<string, unknown>;
43
58
  /** Optional FK — consuming project can use this for app-specific references */
44
59
  feedbackId?: string;
45
60
  /** Subject fallback when DB template is missing */
46
61
  fallbackSubject?: string;
47
62
  /** HTML fallback when DB template is missing */
48
63
  fallbackHtml?: string;
64
+ /** Plain text fallback when DB template is missing */
65
+ fallbackText?: string;
49
66
  }
50
67
  export interface EmailTemplate {
51
68
  id: string;
@@ -70,10 +87,15 @@ export interface EmailLogEntry {
70
87
  subject: string;
71
88
  template_slug: string | null;
72
89
  variables_used: Record<string, string>;
73
- status: 'pending' | 'sent' | 'failed';
90
+ email_type: string | null;
91
+ metadata: Record<string, unknown> | null;
92
+ status: 'pending' | 'sent' | 'failed' | 'delivered' | 'opened' | 'clicked' | 'bounced' | 'complained';
74
93
  error_message: string | null;
75
94
  mailgun_message_id: string | null;
76
95
  sent_at: string | null;
96
+ delivered_at: string | null;
97
+ opened_at: string | null;
98
+ clicked_at: string | null;
77
99
  created_at: string;
78
100
  }
79
101
  export interface MailgunResponse {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/shared/email/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/shared/email/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Mailgun Webhook Routes — optional route factory for delivery tracking.
3
+ *
4
+ * Usage:
5
+ * import { addMailgunWebhookRoutes } from '@soulbatical/tetra-core';
6
+ * addMailgunWebhookRoutes(router, { signingKey: process.env.MAILGUN_WEBHOOK_SIGNING_KEY });
7
+ *
8
+ * @module @soulbatical/tetra-core/email
9
+ */
10
+ import { Router } from 'express';
11
+ import type { SupabaseClient } from '@supabase/supabase-js';
12
+ interface MailgunWebhookConfig {
13
+ /** Mailgun webhook signing key for signature verification */
14
+ signingKey?: string;
15
+ /** Supabase client (systemDB or service_role) for updating email_logs */
16
+ supabase: SupabaseClient;
17
+ /** Max age of webhook timestamp in seconds (default: 30) */
18
+ maxTimestampAge?: number;
19
+ /** Set true in development to skip signature verification */
20
+ skipVerification?: boolean;
21
+ }
22
+ /**
23
+ * Add Mailgun webhook route to a router.
24
+ * Handles: delivered, opened, clicked, bounced, failed, complained events.
25
+ * Updates email_logs table with delivery tracking data.
26
+ */
27
+ export declare function addMailgunWebhookRoutes(router: Router, config: MailgunWebhookConfig): void;
28
+ export {};
29
+ //# sourceMappingURL=webhookRoutes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhookRoutes.d.ts","sourceRoot":"","sources":["../../../src/shared/email/webhookRoutes.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AAEpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,UAAU,oBAAoB;IAC5B,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,QAAQ,EAAE,cAAc,CAAC;IACzB,4DAA4D;IAC5D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AA2BD;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,GAAG,IAAI,CA0G1F"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Mailgun Webhook Routes — optional route factory for delivery tracking.
3
+ *
4
+ * Usage:
5
+ * import { addMailgunWebhookRoutes } from '@soulbatical/tetra-core';
6
+ * addMailgunWebhookRoutes(router, { signingKey: process.env.MAILGUN_WEBHOOK_SIGNING_KEY });
7
+ *
8
+ * @module @soulbatical/tetra-core/email
9
+ */
10
+ import crypto from 'crypto';
11
+ function verifySignature(timestamp, token, signature, signingKey, maxAge) {
12
+ const currentTime = Date.now() / 1000;
13
+ const webhookTime = parseInt(timestamp, 10);
14
+ const timestampAge = currentTime - webhookTime;
15
+ // Reject timestamps too far in the future (clock skew tolerance: 5 seconds)
16
+ if (timestampAge < -5)
17
+ return false;
18
+ // Reject timestamps older than maxAge
19
+ if (timestampAge > maxAge)
20
+ return false;
21
+ // Verify HMAC signature using timing-safe comparison
22
+ const hmac = crypto.createHmac('sha256', signingKey);
23
+ const digest = hmac.update(timestamp + token).digest('hex');
24
+ if (digest.length !== signature.length)
25
+ return false;
26
+ return crypto.timingSafeEqual(Buffer.from(digest, 'hex'), Buffer.from(signature, 'hex'));
27
+ }
28
+ /**
29
+ * Add Mailgun webhook route to a router.
30
+ * Handles: delivered, opened, clicked, bounced, failed, complained events.
31
+ * Updates email_logs table with delivery tracking data.
32
+ */
33
+ export function addMailgunWebhookRoutes(router, config) {
34
+ const maxAge = config.maxTimestampAge ?? 30;
35
+ router.post('/mailgun', async (req, res) => {
36
+ try {
37
+ const event = req.body;
38
+ if (!event?.signature || !event?.['event-data']) {
39
+ res.status(400).json({ error: 'Invalid webhook structure' });
40
+ return;
41
+ }
42
+ // Verify signature
43
+ const { timestamp, token, signature } = event.signature;
44
+ if (!config.skipVerification) {
45
+ if (!config.signingKey) {
46
+ console.error('[email/webhook] MAILGUN_WEBHOOK_SIGNING_KEY not configured');
47
+ res.status(401).json({ error: 'Webhook signing key not configured' });
48
+ return;
49
+ }
50
+ if (!verifySignature(timestamp, token, signature, config.signingKey, maxAge)) {
51
+ console.warn('[email/webhook] Invalid Mailgun webhook signature');
52
+ res.status(401).json({ error: 'Invalid signature' });
53
+ return;
54
+ }
55
+ }
56
+ const eventData = event['event-data'];
57
+ const eventType = eventData.event;
58
+ const recipient = eventData.recipient?.toLowerCase();
59
+ const eventTimestamp = new Date(eventData.timestamp * 1000).toISOString();
60
+ if (!recipient) {
61
+ res.status(200).json({ message: 'No recipient' });
62
+ return;
63
+ }
64
+ // Find most recent email log for this recipient
65
+ const { data: emailLog } = await config.supabase
66
+ .from('email_logs')
67
+ .select('id, status, opened_at, clicked_at')
68
+ .eq('to_email', recipient)
69
+ .order('created_at', { ascending: false })
70
+ .limit(1)
71
+ .single();
72
+ if (!emailLog) {
73
+ res.status(200).json({ message: 'No matching log' });
74
+ return;
75
+ }
76
+ // Build updates based on event type
77
+ const updates = {};
78
+ switch (eventType) {
79
+ case 'delivered':
80
+ updates.status = 'delivered';
81
+ updates.delivered_at = eventTimestamp;
82
+ break;
83
+ case 'opened':
84
+ if (!emailLog.opened_at)
85
+ updates.opened_at = eventTimestamp;
86
+ if (emailLog.status === 'sent' || emailLog.status === 'delivered') {
87
+ updates.status = 'opened';
88
+ }
89
+ break;
90
+ case 'clicked':
91
+ if (!emailLog.clicked_at)
92
+ updates.clicked_at = eventTimestamp;
93
+ updates.status = 'clicked';
94
+ break;
95
+ case 'bounced':
96
+ case 'failed':
97
+ updates.status = eventType;
98
+ updates.error_message =
99
+ eventData['delivery-status']?.message ||
100
+ eventData['delivery-status']?.description ||
101
+ `Email ${eventType}`;
102
+ break;
103
+ case 'complained':
104
+ updates.status = 'complained';
105
+ break;
106
+ default:
107
+ res.status(200).json({ message: 'ok' });
108
+ return;
109
+ }
110
+ if (Object.keys(updates).length > 0) {
111
+ await config.supabase
112
+ .from('email_logs')
113
+ .update(updates)
114
+ .eq('id', emailLog.id);
115
+ }
116
+ res.status(200).json({ message: 'ok' });
117
+ }
118
+ catch (error) {
119
+ console.error('[email/webhook] Error processing webhook:', error);
120
+ // Return 200 to prevent Mailgun retries
121
+ res.status(200).json({ message: 'error logged' });
122
+ }
123
+ });
124
+ }
125
+ //# sourceMappingURL=webhookRoutes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhookRoutes.js","sourceRoot":"","sources":["../../../src/shared/email/webhookRoutes.ts"],"names":[],"mappings":"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"}