@soulbatical/tetra-core 0.1.39 → 0.1.41

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 (56) 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 +4 -2
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +3 -1
  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/adminRoutes.d.ts +30 -0
  14. package/dist/shared/email/adminRoutes.d.ts.map +1 -0
  15. package/dist/shared/email/adminRoutes.js +227 -0
  16. package/dist/shared/email/adminRoutes.js.map +1 -0
  17. package/dist/shared/email/index.d.ts +3 -1
  18. package/dist/shared/email/index.d.ts.map +1 -1
  19. package/dist/shared/email/index.js +3 -0
  20. package/dist/shared/email/index.js.map +1 -1
  21. package/dist/shared/email/mailgun.d.ts +4 -1
  22. package/dist/shared/email/mailgun.d.ts.map +1 -1
  23. package/dist/shared/email/mailgun.js +41 -10
  24. package/dist/shared/email/mailgun.js.map +1 -1
  25. package/dist/shared/email/smtp.d.ts +4 -1
  26. package/dist/shared/email/smtp.d.ts.map +1 -1
  27. package/dist/shared/email/smtp.js +14 -2
  28. package/dist/shared/email/smtp.js.map +1 -1
  29. package/dist/shared/email/types.d.ts +23 -1
  30. package/dist/shared/email/types.d.ts.map +1 -1
  31. package/dist/shared/email/webhookRoutes.d.ts +29 -0
  32. package/dist/shared/email/webhookRoutes.d.ts.map +1 -0
  33. package/dist/shared/email/webhookRoutes.js +125 -0
  34. package/dist/shared/email/webhookRoutes.js.map +1 -0
  35. package/dist/shared/planner/GoogleCalendarService.d.ts +103 -0
  36. package/dist/shared/planner/GoogleCalendarService.d.ts.map +1 -0
  37. package/dist/shared/planner/GoogleCalendarService.js +365 -0
  38. package/dist/shared/planner/GoogleCalendarService.js.map +1 -0
  39. package/dist/shared/planner/PlannerService.d.ts +170 -0
  40. package/dist/shared/planner/PlannerService.d.ts.map +1 -0
  41. package/dist/shared/planner/PlannerService.js +860 -0
  42. package/dist/shared/planner/PlannerService.js.map +1 -0
  43. package/dist/shared/planner/index.d.ts +35 -0
  44. package/dist/shared/planner/index.d.ts.map +1 -0
  45. package/dist/shared/planner/index.js +34 -0
  46. package/dist/shared/planner/index.js.map +1 -0
  47. package/dist/shared/planner/routes.d.ts +67 -0
  48. package/dist/shared/planner/routes.d.ts.map +1 -0
  49. package/dist/shared/planner/routes.js +524 -0
  50. package/dist/shared/planner/routes.js.map +1 -0
  51. package/dist/shared/planner/types.d.ts +262 -0
  52. package/dist/shared/planner/types.d.ts.map +1 -0
  53. package/dist/shared/planner/types.js +9 -0
  54. package/dist/shared/planner/types.js.map +1 -0
  55. package/package.json +1 -1
  56. package/src/shared/email/migrations/004_add_email_logs_tracking_columns.sql +15 -0
@@ -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":"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"}
@@ -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":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,2DAA2D;IAC3D,WAAW,EAAE,MAAM,CAAC;IACpB,oDAAoD;IACpD,eAAe,EAAE,IAAI,GAAG,IAAI,CAAC;IAC7B,8CAA8C;IAC9C,WAAW,EAAE,MAAM,CAAC;IACpB,+FAA+F;IAC/F,SAAS,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;IACzC,2CAA2C;IAC3C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2CAA2C;IAC3C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qDAAqD;IACrD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gFAAgF;IAChF,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,qCAAqC;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kCAAkC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uBAAuB;IACvB,WAAW,CAAC,EAAE,eAAe,EAAE,CAAC;IAChC,oFAAoF;IACpF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gDAAgD;IAChD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sDAAsD;IACtD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,OAAO,EAAE,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACzC,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,YAAY,CAAC;IACtG,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,gDAAgD;AAChD,MAAM,MAAM,iBAAiB,GAAG,eAAe,GAAG,YAAY,CAAC"}
@@ -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":"AAAA;;;;;;;;GAQG;AAGH,OAAO,MAAM,MAAM,QAAQ,CAAC;AAgB5B,SAAS,eAAe,CACtB,SAAiB,EACjB,KAAa,EACb,SAAiB,EACjB,UAAkB,EAClB,MAAc;IAEd,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;IACtC,MAAM,WAAW,GAAG,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IAC5C,MAAM,YAAY,GAAG,WAAW,GAAG,WAAW,CAAC;IAE/C,4EAA4E;IAC5E,IAAI,YAAY,GAAG,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACpC,sCAAsC;IACtC,IAAI,YAAY,GAAG,MAAM;QAAE,OAAO,KAAK,CAAC;IAExC,qDAAqD;IACrD,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IACrD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5D,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACrD,OAAO,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC;AAC3F,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAAc,EAAE,MAA4B;IAClF,MAAM,MAAM,GAAG,MAAM,CAAC,eAAe,IAAI,EAAE,CAAC;IAE5C,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;QAC5D,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC;YAEvB,IAAI,CAAC,KAAK,EAAE,SAAS,IAAI,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC;gBAChD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,2BAA2B,EAAE,CAAC,CAAC;gBAC7D,OAAO;YACT,CAAC;YAED,mBAAmB;YACnB,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC,SAAS,CAAC;YAExD,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC;gBAC7B,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;oBACvB,OAAO,CAAC,KAAK,CAAC,4DAA4D,CAAC,CAAC;oBAC5E,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,oCAAoC,EAAE,CAAC,CAAC;oBACtE,OAAO;gBACT,CAAC;gBAED,IAAI,CAAC,eAAe,CAAC,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,EAAE,CAAC;oBAC7E,OAAO,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC;oBAClE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAC;oBACrD,OAAO;gBACT,CAAC;YACH,CAAC;YAED,MAAM,SAAS,GAAG,KAAK,CAAC,YAAY,CAAC,CAAC;YACtC,MAAM,SAAS,GAAqB,SAAS,CAAC,KAAK,CAAC;YACpD,MAAM,SAAS,GAAG,SAAS,CAAC,SAAS,EAAE,WAAW,EAAE,CAAC;YACrD,MAAM,cAAc,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;YAE1E,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC;gBAClD,OAAO;YACT,CAAC;YAED,gDAAgD;YAChD,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,QAAQ;iBAC7C,IAAI,CAAC,YAAY,CAAC;iBAClB,MAAM,CAAC,mCAAmC,CAAC;iBAC3C,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC;iBACzB,KAAK,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;iBACzC,KAAK,CAAC,CAAC,CAAC;iBACR,MAAM,EAAE,CAAC;YAEZ,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC,CAAC;gBACrD,OAAO;YACT,CAAC;YAED,oCAAoC;YACpC,MAAM,OAAO,GAA4B,EAAE,CAAC;YAE5C,QAAQ,SAAS,EAAE,CAAC;gBAClB,KAAK,WAAW;oBACd,OAAO,CAAC,MAAM,GAAG,WAAW,CAAC;oBAC7B,OAAO,CAAC,YAAY,GAAG,cAAc,CAAC;oBACtC,MAAM;gBAER,KAAK,QAAQ;oBACX,IAAI,CAAC,QAAQ,CAAC,SAAS;wBAAE,OAAO,CAAC,SAAS,GAAG,cAAc,CAAC;oBAC5D,IAAI,QAAQ,CAAC,MAAM,KAAK,MAAM,IAAI,QAAQ,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;wBAClE,OAAO,CAAC,MAAM,GAAG,QAAQ,CAAC;oBAC5B,CAAC;oBACD,MAAM;gBAER,KAAK,SAAS;oBACZ,IAAI,CAAC,QAAQ,CAAC,UAAU;wBAAE,OAAO,CAAC,UAAU,GAAG,cAAc,CAAC;oBAC9D,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;oBAC3B,MAAM;gBAER,KAAK,SAAS,CAAC;gBACf,KAAK,QAAQ;oBACX,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;oBAC3B,OAAO,CAAC,aAAa;wBACnB,SAAS,CAAC,iBAAiB,CAAC,EAAE,OAAO;4BACrC,SAAS,CAAC,iBAAiB,CAAC,EAAE,WAAW;4BACzC,SAAS,SAAS,EAAE,CAAC;oBACvB,MAAM;gBAER,KAAK,YAAY;oBACf,OAAO,CAAC,MAAM,GAAG,YAAY,CAAC;oBAC9B,MAAM;gBAER;oBACE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;oBACxC,OAAO;YACX,CAAC;YAED,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACpC,MAAM,MAAM,CAAC,QAAQ;qBAClB,IAAI,CAAC,YAAY,CAAC;qBAClB,MAAM,CAAC,OAAO,CAAC;qBACf,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;YAC3B,CAAC;YAED,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,2CAA2C,EAAE,KAAK,CAAC,CAAC;YAClE,wCAAwC;YACxC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC;QACpD,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * GoogleCalendarService — Google Calendar OAuth + event sync
3
+ *
4
+ * Handles:
5
+ * - OAuth2 consent URL generation
6
+ * - Token exchange and storage
7
+ * - Token auto-refresh
8
+ * - Calendar event CRUD (create, update, delete)
9
+ * - Calendar listing and selection
10
+ * - Connection status check
11
+ *
12
+ * Uses lazy import for googleapis to avoid requiring it in projects that don't use calendar sync.
13
+ *
14
+ * Usage:
15
+ * ```typescript
16
+ * import { GoogleCalendarService } from '@soulbatical/tetra-core';
17
+ *
18
+ * const calService = new GoogleCalendarService({
19
+ * google: { clientId, clientSecret, redirectUri },
20
+ * });
21
+ * const url = calService.getAuthUrl(userId);
22
+ * ```
23
+ */
24
+ import type { PlannerCalendarConfig } from './types.js';
25
+ interface AppointmentEventData {
26
+ title: string;
27
+ description?: string;
28
+ startTime: string;
29
+ endTime: string;
30
+ location?: string;
31
+ type?: string;
32
+ }
33
+ export declare class GoogleCalendarService {
34
+ private config;
35
+ private googleModule;
36
+ constructor(config: PlannerCalendarConfig);
37
+ private getGoogle;
38
+ private getSystemDB;
39
+ private get scopes();
40
+ private get timezone();
41
+ private createOAuth2Client;
42
+ /**
43
+ * Get an authenticated OAuth2 client for a user.
44
+ * Auto-refreshes expired tokens and persists new ones.
45
+ */
46
+ private getAuthenticatedClient;
47
+ /**
48
+ * Get the user's selected calendar ID.
49
+ */
50
+ private getCalendarId;
51
+ /**
52
+ * Generate Google OAuth2 consent URL.
53
+ */
54
+ getAuthUrl(userId: string, state?: string): Promise<string>;
55
+ /**
56
+ * Exchange authorization code for tokens and store them.
57
+ */
58
+ handleCallback(code: string, userId: string, organizationId: string): Promise<void>;
59
+ /**
60
+ * Create a Google Calendar event. Returns event ID or null.
61
+ */
62
+ createEvent(userId: string, data: AppointmentEventData): Promise<string | null>;
63
+ /**
64
+ * Update a Google Calendar event.
65
+ */
66
+ updateEvent(userId: string, eventId: string, data: AppointmentEventData): Promise<void>;
67
+ /**
68
+ * Delete a Google Calendar event.
69
+ */
70
+ deleteEvent(userId: string, eventId: string): Promise<void>;
71
+ /**
72
+ * List all calendars the user has write access to.
73
+ */
74
+ listCalendars(userId: string): Promise<Array<{
75
+ id: string;
76
+ name: string;
77
+ isPrimary: boolean;
78
+ color: string;
79
+ isSelected: boolean;
80
+ }> | null>;
81
+ /**
82
+ * Set which Google Calendar to sync to.
83
+ */
84
+ selectCalendar(userId: string, calendarId: string): Promise<boolean>;
85
+ /**
86
+ * Check if a user has an active Google Calendar connection.
87
+ */
88
+ isConnected(userId: string): Promise<boolean>;
89
+ /**
90
+ * Disconnect Google Calendar for a user.
91
+ */
92
+ disconnect(userId: string): Promise<void>;
93
+ /**
94
+ * Fetch events from Google Calendar for a date range (for bidirectional sync).
95
+ * Returns busy time blocks.
96
+ */
97
+ getBusySlots(userId: string, dateStart: string, dateEnd: string): Promise<Array<{
98
+ start_time: string;
99
+ end_time: string;
100
+ }>>;
101
+ }
102
+ export {};
103
+ //# sourceMappingURL=GoogleCalendarService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GoogleCalendarService.d.ts","sourceRoot":"","sources":["../../../src/shared/planner/GoogleCalendarService.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAWxD,UAAU,oBAAoB;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,qBAAqB;IAChC,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,YAAY,CAAa;gBAErB,MAAM,EAAE,qBAAqB;YAM3B,SAAS;YAcT,WAAW;IAOzB,OAAO,KAAK,MAAM,GAEjB;IAED,OAAO,KAAK,QAAQ,GAEnB;YAEa,kBAAkB;IAMhC;;;OAGG;YACW,sBAAsB;IA4DpC;;OAEG;YACW,aAAa;IAY3B;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAYjE;;OAEG;IACG,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmCzF;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IA4BrF;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IA2B7F;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBjE;;OAEG;IACG,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;QACjD,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,OAAO,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,OAAO,CAAC;KACrB,CAAC,GAAG,IAAI,CAAC;IAyBV;;OAEG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAsB1E;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAgBnD;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAU/C;;;OAGG;IACG,YAAY,CAChB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,KAAK,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CA8B5D"}