@realtimex/email-automator 2.21.1 → 2.21.3

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.
@@ -45,44 +45,12 @@ router.get('/',
45
45
 
46
46
  if (error) throw error;
47
47
 
48
- // Debug: Log draft content structure for first few emails
49
- if (data && data.length > 0) {
50
- logger.info(`Found ${data.length} drafts with draft_status='${status}'`);
51
- data.slice(0, 3).forEach((email, idx) => {
52
- const aiAnalysis = email.ai_analysis as any;
53
- logger.debug(`Draft ${idx + 1} content check`, {
54
- emailId: email.id,
55
- hasDraftContent: !!email.draft_content,
56
- hasAiAnalysis: !!email.ai_analysis,
57
- aiAnalysisKeys: email.ai_analysis ? Object.keys(email.ai_analysis) : [],
58
- hasDraftResponse: !!aiAnalysis?.draft_response,
59
- hasDraftContentInAi: !!aiAnalysis?.draft_content,
60
- draftResponseLength: aiAnalysis?.draft_response?.length || 0,
61
- draftContentLength: aiAnalysis?.draft_content?.length || 0,
62
- persistedDraftLength: email.draft_content?.length || 0
63
- });
64
- });
65
- }
66
-
67
48
  // Filter out drafts without content (these can't be sent)
68
49
  const validDrafts = (data || []).filter(email => {
69
50
  const aiAnalysis = email.ai_analysis as any;
70
- const hasContent = email.draft_content || aiAnalysis?.draft_response || aiAnalysis?.draft_content;
71
-
72
- if (!hasContent) {
73
- logger.debug('Draft without content filtered out', {
74
- emailId: email.id,
75
- subject: email.subject,
76
- hasAiAnalysis: !!email.ai_analysis,
77
- aiAnalysisKeys: email.ai_analysis ? Object.keys(email.ai_analysis) : []
78
- });
79
- }
80
-
81
- return hasContent;
51
+ return email.draft_content || aiAnalysis?.draft_response || aiAnalysis?.draft_content;
82
52
  });
83
53
 
84
- logger.info(`Returning ${validDrafts.length} valid drafts out of ${data?.length || 0} total`);
85
-
86
54
  res.json({
87
55
  drafts: validDrafts,
88
56
  total: validDrafts.length
@@ -736,8 +736,36 @@ export class EmailProcessorService {
736
736
  let conditionText = '';
737
737
  if (r.condition) {
738
738
  const cond = r.condition as any;
739
+
740
+ // Handle new simple condition format: {"category": "news"}
741
+ if (cond.category) {
742
+ conditionText = `When category is "${cond.category}"`;
743
+ }
744
+ if (cond.sentiment) {
745
+ conditionText += (conditionText ? ' AND ' : 'When ') + `sentiment is "${cond.sentiment}"`;
746
+ }
747
+ if (cond.priority) {
748
+ conditionText += (conditionText ? ' AND ' : 'When ') + `priority is "${cond.priority}"`;
749
+ }
750
+ if (cond.sender_email) {
751
+ conditionText += (conditionText ? ' AND ' : 'When ') + `sender is "${cond.sender_email}"`;
752
+ }
753
+ if (cond.sender_domain) {
754
+ conditionText += (conditionText ? ' AND ' : 'When ') + `sender domain is "${cond.sender_domain}"`;
755
+ }
756
+ if (cond.sender_contains) {
757
+ conditionText += (conditionText ? ' AND ' : 'When ') + `sender contains "${cond.sender_contains}"`;
758
+ }
759
+ if (cond.subject_contains) {
760
+ conditionText += (conditionText ? ' AND ' : 'When ') + `subject contains "${cond.subject_contains}"`;
761
+ }
762
+ if (cond.body_contains) {
763
+ conditionText += (conditionText ? ' AND ' : 'When ') + `body contains "${cond.body_contains}"`;
764
+ }
765
+
766
+ // Handle legacy format with field/operator/value
739
767
  if (cond.field) {
740
- conditionText = `When ${cond.field}`;
768
+ conditionText += (conditionText ? ' AND ' : 'When ') + cond.field;
741
769
  if (cond.operator === 'equals') {
742
770
  conditionText += ` equals "${cond.value}"`;
743
771
  } else if (cond.operator === 'contains') {
@@ -748,6 +776,7 @@ export class EmailProcessorService {
748
776
  conditionText += ` ${cond.operator} "${cond.value}"`;
749
777
  }
750
778
  }
779
+
751
780
  if (cond.is_useless === true) {
752
781
  conditionText += (conditionText ? ' AND ' : 'When ') + 'email is useless/low-value';
753
782
  }
@@ -30,7 +30,7 @@ export function getServerSupabase(forceRefresh = false): SupabaseClient | null {
30
30
  const key = config.supabase.anonKey;
31
31
 
32
32
  if (!url || !key || !isValidUrl(url)) {
33
- logger.debug('Supabase not configured or invalid URL - skipping client initialization');
33
+ // BYOK mode: Supabase configured via UI, not .env - this is expected
34
34
  return null;
35
35
  }
36
36
 
@@ -56,7 +56,7 @@ export function getServiceRoleSupabase(): SupabaseClient | null {
56
56
  const key = config.supabase.serviceRoleKey;
57
57
 
58
58
  if (!url || !key || !isValidUrl(url)) {
59
- logger.debug('Service role Supabase not configured or invalid URL');
59
+ // BYOK mode: Service role Supabase configured via UI, not .env - this is expected
60
60
  return null;
61
61
  }
62
62
 
@@ -28,39 +28,11 @@ router.get('/', apiRateLimit, authMiddleware, asyncHandler(async (req, res) => {
28
28
  const { data, error, count } = await query;
29
29
  if (error)
30
30
  throw error;
31
- // Debug: Log draft content structure for first few emails
32
- if (data && data.length > 0) {
33
- logger.info(`Found ${data.length} drafts with draft_status='${status}'`);
34
- data.slice(0, 3).forEach((email, idx) => {
35
- const aiAnalysis = email.ai_analysis;
36
- logger.debug(`Draft ${idx + 1} content check`, {
37
- emailId: email.id,
38
- hasDraftContent: !!email.draft_content,
39
- hasAiAnalysis: !!email.ai_analysis,
40
- aiAnalysisKeys: email.ai_analysis ? Object.keys(email.ai_analysis) : [],
41
- hasDraftResponse: !!aiAnalysis?.draft_response,
42
- hasDraftContentInAi: !!aiAnalysis?.draft_content,
43
- draftResponseLength: aiAnalysis?.draft_response?.length || 0,
44
- draftContentLength: aiAnalysis?.draft_content?.length || 0,
45
- persistedDraftLength: email.draft_content?.length || 0
46
- });
47
- });
48
- }
49
31
  // Filter out drafts without content (these can't be sent)
50
32
  const validDrafts = (data || []).filter(email => {
51
33
  const aiAnalysis = email.ai_analysis;
52
- const hasContent = email.draft_content || aiAnalysis?.draft_response || aiAnalysis?.draft_content;
53
- if (!hasContent) {
54
- logger.debug('Draft without content filtered out', {
55
- emailId: email.id,
56
- subject: email.subject,
57
- hasAiAnalysis: !!email.ai_analysis,
58
- aiAnalysisKeys: email.ai_analysis ? Object.keys(email.ai_analysis) : []
59
- });
60
- }
61
- return hasContent;
34
+ return email.draft_content || aiAnalysis?.draft_response || aiAnalysis?.draft_content;
62
35
  });
63
- logger.info(`Returning ${validDrafts.length} valid drafts out of ${data?.length || 0} total`);
64
36
  res.json({
65
37
  drafts: validDrafts,
66
38
  total: validDrafts.length
@@ -612,8 +612,34 @@ export class EmailProcessorService {
612
612
  let conditionText = '';
613
613
  if (r.condition) {
614
614
  const cond = r.condition;
615
+ // Handle new simple condition format: {"category": "news"}
616
+ if (cond.category) {
617
+ conditionText = `When category is "${cond.category}"`;
618
+ }
619
+ if (cond.sentiment) {
620
+ conditionText += (conditionText ? ' AND ' : 'When ') + `sentiment is "${cond.sentiment}"`;
621
+ }
622
+ if (cond.priority) {
623
+ conditionText += (conditionText ? ' AND ' : 'When ') + `priority is "${cond.priority}"`;
624
+ }
625
+ if (cond.sender_email) {
626
+ conditionText += (conditionText ? ' AND ' : 'When ') + `sender is "${cond.sender_email}"`;
627
+ }
628
+ if (cond.sender_domain) {
629
+ conditionText += (conditionText ? ' AND ' : 'When ') + `sender domain is "${cond.sender_domain}"`;
630
+ }
631
+ if (cond.sender_contains) {
632
+ conditionText += (conditionText ? ' AND ' : 'When ') + `sender contains "${cond.sender_contains}"`;
633
+ }
634
+ if (cond.subject_contains) {
635
+ conditionText += (conditionText ? ' AND ' : 'When ') + `subject contains "${cond.subject_contains}"`;
636
+ }
637
+ if (cond.body_contains) {
638
+ conditionText += (conditionText ? ' AND ' : 'When ') + `body contains "${cond.body_contains}"`;
639
+ }
640
+ // Handle legacy format with field/operator/value
615
641
  if (cond.field) {
616
- conditionText = `When ${cond.field}`;
642
+ conditionText += (conditionText ? ' AND ' : 'When ') + cond.field;
617
643
  if (cond.operator === 'equals') {
618
644
  conditionText += ` equals "${cond.value}"`;
619
645
  }
@@ -23,7 +23,7 @@ export function getServerSupabase(forceRefresh = false) {
23
23
  const url = config.supabase.url;
24
24
  const key = config.supabase.anonKey;
25
25
  if (!url || !key || !isValidUrl(url)) {
26
- logger.debug('Supabase not configured or invalid URL - skipping client initialization');
26
+ // BYOK mode: Supabase configured via UI, not .env - this is expected
27
27
  return null;
28
28
  }
29
29
  try {
@@ -46,7 +46,7 @@ export function getServiceRoleSupabase() {
46
46
  const url = config.supabase.url;
47
47
  const key = config.supabase.serviceRoleKey;
48
48
  if (!url || !key || !isValidUrl(url)) {
49
- logger.debug('Service role Supabase not configured or invalid URL');
49
+ // BYOK mode: Service role Supabase configured via UI, not .env - this is expected
50
50
  return null;
51
51
  }
52
52
  try {