@peopl-health/nexus 1.5.10 → 1.6.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/CHANGELOG.md +0 -0
- package/LICENSE +0 -0
- package/MIGRATION_GUIDE.md +0 -0
- package/README.md +0 -0
- package/examples/.env.example +0 -0
- package/examples/assistants/BaseAssistant.js +0 -0
- package/examples/assistants/DoctorScheduleAssistant.js +0 -0
- package/examples/assistants/ExampleAssistant.js +0 -0
- package/examples/assistants/index.js +0 -0
- package/examples/basic-usage.js +7 -8
- package/examples/consumer-server.js +0 -0
- package/lib/adapters/BaileysProvider.js +0 -0
- package/lib/adapters/TwilioProvider.js +5 -177
- package/lib/adapters/index.js +0 -0
- package/lib/adapters/registry.js +0 -0
- package/lib/assistants/BaseAssistant.js +2 -3
- package/lib/assistants/index.js +0 -0
- package/lib/config/airtableConfig.js +0 -0
- package/lib/config/awsConfig.js +0 -0
- package/lib/config/configLoader.js +0 -0
- package/lib/config/llmConfig.js +0 -0
- package/lib/config/mongoAuthConfig.js +0 -0
- package/lib/config/runtimeConfig.js +0 -0
- package/lib/controllers/assistantController.js +0 -0
- package/lib/controllers/conversationController.js +0 -0
- package/lib/controllers/mediaController.js +0 -0
- package/lib/controllers/messageController.js +0 -0
- package/lib/controllers/templateController.js +0 -0
- package/lib/controllers/templateFlowController.js +0 -0
- package/lib/controllers/uploadController.js +0 -0
- package/lib/core/MessageProvider.js +0 -0
- package/lib/core/NexusMessaging.js +0 -0
- package/lib/core/index.js +0 -0
- package/lib/helpers/assistantHelper.js +0 -0
- package/lib/helpers/baileysHelper.js +0 -0
- package/lib/helpers/filesHelper.js +0 -0
- package/lib/helpers/llmsHelper.js +0 -0
- package/lib/helpers/mediaHelper.js +0 -0
- package/lib/helpers/mongoHelper.js +0 -0
- package/lib/helpers/qrHelper.js +0 -0
- package/lib/helpers/twilioHelper.js +0 -0
- package/lib/helpers/twilioMediaProcessor.js +0 -0
- package/lib/helpers/whatsappHelper.js +0 -0
- package/lib/index.d.ts +0 -0
- package/lib/index.js +0 -0
- package/lib/interactive/index.js +0 -0
- package/lib/interactive/registry.js +0 -0
- package/lib/interactive/twilioMapper.js +0 -0
- package/lib/models/agendaMessageModel.js +0 -0
- package/lib/models/index.js +0 -0
- package/lib/models/messageModel.js +1 -2
- package/lib/models/templateModel.js +0 -0
- package/lib/models/threadModel.js +0 -0
- package/lib/routes/index.js +0 -0
- package/lib/services/airtableService.js +0 -0
- package/lib/services/assistantService.js +0 -0
- package/lib/services/conversationService.js +0 -0
- package/lib/services/twilioService.js +0 -0
- package/lib/storage/MongoStorage.js +4 -15
- package/lib/storage/NoopStorage.js +0 -0
- package/lib/storage/index.js +0 -0
- package/lib/storage/registry.js +0 -0
- package/lib/templates/predefinedTemplates.js +0 -0
- package/lib/templates/templateStructure.js +0 -0
- package/lib/utils/dateUtils.js +0 -0
- package/lib/utils/defaultLLMProvider.js +0 -0
- package/lib/utils/errorHandler.js +0 -0
- package/lib/utils/index.js +0 -0
- package/lib/utils/logger.js +0 -0
- package/lib/utils/mediaValidator.js +0 -0
- package/lib/utils/messageParser.js +0 -0
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
File without changes
|
package/LICENSE
CHANGED
|
File without changes
|
package/MIGRATION_GUIDE.md
CHANGED
|
File without changes
|
package/README.md
CHANGED
|
File without changes
|
package/examples/.env.example
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/examples/basic-usage.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
const express = require('express');
|
|
2
|
-
require('
|
|
3
|
-
const { Nexus, setupDefaultRoutes } = require('@peopl-health/nexus');
|
|
2
|
+
const { NexusMessaging, setupDefaultRoutes } = require('@peopl-health/nexus');
|
|
4
3
|
|
|
5
4
|
const app = express();
|
|
6
5
|
app.use(express.json());
|
|
7
6
|
|
|
8
7
|
async function startServer() {
|
|
9
8
|
// Initialize Nexus with all services
|
|
10
|
-
const nexus = new
|
|
9
|
+
const nexus = new NexusMessaging();
|
|
11
10
|
|
|
12
11
|
await nexus.initialize({
|
|
13
12
|
// MongoDB connection
|
|
@@ -18,7 +17,7 @@ async function startServer() {
|
|
|
18
17
|
providerConfig: {
|
|
19
18
|
accountSid: process.env.TWILIO_ACCOUNT_SID,
|
|
20
19
|
authToken: process.env.TWILIO_AUTH_TOKEN,
|
|
21
|
-
|
|
20
|
+
phoneNumber: process.env.TWILIO_PHONE_NUMBER
|
|
22
21
|
}
|
|
23
22
|
});
|
|
24
23
|
|
|
@@ -28,7 +27,7 @@ async function startServer() {
|
|
|
28
27
|
// Add webhook endpoint for incoming messages
|
|
29
28
|
app.post('/webhook', async (req, res) => {
|
|
30
29
|
try {
|
|
31
|
-
await nexus.
|
|
30
|
+
await nexus.processIncomingMessage(req.body);
|
|
32
31
|
res.status(200).send('OK');
|
|
33
32
|
} catch (error) {
|
|
34
33
|
console.error('Webhook error:', error);
|
|
@@ -39,10 +38,10 @@ async function startServer() {
|
|
|
39
38
|
// Custom endpoint example
|
|
40
39
|
app.get('/status', (req, res) => {
|
|
41
40
|
res.json({
|
|
42
|
-
connected: nexus.
|
|
41
|
+
connected: nexus.isConnected(),
|
|
43
42
|
provider: 'twilio',
|
|
44
|
-
mongodb: nexus.
|
|
45
|
-
airtable: !!nexus.
|
|
43
|
+
mongodb: nexus.mongodb?.readyState === 1,
|
|
44
|
+
airtable: !!nexus.airtable
|
|
46
45
|
});
|
|
47
46
|
});
|
|
48
47
|
|
|
File without changes
|
|
File without changes
|
|
@@ -44,11 +44,10 @@ class TwilioProvider extends MessageProvider {
|
|
|
44
44
|
throw new Error('Twilio provider not initialized');
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
const {
|
|
47
|
+
const { to, message, fileUrl, fileType, variables, contentSid } = messageData;
|
|
48
48
|
|
|
49
49
|
const formattedFrom = this.ensureWhatsAppFormat(this.whatsappNumber);
|
|
50
|
-
const formattedTo = this.ensureWhatsAppFormat(
|
|
51
|
-
|
|
50
|
+
const formattedTo = this.ensureWhatsAppFormat(to);
|
|
52
51
|
|
|
53
52
|
if (!formattedFrom || !formattedTo) {
|
|
54
53
|
throw new Error('Invalid sender or recipient number');
|
|
@@ -61,12 +60,6 @@ class TwilioProvider extends MessageProvider {
|
|
|
61
60
|
|
|
62
61
|
// Handle template messages
|
|
63
62
|
if (contentSid) {
|
|
64
|
-
// Render template and add to messageData for storage
|
|
65
|
-
const renderedMessage = await this.renderTemplate(contentSid, variables);
|
|
66
|
-
if (renderedMessage) {
|
|
67
|
-
messageData.body = renderedMessage; // Add rendered content for storage
|
|
68
|
-
}
|
|
69
|
-
|
|
70
63
|
messageParams.contentSid = contentSid;
|
|
71
64
|
if (variables && Object.keys(variables).length > 0) {
|
|
72
65
|
const formattedVariables = {};
|
|
@@ -147,18 +140,17 @@ class TwilioProvider extends MessageProvider {
|
|
|
147
140
|
: async (payload) => await this.sendMessage(payload);
|
|
148
141
|
|
|
149
142
|
console.log('[TwilioProvider] Scheduled message created', {
|
|
150
|
-
to: scheduledMessage.code,
|
|
143
|
+
to: scheduledMessage.to || scheduledMessage.code,
|
|
151
144
|
delay,
|
|
152
145
|
hasContentSid: Boolean(scheduledMessage.contentSid)
|
|
153
146
|
});
|
|
154
147
|
|
|
155
148
|
setTimeout(async () => {
|
|
156
149
|
try {
|
|
157
|
-
|
|
158
|
-
const payload = scheduledMessage.toObject ? scheduledMessage.toObject() : { ...scheduledMessage };
|
|
150
|
+
const payload = { ...scheduledMessage };
|
|
159
151
|
delete payload.__nexusSend;
|
|
160
152
|
console.log('[TwilioProvider] Timer fired', {
|
|
161
|
-
to: payload.code,
|
|
153
|
+
to: payload.to || payload.code,
|
|
162
154
|
hasMessage: Boolean(payload.message || payload.body),
|
|
163
155
|
hasMedia: Boolean(payload.fileUrl)
|
|
164
156
|
});
|
|
@@ -319,170 +311,6 @@ class TwilioProvider extends MessageProvider {
|
|
|
319
311
|
}
|
|
320
312
|
}
|
|
321
313
|
|
|
322
|
-
/**
|
|
323
|
-
* Render template content with variables
|
|
324
|
-
* @param {string} contentSid - The Twilio content SID
|
|
325
|
-
* @param {Object} variables - The variables object with keys like "1", "2"
|
|
326
|
-
* @returns {Promise<string|null>} The rendered message content or null if not found
|
|
327
|
-
*/
|
|
328
|
-
async renderTemplate(contentSid, variables) {
|
|
329
|
-
try {
|
|
330
|
-
if (!contentSid) return null;
|
|
331
|
-
|
|
332
|
-
const template = await this.getTemplate(contentSid);
|
|
333
|
-
|
|
334
|
-
if (!template || !template.types) {
|
|
335
|
-
console.warn('[TwilioProvider] Template not found or has no types:', contentSid);
|
|
336
|
-
return null;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
// Extract text content from different template types
|
|
340
|
-
let textContent = this.extractTextFromTemplate(template);
|
|
341
|
-
|
|
342
|
-
if (!textContent) {
|
|
343
|
-
console.warn('[TwilioProvider] No text content found in template:', contentSid);
|
|
344
|
-
return null;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// Render variables if provided
|
|
348
|
-
if (variables && typeof variables === 'object' && Object.keys(variables).length > 0) {
|
|
349
|
-
return this.renderTemplateWithVariables(textContent, variables);
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
return textContent.trim();
|
|
353
|
-
} catch (error) {
|
|
354
|
-
console.error('[TwilioProvider] Error rendering template:', error.message);
|
|
355
|
-
return null;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
/**
|
|
360
|
-
* Extract text content from different template types
|
|
361
|
-
* @param {Object} template - The Twilio template object
|
|
362
|
-
* @returns {string} The extracted text content
|
|
363
|
-
*/
|
|
364
|
-
extractTextFromTemplate(template) {
|
|
365
|
-
const types = template.types || {};
|
|
366
|
-
|
|
367
|
-
// Handle plain text templates
|
|
368
|
-
if (types['twilio/text']) {
|
|
369
|
-
return types['twilio/text'].body || '';
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// Handle quick reply templates
|
|
373
|
-
if (types['twilio/quick-reply']) {
|
|
374
|
-
const quickReply = types['twilio/quick-reply'];
|
|
375
|
-
let text = quickReply.body || '';
|
|
376
|
-
|
|
377
|
-
// Add quick reply options
|
|
378
|
-
if (quickReply.actions && Array.isArray(quickReply.actions)) {
|
|
379
|
-
const options = quickReply.actions
|
|
380
|
-
.filter(action => action.title)
|
|
381
|
-
.map(action => `• ${action.title}`)
|
|
382
|
-
.join('\n');
|
|
383
|
-
if (options) {
|
|
384
|
-
text += (text ? '\n\n' : '') + options;
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
return text;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
// Handle list templates
|
|
392
|
-
if (types['twilio/list']) {
|
|
393
|
-
const list = types['twilio/list'];
|
|
394
|
-
let text = list.body || '';
|
|
395
|
-
|
|
396
|
-
// Add list items
|
|
397
|
-
if (list.items && Array.isArray(list.items)) {
|
|
398
|
-
const items = list.items
|
|
399
|
-
.filter(item => item.title)
|
|
400
|
-
.map((item, index) => `${index + 1}. ${item.title}`)
|
|
401
|
-
.join('\n');
|
|
402
|
-
if (items) {
|
|
403
|
-
text += (text ? '\n\n' : '') + items;
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
return text;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
// Handle button templates
|
|
411
|
-
if (types['twilio/button']) {
|
|
412
|
-
const button = types['twilio/button'];
|
|
413
|
-
let text = button.body || '';
|
|
414
|
-
|
|
415
|
-
// Add button options
|
|
416
|
-
if (button.actions && Array.isArray(button.actions)) {
|
|
417
|
-
const buttons = button.actions
|
|
418
|
-
.filter(action => action.title)
|
|
419
|
-
.map(action => `[${action.title}]`)
|
|
420
|
-
.join(' ');
|
|
421
|
-
if (buttons) {
|
|
422
|
-
text += (text ? '\n\n' : '') + buttons;
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
return text;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
// Handle flow templates (fallback to body)
|
|
430
|
-
if (types['twilio/flows']) {
|
|
431
|
-
return types['twilio/flows'].body || '';
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
// Handle media templates (extract caption)
|
|
435
|
-
if (types['twilio/media']) {
|
|
436
|
-
return types['twilio/media'].caption || '';
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
// Fallback: try to find any body content
|
|
440
|
-
for (const typeKey of Object.keys(types)) {
|
|
441
|
-
const type = types[typeKey];
|
|
442
|
-
if (type && typeof type === 'object' && type.body) {
|
|
443
|
-
return type.body;
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
return '';
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
/**
|
|
451
|
-
* Render template content with variables
|
|
452
|
-
* @param {string} templateBody - The template body with placeholders like {{1}}, {{2}}
|
|
453
|
-
* @param {Object} variables - The variables object with keys like "1", "2"
|
|
454
|
-
* @returns {string} The rendered message content
|
|
455
|
-
*/
|
|
456
|
-
renderTemplateWithVariables(templateBody, variables) {
|
|
457
|
-
if (!templateBody || typeof templateBody !== 'string') {
|
|
458
|
-
return '';
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
if (!variables || typeof variables !== 'object') {
|
|
462
|
-
return templateBody;
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
try {
|
|
466
|
-
let rendered = templateBody;
|
|
467
|
-
|
|
468
|
-
// Replace placeholders like {{1}}, {{2}}, etc. with variable values
|
|
469
|
-
Object.keys(variables).forEach(key => {
|
|
470
|
-
const placeholder = `{{${key}}}`;
|
|
471
|
-
const value = variables[key] || '';
|
|
472
|
-
|
|
473
|
-
// Simple string replacement - more reliable than regex for this use case
|
|
474
|
-
if (rendered.includes(placeholder)) {
|
|
475
|
-
rendered = rendered.replace(new RegExp(placeholder.replace(/[{}]/g, '\\$&'), 'g'), value);
|
|
476
|
-
}
|
|
477
|
-
});
|
|
478
|
-
|
|
479
|
-
return rendered.trim();
|
|
480
|
-
} catch (error) {
|
|
481
|
-
console.warn('[TwilioProvider] Error rendering template variables:', error.message);
|
|
482
|
-
return templateBody; // Return original template if rendering fails
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
|
|
486
314
|
/**
|
|
487
315
|
* Check template approval status using Twilio Content API helpers
|
|
488
316
|
*/
|
package/lib/adapters/index.js
CHANGED
|
File without changes
|
package/lib/adapters/registry.js
CHANGED
|
File without changes
|
|
@@ -67,7 +67,7 @@ class BaseAssistant {
|
|
|
67
67
|
this.thread = thread;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
set_replies(replies) {
|
|
71
71
|
this.replies = replies;
|
|
72
72
|
}
|
|
73
73
|
|
|
@@ -230,8 +230,7 @@ class BaseAssistant {
|
|
|
230
230
|
if (!this.lastMessages) return [];
|
|
231
231
|
return [{
|
|
232
232
|
role: 'assistant',
|
|
233
|
-
content: `Últimos mensajes para ${code}:
|
|
234
|
-
${this.lastMessages}`
|
|
233
|
+
content: `Últimos mensajes para ${code}: \n${this.lastMessages}`
|
|
235
234
|
}];
|
|
236
235
|
}
|
|
237
236
|
|
package/lib/assistants/index.js
CHANGED
|
File without changes
|
|
File without changes
|
package/lib/config/awsConfig.js
CHANGED
|
File without changes
|
|
File without changes
|
package/lib/config/llmConfig.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/lib/core/index.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/lib/helpers/qrHelper.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/lib/index.d.ts
CHANGED
|
File without changes
|
package/lib/index.js
CHANGED
|
File without changes
|
package/lib/interactive/index.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/lib/models/index.js
CHANGED
|
File without changes
|
|
@@ -68,8 +68,7 @@ async function insertMessage(values) {
|
|
|
68
68
|
reply_id: values.reply_id,
|
|
69
69
|
from_me: values.from_me,
|
|
70
70
|
processed: skipNumbers.includes(values.numero),
|
|
71
|
-
media: values.media ? values.media : null
|
|
72
|
-
content_sid: values.content_sid || null
|
|
71
|
+
media: values.media ? values.media : null
|
|
73
72
|
};
|
|
74
73
|
|
|
75
74
|
await Message.findOneAndUpdate(
|
|
File without changes
|
|
File without changes
|
package/lib/routes/index.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -66,11 +66,10 @@ class MongoStorage {
|
|
|
66
66
|
from: messageData?.from,
|
|
67
67
|
provider: messageData?.provider || 'unknown',
|
|
68
68
|
hasRaw: Boolean(messageData?.raw),
|
|
69
|
-
hasMedia: Boolean(messageData?.media || messageData?.fileUrl)
|
|
70
|
-
hasContentSid: Boolean(messageData?.contentSid)
|
|
69
|
+
hasMedia: Boolean(messageData?.media || messageData?.fileUrl)
|
|
71
70
|
});
|
|
72
71
|
const enrichedMessage = await this._enrichTwilioMedia(messageData);
|
|
73
|
-
const values = this.
|
|
72
|
+
const values = this.buildLegacyMessageValues(enrichedMessage);
|
|
74
73
|
const { insertMessage } = require('../models/messageModel');
|
|
75
74
|
await insertMessage(values);
|
|
76
75
|
console.log('[MongoStorage] Message stored', {
|
|
@@ -167,8 +166,7 @@ class MongoStorage {
|
|
|
167
166
|
return trimmed;
|
|
168
167
|
}
|
|
169
168
|
|
|
170
|
-
|
|
171
|
-
buildMessageValues(messageData = {}) {
|
|
169
|
+
buildLegacyMessageValues(messageData = {}) {
|
|
172
170
|
const numero = messageData.to || messageData.code || messageData.numero || messageData.from;
|
|
173
171
|
const rawNumero = typeof numero === 'string' ? numero : '';
|
|
174
172
|
const normalizedNumero = this.normalizeNumero(rawNumero);
|
|
@@ -177,16 +175,7 @@ class MongoStorage {
|
|
|
177
175
|
const now = new Date();
|
|
178
176
|
const timestamp = now.toISOString();
|
|
179
177
|
const nombre = messageData.nombre_whatsapp || messageData.author || messageData.fromName || runtimeConfig.get('USER_DB_MONGO') || process.env.USER_DB_MONGO || 'Nexus';
|
|
180
|
-
|
|
181
|
-
// Use message body directly (template rendering is now handled by the provider)
|
|
182
|
-
let textBody = messageData.message || messageData.body;
|
|
183
|
-
|
|
184
|
-
if (!textBody && isMedia) {
|
|
185
|
-
textBody = `[Media:${messageData.fileType || 'attachment'}]`;
|
|
186
|
-
} else if (!textBody) {
|
|
187
|
-
textBody = '';
|
|
188
|
-
}
|
|
189
|
-
|
|
178
|
+
const textBody = messageData.message || messageData.body || (messageData.contentSid ? `[Template:${messageData.contentSid}]` : isMedia ? `[Media:${messageData.fileType || 'attachment'}]` : '');
|
|
190
179
|
const providerId = messageData.messageId || messageData.sid || messageData.id || messageData._id || `pending-${now.getTime()}-${Math.floor(Math.random()*1000)}`;
|
|
191
180
|
|
|
192
181
|
const media = messageData.media || (messageData.fileUrl ? {
|
|
File without changes
|
package/lib/storage/index.js
CHANGED
|
File without changes
|
package/lib/storage/registry.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/lib/utils/dateUtils.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/lib/utils/index.js
CHANGED
|
File without changes
|
package/lib/utils/logger.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peopl-health/nexus",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "Core messaging and assistant library for WhatsApp communication platforms",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"whatsapp",
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"airtable": "^0.12.2",
|
|
74
74
|
"aws-sdk": "2.1674.0",
|
|
75
75
|
"axios": "^1.5.0",
|
|
76
|
-
"dotenv": "^16.
|
|
76
|
+
"dotenv": "^16.4.7",
|
|
77
77
|
"moment-timezone": "^0.5.43",
|
|
78
78
|
"mongoose": "^7.5.0",
|
|
79
79
|
"multer": "1.4.5-lts.1",
|
|
@@ -102,4 +102,4 @@
|
|
|
102
102
|
"publishConfig": {
|
|
103
103
|
"access": "public"
|
|
104
104
|
}
|
|
105
|
-
}
|
|
105
|
+
}
|