catalist-support-agent 1.0.0
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.
- package/dist/admin-portal.d.ts +43 -0
- package/dist/admin-portal.d.ts.map +1 -0
- package/dist/admin-portal.js +166 -0
- package/dist/admin-portal.js.map +1 -0
- package/dist/analysis/entities.d.ts +73 -0
- package/dist/analysis/entities.d.ts.map +1 -0
- package/dist/analysis/entities.js +378 -0
- package/dist/analysis/entities.js.map +1 -0
- package/dist/analysis/index.d.ts +44 -0
- package/dist/analysis/index.d.ts.map +1 -0
- package/dist/analysis/index.js +243 -0
- package/dist/analysis/index.js.map +1 -0
- package/dist/analysis/intent.d.ts +49 -0
- package/dist/analysis/intent.d.ts.map +1 -0
- package/dist/analysis/intent.js +320 -0
- package/dist/analysis/intent.js.map +1 -0
- package/dist/analysis/sentiment.d.ts +57 -0
- package/dist/analysis/sentiment.d.ts.map +1 -0
- package/dist/analysis/sentiment.js +351 -0
- package/dist/analysis/sentiment.js.map +1 -0
- package/dist/brand/compliance.d.ts +122 -0
- package/dist/brand/compliance.d.ts.map +1 -0
- package/dist/brand/compliance.js +378 -0
- package/dist/brand/compliance.js.map +1 -0
- package/dist/brand/forbidden-terms.d.ts +99 -0
- package/dist/brand/forbidden-terms.d.ts.map +1 -0
- package/dist/brand/forbidden-terms.js +265 -0
- package/dist/brand/forbidden-terms.js.map +1 -0
- package/dist/brand/index.d.ts +10 -0
- package/dist/brand/index.d.ts.map +1 -0
- package/dist/brand/index.js +12 -0
- package/dist/brand/index.js.map +1 -0
- package/dist/config.d.ts +325 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +492 -0
- package/dist/config.js.map +1 -0
- package/dist/delivery/index.d.ts +84 -0
- package/dist/delivery/index.d.ts.map +1 -0
- package/dist/delivery/index.js +435 -0
- package/dist/delivery/index.js.map +1 -0
- package/dist/embeddings/cache.d.ts +96 -0
- package/dist/embeddings/cache.d.ts.map +1 -0
- package/dist/embeddings/cache.js +193 -0
- package/dist/embeddings/cache.js.map +1 -0
- package/dist/embeddings/index.d.ts +152 -0
- package/dist/embeddings/index.d.ts.map +1 -0
- package/dist/embeddings/index.js +337 -0
- package/dist/embeddings/index.js.map +1 -0
- package/dist/embeddings/openai-client.d.ts +67 -0
- package/dist/embeddings/openai-client.d.ts.map +1 -0
- package/dist/embeddings/openai-client.js +190 -0
- package/dist/embeddings/openai-client.js.map +1 -0
- package/dist/errors.d.ts +302 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +508 -0
- package/dist/errors.js.map +1 -0
- package/dist/escalation/index.d.ts +93 -0
- package/dist/escalation/index.d.ts.map +1 -0
- package/dist/escalation/index.js +436 -0
- package/dist/escalation/index.js.map +1 -0
- package/dist/extraction/deduplication.d.ts +97 -0
- package/dist/extraction/deduplication.d.ts.map +1 -0
- package/dist/extraction/deduplication.js +271 -0
- package/dist/extraction/deduplication.js.map +1 -0
- package/dist/extraction/gmail-extractor.d.ts +160 -0
- package/dist/extraction/gmail-extractor.d.ts.map +1 -0
- package/dist/extraction/gmail-extractor.js +396 -0
- package/dist/extraction/gmail-extractor.js.map +1 -0
- package/dist/extraction/gmail-token-manager.d.ts +36 -0
- package/dist/extraction/gmail-token-manager.d.ts.map +1 -0
- package/dist/extraction/gmail-token-manager.js +146 -0
- package/dist/extraction/gmail-token-manager.js.map +1 -0
- package/dist/extraction/index.d.ts +13 -0
- package/dist/extraction/index.d.ts.map +1 -0
- package/dist/extraction/index.js +20 -0
- package/dist/extraction/index.js.map +1 -0
- package/dist/extraction/pii-handler.d.ts +100 -0
- package/dist/extraction/pii-handler.d.ts.map +1 -0
- package/dist/extraction/pii-handler.js +295 -0
- package/dist/extraction/pii-handler.js.map +1 -0
- package/dist/extraction/pipeline.d.ts +94 -0
- package/dist/extraction/pipeline.d.ts.map +1 -0
- package/dist/extraction/pipeline.js +380 -0
- package/dist/extraction/pipeline.js.map +1 -0
- package/dist/extraction/quality-filter.d.ts +99 -0
- package/dist/extraction/quality-filter.d.ts.map +1 -0
- package/dist/extraction/quality-filter.js +370 -0
- package/dist/extraction/quality-filter.js.map +1 -0
- package/dist/extraction/rate-limiter.d.ts +90 -0
- package/dist/extraction/rate-limiter.d.ts.map +1 -0
- package/dist/extraction/rate-limiter.js +242 -0
- package/dist/extraction/rate-limiter.js.map +1 -0
- package/dist/extraction/state-manager.d.ts +126 -0
- package/dist/extraction/state-manager.d.ts.map +1 -0
- package/dist/extraction/state-manager.js +344 -0
- package/dist/extraction/state-manager.js.map +1 -0
- package/dist/generation/index.d.ts +75 -0
- package/dist/generation/index.d.ts.map +1 -0
- package/dist/generation/index.js +641 -0
- package/dist/generation/index.js.map +1 -0
- package/dist/index.d.ts +96 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +233 -0
- package/dist/index.js.map +1 -0
- package/dist/intake/index.d.ts +15 -0
- package/dist/intake/index.d.ts.map +1 -0
- package/dist/intake/index.js +19 -0
- package/dist/intake/index.js.map +1 -0
- package/dist/intake/normalizer.d.ts +163 -0
- package/dist/intake/normalizer.d.ts.map +1 -0
- package/dist/intake/normalizer.js +309 -0
- package/dist/intake/normalizer.js.map +1 -0
- package/dist/intake/postmark.d.ts +72 -0
- package/dist/intake/postmark.d.ts.map +1 -0
- package/dist/intake/postmark.js +276 -0
- package/dist/intake/postmark.js.map +1 -0
- package/dist/intake/slack.d.ts +106 -0
- package/dist/intake/slack.d.ts.map +1 -0
- package/dist/intake/slack.js +378 -0
- package/dist/intake/slack.js.map +1 -0
- package/dist/intake/twilio.d.ts +86 -0
- package/dist/intake/twilio.d.ts.map +1 -0
- package/dist/intake/twilio.js +283 -0
- package/dist/intake/twilio.js.map +1 -0
- package/dist/knowledge/index.d.ts +100 -0
- package/dist/knowledge/index.d.ts.map +1 -0
- package/dist/knowledge/index.js +516 -0
- package/dist/knowledge/index.js.map +1 -0
- package/dist/knowledge/invoice-resolver.d.ts +62 -0
- package/dist/knowledge/invoice-resolver.d.ts.map +1 -0
- package/dist/knowledge/invoice-resolver.js +267 -0
- package/dist/knowledge/invoice-resolver.js.map +1 -0
- package/dist/types.d.ts +535 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +48 -0
- package/dist/types.js.map +1 -0
- package/ga-service-account.json +13 -0
- package/gmail-knowledge-migration.sql +149 -0
- package/nul +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delivery Pipeline Module
|
|
3
|
+
*
|
|
4
|
+
* Handles response delivery across all channels:
|
|
5
|
+
* - Email via Postmark
|
|
6
|
+
* - SMS via Twilio
|
|
7
|
+
* - Slack messages via API
|
|
8
|
+
*
|
|
9
|
+
* Includes retry logic, status tracking, and engagement monitoring.
|
|
10
|
+
*/
|
|
11
|
+
import { createClient } from '@supabase/supabase-js';
|
|
12
|
+
import { config, isChannelEnabled } from '../config.js';
|
|
13
|
+
import { DeliveryError } from '../errors.js';
|
|
14
|
+
import { createDeliveryId } from '../types.js';
|
|
15
|
+
// =============================================================================
|
|
16
|
+
// Delivery Service
|
|
17
|
+
// =============================================================================
|
|
18
|
+
export class DeliveryService {
|
|
19
|
+
supabase;
|
|
20
|
+
constructor() {
|
|
21
|
+
this.supabase = createClient(config.supabase.url, config.supabase.serviceRoleKey);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Deliver a response via the appropriate channel
|
|
25
|
+
*/
|
|
26
|
+
async deliver(response, channel, recipientInfo) {
|
|
27
|
+
const deliveryId = createDeliveryId(`del-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`);
|
|
28
|
+
// Create delivery record
|
|
29
|
+
const { error: insertError } = await this.supabase.from('support_deliveries').insert({
|
|
30
|
+
id: deliveryId,
|
|
31
|
+
response_id: response.id,
|
|
32
|
+
conversation_id: response.conversationId,
|
|
33
|
+
channel,
|
|
34
|
+
status: 'pending',
|
|
35
|
+
status_data: { queuedAt: new Date().toISOString() },
|
|
36
|
+
});
|
|
37
|
+
if (insertError) {
|
|
38
|
+
throw new DeliveryError('Failed to create delivery record', channel, 'preparation', {
|
|
39
|
+
cause: new Error(insertError.message),
|
|
40
|
+
conversationId: response.conversationId,
|
|
41
|
+
messageId: response.messageId,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
// Route to appropriate delivery method
|
|
46
|
+
let result;
|
|
47
|
+
switch (channel) {
|
|
48
|
+
case 'email':
|
|
49
|
+
result = await this.deliverEmail(response, recipientInfo);
|
|
50
|
+
break;
|
|
51
|
+
case 'sms':
|
|
52
|
+
result = await this.deliverSms(response, recipientInfo);
|
|
53
|
+
break;
|
|
54
|
+
case 'slack':
|
|
55
|
+
result = await this.deliverSlack(response, recipientInfo);
|
|
56
|
+
break;
|
|
57
|
+
default:
|
|
58
|
+
throw new DeliveryError(`Unknown channel: ${channel}`, channel, 'preparation');
|
|
59
|
+
}
|
|
60
|
+
// Update delivery status
|
|
61
|
+
await this.updateDeliveryStatus(deliveryId, {
|
|
62
|
+
status: result.success ? 'sent' : 'failed',
|
|
63
|
+
sentAt: result.success ? new Date().toISOString() : undefined,
|
|
64
|
+
messageId: result.messageId,
|
|
65
|
+
...(result.error && {
|
|
66
|
+
failedAt: new Date().toISOString(),
|
|
67
|
+
error: result.error,
|
|
68
|
+
retryable: result.retryable ?? false,
|
|
69
|
+
}),
|
|
70
|
+
});
|
|
71
|
+
return {
|
|
72
|
+
deliveryId,
|
|
73
|
+
success: result.success,
|
|
74
|
+
messageId: result.messageId,
|
|
75
|
+
error: result.error,
|
|
76
|
+
timestamp: new Date().toISOString(),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
// Update delivery status to failed
|
|
81
|
+
await this.updateDeliveryStatus(deliveryId, {
|
|
82
|
+
status: 'failed',
|
|
83
|
+
failedAt: new Date().toISOString(),
|
|
84
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
85
|
+
retryable: error instanceof DeliveryError ? error.recoverable : false,
|
|
86
|
+
});
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Deliver response via email (Postmark)
|
|
92
|
+
*/
|
|
93
|
+
async deliverEmail(response, recipient) {
|
|
94
|
+
if (!isChannelEnabled('postmark')) {
|
|
95
|
+
return {
|
|
96
|
+
success: false,
|
|
97
|
+
error: 'Postmark not configured',
|
|
98
|
+
retryable: false,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
if (!recipient.email) {
|
|
102
|
+
return {
|
|
103
|
+
success: false,
|
|
104
|
+
error: 'No email address provided',
|
|
105
|
+
retryable: false,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
const emailFormatting = response.formatting.email;
|
|
109
|
+
if (!emailFormatting) {
|
|
110
|
+
return {
|
|
111
|
+
success: false,
|
|
112
|
+
error: 'No email formatting available',
|
|
113
|
+
retryable: false,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
// Call Postmark API
|
|
118
|
+
const postmarkResponse = await fetch('https://api.postmarkapp.com/email', {
|
|
119
|
+
method: 'POST',
|
|
120
|
+
headers: {
|
|
121
|
+
Accept: 'application/json',
|
|
122
|
+
'Content-Type': 'application/json',
|
|
123
|
+
'X-Postmark-Server-Token': config.postmark.serverToken || '',
|
|
124
|
+
},
|
|
125
|
+
body: JSON.stringify({
|
|
126
|
+
From: config.postmark.fromAddress,
|
|
127
|
+
To: recipient.email,
|
|
128
|
+
Subject: emailFormatting.subject,
|
|
129
|
+
TextBody: emailFormatting.textBody,
|
|
130
|
+
HtmlBody: emailFormatting.htmlBody,
|
|
131
|
+
ReplyTo: config.postmark.replyToAddress || config.postmark.fromAddress,
|
|
132
|
+
MessageStream: config.postmark.messageStream,
|
|
133
|
+
TrackOpens: true,
|
|
134
|
+
TrackLinks: 'HtmlOnly',
|
|
135
|
+
Tag: 'support-agent',
|
|
136
|
+
Metadata: {
|
|
137
|
+
conversationId: response.conversationId,
|
|
138
|
+
responseId: response.id,
|
|
139
|
+
},
|
|
140
|
+
}),
|
|
141
|
+
});
|
|
142
|
+
if (!postmarkResponse.ok) {
|
|
143
|
+
const errorData = await postmarkResponse.json().catch(() => ({}));
|
|
144
|
+
return {
|
|
145
|
+
success: false,
|
|
146
|
+
error: `Postmark error: ${errorData.Message || postmarkResponse.statusText}`,
|
|
147
|
+
retryable: postmarkResponse.status >= 500,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
const result = await postmarkResponse.json();
|
|
151
|
+
return {
|
|
152
|
+
success: true,
|
|
153
|
+
messageId: result.MessageID,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
return {
|
|
158
|
+
success: false,
|
|
159
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
160
|
+
retryable: true,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Deliver response via SMS (Twilio)
|
|
166
|
+
*/
|
|
167
|
+
async deliverSms(response, recipient) {
|
|
168
|
+
if (!isChannelEnabled('twilio')) {
|
|
169
|
+
return {
|
|
170
|
+
success: false,
|
|
171
|
+
error: 'Twilio not configured',
|
|
172
|
+
retryable: false,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
if (!recipient.phone) {
|
|
176
|
+
return {
|
|
177
|
+
success: false,
|
|
178
|
+
error: 'No phone number provided',
|
|
179
|
+
retryable: false,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
const smsFormatting = response.formatting.sms;
|
|
183
|
+
if (!smsFormatting) {
|
|
184
|
+
return {
|
|
185
|
+
success: false,
|
|
186
|
+
error: 'No SMS formatting available',
|
|
187
|
+
retryable: false,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
try {
|
|
191
|
+
const accountSid = config.twilio.accountSid;
|
|
192
|
+
const authToken = config.twilio.authToken;
|
|
193
|
+
const body = new URLSearchParams({
|
|
194
|
+
To: recipient.phone,
|
|
195
|
+
From: config.twilio.fromNumber || '',
|
|
196
|
+
Body: smsFormatting.body,
|
|
197
|
+
});
|
|
198
|
+
if (config.twilio.messagingServiceSid) {
|
|
199
|
+
body.set('MessagingServiceSid', config.twilio.messagingServiceSid);
|
|
200
|
+
body.delete('From');
|
|
201
|
+
}
|
|
202
|
+
const twilioResponse = await fetch(`https://api.twilio.com/2010-04-01/Accounts/${accountSid}/Messages.json`, {
|
|
203
|
+
method: 'POST',
|
|
204
|
+
headers: {
|
|
205
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
206
|
+
Authorization: `Basic ${Buffer.from(`${accountSid}:${authToken}`).toString('base64')}`,
|
|
207
|
+
},
|
|
208
|
+
body: body.toString(),
|
|
209
|
+
});
|
|
210
|
+
if (!twilioResponse.ok) {
|
|
211
|
+
const errorData = await twilioResponse.json().catch(() => ({}));
|
|
212
|
+
return {
|
|
213
|
+
success: false,
|
|
214
|
+
error: `Twilio error: ${errorData.message || twilioResponse.statusText}`,
|
|
215
|
+
retryable: twilioResponse.status >= 500,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
const result = await twilioResponse.json();
|
|
219
|
+
return {
|
|
220
|
+
success: true,
|
|
221
|
+
messageId: result.sid,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
return {
|
|
226
|
+
success: false,
|
|
227
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
228
|
+
retryable: true,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Deliver response via Slack
|
|
234
|
+
*/
|
|
235
|
+
async deliverSlack(response, recipient) {
|
|
236
|
+
if (!isChannelEnabled('slack')) {
|
|
237
|
+
return {
|
|
238
|
+
success: false,
|
|
239
|
+
error: 'Slack not configured',
|
|
240
|
+
retryable: false,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
if (!recipient.slackChannelId) {
|
|
244
|
+
return {
|
|
245
|
+
success: false,
|
|
246
|
+
error: 'No Slack channel provided',
|
|
247
|
+
retryable: false,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
const slackFormatting = response.formatting.slack;
|
|
251
|
+
if (!slackFormatting) {
|
|
252
|
+
return {
|
|
253
|
+
success: false,
|
|
254
|
+
error: 'No Slack formatting available',
|
|
255
|
+
retryable: false,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
try {
|
|
259
|
+
const slackResponse = await fetch('https://slack.com/api/chat.postMessage', {
|
|
260
|
+
method: 'POST',
|
|
261
|
+
headers: {
|
|
262
|
+
'Content-Type': 'application/json; charset=utf-8',
|
|
263
|
+
Authorization: `Bearer ${config.slack.botToken}`,
|
|
264
|
+
},
|
|
265
|
+
body: JSON.stringify({
|
|
266
|
+
channel: recipient.slackChannelId,
|
|
267
|
+
text: slackFormatting.text,
|
|
268
|
+
blocks: slackFormatting.blocks,
|
|
269
|
+
thread_ts: recipient.slackThreadTs,
|
|
270
|
+
unfurl_links: false,
|
|
271
|
+
unfurl_media: false,
|
|
272
|
+
}),
|
|
273
|
+
});
|
|
274
|
+
const result = await slackResponse.json();
|
|
275
|
+
if (!result.ok) {
|
|
276
|
+
return {
|
|
277
|
+
success: false,
|
|
278
|
+
error: `Slack error: ${result.error}`,
|
|
279
|
+
retryable: ['rate_limited', 'internal_error'].includes(result.error),
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
return {
|
|
283
|
+
success: true,
|
|
284
|
+
messageId: result.ts,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
catch (error) {
|
|
288
|
+
return {
|
|
289
|
+
success: false,
|
|
290
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
291
|
+
retryable: true,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Update delivery status
|
|
297
|
+
*/
|
|
298
|
+
async updateDeliveryStatus(deliveryId, status) {
|
|
299
|
+
await this.supabase
|
|
300
|
+
.from('support_deliveries')
|
|
301
|
+
.update({
|
|
302
|
+
status: status.status,
|
|
303
|
+
status_data: status,
|
|
304
|
+
external_message_id: status.messageId,
|
|
305
|
+
})
|
|
306
|
+
.eq('id', deliveryId);
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Retry a failed delivery with exponential backoff
|
|
310
|
+
*/
|
|
311
|
+
async retryDelivery(deliveryId, maxRetries = 3) {
|
|
312
|
+
const { data: delivery, error } = await this.supabase
|
|
313
|
+
.from('support_deliveries')
|
|
314
|
+
.select('*, support_responses(*)')
|
|
315
|
+
.eq('id', deliveryId)
|
|
316
|
+
.single();
|
|
317
|
+
if (error || !delivery) {
|
|
318
|
+
throw new DeliveryError('Delivery not found', 'email', 'preparation', {
|
|
319
|
+
context: { deliveryId },
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
if (delivery.retry_count >= maxRetries) {
|
|
323
|
+
return null;
|
|
324
|
+
}
|
|
325
|
+
// Exponential backoff
|
|
326
|
+
const backoffMs = Math.pow(2, delivery.retry_count) * 1000;
|
|
327
|
+
await new Promise((resolve) => setTimeout(resolve, backoffMs));
|
|
328
|
+
// Update retry count
|
|
329
|
+
await this.supabase
|
|
330
|
+
.from('support_deliveries')
|
|
331
|
+
.update({
|
|
332
|
+
retry_count: delivery.retry_count + 1,
|
|
333
|
+
retry_history: [
|
|
334
|
+
...(delivery.retry_history || []),
|
|
335
|
+
{
|
|
336
|
+
attempt: delivery.retry_count + 1,
|
|
337
|
+
timestamp: new Date().toISOString(),
|
|
338
|
+
},
|
|
339
|
+
],
|
|
340
|
+
})
|
|
341
|
+
.eq('id', deliveryId);
|
|
342
|
+
// Re-attempt delivery (would need full response and recipient info)
|
|
343
|
+
// This is a placeholder - actual implementation would fetch and retry
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Handle delivery status webhook (Postmark, Twilio callbacks)
|
|
348
|
+
*/
|
|
349
|
+
async handleStatusWebhook(provider, messageId, status, details) {
|
|
350
|
+
const { data: delivery } = await this.supabase
|
|
351
|
+
.from('support_deliveries')
|
|
352
|
+
.select('id')
|
|
353
|
+
.eq('external_message_id', messageId)
|
|
354
|
+
.single();
|
|
355
|
+
if (!delivery) {
|
|
356
|
+
console.warn(`Delivery not found for message: ${messageId}`);
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
const statusData = status === 'delivered'
|
|
360
|
+
? { status: 'delivered', deliveredAt: new Date().toISOString(), messageId }
|
|
361
|
+
: status === 'bounced'
|
|
362
|
+
? { status: 'bounced', bouncedAt: new Date().toISOString(), bounceType: details?.bounceType ?? 'hard_bounce' }
|
|
363
|
+
: { status: 'failed', failedAt: new Date().toISOString(), error: details?.error ?? 'Unknown', retryable: false };
|
|
364
|
+
await this.supabase
|
|
365
|
+
.from('support_deliveries')
|
|
366
|
+
.update({
|
|
367
|
+
status: statusData.status,
|
|
368
|
+
status_data: statusData,
|
|
369
|
+
})
|
|
370
|
+
.eq('id', delivery.id);
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Record engagement metrics (opens, clicks)
|
|
374
|
+
*/
|
|
375
|
+
async recordEngagement(messageId, event, details) {
|
|
376
|
+
const { data: delivery } = await this.supabase
|
|
377
|
+
.from('support_deliveries')
|
|
378
|
+
.select('id, engagement_data')
|
|
379
|
+
.eq('external_message_id', messageId)
|
|
380
|
+
.single();
|
|
381
|
+
if (!delivery) {
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
const existingData = delivery.engagement_data || {};
|
|
385
|
+
const events = existingData.events || [];
|
|
386
|
+
await this.supabase
|
|
387
|
+
.from('support_deliveries')
|
|
388
|
+
.update({
|
|
389
|
+
engagement_data: {
|
|
390
|
+
...existingData,
|
|
391
|
+
events: [
|
|
392
|
+
...events,
|
|
393
|
+
{
|
|
394
|
+
type: event,
|
|
395
|
+
timestamp: new Date().toISOString(),
|
|
396
|
+
...(details?.link && { link: details.link }),
|
|
397
|
+
},
|
|
398
|
+
],
|
|
399
|
+
[`${event}Count`]: (existingData[`${event}Count`] || 0) + 1,
|
|
400
|
+
[`first${event.charAt(0).toUpperCase() + event.slice(1)}`]: existingData[`first${event.charAt(0).toUpperCase() + event.slice(1)}`] ||
|
|
401
|
+
new Date().toISOString(),
|
|
402
|
+
},
|
|
403
|
+
})
|
|
404
|
+
.eq('id', delivery.id);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
// =============================================================================
|
|
408
|
+
// Singleton and Utility Functions
|
|
409
|
+
// =============================================================================
|
|
410
|
+
let deliveryService = null;
|
|
411
|
+
export function getDeliveryService() {
|
|
412
|
+
if (!deliveryService) {
|
|
413
|
+
deliveryService = new DeliveryService();
|
|
414
|
+
}
|
|
415
|
+
return deliveryService;
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Deliver a response
|
|
419
|
+
*/
|
|
420
|
+
export async function deliverResponse(response, channel, recipient) {
|
|
421
|
+
return getDeliveryService().deliver(response, channel, recipient);
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Handle delivery status webhook
|
|
425
|
+
*/
|
|
426
|
+
export async function handleDeliveryWebhook(provider, messageId, status, details) {
|
|
427
|
+
return getDeliveryService().handleStatusWebhook(provider, messageId, status, details);
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Record engagement event
|
|
431
|
+
*/
|
|
432
|
+
export async function recordEngagementEvent(messageId, event, details) {
|
|
433
|
+
return getDeliveryService().recordEngagement(messageId, event, details);
|
|
434
|
+
}
|
|
435
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/delivery/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LRU Cache for Embedding Queries
|
|
3
|
+
*
|
|
4
|
+
* In-memory cache with TTL support to reduce redundant embedding API calls.
|
|
5
|
+
* Stores query text -> embedding vector mappings.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Simple LRU Cache with TTL support
|
|
9
|
+
*/
|
|
10
|
+
export declare class LRUCache<K, V> {
|
|
11
|
+
private cache;
|
|
12
|
+
private readonly maxSize;
|
|
13
|
+
private readonly ttlMs;
|
|
14
|
+
constructor(maxSize?: number, ttlMs?: number);
|
|
15
|
+
/**
|
|
16
|
+
* Get a value from the cache
|
|
17
|
+
*/
|
|
18
|
+
get(key: K): V | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Set a value in the cache
|
|
21
|
+
*/
|
|
22
|
+
set(key: K, value: V, customTtlMs?: number): void;
|
|
23
|
+
/**
|
|
24
|
+
* Check if key exists and is not expired
|
|
25
|
+
*/
|
|
26
|
+
has(key: K): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Delete a key from the cache
|
|
29
|
+
*/
|
|
30
|
+
delete(key: K): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Clear all entries
|
|
33
|
+
*/
|
|
34
|
+
clear(): void;
|
|
35
|
+
/**
|
|
36
|
+
* Get current cache size
|
|
37
|
+
*/
|
|
38
|
+
get size(): number;
|
|
39
|
+
/**
|
|
40
|
+
* Remove expired entries
|
|
41
|
+
*/
|
|
42
|
+
prune(): number;
|
|
43
|
+
/**
|
|
44
|
+
* Get cache statistics
|
|
45
|
+
*/
|
|
46
|
+
getStats(): {
|
|
47
|
+
size: number;
|
|
48
|
+
maxSize: number;
|
|
49
|
+
ttlMs: number;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Specialized cache for embedding vectors
|
|
54
|
+
* Uses content hash as key to handle exact and near-duplicate queries
|
|
55
|
+
*/
|
|
56
|
+
export declare class EmbeddingCache {
|
|
57
|
+
private cache;
|
|
58
|
+
private hits;
|
|
59
|
+
private misses;
|
|
60
|
+
constructor(maxSize?: number, ttlMs?: number);
|
|
61
|
+
/**
|
|
62
|
+
* Generate a cache key from text
|
|
63
|
+
* Simple hash function for in-memory use
|
|
64
|
+
*/
|
|
65
|
+
private generateKey;
|
|
66
|
+
/**
|
|
67
|
+
* Get embedding from cache
|
|
68
|
+
*/
|
|
69
|
+
get(text: string): number[] | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* Store embedding in cache
|
|
72
|
+
*/
|
|
73
|
+
set(text: string, embedding: number[]): void;
|
|
74
|
+
/**
|
|
75
|
+
* Check if text has cached embedding
|
|
76
|
+
*/
|
|
77
|
+
has(text: string): boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Clear the cache
|
|
80
|
+
*/
|
|
81
|
+
clear(): void;
|
|
82
|
+
/**
|
|
83
|
+
* Get cache statistics
|
|
84
|
+
*/
|
|
85
|
+
getStats(): {
|
|
86
|
+
size: number;
|
|
87
|
+
hits: number;
|
|
88
|
+
misses: number;
|
|
89
|
+
hitRate: number;
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Prune expired entries
|
|
93
|
+
*/
|
|
94
|
+
prune(): number;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/embeddings/cache.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH;;GAEG;AACH,qBAAa,QAAQ,CAAC,CAAC,EAAE,CAAC;IACxB,OAAO,CAAC,KAAK,CAAwB;IACrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;gBAEnB,OAAO,GAAE,MAAa,EAAE,KAAK,GAAE,MAAe;IAM1D;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS;IAoB1B;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI;IAkBjD;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,OAAO;IAYpB;;OAEG;IACH,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,OAAO;IAIvB;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;OAEG;IACH,KAAK,IAAI,MAAM;IAcf;;OAEG;IACH,QAAQ,IAAI;QACV,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;KACf;CAOF;AAED;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,MAAM,CAAa;gBAEf,OAAO,GAAE,MAAa,EAAE,KAAK,GAAE,MAAe;IAI1D;;;OAGG;IACH,OAAO,CAAC,WAAW;IAcnB;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS;IAavC;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI;IAK5C;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAK1B;;OAEG;IACH,KAAK,IAAI,IAAI;IAMb;;OAEG;IACH,QAAQ,IAAI;QACV,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;KACjB;IAUD;;OAEG;IACH,KAAK,IAAI,MAAM;CAGhB"}
|