@peopl-health/nexus 4.2.0 → 4.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,18 +1,12 @@
|
|
|
1
1
|
const { Historial_Clinico_ID, Symptoms_ID } = require('../config/airtableConfig');
|
|
2
2
|
|
|
3
3
|
const { logger } = require('../utils/logger');
|
|
4
|
-
const { parseDate } = require('../utils/dateUtils');
|
|
5
4
|
|
|
6
5
|
const { Thread } = require('../models/threadModel');
|
|
7
|
-
const TemplateModel = require('../models/templateModel');
|
|
8
|
-
|
|
9
|
-
const { pollTemplateApproval } = require('../helpers/templateApprovalPoller');
|
|
10
6
|
|
|
11
7
|
const { getRecordByFilter } = require('../services/airtableService');
|
|
12
8
|
|
|
13
|
-
const { sendMessage
|
|
14
|
-
|
|
15
|
-
const { Template } = require('../templates/templateStructure');
|
|
9
|
+
const { sendMessage } = require('../core/NexusMessaging');
|
|
16
10
|
|
|
17
11
|
const toMap = (arr, keyFn, valFn) => arr.reduce((m, item) => {
|
|
18
12
|
const key = keyFn(item);
|
|
@@ -131,7 +125,6 @@ const processConversations = async (threads, airtableNameMap) => {
|
|
|
131
125
|
};
|
|
132
126
|
|
|
133
127
|
const startConversation = async (phoneNumber, message, name, { triggeredBy } = {}) => {
|
|
134
|
-
|
|
135
128
|
const existing = await Thread.findOne({ code: phoneNumber });
|
|
136
129
|
if (existing) {
|
|
137
130
|
const err = new Error('Conversation already exists');
|
|
@@ -139,93 +132,17 @@ const startConversation = async (phoneNumber, message, name, { triggeredBy } = {
|
|
|
139
132
|
throw err;
|
|
140
133
|
}
|
|
141
134
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const twilioContent = await template.save();
|
|
147
|
-
|
|
148
|
-
const currentDate = new Date();
|
|
149
|
-
const dateCreated = parseDate(twilioContent.dateCreated, currentDate);
|
|
150
|
-
|
|
151
|
-
await TemplateModel.create({
|
|
152
|
-
sid: twilioContent.sid,
|
|
153
|
-
name: (twilioContent.friendlyName || `template_${twilioContent.sid}`).replace(/[^a-zA-Z0-9_]/g, '_').toLowerCase(),
|
|
154
|
-
friendlyName: twilioContent.friendlyName,
|
|
155
|
-
category: 'UTILITY',
|
|
156
|
-
language: 'es',
|
|
157
|
-
status: twilioContent.status,
|
|
158
|
-
body: message,
|
|
159
|
-
variables: [],
|
|
160
|
-
components: twilioContent.components || [],
|
|
161
|
-
dateCreated,
|
|
162
|
-
lastUpdated: currentDate
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
const timestamp = Date.now().toString();
|
|
166
|
-
const randomSuffix = Math.floor(Math.random() * 1000).toString().padStart(3, '0');
|
|
167
|
-
const approvalName = `${templateName}_${timestamp}_${randomSuffix}`.toLowerCase().replace(/[^a-z0-9_]/g, '_');
|
|
168
|
-
const approvalResponse = await provider.submitForApproval(twilioContent.sid, approvalName, 'UTILITY');
|
|
169
|
-
|
|
170
|
-
const validSubmittedDate = parseDate(approvalResponse.date_created || approvalResponse.dateCreated);
|
|
171
|
-
const validUpdatedDate = parseDate(approvalResponse.date_updated || approvalResponse.dateUpdated, validSubmittedDate);
|
|
172
|
-
|
|
173
|
-
await TemplateModel.updateOne(
|
|
174
|
-
{ sid: twilioContent.sid },
|
|
175
|
-
{
|
|
176
|
-
status: 'PENDING',
|
|
177
|
-
approvalRequest: {
|
|
178
|
-
sid: approvalResponse.sid,
|
|
179
|
-
status: approvalResponse.status || 'PENDING',
|
|
180
|
-
dateSubmitted: validSubmittedDate,
|
|
181
|
-
dateUpdated: validUpdatedDate,
|
|
182
|
-
rejectionReason: approvalResponse.rejection_reason || ''
|
|
183
|
-
}
|
|
184
|
-
}
|
|
135
|
+
await Thread.findOneAndUpdate(
|
|
136
|
+
{ code: phoneNumber },
|
|
137
|
+
{ code: phoneNumber, ...(name && { nombre: name }), active: true },
|
|
138
|
+
{ upsert: true, new: true }
|
|
185
139
|
);
|
|
186
140
|
|
|
187
|
-
|
|
188
|
-
phoneNumber,
|
|
189
|
-
templateSid: twilioContent.sid,
|
|
190
|
-
approvalStatus: approvalResponse.status
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
pollTemplateApproval(twilioContent.sid, {
|
|
194
|
-
label: '[StartConversation]',
|
|
195
|
-
logContext: { phoneNumber },
|
|
196
|
-
onApproved: async (prov) => {
|
|
197
|
-
const thread = await Thread.findOneAndUpdate(
|
|
198
|
-
{ code: phoneNumber },
|
|
199
|
-
{ code: phoneNumber, ...(name && { nombre: name }), active: true },
|
|
200
|
-
{ upsert: true, new: true }
|
|
201
|
-
);
|
|
202
|
-
logger.info('[StartConversation] Thread ready', { phoneNumber, threadId: thread._id });
|
|
203
|
-
await sendMessage({ code: phoneNumber, contentSid: twilioContent.sid, variables: {}, triggeredBy: triggeredBy || null });
|
|
204
|
-
logger.info('[StartConversation] Template sent successfully', { phoneNumber, templateSid: twilioContent.sid });
|
|
205
|
-
await TemplateModel.updateOne({ sid: twilioContent.sid }, { status: 'APPROVED' });
|
|
206
|
-
try {
|
|
207
|
-
await prov.deleteTemplate(twilioContent.sid);
|
|
208
|
-
logger.info('[StartConversation] Template cleaned up', { templateSid: twilioContent.sid });
|
|
209
|
-
} catch (deleteErr) {
|
|
210
|
-
logger.warn('[StartConversation] Failed to delete template after send', { templateSid: twilioContent.sid, error: deleteErr.message });
|
|
211
|
-
}
|
|
212
|
-
},
|
|
213
|
-
onRejected: async (prov) => {
|
|
214
|
-
logger.warn('[StartConversation] Template rejected', { phoneNumber, templateSid: twilioContent.sid });
|
|
215
|
-
await TemplateModel.updateOne({ sid: twilioContent.sid }, { status: 'REJECTED' });
|
|
216
|
-
try {
|
|
217
|
-
await prov.deleteTemplate(twilioContent.sid);
|
|
218
|
-
} catch (deleteErr) {
|
|
219
|
-
logger.warn('[StartConversation] Failed to delete rejected template', { templateSid: twilioContent.sid, error: deleteErr.message });
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
});
|
|
141
|
+
const result = await sendMessage({ code: phoneNumber, body: message, triggeredBy: triggeredBy || null });
|
|
223
142
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
approvalStatus: approvalResponse.status || 'PENDING'
|
|
228
|
-
};
|
|
143
|
+
logger.info('[StartConversation] Send routed', { phoneNumber, messageId: result?.messageId, status: result?.status });
|
|
144
|
+
|
|
145
|
+
return { phoneNumber, messageId: result?.messageId, status: result?.status || null };
|
|
229
146
|
};
|
|
230
147
|
|
|
231
148
|
module.exports = {
|
package/package.json
CHANGED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
const { logger } = require('../utils/logger');
|
|
2
|
-
|
|
3
|
-
const getMessaging = () => require('../core/NexusMessaging');
|
|
4
|
-
|
|
5
|
-
const MAX_ATTEMPTS = 40;
|
|
6
|
-
const POLL_INTERVAL_MS = 15 * 60 * 1000;
|
|
7
|
-
|
|
8
|
-
function pollTemplateApproval(templateSid, { label, logContext = {}, onApproved, onRejected }) {
|
|
9
|
-
const { requireProvider } = getMessaging();
|
|
10
|
-
const provider = requireProvider();
|
|
11
|
-
|
|
12
|
-
const poll = (attempt = 0) => {
|
|
13
|
-
if (attempt >= MAX_ATTEMPTS) {
|
|
14
|
-
logger.warn(`${label} Max approval poll attempts reached, giving up`, { ...logContext, templateSid, attempts: MAX_ATTEMPTS });
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
logger.info(`${label} Scheduling approval check`, { ...logContext, templateSid, attempt, nextCheckInMs: POLL_INTERVAL_MS });
|
|
19
|
-
|
|
20
|
-
setTimeout(() => {
|
|
21
|
-
(async () => {
|
|
22
|
-
logger.info(`${label} Checking approval status`, { ...logContext, templateSid, attempt });
|
|
23
|
-
|
|
24
|
-
const status = await provider.checkApprovalStatus(templateSid);
|
|
25
|
-
const approvalStatus = status?.approvalRequest?.status?.toUpperCase();
|
|
26
|
-
|
|
27
|
-
logger.info(`${label} Approval status received`, { ...logContext, templateSid, approvalStatus, attempt });
|
|
28
|
-
|
|
29
|
-
if (approvalStatus === 'APPROVED') {
|
|
30
|
-
await onApproved(provider);
|
|
31
|
-
} else if (approvalStatus === 'REJECTED') {
|
|
32
|
-
if (onRejected) {
|
|
33
|
-
await onRejected(provider);
|
|
34
|
-
} else {
|
|
35
|
-
logger.warn(`${label} Template rejected`, { ...logContext, templateSid });
|
|
36
|
-
try {
|
|
37
|
-
await provider.deleteTemplate(templateSid);
|
|
38
|
-
logger.info(`${label} Rejected template deleted`, { ...logContext, templateSid });
|
|
39
|
-
} catch (deleteErr) {
|
|
40
|
-
logger.warn(`${label} Failed to delete rejected template`, { ...logContext, templateSid, error: deleteErr.message });
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
} else {
|
|
44
|
-
logger.info(`${label} Still pending, will retry`, { ...logContext, templateSid, approvalStatus, attempt });
|
|
45
|
-
poll(attempt + 1);
|
|
46
|
-
}
|
|
47
|
-
})().catch((err) => {
|
|
48
|
-
logger.error(`${label} Error during approval poll`, { ...logContext, templateSid, error: err.message, attempt });
|
|
49
|
-
if (attempt + 1 < MAX_ATTEMPTS) {
|
|
50
|
-
poll(attempt + 1);
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
}, POLL_INTERVAL_MS);
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
poll();
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
module.exports = { pollTemplateApproval };
|